---
# System prepended metadata

title: R&D `gorm`

---

# R&D `gorm` 
## Get 
```bash=
$ go get -u gorm.io/gorm
```

## Issue When Running Examples 
### Error
```bash=
# github.com/mattn/go-sqlite3
cgo: exec gcc: exec: "gcc": executable file not found in %PATH%
```
### Solution
```bash=
choco install mingw -y
```

## Basic
### Initiation
```go=
db, err := gorm.Open(sqlite.Open("some.db"),
        &gorm.config{})
```
### Migration
```go=
type A struct{

}

db.AutoMigrate(&A{})

```
### Create
```go=
a := &A{...data}
db.Create(a)
```

### Delete
```go=
db.Where("field/coolumn",value).Delete(&A{})
```

### Update
```go=
db.Where("field/coolumn",value).Update("field/column",value)
```

### Relation - Belongs To
```go=
type Parent struct {
	gorm.Model
	Name string
}

type Child struct {
	gorm.Model
	Name     string
	ParentID uint
	Parent   *Parent `gorm:"foreignKey:ParentID"`
}
```

### Preloading
```go=
type A struct{
    ....
    BID....
    B *B
}

type B struct{
    ....
    
}

a := &A{}
db.Preload("B").Where(.....).Find(a)
```

### Custom Table Name
```go=
// need to implement schema.Tabler interface

type A struct{
.....
}

func (a *A) TableName() string{
    return "A"
}
```

## From DB To Struct
I couldn't find any direct information on how gorm(gorm.io) uses database to generate struct, but found a library that does the job. It generates struct from sqlite3 database attaches tagging like `gorm:""...`, also there are other functionalities. Such as json tagging, creating http server and so on...

### Install 
```bash=
go get -u github.com/smallnest/gen
```

This will download the executable.

### Command 
```bash=
gen --sqltype=sqlite3 --connstr "./test.db" --gorm --out ./example --database main
```

This will generate some files in the example directory.

