github.com/systematiccaos/gorm@v1.22.6/schema/field_test.go (about)

     1  package schema_test
     2  
     3  import (
     4  	"database/sql"
     5  	"reflect"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/systematiccaos/gorm"
    11  	"github.com/systematiccaos/gorm/schema"
    12  	"github.com/systematiccaos/gorm/utils/tests"
    13  )
    14  
    15  func TestFieldValuerAndSetter(t *testing.T) {
    16  	var (
    17  		userSchema, _ = schema.Parse(&tests.User{}, &sync.Map{}, schema.NamingStrategy{})
    18  		user          = tests.User{
    19  			Model: gorm.Model{
    20  				ID:        10,
    21  				CreatedAt: time.Now(),
    22  				UpdatedAt: time.Now(),
    23  				DeletedAt: gorm.DeletedAt{Time: time.Now(), Valid: true},
    24  			},
    25  			Name:     "valuer_and_setter",
    26  			Age:      18,
    27  			Birthday: tests.Now(),
    28  			Active:   true,
    29  		}
    30  		reflectValue = reflect.ValueOf(&user)
    31  	)
    32  
    33  	// test valuer
    34  	values := map[string]interface{}{
    35  		"name":       user.Name,
    36  		"id":         user.ID,
    37  		"created_at": user.CreatedAt,
    38  		"updated_at": user.UpdatedAt,
    39  		"deleted_at": user.DeletedAt,
    40  		"age":        user.Age,
    41  		"birthday":   user.Birthday,
    42  		"active":     true,
    43  	}
    44  	checkField(t, userSchema, reflectValue, values)
    45  
    46  	var f *bool
    47  	// test setter
    48  	newValues := map[string]interface{}{
    49  		"name":       "valuer_and_setter_2",
    50  		"id":         2,
    51  		"created_at": time.Now(),
    52  		"updated_at": nil,
    53  		"deleted_at": time.Now(),
    54  		"age":        20,
    55  		"birthday":   time.Now(),
    56  		"active":     f,
    57  	}
    58  
    59  	for k, v := range newValues {
    60  		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
    61  			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
    62  		}
    63  	}
    64  	newValues["updated_at"] = time.Time{}
    65  	newValues["active"] = false
    66  	checkField(t, userSchema, reflectValue, newValues)
    67  
    68  	// test valuer and other type
    69  	age := myint(10)
    70  	var nilTime *time.Time
    71  	newValues2 := map[string]interface{}{
    72  		"name":       sql.NullString{String: "valuer_and_setter_3", Valid: true},
    73  		"id":         &sql.NullInt64{Int64: 3, Valid: true},
    74  		"created_at": tests.Now(),
    75  		"updated_at": nilTime,
    76  		"deleted_at": time.Now(),
    77  		"age":        &age,
    78  		"birthday":   mytime(time.Now()),
    79  		"active":     mybool(true),
    80  	}
    81  
    82  	for k, v := range newValues2 {
    83  		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
    84  			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
    85  		}
    86  	}
    87  	newValues2["updated_at"] = time.Time{}
    88  	checkField(t, userSchema, reflectValue, newValues2)
    89  }
    90  
    91  func TestPointerFieldValuerAndSetter(t *testing.T) {
    92  	var (
    93  		userSchema, _      = schema.Parse(&User{}, &sync.Map{}, schema.NamingStrategy{})
    94  		name               = "pointer_field_valuer_and_setter"
    95  		age           uint = 18
    96  		active             = true
    97  		user               = User{
    98  			Model: &gorm.Model{
    99  				ID:        10,
   100  				CreatedAt: time.Now(),
   101  				DeletedAt: gorm.DeletedAt{Time: time.Now(), Valid: true},
   102  			},
   103  			Name:     &name,
   104  			Age:      &age,
   105  			Birthday: tests.Now(),
   106  			Active:   &active,
   107  		}
   108  		reflectValue = reflect.ValueOf(&user)
   109  	)
   110  
   111  	// test valuer
   112  	values := map[string]interface{}{
   113  		"name":       user.Name,
   114  		"id":         user.ID,
   115  		"created_at": user.CreatedAt,
   116  		"deleted_at": user.DeletedAt,
   117  		"age":        user.Age,
   118  		"birthday":   user.Birthday,
   119  		"active":     true,
   120  	}
   121  	checkField(t, userSchema, reflectValue, values)
   122  
   123  	// test setter
   124  	newValues := map[string]interface{}{
   125  		"name":       "valuer_and_setter_2",
   126  		"id":         2,
   127  		"created_at": time.Now(),
   128  		"deleted_at": time.Now(),
   129  		"age":        20,
   130  		"birthday":   time.Now(),
   131  		"active":     false,
   132  	}
   133  
   134  	for k, v := range newValues {
   135  		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
   136  			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
   137  		}
   138  	}
   139  	checkField(t, userSchema, reflectValue, newValues)
   140  
   141  	// test valuer and other type
   142  	age2 := myint(10)
   143  	newValues2 := map[string]interface{}{
   144  		"name":       sql.NullString{String: "valuer_and_setter_3", Valid: true},
   145  		"id":         &sql.NullInt64{Int64: 3, Valid: true},
   146  		"created_at": tests.Now(),
   147  		"deleted_at": time.Now(),
   148  		"age":        &age2,
   149  		"birthday":   mytime(time.Now()),
   150  		"active":     mybool(true),
   151  	}
   152  
   153  	for k, v := range newValues2 {
   154  		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
   155  			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
   156  		}
   157  	}
   158  	checkField(t, userSchema, reflectValue, newValues2)
   159  }
   160  
   161  func TestAdvancedDataTypeValuerAndSetter(t *testing.T) {
   162  	var (
   163  		userSchema, _ = schema.Parse(&AdvancedDataTypeUser{}, &sync.Map{}, schema.NamingStrategy{})
   164  		name          = "advanced_data_type_valuer_and_setter"
   165  		deletedAt     = mytime(time.Now())
   166  		isAdmin       = mybool(false)
   167  		user          = AdvancedDataTypeUser{
   168  			ID:           sql.NullInt64{Int64: 10, Valid: true},
   169  			Name:         &sql.NullString{String: name, Valid: true},
   170  			Birthday:     sql.NullTime{Time: time.Now(), Valid: true},
   171  			RegisteredAt: mytime(time.Now()),
   172  			DeletedAt:    &deletedAt,
   173  			Active:       mybool(true),
   174  			Admin:        &isAdmin,
   175  		}
   176  		reflectValue = reflect.ValueOf(&user)
   177  	)
   178  
   179  	// test valuer
   180  	values := map[string]interface{}{
   181  		"id":            user.ID,
   182  		"name":          user.Name,
   183  		"birthday":      user.Birthday,
   184  		"registered_at": user.RegisteredAt,
   185  		"deleted_at":    user.DeletedAt,
   186  		"active":        user.Active,
   187  		"admin":         user.Admin,
   188  	}
   189  	checkField(t, userSchema, reflectValue, values)
   190  
   191  	// test setter
   192  	newDeletedAt := mytime(time.Now())
   193  	newIsAdmin := mybool(true)
   194  	newValues := map[string]interface{}{
   195  		"id":            sql.NullInt64{Int64: 1, Valid: true},
   196  		"name":          &sql.NullString{String: name + "rename", Valid: true},
   197  		"birthday":      time.Now(),
   198  		"registered_at": mytime(time.Now()),
   199  		"deleted_at":    &newDeletedAt,
   200  		"active":        mybool(false),
   201  		"admin":         &newIsAdmin,
   202  	}
   203  
   204  	for k, v := range newValues {
   205  		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
   206  			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
   207  		}
   208  	}
   209  	checkField(t, userSchema, reflectValue, newValues)
   210  
   211  	newValues2 := map[string]interface{}{
   212  		"id":            5,
   213  		"name":          name + "rename2",
   214  		"birthday":      time.Now(),
   215  		"registered_at": time.Now(),
   216  		"deleted_at":    time.Now(),
   217  		"active":        true,
   218  		"admin":         false,
   219  	}
   220  
   221  	for k, v := range newValues2 {
   222  		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
   223  			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
   224  		}
   225  	}
   226  	checkField(t, userSchema, reflectValue, newValues2)
   227  }
   228  
   229  type UserWithPermissionControl struct {
   230  	ID    uint
   231  	Name  string `gorm:"-"`
   232  	Name2 string `gorm:"->"`
   233  	Name3 string `gorm:"<-"`
   234  	Name4 string `gorm:"<-:create"`
   235  	Name5 string `gorm:"<-:update"`
   236  	Name6 string `gorm:"<-:create,update"`
   237  	Name7 string `gorm:"->:false;<-:create,update"`
   238  	Name8 string `gorm:"->;-:migration"`
   239  }
   240  
   241  func TestParseFieldWithPermission(t *testing.T) {
   242  	user, err := schema.Parse(&UserWithPermissionControl{}, &sync.Map{}, schema.NamingStrategy{})
   243  	if err != nil {
   244  		t.Fatalf("Failed to parse user with permission, got error %v", err)
   245  	}
   246  
   247  	fields := []*schema.Field{
   248  		{Name: "ID", DBName: "id", BindNames: []string{"ID"}, DataType: schema.Uint, PrimaryKey: true, Size: 64, Creatable: true, Updatable: true, Readable: true, HasDefaultValue: true, AutoIncrement: true},
   249  		{Name: "Name", DBName: "", BindNames: []string{"Name"}, DataType: "", Tag: `gorm:"-"`, Creatable: false, Updatable: false, Readable: false},
   250  		{Name: "Name2", DBName: "name2", BindNames: []string{"Name2"}, DataType: schema.String, Tag: `gorm:"->"`, Creatable: false, Updatable: false, Readable: true},
   251  		{Name: "Name3", DBName: "name3", BindNames: []string{"Name3"}, DataType: schema.String, Tag: `gorm:"<-"`, Creatable: true, Updatable: true, Readable: true},
   252  		{Name: "Name4", DBName: "name4", BindNames: []string{"Name4"}, DataType: schema.String, Tag: `gorm:"<-:create"`, Creatable: true, Updatable: false, Readable: true},
   253  		{Name: "Name5", DBName: "name5", BindNames: []string{"Name5"}, DataType: schema.String, Tag: `gorm:"<-:update"`, Creatable: false, Updatable: true, Readable: true},
   254  		{Name: "Name6", DBName: "name6", BindNames: []string{"Name6"}, DataType: schema.String, Tag: `gorm:"<-:create,update"`, Creatable: true, Updatable: true, Readable: true},
   255  		{Name: "Name7", DBName: "name7", BindNames: []string{"Name7"}, DataType: schema.String, Tag: `gorm:"->:false;<-:create,update"`, Creatable: true, Updatable: true, Readable: false},
   256  		{Name: "Name8", DBName: "name8", BindNames: []string{"Name8"}, DataType: schema.String, Tag: `gorm:"->;-:migration"`, Creatable: false, Updatable: false, Readable: true, IgnoreMigration: true},
   257  	}
   258  
   259  	for _, f := range fields {
   260  		checkSchemaField(t, user, f, func(f *schema.Field) {})
   261  	}
   262  }
   263  
   264  type ID int64
   265  type INT int
   266  type INT8 int8
   267  type INT16 int16
   268  type INT32 int32
   269  type INT64 int64
   270  type UINT uint
   271  type UINT8 uint8
   272  type UINT16 uint16
   273  type UINT32 uint32
   274  type UINT64 uint64
   275  type FLOAT32 float32
   276  type FLOAT64 float64
   277  type BOOL bool
   278  type STRING string
   279  type TypeAlias struct {
   280  	ID
   281  	INT     `gorm:"column:fint"`
   282  	INT8    `gorm:"column:fint8"`
   283  	INT16   `gorm:"column:fint16"`
   284  	INT32   `gorm:"column:fint32"`
   285  	INT64   `gorm:"column:fint64"`
   286  	UINT    `gorm:"column:fuint"`
   287  	UINT8   `gorm:"column:fuint8"`
   288  	UINT16  `gorm:"column:fuint16"`
   289  	UINT32  `gorm:"column:fuint32"`
   290  	UINT64  `gorm:"column:fuint64"`
   291  	FLOAT32 `gorm:"column:ffloat32"`
   292  	FLOAT64 `gorm:"column:ffloat64"`
   293  	BOOL    `gorm:"column:fbool"`
   294  	STRING  `gorm:"column:fstring"`
   295  }
   296  
   297  func TestTypeAliasField(t *testing.T) {
   298  	alias, err := schema.Parse(&TypeAlias{}, &sync.Map{}, schema.NamingStrategy{})
   299  	if err != nil {
   300  		t.Fatalf("Failed to parse TypeAlias with permission, got error %v", err)
   301  	}
   302  
   303  	fields := []*schema.Field{
   304  		{Name: "ID", DBName: "id", BindNames: []string{"ID"}, DataType: schema.Int, Creatable: true, Updatable: true, Readable: true, Size: 64, PrimaryKey: true, HasDefaultValue: true, AutoIncrement: true},
   305  		{Name: "INT", DBName: "fint", BindNames: []string{"INT"}, DataType: schema.Int, Creatable: true, Updatable: true, Readable: true, Size: 64, Tag: `gorm:"column:fint"`},
   306  		{Name: "INT8", DBName: "fint8", BindNames: []string{"INT8"}, DataType: schema.Int, Creatable: true, Updatable: true, Readable: true, Size: 8, Tag: `gorm:"column:fint8"`},
   307  		{Name: "INT16", DBName: "fint16", BindNames: []string{"INT16"}, DataType: schema.Int, Creatable: true, Updatable: true, Readable: true, Size: 16, Tag: `gorm:"column:fint16"`},
   308  		{Name: "INT32", DBName: "fint32", BindNames: []string{"INT32"}, DataType: schema.Int, Creatable: true, Updatable: true, Readable: true, Size: 32, Tag: `gorm:"column:fint32"`},
   309  		{Name: "INT64", DBName: "fint64", BindNames: []string{"INT64"}, DataType: schema.Int, Creatable: true, Updatable: true, Readable: true, Size: 64, Tag: `gorm:"column:fint64"`},
   310  		{Name: "UINT", DBName: "fuint", BindNames: []string{"UINT"}, DataType: schema.Uint, Creatable: true, Updatable: true, Readable: true, Size: 64, Tag: `gorm:"column:fuint"`},
   311  		{Name: "UINT8", DBName: "fuint8", BindNames: []string{"UINT8"}, DataType: schema.Uint, Creatable: true, Updatable: true, Readable: true, Size: 8, Tag: `gorm:"column:fuint8"`},
   312  		{Name: "UINT16", DBName: "fuint16", BindNames: []string{"UINT16"}, DataType: schema.Uint, Creatable: true, Updatable: true, Readable: true, Size: 16, Tag: `gorm:"column:fuint16"`},
   313  		{Name: "UINT32", DBName: "fuint32", BindNames: []string{"UINT32"}, DataType: schema.Uint, Creatable: true, Updatable: true, Readable: true, Size: 32, Tag: `gorm:"column:fuint32"`},
   314  		{Name: "UINT64", DBName: "fuint64", BindNames: []string{"UINT64"}, DataType: schema.Uint, Creatable: true, Updatable: true, Readable: true, Size: 64, Tag: `gorm:"column:fuint64"`},
   315  		{Name: "FLOAT32", DBName: "ffloat32", BindNames: []string{"FLOAT32"}, DataType: schema.Float, Creatable: true, Updatable: true, Readable: true, Size: 32, Tag: `gorm:"column:ffloat32"`},
   316  		{Name: "FLOAT64", DBName: "ffloat64", BindNames: []string{"FLOAT64"}, DataType: schema.Float, Creatable: true, Updatable: true, Readable: true, Size: 64, Tag: `gorm:"column:ffloat64"`},
   317  		{Name: "BOOL", DBName: "fbool", BindNames: []string{"BOOL"}, DataType: schema.Bool, Creatable: true, Updatable: true, Readable: true, Tag: `gorm:"column:fbool"`},
   318  		{Name: "STRING", DBName: "fstring", BindNames: []string{"STRING"}, DataType: schema.String, Creatable: true, Updatable: true, Readable: true, Tag: `gorm:"column:fstring"`},
   319  	}
   320  
   321  	for _, f := range fields {
   322  		checkSchemaField(t, alias, f, func(f *schema.Field) {})
   323  	}
   324  }