Saltar al contenido

Cheatsheet de GORM en Go

Una colección de snippets de GORM que tengo a mano cuando arranco un proyecto en Go — instalación, modelos, validaciones, relaciones many-to-many, hooks y consultas más comunes.

3 min de lectura
  • go
  • gorm
  • snippets

Este artículo se escribió originalmente en 2021. Los snippets siguen funcionando con GORM v2; si estás en una versión más nueva, revisa la documentación oficial para confirmar la API.

Esta es una colección de snippets de GORM que suelo usar dentro de mis proyectos personales. La lista va a ir creciendo conforme descubra cosas nuevas. Puedes revisar la documentación completa en gorm.io.

¿Cómo instalar GORM?

go get gorm.io/gorm

¿Cómo actualizar GORM?

Similar a la instalación pero con el flag -u (update):

go get -u gorm.io/gorm

Crear un modelo simple

package models
 
import (
  "gorm.io/gorm"
)
 
type Article struct {
  gorm.Model
  Title string
}

Crear tablas y correr migraciones (AutoMigrate)

package models
 
import (
  "fmt"
 
  "gorm.io/driver/postgres"
  "gorm.io/gorm"
)
 
type User struct {
  gorm.Model
  Username string
  Email    string `gorm:"unique" binding:"required"`
}
 
// dbDsn = postgresql://postgres_user:postgres_pass@database:5432/my-app
func SetupModels(dbDsn string) *gorm.DB {
  db, err := gorm.Open(postgres.Open(dbDsn), &gorm.Config{})
  if err != nil {
    fmt.Println(err)
    panic("Failed to load the database")
  }
 
  db.AutoMigrate(
    &User{},
  )
 
  return db
}

CRUD básico

package main
 
import (
  "gorm.io/gorm"
)
 
type Article struct {
  gorm.Model
  Title string
}
 
// create
article := Article{ Title: "My new article" }
db.Create(&article)
 
// get all
articles := []Article{}
db.Find(&articles)
 
// get one
id := 1
db.First(&article, id)
 
// update
article.Title = "Article title updated!"
db.Save(&article)
 
// delete
db.Delete(&article)
db.Where("id = ?", "2").Delete(&article)

Validaciones a nivel de campo

Campo requerido:

package models
 
import (
  "gorm.io/gorm"
)
 
type Article struct {
  gorm.Model
  Title            string `binding:"required"`
  ShortDescription string `binding:"required"`
}

Campo único:

package models
 
import (
  "gorm.io/gorm"
)
 
type User struct {
  gorm.Model
  Email string `gorm:"unique" binding:"required"`
}

Puedes revisar otros field tags aquí.

Relación Many-to-Many con referencia mutua

El nombre de la tabla intermedia será article_categories.

package models
 
import (
  "gorm.io/gorm"
)
 
type Article struct {
  gorm.Model
  Categories []*Category `gorm:"many2many:article_categories"`
}
 
type Category struct {
  gorm.Model
  Articles []*Article `gorm:"many2many:article_categories"`
}

Cargar datos relacionados (Eager Loading)

Tomando como ejemplo la relación many-to-many anterior, podemos traer los artículos junto con sus categorías así:

articles := []models.Article{}
db.Preload("Categories").Find(&articles)

Crear un registro many-to-many sin crear sus asociados (Skip Auto Create/Update)

Para relaciones many-to-many, GORM hará un upsert (update o insert si el registro no existe) antes de crear la fila en la tabla intermedia. Para saltarse ese paso podemos usar Omit:

article := models.Article{ Title: "My new article" }
category := models.Category{ ID: 1 } // ya existe en la base de datos
article.Categories = append(article.Categories, category)
 
r := db.Omit("Categories.*").Create(&article)

En este ejemplo sabemos que la categoría con ID 1 ya existe, por lo tanto no queremos que GORM intente crearla otra vez. Solo queremos asociar el nuevo artículo con esa categoría.

Obtener un registro por id (GetById)

Hay varias formas. Usando First:

article := models.Article{}
 
db.First(&article, 10)
db.First(&article, "10")
db.First(&article, "id = ?", "10")

Usando Where:

article := models.Article{}
 
db.Where("id = ?", id).First(&article)

Ordenar por un campo (OrderBy)

Acá ordenamos por la columna created_at de la tabla articles:

articles := []models.Article{}
db.Order("created_at desc").Find(&articles)
db.Order("created_at asc").Find(&articles)

Contar registros (Count)

var count int64
db.Model(&models.Article{}).Count(&count)

Verificar si el registro fue encontrado (ErrRecordNotFound)

import (
  "errors"
  "fmt"
 
  "gorm.io/gorm"
)
 
name := "design"
category := models.Category{}
 
r := db.Where("name = ?", name).First(&category)
 
if r.Error != nil {
  if errors.Is(r.Error, gorm.ErrRecordNotFound) {
    fmt.Printf("category with name %s doesn't exist", name)
  }
}

Modificar el contenido antes de guardar (BeforeCreate hook)

package models
 
import (
  "fmt"
 
  "github.com/gosimple/slug"
  "gorm.io/gorm"
)
 
type Category struct {
  gorm.Model
  Name string
  Slug string
  Url  string
}
 
func (c *Category) BeforeCreate(tx *gorm.DB) error {
  slg := slug.Make(c.Name)
  url := fmt.Sprintf("/%s/", slg)
 
  c.Slug = slg
  c.Url = url
 
  return nil
}

¡Eso es todo por ahora! Si encuentro snippets nuevos que valga la pena guardar, los voy sumando.