DEV Community

Cover image for Go-GORM: CRUD basico + Postgres Docker (Parte 1).
Carlos Andres Lopez
Carlos Andres Lopez

Posted on

Go-GORM: CRUD basico + Postgres Docker (Parte 1).

Objetivo principal:

Implementar las operaciones básicas sobre una base de datos relacional empleando una base de datos ejecutandose en un contenedor.

Objetivos especificos:

  • Crear contenedor Docker con Postgres
  • Conectarse a la base de datos en Docker
  • Implementar adición de datos (Create)
  • Implementar consulta de datos (Read)
  • Implementar actualización de datos (Update)
  • Implementar eliminación de datos (Delete)

Introduccion:

Se inicia con un modelo de tablas que describe la aridad y se empelará para crear los modelos implementados mediante la librería GORM (Go Object Relational Mapping) y una base de datos relacional, para este ejemplo PostgreSQL.

Descripcion del problema:

Se requiere registrar la informacion de los clientes y los pedidos que realizan.

MER para el ejemplo

Preparacion.

Se crea carpeta de trabajo pedidos_test y dentro de ella se crea la carpeta /app. Además creamos los archivos para de soporte del proyecto .gitignore, Makefile, docker-compose.yml, .env y README.md.

Luego iniciamos el repositorio git y con eso completamos la estructura del proyecto.

Directorio de proyecto

Base de datos.

Si bien es mas fácil trabajar con una base de datos mas sencilla como sqlite, se implmentará un contenedor que nos permitirá a futuro emplear este proyecto base para crear otros proyectos y abordar diferentes enfoques.

Este es un codigo basico del contenedor que ejecuta el servidor postgres, que se encuentra en el archivo docker-compose.yml.

volumes:
    pg-pedidos:

services:
    postgres-pedidos-service:
        image: postgres:16
        environment:
            POSTGRES_USER: ${DB_USER}
            POSTGRES_PASSWORD: ${DB_PASSWORD}
            POSTGRES_DB: ${DB_NAME}
        ports:
          - "5432:5432" 
        volumes:
            - pg-pedidos:/var/lib/postgresql/data
        healthcheck:
            test: [ "CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}" ]
            interval: 10s
            timeout: 5s
            retries: 6
        restart: unless-stopped
Enter fullscreen mode Exit fullscreen mode

El archivo Makefile puede inicializarse desde ahora pero mas adelante será modificado para gestionar la compilación de la aplicación en Go. Este es el archivo Makefile inicial.

up:
    @echo "Iniciando imagen docker.."
    docker compose up -d
    @echo "Imagenes docker iniciadas!"

down:
    @echo "Deteniendo imagenes docker"
    docker compose down 
    @echo "Hecho!"
Enter fullscreen mode Exit fullscreen mode

Esto nos ayudará a gestionar facilmente el codigo y el contenedor en la medida en que progresamos o complejizamos nuestros códigos.

Se deben agregar finalmente las credenciales, las cuales estarán en el archivo .env, estas serán requeridas en varias instacias del ejercicio.

DB_HOST=localhost
DB_PORT=5432
DB_USER=adminapp
DB_PASSWORD=verysecret
DB_NAME=pedidos
Enter fullscreen mode Exit fullscreen mode

Con esto pasamos a probar la ejecución del contenedor y la base de datos, para ello en la terminal ejecutamos el comando make up, el cual levnata el servicio.

Terminal ejecutando make up

Se puede observar que el servidor se ejecuta (uso podman desktop para observarlo mediante una interfaz grafica) y se verifica que esta corriendo.

Podman desktop mostrando servicio

Aplicacion en Go

A continuación me posiciono en la carpeta app e inicializo el proyecto en go y creo el archivo principal

go mod init add_pedidos
Enter fullscreen mode Exit fullscreen mode
touch main.go
Enter fullscreen mode Exit fullscreen mode

Lo siguiente es importar las librerias de GORM necesarias, la librería GORM y el manejadores (driver) de postgres y la librería necesaria para leer las variables de entorno.

go get -u gorm.io/gorm \
go get -u gorm.io/driver/postgres \
go get -u github.com/joho/godotenv
Enter fullscreen mode Exit fullscreen mode

Se puede encontrar en la documentacion del paquete gorm los manejadores para diversas bases de datos.