### Experiment 
This was my original struct:
```go=
type User struct {
	gorm.Model
	ID string 
	UserName string 
	Email string
}
```
- After doing Database operations, I have a `test.db` database file.
- Then I ran the command
- An `example` directory was created
- Inside it , there was 2 files, one `model_base.go` which I need to look deeper, it has Database Actions, Table Information, Column/Field structure ....
// Sample : 
```go=
package model

import "fmt"

// Action CRUD actions
type Action int32

var (
	// Create action when record is created
	Create = Action(0)

	// RetrieveOne action when a record is retrieved from db
	RetrieveOne = Action(1)

	// RetrieveMany action when record(s) are retrieved from db
	RetrieveMany = Action(2)

	// Update action when record is updated in db
	Update = Action(3)

	// Delete action when record is deleted in db
	Delete = Action(4)

	// FetchDDL action when fetching ddl info from db
	FetchDDL = Action(5)

	tables map[string]*TableInfo
)

func init() {
	tables = make(map[string]*TableInfo)

	tables["users"] = usersTableInfo
}

// String describe the action
func (i Action) String() string {
	switch i {
	case Create:
		return "Create"
	case RetrieveOne:
		return "RetrieveOne"
	case RetrieveMany:
		return "RetrieveMany"
	case Update:
		return "Update"
	case Delete:
		return "Delete"
	case FetchDDL:
		return "FetchDDL"
	default:
		return fmt.Sprintf("unknown action: %d", int(i))
	}
}

// Model interface methods for database structs generated
type Model interface {
	TableName() string
	BeforeSave() error
	Prepare()
	Validate(action Action) error
	TableInfo() *TableInfo
}

// TableInfo describes a table in the database
type TableInfo struct {
	Name    string        `json:"name"`
	Columns []*ColumnInfo `json:"columns"`
}

// ColumnInfo describes a column in the database table
type ColumnInfo struct {
	Index              int    `json:"index"`
	GoFieldName        string `json:"go_field_name"`
	GoFieldType        string `json:"go_field_type"`
	JSONFieldName      string `json:"json_field_name"`
	ProtobufFieldName  string `json:"protobuf_field_name"`
	ProtobufType       string `json:"protobuf_field_type"`
	ProtobufPos        int    `json:"protobuf_field_pos"`
	Comment            string `json:"comment"`
	Notes              string `json:"notes"`
	Name               string `json:"name"`
	Nullable           bool   `json:"is_nullable"`
	DatabaseTypeName   string `json:"database_type_name"`
	DatabaseTypePretty string `json:"database_type_pretty"`
	IsPrimaryKey       bool   `json:"is_primary_key"`
	IsAutoIncrement    bool   `json:"is_auto_increment"`
	IsArray            bool   `json:"is_array"`
	ColumnType         string `json:"column_type"`
	ColumnLength       int64  `json:"column_length"`
	DefaultValue       string `json:"default_value"`
}

// GetTableInfo retrieve TableInfo for a table
func GetTableInfo(name string) (*TableInfo, bool) {
	val, ok := tables[name]
	return val, ok
}

```
- Another file was `users.go`, In which the Users struct can be seen as it was generated.
// Sample : 
```go=
package model

import (
	"database/sql"
	"time"

	"github.com/guregu/null"
	"github.com/satori/go.uuid"
)

var (
	_ = time.Second
	_ = sql.LevelDefault
	_ = null.Bool{}
	_ = uuid.UUID{}
)

/*
DB Table Details
-------------------------------------


CREATE TABLE `users` (`id` text,`created_at` datetime,`updated_at` datetime,`deleted_at` datetime,`user_name` text,`email` text,PRIMARY KEY (`id`))

JSON Sample
-------------------------------------
{    "id": "FuFucxUKhGIeGEGBssVmIfBIt",    "created_at": "2216-08-15T03:54:05.076014368+06:00",    "updated_at": "2105-11-06T03:36:23.232552451+06:00",    "deleted_at": "2175-04-06T13:42:14.949882557+06:00",    "user_name": "NsTIHILujbHtVWZPZJGYfjepV",    "email": "YPGuOkqDrSvZfSRHUgauXZLcM"}



*/

// Users struct is a row record of the users table in the main database
type Users struct {
	//[ 0] id                                             text                 null: false  primary: true   isArray: false  auto: false  col: text            len: -1      default: []
	ID string `gorm:"primary_key;column:id;type:text;" json:"id"`
	//[ 1] created_at                                     datetime             null: true   primary: false  isArray: false  auto: false  col: datetime        len: -1      default: []
	CreatedAt time.Time `gorm:"column:created_at;type:datetime;" json:"created_at"`
	//[ 2] updated_at                                     datetime             null: true   primary: false  isArray: false  auto: false  col: datetime        len: -1      default: []
	UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;" json:"updated_at"`
	//[ 3] deleted_at                                     datetime             null: true   primary: false  isArray: false  auto: false  col: datetime        len: -1      default: []
	DeletedAt time.Time `gorm:"column:deleted_at;type:datetime;" json:"deleted_at"`
	//[ 4] user_name                                      text                 null: true   primary: false  isArray: false  auto: false  col: text            len: -1      default: []
	UserName sql.NullString `gorm:"column:user_name;type:text;" json:"user_name"`
	//[ 5] email                                          text                 null: true   primary: false  isArray: false  auto: false  col: text            len: -1      default: []
	Email sql.NullString `gorm:"column:email;type:text;" json:"email"`
}

