# 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
}
```