diff --git a/go.mod b/go.mod index 159394d4..a1cca8b9 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( golang.org/x/crypto v0.14.0 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/sys v0.14.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.15.0 // indirect gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c // indirect gorm.io/hints v1.1.0 // indirect diff --git a/main_test.go b/main_test.go index 60a388f7..b980fb86 100644 --- a/main_test.go +++ b/main_test.go @@ -11,10 +11,26 @@ import ( func TestGORM(t *testing.T) { user := User{Name: "jinzhu"} - DB.Create(&user) + if err := DB.Create(&user).Error; err != nil { + t.Fatal(err) + } + + var st2 User + if err := DB.First(&st2, 1).Error; err != nil { + t.Fatal(err) + } + + if st2.ID != 1 { + t.Fatalf("expected ID 1, got %d", st2.ID) + } + + st2.Name = "new User" + if err := DB.Save(&st2).Error; err != nil { + t.Fatal(err) + } - var result User - if err := DB.First(&result, user.ID).Error; err != nil { - t.Errorf("Failed, got error: %v", err) + var st3 User + if err := DB.First(&st3, 1).Error; err != nil { + t.Fatal(err) } } diff --git a/models.go b/models.go index 692a6842..66774144 100644 --- a/models.go +++ b/models.go @@ -2,9 +2,12 @@ package main import ( "database/sql" + "database/sql/driver" + "fmt" "time" "gorm.io/gorm" + "gorm.io/gorm/schema" ) // User has one `Account` (has one), many `Pets` (has many) and `Toys` (has many - polymorphic) @@ -12,21 +15,10 @@ import ( // He speaks many languages (many to many) and has many friends (many to many - single-table) // His pet also has one Toy (has one - polymorphic) type User struct { - gorm.Model + ID uint `gorm:"primarykey"` Name string - Age uint - Birthday *time.Time - Account Account - Pets []*Pet - Toys []Toy `gorm:"polymorphic:Owner"` - CompanyID *int - Company Company - ManagerID *uint - Manager *User - Team []User `gorm:"foreignkey:ManagerID"` - Languages []Language `gorm:"many2many:UserSpeak"` - Friends []*User `gorm:"many2many:user_friends"` - Active bool + CreatedAt Time `gorm:"not null"` + UpdatedAt Time `gorm:"not null"` } type Account struct { @@ -58,3 +50,68 @@ type Language struct { Code string `gorm:"primarykey"` Name string } + +type Time struct { + date time.Time +} + +func NewTime(year, month, day, hour, min, sec int) Time { + return Time{ + date: time.Date(year, time.Month(month), day, hour, min, sec, 0, time.UTC), + } +} + +// GormDataType returns gorm common data type. This type is used for the field's column type. +func (Time) GormDataType() string { + return "time" +} + +// GormDBDataType returns gorm DB data type based on the current using database. +func (Time) GormDBDataType(db *gorm.DB, field *schema.Field) string { + switch db.Dialector.Name() { + case "mysql": + return "TIME" + case "postgres": + return "TIME" + case "sqlserver": + return "TIME" + case "sqlite": + return "TEXT" + default: + return "" + } +} + +// Scan implements sql.Scanner interface and scans value into Time, +func (t *Time) Scan(src interface{}) error { + switch v := src.(type) { + case []byte: + return t.setFromString(string(v)) + case string: + return t.setFromString(v) + case time.Time: + t.setFromTime(v) + default: + return fmt.Errorf("failed to scan value: %v", v) + } + + return nil +} + +func (t *Time) setFromString(str string) error { + time, err := time.Parse(time.DateTime, str) + if err != nil { + return err + } + t.date = time + return nil +} + +func (t *Time) setFromTime(src time.Time) { + *t = NewTime(src.Year(), int(src.Month()), src.Day(), src.Hour(), src.Minute(), src.Second()) +} + +// Value implements driver.Valuer interface and returns string format of Time. +func (t Time) Value() (driver.Value, error) { + return t.date.Format(time.DateTime), nil +}