Se debe crear una carpeta que contendrá la definicion de las tablas (modelo de datos) llamada modelo_app.go y la carpeta /db que contendra el codigo de conexion con la base de datos dblib_pg.go.

Directorio de /app


package models

import (
    "time"

    "gorm.io/gorm"
)

type Cliente struct {
    Nombre1       string     // Cadena obligatoria
    Nombre2       *string    // Cadena que puede ser vacia
    Apellido1     string     // Cadena obligatoria
    Apellido2     *string    // Cadena que puede ser vacia
    TipoDocumento string     // Cadena obligatoria
    Documento     string     `gorm:"primaryKey;not null"`
    CreatedAt     time.Time  // Gestionada automaticamente por GORM al crear registro
    UpdatedAt     time.Time  // Gestionada automaticamente por GORM al actualizar registro
    Enabled       bool       // Indicador de registro activo
    Contactos     []Contacto `gorm:"foreignkey:ClienteDoc;references:Documento"`
}

type Contacto struct {
    gorm.Model
    TipoDato   string    // Tipo de registro, puede ser correo, telefono, etc
    Dato       string    // El valor registrado
    CreatedAt  time.Time // Gestionada automaticamente por GORM al crear registro
    UpdatedAt  time.Time // Gestionada automaticamente por GORM al actualizar registro
    Enabled    bool      // Indicador de registro activo
    ClienteDoc string    //llave foranea IDCliente
}
Enter fullscreen mode Exit fullscreen mode
package db

import (
    "fmt"
    "os"

    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

var Database *gorm.DB

func Connect() {
    var err error

    dbHost := os.Getenv("DB_HOST")
    dbPuerto := os.Getenv("DB_PORT")
    dbUsuario := os.Getenv("DB_USER")
    dbPw := os.Getenv("DB_PASSWORD")
    dbNombre := os.Getenv("DB_NAME")

    fmt.Println("Conectando con " + dbHost + ":" + dbPuerto)
    dsn := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", dbUsuario, dbPw, dbHost, dbPuerto, dbNombre)
    Database, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})

    if err != nil {
        fmt.Printf("Error en conexion a la base de datos")
        panic(err)
    } else {
        fmt.Println("Conexion con base de datos exitosa!")
    }
}

Enter fullscreen mode Exit fullscreen mode

Finalmente se integra desde el programa principal main.go la conexion a la base de datos, la creacion de las tablas y la prueba de registro de datos.

package main

import (
    "app_pedidos/db"
    "app_pedidos/models"
    "context"
    "log"

    "github.com/joho/godotenv"
    "gorm.io/gorm"
)

func main() {
    loadEnv()
    db.Connect()
    db.Database.AutoMigrate(&models.Cliente{})
    db.Database.AutoMigrate(&models.Contacto{})
    NuevoCliente()
    NuevoContacto()
}

func loadEnv() {
    err := godotenv.Load("../.env")
    if err != nil {
        log.Fatal("Error encontrando .env file")
    }
}

func NuevoCliente() {
    cliente := models.Cliente{
        Nombre1:       "Juan",
        Apellido1:     "Perez",
        TipoDocumento: "DNI",
        Documento:     "2012",
    }

    ctx := context.Background()
    err := gorm.G[models.Cliente](db.Database).Create(ctx, &cliente)

    if err != nil {
        panic(err)
    } else {
        log.Println("Cliente creado correctamente")
    }

}

func NuevoContacto() {
    contacto := models.Contacto{
        TipoDato:   "correo",
        Dato:       "jaun@test.com",
        ClienteDoc: "2012",
    }

    ctx := context.Background()
    err := gorm.G[models.Contacto](db.Database).Create(ctx, &contacto)

    if err != nil {
        panic(err)
    } else {
        log.Println("Contacto creado correctamente")
    }

}
Enter fullscreen mode Exit fullscreen mode

Ejecutar codigo del programa

Se debe ir a la carpeta /app y alli ejecutar el programa principal con el comando go run main.go

Terminal ejecutando codigo go

Esto crea la conexion a la base de datos, crea las tablas y adiciona registros basicos de clientes y contactos.

Se puede observar que en la base de datos han quedado registrados los valores del ejemplo.

DBeaver consulta clientes

DBeaver consulta contactos

Este es un ejemplo basico de implmenetacion, en la segunda parte se completará el ejercicio completando la actualización y la consulta de registros.

Hasta pronto!

Top comments (0)