var usersTableInfo = &TableInfo{
	Name: "users",
	Columns: []*ColumnInfo{

		&ColumnInfo{
			Index:              0,
			Name:               "id",
			Comment:            ``,
			Notes:              ``,
			Nullable:           false,
			DatabaseTypeName:   "text",
			DatabaseTypePretty: "text",
			IsPrimaryKey:       true,
			IsAutoIncrement:    false,
			IsArray:            false,
			ColumnType:         "text",
			ColumnLength:       -1,
			GoFieldName:        "ID",
			GoFieldType:        "string",
			JSONFieldName:      "id",
			ProtobufFieldName:  "id",
			ProtobufType:       "string",
			ProtobufPos:        1,
		},

		&ColumnInfo{
			Index:              1,
			Name:               "created_at",
			Comment:            ``,
			Notes:              ``,
			Nullable:           true,
			DatabaseTypeName:   "datetime",
			DatabaseTypePretty: "datetime",
			IsPrimaryKey:       false,
			IsAutoIncrement:    false,
			IsArray:            false,
			ColumnType:         "datetime",
			ColumnLength:       -1,
			GoFieldName:        "CreatedAt",
			GoFieldType:        "time.Time",
			JSONFieldName:      "created_at",
			ProtobufFieldName:  "created_at",
			ProtobufType:       "google.protobuf.Timestamp",
			ProtobufPos:        2,
		},

		&ColumnInfo{
			Index:              2,
			Name:               "updated_at",
			Comment:            ``,
			Notes:              ``,
			Nullable:           true,
			DatabaseTypeName:   "datetime",
			DatabaseTypePretty: "datetime",
			IsPrimaryKey:       false,
			IsAutoIncrement:    false,
			IsArray:            false,
			ColumnType:         "datetime",
			ColumnLength:       -1,
			GoFieldName:        "UpdatedAt",
			GoFieldType:        "time.Time",
			JSONFieldName:      "updated_at",
			ProtobufFieldName:  "updated_at",
			ProtobufType:       "google.protobuf.Timestamp",
			ProtobufPos:        3,
		},

		&ColumnInfo{
			Index:              3,
			Name:               "deleted_at",
			Comment:            ``,
			Notes:              ``,
			Nullable:           true,
			DatabaseTypeName:   "datetime",
			DatabaseTypePretty: "datetime",
			IsPrimaryKey:       false,
			IsAutoIncrement:    false,
			IsArray:            false,
			ColumnType:         "datetime",
			ColumnLength:       -1,
			GoFieldName:        "DeletedAt",
			GoFieldType:        "time.Time",
			JSONFieldName:      "deleted_at",
			ProtobufFieldName:  "deleted_at",
			ProtobufType:       "google.protobuf.Timestamp",
			ProtobufPos:        4,
		},

		&ColumnInfo{
			Index:              4,
			Name:               "user_name",
			Comment:            ``,
			Notes:              ``,
			Nullable:           true,
			DatabaseTypeName:   "text",
			DatabaseTypePretty: "text",
			IsPrimaryKey:       false,
			IsAutoIncrement:    false,
			IsArray:            false,
			ColumnType:         "text",
			ColumnLength:       -1,
			GoFieldName:        "UserName",
			GoFieldType:        "sql.NullString",
			JSONFieldName:      "user_name",
			ProtobufFieldName:  "user_name",
			ProtobufType:       "string",
			ProtobufPos:        5,
		},

		&ColumnInfo{
			Index:              5,
			Name:               "email",
			Comment:            ``,
			Notes:              ``,
			Nullable:           true,
			DatabaseTypeName:   "text",
			DatabaseTypePretty: "text",
			IsPrimaryKey:       false,
			IsAutoIncrement:    false,
			IsArray:            false,
			ColumnType:         "text",
			ColumnLength:       -1,
			GoFieldName:        "Email",
			GoFieldType:        "sql.NullString",
			JSONFieldName:      "email",
			ProtobufFieldName:  "email",
			ProtobufType:       "string",
			ProtobufPos:        6,
		},
	},
}

// TableName sets the insert table name for this struct type
func (u *Users) TableName() string {
	return "users"
}

// BeforeSave invoked before saving, return an error if field is not populated.
func (u *Users) BeforeSave() error {
	return nil
}

// Prepare invoked before saving, can be used to populate fields etc.
func (u *Users) Prepare() {
}

// Validate invoked before performing action, return an error if field is not populated.
func (u *Users) Validate(action Action) error {
	return nil
}

// TableInfo return table meta data
func (u *Users) TableInfo() *TableInfo {
	return usersTableInfo
}

```