Skip to content

1995parham-teaching/gorm-sample

Repository files navigation

GORM sample


GitHub Workflow Status (with event)

Introduction

Golang doesn't have many ORMs and one the famous one is GORM. Here we want to demonstrate some of its features using a very simple application.

Also, using GORM's AutoMigrate feature is not suitable for production because you cannot find out what is going to be changed on each commit. Atlas can help you with this.

Atlas works based on its configuration defined in atlas.hcl. You can apply migrations with

atlas migrate apply --env local

and see the differences with

atlas migrate diff --env local

GORM

Here is the official GORM package:

The followings are GORM drivers for popular databases:

In the following code we create connection using GORM and have zap as our logger:

import (
 "gorm.io/gorm"
 "gorm.io/driver/postgres"
 "moul.io/zapgorm2"
)

func main() {
 logger, err := zap.NewDevelopment()
 if err != nil {
  logger = zap.NewNop()
 }

 db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
  Logger: zapgorm2.New(logger),
 })
}
type User struct {
 ID uint
 FirstName string

 CreatedAt time.Time
 DeletedAt time.Time
}


db.Where("name = ?", "parham").Last()
db.Where("name = ?", "parham").First()
db.Where("name = ?", "parham").Find()
  • User (structure): plural snake-case as table name
  • ID (field): primary-key by default, please pay attention
  • FirstName (field): snake-case as column name

Hooks as methods on model.

JSON with SQL

You can also create custom JSON based data-types with the following example:

// JSONMap defiend JSON data type, need to implements driver.Valuer, sql.Scanner interface
type JSONMap map[string]interface{}

// Value return json value, implement driver.Valuer interface
func (m JSONMap) Value() (driver.Value, error) {
  if m == nil {
    return nil, nil
  }
  ba, err := m.MarshalJSON()
  return string(ba), err
}

// Scan scan value into Jsonb, implements sql.Scanner interface
func (m *JSONMap) Scan(val interface{}) error {
  var ba []byte
  switch v := val.(type) {
  case []byte:
    ba = v
  case string:
    ba = []byte(v)
  default:
    return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", val))
  }
  t := map[string]interface{}{}
  err := json.Unmarshal(ba, &t)
  *m = JSONMap(t)
  return err
}

// MarshalJSON to output non base64 encoded []byte
func (m JSONMap) MarshalJSON() ([]byte, error) {
  if m == nil {
    return []byte("null"), nil
  }
  t := (map[string]interface{})(m)
  return json.Marshal(t)
}

// UnmarshalJSON to deserialize []byte
func (m *JSONMap) UnmarshalJSON(b []byte) error {
  t := map[string]interface{}{}
  err := json.Unmarshal(b, &t)
  *m = JSONMap(t)
  return err
}

// GormDataType gorm common data type
func (m JSONMap) GormDataType() string {
  return "jsonmap"
}

// GormDBDataType gorm db data type
func (JSONMap) GormDBDataType(db *gorm.DB, field *schema.Field) string {
  switch db.Dialector.Name() {
  case "sqlite":
    return "JSON"
  case "mysql":
    return "JSON"
  case "postgres":
    return "JSONB"
  }
  return ""
}

About

GORM object relational mapper sample

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published