Add serializer support (#5078)
* Update context * Update GormFieldValuer * Add Serializer * Add Serializer Interface * Refactor gorm field * Refactor setter, valuer * Add sync.Pool * Fix test * Add pool manager * Fix pool manager * Add poolInitializer * Add Serializer Scan support * Add Serializer Value method * Add serializer test * Finish Serializer * Fix JSONSerializer for postgres * Fix JSONSerializer for sqlserver * Test serializer tag * Add unixtime serializer * Update go.mod
This commit is contained in:
		
							parent
							
								
									19ac396a22
								
							
						
					
					
						commit
						5299a0f9da
					
				@ -79,10 +79,10 @@ func (association *Association) Replace(values ...interface{}) error {
 | 
				
			|||||||
				switch reflectValue.Kind() {
 | 
									switch reflectValue.Kind() {
 | 
				
			||||||
				case reflect.Slice, reflect.Array:
 | 
									case reflect.Slice, reflect.Array:
 | 
				
			||||||
					for i := 0; i < reflectValue.Len(); i++ {
 | 
										for i := 0; i < reflectValue.Len(); i++ {
 | 
				
			||||||
						association.Error = rel.Field.Set(reflectValue.Index(i), reflect.Zero(rel.Field.FieldType).Interface())
 | 
											association.Error = rel.Field.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.Zero(rel.Field.FieldType).Interface())
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				case reflect.Struct:
 | 
									case reflect.Struct:
 | 
				
			||||||
					association.Error = rel.Field.Set(reflectValue, reflect.Zero(rel.Field.FieldType).Interface())
 | 
										association.Error = rel.Field.Set(association.DB.Statement.Context, reflectValue, reflect.Zero(rel.Field.FieldType).Interface())
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				for _, ref := range rel.References {
 | 
									for _, ref := range rel.References {
 | 
				
			||||||
@ -96,12 +96,12 @@ func (association *Association) Replace(values ...interface{}) error {
 | 
				
			|||||||
				primaryFields []*schema.Field
 | 
									primaryFields []*schema.Field
 | 
				
			||||||
				foreignKeys   []string
 | 
									foreignKeys   []string
 | 
				
			||||||
				updateMap     = map[string]interface{}{}
 | 
									updateMap     = map[string]interface{}{}
 | 
				
			||||||
				relValues     = schema.GetRelationsValues(reflectValue, []*schema.Relationship{rel})
 | 
									relValues     = schema.GetRelationsValues(association.DB.Statement.Context, reflectValue, []*schema.Relationship{rel})
 | 
				
			||||||
				modelValue    = reflect.New(rel.FieldSchema.ModelType).Interface()
 | 
									modelValue    = reflect.New(rel.FieldSchema.ModelType).Interface()
 | 
				
			||||||
				tx            = association.DB.Model(modelValue)
 | 
									tx            = association.DB.Model(modelValue)
 | 
				
			||||||
			)
 | 
								)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if _, rvs := schema.GetIdentityFieldValuesMap(relValues, rel.FieldSchema.PrimaryFields); len(rvs) > 0 {
 | 
								if _, rvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, relValues, rel.FieldSchema.PrimaryFields); len(rvs) > 0 {
 | 
				
			||||||
				if column, values := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, rvs); len(values) > 0 {
 | 
									if column, values := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, rvs); len(values) > 0 {
 | 
				
			||||||
					tx.Not(clause.IN{Column: column, Values: values})
 | 
										tx.Not(clause.IN{Column: column, Values: values})
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@ -117,7 +117,7 @@ func (association *Association) Replace(values ...interface{}) error {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if _, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields); len(pvs) > 0 {
 | 
								if _, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields); len(pvs) > 0 {
 | 
				
			||||||
				column, values := schema.ToQueryValues(rel.FieldSchema.Table, foreignKeys, pvs)
 | 
									column, values := schema.ToQueryValues(rel.FieldSchema.Table, foreignKeys, pvs)
 | 
				
			||||||
				association.Error = tx.Where(clause.IN{Column: column, Values: values}).UpdateColumns(updateMap).Error
 | 
									association.Error = tx.Where(clause.IN{Column: column, Values: values}).UpdateColumns(updateMap).Error
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -143,14 +143,14 @@ func (association *Association) Replace(values ...interface{}) error {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields)
 | 
								_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
 | 
				
			||||||
			if column, values := schema.ToQueryValues(rel.JoinTable.Table, joinPrimaryKeys, pvs); len(values) > 0 {
 | 
								if column, values := schema.ToQueryValues(rel.JoinTable.Table, joinPrimaryKeys, pvs); len(values) > 0 {
 | 
				
			||||||
				tx.Where(clause.IN{Column: column, Values: values})
 | 
									tx.Where(clause.IN{Column: column, Values: values})
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				return ErrPrimaryKeyRequired
 | 
									return ErrPrimaryKeyRequired
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, relPrimaryFields)
 | 
								_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, relPrimaryFields)
 | 
				
			||||||
			if relColumn, relValues := schema.ToQueryValues(rel.JoinTable.Table, joinRelPrimaryKeys, rvs); len(relValues) > 0 {
 | 
								if relColumn, relValues := schema.ToQueryValues(rel.JoinTable.Table, joinRelPrimaryKeys, rvs); len(relValues) > 0 {
 | 
				
			||||||
				tx.Where(clause.Not(clause.IN{Column: relColumn, Values: relValues}))
 | 
									tx.Where(clause.Not(clause.IN{Column: relColumn, Values: relValues}))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -186,11 +186,11 @@ func (association *Association) Delete(values ...interface{}) error {
 | 
				
			|||||||
		case schema.BelongsTo:
 | 
							case schema.BelongsTo:
 | 
				
			||||||
			tx := association.DB.Model(reflect.New(rel.Schema.ModelType).Interface())
 | 
								tx := association.DB.Model(reflect.New(rel.Schema.ModelType).Interface())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, rel.Schema.PrimaryFields)
 | 
								_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, rel.Schema.PrimaryFields)
 | 
				
			||||||
			pcolumn, pvalues := schema.ToQueryValues(rel.Schema.Table, rel.Schema.PrimaryFieldDBNames, pvs)
 | 
								pcolumn, pvalues := schema.ToQueryValues(rel.Schema.Table, rel.Schema.PrimaryFieldDBNames, pvs)
 | 
				
			||||||
			conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 | 
								conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, primaryFields)
 | 
								_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, primaryFields)
 | 
				
			||||||
			relColumn, relValues := schema.ToQueryValues(rel.Schema.Table, foreignKeys, rvs)
 | 
								relColumn, relValues := schema.ToQueryValues(rel.Schema.Table, foreignKeys, rvs)
 | 
				
			||||||
			conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 | 
								conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -198,11 +198,11 @@ func (association *Association) Delete(values ...interface{}) error {
 | 
				
			|||||||
		case schema.HasOne, schema.HasMany:
 | 
							case schema.HasOne, schema.HasMany:
 | 
				
			||||||
			tx := association.DB.Model(reflect.New(rel.FieldSchema.ModelType).Interface())
 | 
								tx := association.DB.Model(reflect.New(rel.FieldSchema.ModelType).Interface())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields)
 | 
								_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
 | 
				
			||||||
			pcolumn, pvalues := schema.ToQueryValues(rel.FieldSchema.Table, foreignKeys, pvs)
 | 
								pcolumn, pvalues := schema.ToQueryValues(rel.FieldSchema.Table, foreignKeys, pvs)
 | 
				
			||||||
			conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 | 
								conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, rel.FieldSchema.PrimaryFields)
 | 
								_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, rel.FieldSchema.PrimaryFields)
 | 
				
			||||||
			relColumn, relValues := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, rvs)
 | 
								relColumn, relValues := schema.ToQueryValues(rel.FieldSchema.Table, rel.FieldSchema.PrimaryFieldDBNames, rvs)
 | 
				
			||||||
			conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 | 
								conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -228,11 +228,11 @@ func (association *Association) Delete(values ...interface{}) error {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_, pvs := schema.GetIdentityFieldValuesMap(reflectValue, primaryFields)
 | 
								_, pvs := schema.GetIdentityFieldValuesMap(association.DB.Statement.Context, reflectValue, primaryFields)
 | 
				
			||||||
			pcolumn, pvalues := schema.ToQueryValues(rel.JoinTable.Table, joinPrimaryKeys, pvs)
 | 
								pcolumn, pvalues := schema.ToQueryValues(rel.JoinTable.Table, joinPrimaryKeys, pvs)
 | 
				
			||||||
			conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 | 
								conds = append(conds, clause.IN{Column: pcolumn, Values: pvalues})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_, rvs := schema.GetIdentityFieldValuesMapFromValues(values, relPrimaryFields)
 | 
								_, rvs := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, relPrimaryFields)
 | 
				
			||||||
			relColumn, relValues := schema.ToQueryValues(rel.JoinTable.Table, joinRelPrimaryKeys, rvs)
 | 
								relColumn, relValues := schema.ToQueryValues(rel.JoinTable.Table, joinRelPrimaryKeys, rvs)
 | 
				
			||||||
			conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 | 
								conds = append(conds, clause.IN{Column: relColumn, Values: relValues})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -241,11 +241,11 @@ func (association *Association) Delete(values ...interface{}) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if association.Error == nil {
 | 
							if association.Error == nil {
 | 
				
			||||||
			// clean up deleted values's foreign key
 | 
								// clean up deleted values's foreign key
 | 
				
			||||||
			relValuesMap, _ := schema.GetIdentityFieldValuesMapFromValues(values, rel.FieldSchema.PrimaryFields)
 | 
								relValuesMap, _ := schema.GetIdentityFieldValuesMapFromValues(association.DB.Statement.Context, values, rel.FieldSchema.PrimaryFields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			cleanUpDeletedRelations := func(data reflect.Value) {
 | 
								cleanUpDeletedRelations := func(data reflect.Value) {
 | 
				
			||||||
				if _, zero := rel.Field.ValueOf(data); !zero {
 | 
									if _, zero := rel.Field.ValueOf(association.DB.Statement.Context, data); !zero {
 | 
				
			||||||
					fieldValue := reflect.Indirect(rel.Field.ReflectValueOf(data))
 | 
										fieldValue := reflect.Indirect(rel.Field.ReflectValueOf(association.DB.Statement.Context, data))
 | 
				
			||||||
					primaryValues := make([]interface{}, len(rel.FieldSchema.PrimaryFields))
 | 
										primaryValues := make([]interface{}, len(rel.FieldSchema.PrimaryFields))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					switch fieldValue.Kind() {
 | 
										switch fieldValue.Kind() {
 | 
				
			||||||
@ -253,7 +253,7 @@ func (association *Association) Delete(values ...interface{}) error {
 | 
				
			|||||||
						validFieldValues := reflect.Zero(rel.Field.IndirectFieldType)
 | 
											validFieldValues := reflect.Zero(rel.Field.IndirectFieldType)
 | 
				
			||||||
						for i := 0; i < fieldValue.Len(); i++ {
 | 
											for i := 0; i < fieldValue.Len(); i++ {
 | 
				
			||||||
							for idx, field := range rel.FieldSchema.PrimaryFields {
 | 
												for idx, field := range rel.FieldSchema.PrimaryFields {
 | 
				
			||||||
								primaryValues[idx], _ = field.ValueOf(fieldValue.Index(i))
 | 
													primaryValues[idx], _ = field.ValueOf(association.DB.Statement.Context, fieldValue.Index(i))
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; !ok {
 | 
												if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; !ok {
 | 
				
			||||||
@ -261,23 +261,23 @@ func (association *Association) Delete(values ...interface{}) error {
 | 
				
			|||||||
							}
 | 
												}
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						association.Error = rel.Field.Set(data, validFieldValues.Interface())
 | 
											association.Error = rel.Field.Set(association.DB.Statement.Context, data, validFieldValues.Interface())
 | 
				
			||||||
					case reflect.Struct:
 | 
										case reflect.Struct:
 | 
				
			||||||
						for idx, field := range rel.FieldSchema.PrimaryFields {
 | 
											for idx, field := range rel.FieldSchema.PrimaryFields {
 | 
				
			||||||
							primaryValues[idx], _ = field.ValueOf(fieldValue)
 | 
												primaryValues[idx], _ = field.ValueOf(association.DB.Statement.Context, fieldValue)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; ok {
 | 
											if _, ok := relValuesMap[utils.ToStringKey(primaryValues...)]; ok {
 | 
				
			||||||
							if association.Error = rel.Field.Set(data, reflect.Zero(rel.FieldSchema.ModelType).Interface()); association.Error != nil {
 | 
												if association.Error = rel.Field.Set(association.DB.Statement.Context, data, reflect.Zero(rel.FieldSchema.ModelType).Interface()); association.Error != nil {
 | 
				
			||||||
								break
 | 
													break
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							if rel.JoinTable == nil {
 | 
												if rel.JoinTable == nil {
 | 
				
			||||||
								for _, ref := range rel.References {
 | 
													for _, ref := range rel.References {
 | 
				
			||||||
									if ref.OwnPrimaryKey || ref.PrimaryValue != "" {
 | 
														if ref.OwnPrimaryKey || ref.PrimaryValue != "" {
 | 
				
			||||||
										association.Error = ref.ForeignKey.Set(fieldValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 | 
															association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, fieldValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 | 
				
			||||||
									} else {
 | 
														} else {
 | 
				
			||||||
										association.Error = ref.ForeignKey.Set(data, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 | 
															association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, data, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 | 
				
			||||||
									}
 | 
														}
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
@ -329,14 +329,14 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 | 
				
			|||||||
			switch rv.Kind() {
 | 
								switch rv.Kind() {
 | 
				
			||||||
			case reflect.Slice, reflect.Array:
 | 
								case reflect.Slice, reflect.Array:
 | 
				
			||||||
				if rv.Len() > 0 {
 | 
									if rv.Len() > 0 {
 | 
				
			||||||
					association.Error = association.Relationship.Field.Set(source, rv.Index(0).Addr().Interface())
 | 
										association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, rv.Index(0).Addr().Interface())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if association.Relationship.Field.FieldType.Kind() == reflect.Struct {
 | 
										if association.Relationship.Field.FieldType.Kind() == reflect.Struct {
 | 
				
			||||||
						assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv.Index(0)})
 | 
											assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv.Index(0)})
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			case reflect.Struct:
 | 
								case reflect.Struct:
 | 
				
			||||||
				association.Error = association.Relationship.Field.Set(source, rv.Addr().Interface())
 | 
									association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, rv.Addr().Interface())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if association.Relationship.Field.FieldType.Kind() == reflect.Struct {
 | 
									if association.Relationship.Field.FieldType.Kind() == reflect.Struct {
 | 
				
			||||||
					assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv})
 | 
										assignBacks = append(assignBacks, assignBack{Source: source, Dest: rv})
 | 
				
			||||||
@ -344,7 +344,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		case schema.HasMany, schema.Many2Many:
 | 
							case schema.HasMany, schema.Many2Many:
 | 
				
			||||||
			elemType := association.Relationship.Field.IndirectFieldType.Elem()
 | 
								elemType := association.Relationship.Field.IndirectFieldType.Elem()
 | 
				
			||||||
			fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(source))
 | 
								fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, source))
 | 
				
			||||||
			if clear {
 | 
								if clear {
 | 
				
			||||||
				fieldValue = reflect.New(association.Relationship.Field.IndirectFieldType).Elem()
 | 
									fieldValue = reflect.New(association.Relationship.Field.IndirectFieldType).Elem()
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -373,7 +373,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if association.Error == nil {
 | 
								if association.Error == nil {
 | 
				
			||||||
				association.Error = association.Relationship.Field.Set(source, fieldValue.Interface())
 | 
									association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, source, fieldValue.Interface())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -421,7 +421,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 | 
				
			|||||||
			// clear old data
 | 
								// clear old data
 | 
				
			||||||
			if clear && len(values) == 0 {
 | 
								if clear && len(values) == 0 {
 | 
				
			||||||
				for i := 0; i < reflectValue.Len(); i++ {
 | 
									for i := 0; i < reflectValue.Len(); i++ {
 | 
				
			||||||
					if err := association.Relationship.Field.Set(reflectValue.Index(i), reflect.New(association.Relationship.Field.IndirectFieldType).Interface()); err != nil {
 | 
										if err := association.Relationship.Field.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.New(association.Relationship.Field.IndirectFieldType).Interface()); err != nil {
 | 
				
			||||||
						association.Error = err
 | 
											association.Error = err
 | 
				
			||||||
						break
 | 
											break
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@ -429,7 +429,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 | 
				
			|||||||
					if association.Relationship.JoinTable == nil {
 | 
										if association.Relationship.JoinTable == nil {
 | 
				
			||||||
						for _, ref := range association.Relationship.References {
 | 
											for _, ref := range association.Relationship.References {
 | 
				
			||||||
							if !ref.OwnPrimaryKey && ref.PrimaryValue == "" {
 | 
												if !ref.OwnPrimaryKey && ref.PrimaryValue == "" {
 | 
				
			||||||
								if err := ref.ForeignKey.Set(reflectValue.Index(i), reflect.Zero(ref.ForeignKey.FieldType).Interface()); err != nil {
 | 
													if err := ref.ForeignKey.Set(association.DB.Statement.Context, reflectValue.Index(i), reflect.Zero(ref.ForeignKey.FieldType).Interface()); err != nil {
 | 
				
			||||||
									association.Error = err
 | 
														association.Error = err
 | 
				
			||||||
									break
 | 
														break
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
@ -453,12 +453,12 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 | 
				
			|||||||
	case reflect.Struct:
 | 
						case reflect.Struct:
 | 
				
			||||||
		// clear old data
 | 
							// clear old data
 | 
				
			||||||
		if clear && len(values) == 0 {
 | 
							if clear && len(values) == 0 {
 | 
				
			||||||
			association.Error = association.Relationship.Field.Set(reflectValue, reflect.New(association.Relationship.Field.IndirectFieldType).Interface())
 | 
								association.Error = association.Relationship.Field.Set(association.DB.Statement.Context, reflectValue, reflect.New(association.Relationship.Field.IndirectFieldType).Interface())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if association.Relationship.JoinTable == nil && association.Error == nil {
 | 
								if association.Relationship.JoinTable == nil && association.Error == nil {
 | 
				
			||||||
				for _, ref := range association.Relationship.References {
 | 
									for _, ref := range association.Relationship.References {
 | 
				
			||||||
					if !ref.OwnPrimaryKey && ref.PrimaryValue == "" {
 | 
										if !ref.OwnPrimaryKey && ref.PrimaryValue == "" {
 | 
				
			||||||
						association.Error = ref.ForeignKey.Set(reflectValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 | 
											association.Error = ref.ForeignKey.Set(association.DB.Statement.Context, reflectValue, reflect.Zero(ref.ForeignKey.FieldType).Interface())
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -475,7 +475,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, assignBack := range assignBacks {
 | 
						for _, assignBack := range assignBacks {
 | 
				
			||||||
		fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(assignBack.Source))
 | 
							fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, assignBack.Source))
 | 
				
			||||||
		if assignBack.Index > 0 {
 | 
							if assignBack.Index > 0 {
 | 
				
			||||||
			reflect.Indirect(assignBack.Dest).Set(fieldValue.Index(assignBack.Index - 1))
 | 
								reflect.Indirect(assignBack.Dest).Set(fieldValue.Index(assignBack.Index - 1))
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@ -486,7 +486,7 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (association *Association) buildCondition() *DB {
 | 
					func (association *Association) buildCondition() *DB {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		queryConds = association.Relationship.ToQueryConditions(association.DB.Statement.ReflectValue)
 | 
							queryConds = association.Relationship.ToQueryConditions(association.DB.Statement.Context, association.DB.Statement.ReflectValue)
 | 
				
			||||||
		modelValue = reflect.New(association.Relationship.FieldSchema.ModelType).Interface()
 | 
							modelValue = reflect.New(association.Relationship.FieldSchema.ModelType).Interface()
 | 
				
			||||||
		tx         = association.DB.Model(modelValue)
 | 
							tx         = association.DB.Model(modelValue)
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
				
			|||||||
@ -24,8 +24,8 @@ func SaveBeforeAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
				setupReferences := func(obj reflect.Value, elem reflect.Value) {
 | 
									setupReferences := func(obj reflect.Value, elem reflect.Value) {
 | 
				
			||||||
					for _, ref := range rel.References {
 | 
										for _, ref := range rel.References {
 | 
				
			||||||
						if !ref.OwnPrimaryKey {
 | 
											if !ref.OwnPrimaryKey {
 | 
				
			||||||
							pv, _ := ref.PrimaryKey.ValueOf(elem)
 | 
												pv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, elem)
 | 
				
			||||||
							db.AddError(ref.ForeignKey.Set(obj, pv))
 | 
												db.AddError(ref.ForeignKey.Set(db.Statement.Context, obj, pv))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							if dest, ok := db.Statement.Dest.(map[string]interface{}); ok {
 | 
												if dest, ok := db.Statement.Dest.(map[string]interface{}); ok {
 | 
				
			||||||
								dest[ref.ForeignKey.DBName] = pv
 | 
													dest[ref.ForeignKey.DBName] = pv
 | 
				
			||||||
@ -57,8 +57,8 @@ func SaveBeforeAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
							break
 | 
												break
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if _, zero := rel.Field.ValueOf(obj); !zero { // check belongs to relation value
 | 
											if _, zero := rel.Field.ValueOf(db.Statement.Context, obj); !zero { // check belongs to relation value
 | 
				
			||||||
							rv := rel.Field.ReflectValueOf(obj) // relation reflect value
 | 
												rv := rel.Field.ReflectValueOf(db.Statement.Context, obj) // relation reflect value
 | 
				
			||||||
							objs = append(objs, obj)
 | 
												objs = append(objs, obj)
 | 
				
			||||||
							if isPtr {
 | 
												if isPtr {
 | 
				
			||||||
								elems = reflect.Append(elems, rv)
 | 
													elems = reflect.Append(elems, rv)
 | 
				
			||||||
@ -76,8 +76,8 @@ func SaveBeforeAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				case reflect.Struct:
 | 
									case reflect.Struct:
 | 
				
			||||||
					if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero {
 | 
										if _, zero := rel.Field.ValueOf(db.Statement.Context, db.Statement.ReflectValue); !zero {
 | 
				
			||||||
						rv := rel.Field.ReflectValueOf(db.Statement.ReflectValue) // relation reflect value
 | 
											rv := rel.Field.ReflectValueOf(db.Statement.Context, db.Statement.ReflectValue) // relation reflect value
 | 
				
			||||||
						if rv.Kind() != reflect.Ptr {
 | 
											if rv.Kind() != reflect.Ptr {
 | 
				
			||||||
							rv = rv.Addr()
 | 
												rv = rv.Addr()
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
@ -120,18 +120,18 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
						obj := db.Statement.ReflectValue.Index(i)
 | 
											obj := db.Statement.ReflectValue.Index(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if reflect.Indirect(obj).Kind() == reflect.Struct {
 | 
											if reflect.Indirect(obj).Kind() == reflect.Struct {
 | 
				
			||||||
							if _, zero := rel.Field.ValueOf(obj); !zero {
 | 
												if _, zero := rel.Field.ValueOf(db.Statement.Context, obj); !zero {
 | 
				
			||||||
								rv := rel.Field.ReflectValueOf(obj)
 | 
													rv := rel.Field.ReflectValueOf(db.Statement.Context, obj)
 | 
				
			||||||
								if rv.Kind() != reflect.Ptr {
 | 
													if rv.Kind() != reflect.Ptr {
 | 
				
			||||||
									rv = rv.Addr()
 | 
														rv = rv.Addr()
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
								for _, ref := range rel.References {
 | 
													for _, ref := range rel.References {
 | 
				
			||||||
									if ref.OwnPrimaryKey {
 | 
														if ref.OwnPrimaryKey {
 | 
				
			||||||
										fv, _ := ref.PrimaryKey.ValueOf(obj)
 | 
															fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, obj)
 | 
				
			||||||
										db.AddError(ref.ForeignKey.Set(rv, fv))
 | 
															db.AddError(ref.ForeignKey.Set(db.Statement.Context, rv, fv))
 | 
				
			||||||
									} else if ref.PrimaryValue != "" {
 | 
														} else if ref.PrimaryValue != "" {
 | 
				
			||||||
										db.AddError(ref.ForeignKey.Set(rv, ref.PrimaryValue))
 | 
															db.AddError(ref.ForeignKey.Set(db.Statement.Context, rv, ref.PrimaryValue))
 | 
				
			||||||
									}
 | 
														}
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -149,8 +149,8 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
						saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, assignmentColumns)
 | 
											saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, assignmentColumns)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				case reflect.Struct:
 | 
									case reflect.Struct:
 | 
				
			||||||
					if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero {
 | 
										if _, zero := rel.Field.ValueOf(db.Statement.Context, db.Statement.ReflectValue); !zero {
 | 
				
			||||||
						f := rel.Field.ReflectValueOf(db.Statement.ReflectValue)
 | 
											f := rel.Field.ReflectValueOf(db.Statement.Context, db.Statement.ReflectValue)
 | 
				
			||||||
						if f.Kind() != reflect.Ptr {
 | 
											if f.Kind() != reflect.Ptr {
 | 
				
			||||||
							f = f.Addr()
 | 
												f = f.Addr()
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
@ -158,10 +158,10 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
						assignmentColumns := make([]string, 0, len(rel.References))
 | 
											assignmentColumns := make([]string, 0, len(rel.References))
 | 
				
			||||||
						for _, ref := range rel.References {
 | 
											for _, ref := range rel.References {
 | 
				
			||||||
							if ref.OwnPrimaryKey {
 | 
												if ref.OwnPrimaryKey {
 | 
				
			||||||
								fv, _ := ref.PrimaryKey.ValueOf(db.Statement.ReflectValue)
 | 
													fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, db.Statement.ReflectValue)
 | 
				
			||||||
								ref.ForeignKey.Set(f, fv)
 | 
													ref.ForeignKey.Set(db.Statement.Context, f, fv)
 | 
				
			||||||
							} else if ref.PrimaryValue != "" {
 | 
												} else if ref.PrimaryValue != "" {
 | 
				
			||||||
								ref.ForeignKey.Set(f, ref.PrimaryValue)
 | 
													ref.ForeignKey.Set(db.Statement.Context, f, ref.PrimaryValue)
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
							assignmentColumns = append(assignmentColumns, ref.ForeignKey.DBName)
 | 
												assignmentColumns = append(assignmentColumns, ref.ForeignKey.DBName)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
@ -185,23 +185,23 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
				elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10)
 | 
									elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10)
 | 
				
			||||||
				identityMap := map[string]bool{}
 | 
									identityMap := map[string]bool{}
 | 
				
			||||||
				appendToElems := func(v reflect.Value) {
 | 
									appendToElems := func(v reflect.Value) {
 | 
				
			||||||
					if _, zero := rel.Field.ValueOf(v); !zero {
 | 
										if _, zero := rel.Field.ValueOf(db.Statement.Context, v); !zero {
 | 
				
			||||||
						f := reflect.Indirect(rel.Field.ReflectValueOf(v))
 | 
											f := reflect.Indirect(rel.Field.ReflectValueOf(db.Statement.Context, v))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						for i := 0; i < f.Len(); i++ {
 | 
											for i := 0; i < f.Len(); i++ {
 | 
				
			||||||
							elem := f.Index(i)
 | 
												elem := f.Index(i)
 | 
				
			||||||
							for _, ref := range rel.References {
 | 
												for _, ref := range rel.References {
 | 
				
			||||||
								if ref.OwnPrimaryKey {
 | 
													if ref.OwnPrimaryKey {
 | 
				
			||||||
									pv, _ := ref.PrimaryKey.ValueOf(v)
 | 
														pv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, v)
 | 
				
			||||||
									ref.ForeignKey.Set(elem, pv)
 | 
														ref.ForeignKey.Set(db.Statement.Context, elem, pv)
 | 
				
			||||||
								} else if ref.PrimaryValue != "" {
 | 
													} else if ref.PrimaryValue != "" {
 | 
				
			||||||
									ref.ForeignKey.Set(elem, ref.PrimaryValue)
 | 
														ref.ForeignKey.Set(db.Statement.Context, elem, ref.PrimaryValue)
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							relPrimaryValues := make([]interface{}, 0, len(rel.FieldSchema.PrimaryFields))
 | 
												relPrimaryValues := make([]interface{}, 0, len(rel.FieldSchema.PrimaryFields))
 | 
				
			||||||
							for _, pf := range rel.FieldSchema.PrimaryFields {
 | 
												for _, pf := range rel.FieldSchema.PrimaryFields {
 | 
				
			||||||
								if pfv, ok := pf.ValueOf(elem); !ok {
 | 
													if pfv, ok := pf.ValueOf(db.Statement.Context, elem); !ok {
 | 
				
			||||||
									relPrimaryValues = append(relPrimaryValues, pfv)
 | 
														relPrimaryValues = append(relPrimaryValues, pfv)
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
@ -260,21 +260,21 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
					joinValue := reflect.New(rel.JoinTable.ModelType)
 | 
										joinValue := reflect.New(rel.JoinTable.ModelType)
 | 
				
			||||||
					for _, ref := range rel.References {
 | 
										for _, ref := range rel.References {
 | 
				
			||||||
						if ref.OwnPrimaryKey {
 | 
											if ref.OwnPrimaryKey {
 | 
				
			||||||
							fv, _ := ref.PrimaryKey.ValueOf(obj)
 | 
												fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, obj)
 | 
				
			||||||
							ref.ForeignKey.Set(joinValue, fv)
 | 
												ref.ForeignKey.Set(db.Statement.Context, joinValue, fv)
 | 
				
			||||||
						} else if ref.PrimaryValue != "" {
 | 
											} else if ref.PrimaryValue != "" {
 | 
				
			||||||
							ref.ForeignKey.Set(joinValue, ref.PrimaryValue)
 | 
												ref.ForeignKey.Set(db.Statement.Context, joinValue, ref.PrimaryValue)
 | 
				
			||||||
						} else {
 | 
											} else {
 | 
				
			||||||
							fv, _ := ref.PrimaryKey.ValueOf(elem)
 | 
												fv, _ := ref.PrimaryKey.ValueOf(db.Statement.Context, elem)
 | 
				
			||||||
							ref.ForeignKey.Set(joinValue, fv)
 | 
												ref.ForeignKey.Set(db.Statement.Context, joinValue, fv)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					joins = reflect.Append(joins, joinValue)
 | 
										joins = reflect.Append(joins, joinValue)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				appendToElems := func(v reflect.Value) {
 | 
									appendToElems := func(v reflect.Value) {
 | 
				
			||||||
					if _, zero := rel.Field.ValueOf(v); !zero {
 | 
										if _, zero := rel.Field.ValueOf(db.Statement.Context, v); !zero {
 | 
				
			||||||
						f := reflect.Indirect(rel.Field.ReflectValueOf(v))
 | 
											f := reflect.Indirect(rel.Field.ReflectValueOf(db.Statement.Context, v))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						for i := 0; i < f.Len(); i++ {
 | 
											for i := 0; i < f.Len(); i++ {
 | 
				
			||||||
							elem := f.Index(i)
 | 
												elem := f.Index(i)
 | 
				
			||||||
 | 
				
			|||||||
@ -117,9 +117,9 @@ func Create(config *Config) func(db *gorm.DB) {
 | 
				
			|||||||
							break
 | 
												break
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(rv)
 | 
											_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv)
 | 
				
			||||||
						if isZero {
 | 
											if isZero {
 | 
				
			||||||
							db.Statement.Schema.PrioritizedPrimaryField.Set(rv, insertID)
 | 
												db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, insertID)
 | 
				
			||||||
							insertID -= db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
 | 
												insertID -= db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@ -130,16 +130,16 @@ func Create(config *Config) func(db *gorm.DB) {
 | 
				
			|||||||
							break
 | 
												break
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(rv); isZero {
 | 
											if _, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, rv); isZero {
 | 
				
			||||||
							db.Statement.Schema.PrioritizedPrimaryField.Set(rv, insertID)
 | 
												db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, rv, insertID)
 | 
				
			||||||
							insertID += db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
 | 
												insertID += db.Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			case reflect.Struct:
 | 
								case reflect.Struct:
 | 
				
			||||||
				_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.ReflectValue)
 | 
									_, isZero := db.Statement.Schema.PrioritizedPrimaryField.ValueOf(db.Statement.Context, db.Statement.ReflectValue)
 | 
				
			||||||
				if isZero {
 | 
									if isZero {
 | 
				
			||||||
					db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.ReflectValue, insertID)
 | 
										db.Statement.Schema.PrioritizedPrimaryField.Set(db.Statement.Context, db.Statement.ReflectValue, insertID)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -219,23 +219,23 @@ func ConvertToCreateValues(stmt *gorm.Statement) (values clause.Values) {
 | 
				
			|||||||
				values.Values[i] = make([]interface{}, len(values.Columns))
 | 
									values.Values[i] = make([]interface{}, len(values.Columns))
 | 
				
			||||||
				for idx, column := range values.Columns {
 | 
									for idx, column := range values.Columns {
 | 
				
			||||||
					field := stmt.Schema.FieldsByDBName[column.Name]
 | 
										field := stmt.Schema.FieldsByDBName[column.Name]
 | 
				
			||||||
					if values.Values[i][idx], isZero = field.ValueOf(rv); isZero {
 | 
										if values.Values[i][idx], isZero = field.ValueOf(stmt.Context, rv); isZero {
 | 
				
			||||||
						if field.DefaultValueInterface != nil {
 | 
											if field.DefaultValueInterface != nil {
 | 
				
			||||||
							values.Values[i][idx] = field.DefaultValueInterface
 | 
												values.Values[i][idx] = field.DefaultValueInterface
 | 
				
			||||||
							field.Set(rv, field.DefaultValueInterface)
 | 
												field.Set(stmt.Context, rv, field.DefaultValueInterface)
 | 
				
			||||||
						} else if field.AutoCreateTime > 0 || field.AutoUpdateTime > 0 {
 | 
											} else if field.AutoCreateTime > 0 || field.AutoUpdateTime > 0 {
 | 
				
			||||||
							field.Set(rv, curTime)
 | 
												field.Set(stmt.Context, rv, curTime)
 | 
				
			||||||
							values.Values[i][idx], _ = field.ValueOf(rv)
 | 
												values.Values[i][idx], _ = field.ValueOf(stmt.Context, rv)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					} else if field.AutoUpdateTime > 0 && updateTrackTime {
 | 
										} else if field.AutoUpdateTime > 0 && updateTrackTime {
 | 
				
			||||||
						field.Set(rv, curTime)
 | 
											field.Set(stmt.Context, rv, curTime)
 | 
				
			||||||
						values.Values[i][idx], _ = field.ValueOf(rv)
 | 
											values.Values[i][idx], _ = field.ValueOf(stmt.Context, rv)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				for _, field := range stmt.Schema.FieldsWithDefaultDBValue {
 | 
									for _, field := range stmt.Schema.FieldsWithDefaultDBValue {
 | 
				
			||||||
					if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
 | 
										if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
 | 
				
			||||||
						if rvOfvalue, isZero := field.ValueOf(rv); !isZero {
 | 
											if rvOfvalue, isZero := field.ValueOf(stmt.Context, rv); !isZero {
 | 
				
			||||||
							if len(defaultValueFieldsHavingValue[field]) == 0 {
 | 
												if len(defaultValueFieldsHavingValue[field]) == 0 {
 | 
				
			||||||
								defaultValueFieldsHavingValue[field] = make([]interface{}, rValLen)
 | 
													defaultValueFieldsHavingValue[field] = make([]interface{}, rValLen)
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
@ -259,23 +259,23 @@ func ConvertToCreateValues(stmt *gorm.Statement) (values clause.Values) {
 | 
				
			|||||||
			values.Values = [][]interface{}{make([]interface{}, len(values.Columns))}
 | 
								values.Values = [][]interface{}{make([]interface{}, len(values.Columns))}
 | 
				
			||||||
			for idx, column := range values.Columns {
 | 
								for idx, column := range values.Columns {
 | 
				
			||||||
				field := stmt.Schema.FieldsByDBName[column.Name]
 | 
									field := stmt.Schema.FieldsByDBName[column.Name]
 | 
				
			||||||
				if values.Values[0][idx], isZero = field.ValueOf(stmt.ReflectValue); isZero {
 | 
									if values.Values[0][idx], isZero = field.ValueOf(stmt.Context, stmt.ReflectValue); isZero {
 | 
				
			||||||
					if field.DefaultValueInterface != nil {
 | 
										if field.DefaultValueInterface != nil {
 | 
				
			||||||
						values.Values[0][idx] = field.DefaultValueInterface
 | 
											values.Values[0][idx] = field.DefaultValueInterface
 | 
				
			||||||
						field.Set(stmt.ReflectValue, field.DefaultValueInterface)
 | 
											field.Set(stmt.Context, stmt.ReflectValue, field.DefaultValueInterface)
 | 
				
			||||||
					} else if field.AutoCreateTime > 0 || field.AutoUpdateTime > 0 {
 | 
										} else if field.AutoCreateTime > 0 || field.AutoUpdateTime > 0 {
 | 
				
			||||||
						field.Set(stmt.ReflectValue, curTime)
 | 
											field.Set(stmt.Context, stmt.ReflectValue, curTime)
 | 
				
			||||||
						values.Values[0][idx], _ = field.ValueOf(stmt.ReflectValue)
 | 
											values.Values[0][idx], _ = field.ValueOf(stmt.Context, stmt.ReflectValue)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				} else if field.AutoUpdateTime > 0 && updateTrackTime {
 | 
									} else if field.AutoUpdateTime > 0 && updateTrackTime {
 | 
				
			||||||
					field.Set(stmt.ReflectValue, curTime)
 | 
										field.Set(stmt.Context, stmt.ReflectValue, curTime)
 | 
				
			||||||
					values.Values[0][idx], _ = field.ValueOf(stmt.ReflectValue)
 | 
										values.Values[0][idx], _ = field.ValueOf(stmt.Context, stmt.ReflectValue)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for _, field := range stmt.Schema.FieldsWithDefaultDBValue {
 | 
								for _, field := range stmt.Schema.FieldsWithDefaultDBValue {
 | 
				
			||||||
				if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
 | 
									if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
 | 
				
			||||||
					if rvOfvalue, isZero := field.ValueOf(stmt.ReflectValue); !isZero {
 | 
										if rvOfvalue, isZero := field.ValueOf(stmt.Context, stmt.ReflectValue); !isZero {
 | 
				
			||||||
						values.Columns = append(values.Columns, clause.Column{Name: field.DBName})
 | 
											values.Columns = append(values.Columns, clause.Column{Name: field.DBName})
 | 
				
			||||||
						values.Values[0] = append(values.Values[0], rvOfvalue)
 | 
											values.Values[0] = append(values.Values[0], rvOfvalue)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
				
			|||||||
@ -42,7 +42,7 @@ func DeleteBeforeAssociations(db *gorm.DB) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			switch rel.Type {
 | 
								switch rel.Type {
 | 
				
			||||||
			case schema.HasOne, schema.HasMany:
 | 
								case schema.HasOne, schema.HasMany:
 | 
				
			||||||
				queryConds := rel.ToQueryConditions(db.Statement.ReflectValue)
 | 
									queryConds := rel.ToQueryConditions(db.Statement.Context, db.Statement.ReflectValue)
 | 
				
			||||||
				modelValue := reflect.New(rel.FieldSchema.ModelType).Interface()
 | 
									modelValue := reflect.New(rel.FieldSchema.ModelType).Interface()
 | 
				
			||||||
				tx := db.Session(&gorm.Session{NewDB: true}).Model(modelValue)
 | 
									tx := db.Session(&gorm.Session{NewDB: true}).Model(modelValue)
 | 
				
			||||||
				withoutConditions := false
 | 
									withoutConditions := false
 | 
				
			||||||
@ -97,7 +97,7 @@ func DeleteBeforeAssociations(db *gorm.DB) {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				_, foreignValues := schema.GetIdentityFieldValuesMap(db.Statement.ReflectValue, foreignFields)
 | 
									_, foreignValues := schema.GetIdentityFieldValuesMap(db.Statement.Context, db.Statement.ReflectValue, foreignFields)
 | 
				
			||||||
				column, values := schema.ToQueryValues(table, relForeignKeys, foreignValues)
 | 
									column, values := schema.ToQueryValues(table, relForeignKeys, foreignValues)
 | 
				
			||||||
				queryConds = append(queryConds, clause.IN{Column: column, Values: values})
 | 
									queryConds = append(queryConds, clause.IN{Column: column, Values: values})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -123,7 +123,7 @@ func Delete(config *Config) func(db *gorm.DB) {
 | 
				
			|||||||
			db.Statement.AddClauseIfNotExists(clause.Delete{})
 | 
								db.Statement.AddClauseIfNotExists(clause.Delete{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if db.Statement.Schema != nil {
 | 
								if db.Statement.Schema != nil {
 | 
				
			||||||
				_, queryValues := schema.GetIdentityFieldValuesMap(db.Statement.ReflectValue, db.Statement.Schema.PrimaryFields)
 | 
									_, queryValues := schema.GetIdentityFieldValuesMap(db.Statement.Context, db.Statement.ReflectValue, db.Statement.Schema.PrimaryFields)
 | 
				
			||||||
				column, values := schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
 | 
									column, values := schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if len(values) > 0 {
 | 
									if len(values) > 0 {
 | 
				
			||||||
@ -131,7 +131,7 @@ func Delete(config *Config) func(db *gorm.DB) {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if db.Statement.ReflectValue.CanAddr() && db.Statement.Dest != db.Statement.Model && db.Statement.Model != nil {
 | 
									if db.Statement.ReflectValue.CanAddr() && db.Statement.Dest != db.Statement.Model && db.Statement.Model != nil {
 | 
				
			||||||
					_, queryValues = schema.GetIdentityFieldValuesMap(reflect.ValueOf(db.Statement.Model), db.Statement.Schema.PrimaryFields)
 | 
										_, queryValues = schema.GetIdentityFieldValuesMap(db.Statement.Context, reflect.ValueOf(db.Statement.Model), db.Statement.Schema.PrimaryFields)
 | 
				
			||||||
					column, values = schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
 | 
										column, values = schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if len(values) > 0 {
 | 
										if len(values) > 0 {
 | 
				
			||||||
 | 
				
			|||||||
@ -48,7 +48,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		joinIdentityMap, joinForeignValues := schema.GetIdentityFieldValuesMap(reflectValue, foreignFields)
 | 
							joinIdentityMap, joinForeignValues := schema.GetIdentityFieldValuesMap(db.Statement.Context, reflectValue, foreignFields)
 | 
				
			||||||
		if len(joinForeignValues) == 0 {
 | 
							if len(joinForeignValues) == 0 {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -63,11 +63,11 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 | 
				
			|||||||
		for i := 0; i < joinResults.Len(); i++ {
 | 
							for i := 0; i < joinResults.Len(); i++ {
 | 
				
			||||||
			joinIndexValue := joinResults.Index(i)
 | 
								joinIndexValue := joinResults.Index(i)
 | 
				
			||||||
			for idx, field := range joinForeignFields {
 | 
								for idx, field := range joinForeignFields {
 | 
				
			||||||
				fieldValues[idx], _ = field.ValueOf(joinIndexValue)
 | 
									fieldValues[idx], _ = field.ValueOf(db.Statement.Context, joinIndexValue)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for idx, field := range joinRelForeignFields {
 | 
								for idx, field := range joinRelForeignFields {
 | 
				
			||||||
				joinFieldValues[idx], _ = field.ValueOf(joinIndexValue)
 | 
									joinFieldValues[idx], _ = field.ValueOf(db.Statement.Context, joinIndexValue)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if results, ok := joinIdentityMap[utils.ToStringKey(fieldValues...)]; ok {
 | 
								if results, ok := joinIdentityMap[utils.ToStringKey(fieldValues...)]; ok {
 | 
				
			||||||
@ -76,7 +76,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_, foreignValues = schema.GetIdentityFieldValuesMap(joinResults, joinRelForeignFields)
 | 
							_, foreignValues = schema.GetIdentityFieldValuesMap(db.Statement.Context, joinResults, joinRelForeignFields)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		for _, ref := range rel.References {
 | 
							for _, ref := range rel.References {
 | 
				
			||||||
			if ref.OwnPrimaryKey {
 | 
								if ref.OwnPrimaryKey {
 | 
				
			||||||
@ -92,7 +92,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		identityMap, foreignValues = schema.GetIdentityFieldValuesMap(reflectValue, foreignFields)
 | 
							identityMap, foreignValues = schema.GetIdentityFieldValuesMap(db.Statement.Context, reflectValue, foreignFields)
 | 
				
			||||||
		if len(foreignValues) == 0 {
 | 
							if len(foreignValues) == 0 {
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -125,17 +125,17 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 | 
				
			|||||||
	case reflect.Struct:
 | 
						case reflect.Struct:
 | 
				
			||||||
		switch rel.Type {
 | 
							switch rel.Type {
 | 
				
			||||||
		case schema.HasMany, schema.Many2Many:
 | 
							case schema.HasMany, schema.Many2Many:
 | 
				
			||||||
			rel.Field.Set(reflectValue, reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
 | 
								rel.Field.Set(db.Statement.Context, reflectValue, reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			rel.Field.Set(reflectValue, reflect.New(rel.Field.FieldType).Interface())
 | 
								rel.Field.Set(db.Statement.Context, reflectValue, reflect.New(rel.Field.FieldType).Interface())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.Slice, reflect.Array:
 | 
						case reflect.Slice, reflect.Array:
 | 
				
			||||||
		for i := 0; i < reflectValue.Len(); i++ {
 | 
							for i := 0; i < reflectValue.Len(); i++ {
 | 
				
			||||||
			switch rel.Type {
 | 
								switch rel.Type {
 | 
				
			||||||
			case schema.HasMany, schema.Many2Many:
 | 
								case schema.HasMany, schema.Many2Many:
 | 
				
			||||||
				rel.Field.Set(reflectValue.Index(i), reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
 | 
									rel.Field.Set(db.Statement.Context, reflectValue.Index(i), reflect.MakeSlice(rel.Field.IndirectFieldType, 0, 10).Interface())
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				rel.Field.Set(reflectValue.Index(i), reflect.New(rel.Field.FieldType).Interface())
 | 
									rel.Field.Set(db.Statement.Context, reflectValue.Index(i), reflect.New(rel.Field.FieldType).Interface())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -143,7 +143,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 | 
				
			|||||||
	for i := 0; i < reflectResults.Len(); i++ {
 | 
						for i := 0; i < reflectResults.Len(); i++ {
 | 
				
			||||||
		elem := reflectResults.Index(i)
 | 
							elem := reflectResults.Index(i)
 | 
				
			||||||
		for idx, field := range relForeignFields {
 | 
							for idx, field := range relForeignFields {
 | 
				
			||||||
			fieldValues[idx], _ = field.ValueOf(elem)
 | 
								fieldValues[idx], _ = field.ValueOf(db.Statement.Context, elem)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		datas, ok := identityMap[utils.ToStringKey(fieldValues...)]
 | 
							datas, ok := identityMap[utils.ToStringKey(fieldValues...)]
 | 
				
			||||||
@ -154,7 +154,7 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for _, data := range datas {
 | 
							for _, data := range datas {
 | 
				
			||||||
			reflectFieldValue := rel.Field.ReflectValueOf(data)
 | 
								reflectFieldValue := rel.Field.ReflectValueOf(db.Statement.Context, data)
 | 
				
			||||||
			if reflectFieldValue.Kind() == reflect.Ptr && reflectFieldValue.IsNil() {
 | 
								if reflectFieldValue.Kind() == reflect.Ptr && reflectFieldValue.IsNil() {
 | 
				
			||||||
				reflectFieldValue.Set(reflect.New(rel.Field.FieldType.Elem()))
 | 
									reflectFieldValue.Set(reflect.New(rel.Field.FieldType.Elem()))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -162,12 +162,12 @@ func preload(db *gorm.DB, rel *schema.Relationship, conds []interface{}, preload
 | 
				
			|||||||
			reflectFieldValue = reflect.Indirect(reflectFieldValue)
 | 
								reflectFieldValue = reflect.Indirect(reflectFieldValue)
 | 
				
			||||||
			switch reflectFieldValue.Kind() {
 | 
								switch reflectFieldValue.Kind() {
 | 
				
			||||||
			case reflect.Struct:
 | 
								case reflect.Struct:
 | 
				
			||||||
				rel.Field.Set(data, elem.Interface())
 | 
									rel.Field.Set(db.Statement.Context, data, elem.Interface())
 | 
				
			||||||
			case reflect.Slice, reflect.Array:
 | 
								case reflect.Slice, reflect.Array:
 | 
				
			||||||
				if reflectFieldValue.Type().Elem().Kind() == reflect.Ptr {
 | 
									if reflectFieldValue.Type().Elem().Kind() == reflect.Ptr {
 | 
				
			||||||
					rel.Field.Set(data, reflect.Append(reflectFieldValue, elem).Interface())
 | 
										rel.Field.Set(db.Statement.Context, data, reflect.Append(reflectFieldValue, elem).Interface())
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					rel.Field.Set(data, reflect.Append(reflectFieldValue, elem.Elem()).Interface())
 | 
										rel.Field.Set(db.Statement.Context, data, reflect.Append(reflectFieldValue, elem.Elem()).Interface())
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -40,7 +40,7 @@ func BuildQuerySQL(db *gorm.DB) {
 | 
				
			|||||||
		if db.Statement.ReflectValue.Kind() == reflect.Struct && db.Statement.ReflectValue.Type() == db.Statement.Schema.ModelType {
 | 
							if db.Statement.ReflectValue.Kind() == reflect.Struct && db.Statement.ReflectValue.Type() == db.Statement.Schema.ModelType {
 | 
				
			||||||
			var conds []clause.Expression
 | 
								var conds []clause.Expression
 | 
				
			||||||
			for _, primaryField := range db.Statement.Schema.PrimaryFields {
 | 
								for _, primaryField := range db.Statement.Schema.PrimaryFields {
 | 
				
			||||||
				if v, isZero := primaryField.ValueOf(db.Statement.ReflectValue); !isZero {
 | 
									if v, isZero := primaryField.ValueOf(db.Statement.Context, db.Statement.ReflectValue); !isZero {
 | 
				
			||||||
					conds = append(conds, clause.Eq{Column: clause.Column{Table: db.Statement.Table, Name: primaryField.DBName}, Value: v})
 | 
										conds = append(conds, clause.Eq{Column: clause.Column{Table: db.Statement.Table, Name: primaryField.DBName}, Value: v})
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,7 @@ func SetupUpdateReflectValue(db *gorm.DB) {
 | 
				
			|||||||
			if dest, ok := db.Statement.Dest.(map[string]interface{}); ok {
 | 
								if dest, ok := db.Statement.Dest.(map[string]interface{}); ok {
 | 
				
			||||||
				for _, rel := range db.Statement.Schema.Relationships.BelongsTo {
 | 
									for _, rel := range db.Statement.Schema.Relationships.BelongsTo {
 | 
				
			||||||
					if _, ok := dest[rel.Name]; ok {
 | 
										if _, ok := dest[rel.Name]; ok {
 | 
				
			||||||
						rel.Field.Set(db.Statement.ReflectValue, dest[rel.Name])
 | 
											rel.Field.Set(db.Statement.Context, db.Statement.ReflectValue, dest[rel.Name])
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -137,13 +137,13 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 | 
				
			|||||||
	case reflect.Slice, reflect.Array:
 | 
						case reflect.Slice, reflect.Array:
 | 
				
			||||||
		assignValue = func(field *schema.Field, value interface{}) {
 | 
							assignValue = func(field *schema.Field, value interface{}) {
 | 
				
			||||||
			for i := 0; i < stmt.ReflectValue.Len(); i++ {
 | 
								for i := 0; i < stmt.ReflectValue.Len(); i++ {
 | 
				
			||||||
				field.Set(stmt.ReflectValue.Index(i), value)
 | 
									field.Set(stmt.Context, stmt.ReflectValue.Index(i), value)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.Struct:
 | 
						case reflect.Struct:
 | 
				
			||||||
		assignValue = func(field *schema.Field, value interface{}) {
 | 
							assignValue = func(field *schema.Field, value interface{}) {
 | 
				
			||||||
			if stmt.ReflectValue.CanAddr() {
 | 
								if stmt.ReflectValue.CanAddr() {
 | 
				
			||||||
				field.Set(stmt.ReflectValue, value)
 | 
									field.Set(stmt.Context, stmt.ReflectValue, value)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@ -165,7 +165,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 | 
				
			|||||||
					exprs := make([]clause.Expression, len(stmt.Schema.PrimaryFields))
 | 
										exprs := make([]clause.Expression, len(stmt.Schema.PrimaryFields))
 | 
				
			||||||
					var notZero bool
 | 
										var notZero bool
 | 
				
			||||||
					for idx, field := range stmt.Schema.PrimaryFields {
 | 
										for idx, field := range stmt.Schema.PrimaryFields {
 | 
				
			||||||
						value, isZero := field.ValueOf(stmt.ReflectValue.Index(i))
 | 
											value, isZero := field.ValueOf(stmt.Context, stmt.ReflectValue.Index(i))
 | 
				
			||||||
						exprs[idx] = clause.Eq{Column: field.DBName, Value: value}
 | 
											exprs[idx] = clause.Eq{Column: field.DBName, Value: value}
 | 
				
			||||||
						notZero = notZero || !isZero
 | 
											notZero = notZero || !isZero
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@ -178,7 +178,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		case reflect.Struct:
 | 
							case reflect.Struct:
 | 
				
			||||||
			for _, field := range stmt.Schema.PrimaryFields {
 | 
								for _, field := range stmt.Schema.PrimaryFields {
 | 
				
			||||||
				if value, isZero := field.ValueOf(stmt.ReflectValue); !isZero {
 | 
									if value, isZero := field.ValueOf(stmt.Context, stmt.ReflectValue); !isZero {
 | 
				
			||||||
					stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.Eq{Column: field.DBName, Value: value}}})
 | 
										stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.Eq{Column: field.DBName, Value: value}}})
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -258,7 +258,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 | 
				
			|||||||
				if field := updatingSchema.LookUpField(dbName); field != nil {
 | 
									if field := updatingSchema.LookUpField(dbName); field != nil {
 | 
				
			||||||
					if !field.PrimaryKey || !updatingValue.CanAddr() || stmt.Dest != stmt.Model {
 | 
										if !field.PrimaryKey || !updatingValue.CanAddr() || stmt.Dest != stmt.Model {
 | 
				
			||||||
						if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && (!restricted || (!stmt.SkipHooks && field.AutoUpdateTime > 0))) {
 | 
											if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && (!restricted || (!stmt.SkipHooks && field.AutoUpdateTime > 0))) {
 | 
				
			||||||
							value, isZero := field.ValueOf(updatingValue)
 | 
												value, isZero := field.ValueOf(stmt.Context, updatingValue)
 | 
				
			||||||
							if !stmt.SkipHooks && field.AutoUpdateTime > 0 {
 | 
												if !stmt.SkipHooks && field.AutoUpdateTime > 0 {
 | 
				
			||||||
								if field.AutoUpdateTime == schema.UnixNanosecond {
 | 
													if field.AutoUpdateTime == schema.UnixNanosecond {
 | 
				
			||||||
									value = stmt.DB.NowFunc().UnixNano()
 | 
														value = stmt.DB.NowFunc().UnixNano()
 | 
				
			||||||
@ -278,7 +278,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 | 
				
			|||||||
							}
 | 
												}
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						if value, isZero := field.ValueOf(updatingValue); !isZero {
 | 
											if value, isZero := field.ValueOf(stmt.Context, updatingValue); !isZero {
 | 
				
			||||||
							stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.Eq{Column: field.DBName, Value: value}}})
 | 
												stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.Eq{Column: field.DBName, Value: value}}})
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
				
			|||||||
@ -83,7 +83,7 @@ func (db *DB) Save(value interface{}) (tx *DB) {
 | 
				
			|||||||
	case reflect.Struct:
 | 
						case reflect.Struct:
 | 
				
			||||||
		if err := tx.Statement.Parse(value); err == nil && tx.Statement.Schema != nil {
 | 
							if err := tx.Statement.Parse(value); err == nil && tx.Statement.Schema != nil {
 | 
				
			||||||
			for _, pf := range tx.Statement.Schema.PrimaryFields {
 | 
								for _, pf := range tx.Statement.Schema.PrimaryFields {
 | 
				
			||||||
				if _, isZero := pf.ValueOf(reflectValue); isZero {
 | 
									if _, isZero := pf.ValueOf(tx.Statement.Context, reflectValue); isZero {
 | 
				
			||||||
					return tx.callbacks.Create().Execute(tx)
 | 
										return tx.callbacks.Create().Execute(tx)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -199,7 +199,7 @@ func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, bat
 | 
				
			|||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		primaryValue, _ := result.Statement.Schema.PrioritizedPrimaryField.ValueOf(resultsValue.Index(resultsValue.Len() - 1))
 | 
							primaryValue, _ := result.Statement.Schema.PrioritizedPrimaryField.ValueOf(tx.Statement.Context, resultsValue.Index(resultsValue.Len()-1))
 | 
				
			||||||
		queryDB = tx.Clauses(clause.Gt{Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, Value: primaryValue})
 | 
							queryDB = tx.Clauses(clause.Gt{Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, Value: primaryValue})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -216,11 +216,11 @@ func (tx *DB) assignInterfacesToValue(values ...interface{}) {
 | 
				
			|||||||
					switch column := eq.Column.(type) {
 | 
										switch column := eq.Column.(type) {
 | 
				
			||||||
					case string:
 | 
										case string:
 | 
				
			||||||
						if field := tx.Statement.Schema.LookUpField(column); field != nil {
 | 
											if field := tx.Statement.Schema.LookUpField(column); field != nil {
 | 
				
			||||||
							tx.AddError(field.Set(tx.Statement.ReflectValue, eq.Value))
 | 
												tx.AddError(field.Set(tx.Statement.Context, tx.Statement.ReflectValue, eq.Value))
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					case clause.Column:
 | 
										case clause.Column:
 | 
				
			||||||
						if field := tx.Statement.Schema.LookUpField(column.Name); field != nil {
 | 
											if field := tx.Statement.Schema.LookUpField(column.Name); field != nil {
 | 
				
			||||||
							tx.AddError(field.Set(tx.Statement.ReflectValue, eq.Value))
 | 
												tx.AddError(field.Set(tx.Statement.Context, tx.Statement.ReflectValue, eq.Value))
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				} else if andCond, ok := expr.(clause.AndConditions); ok {
 | 
									} else if andCond, ok := expr.(clause.AndConditions); ok {
 | 
				
			||||||
@ -238,9 +238,9 @@ func (tx *DB) assignInterfacesToValue(values ...interface{}) {
 | 
				
			|||||||
				case reflect.Struct:
 | 
									case reflect.Struct:
 | 
				
			||||||
					for _, f := range s.Fields {
 | 
										for _, f := range s.Fields {
 | 
				
			||||||
						if f.Readable {
 | 
											if f.Readable {
 | 
				
			||||||
							if v, isZero := f.ValueOf(reflectValue); !isZero {
 | 
												if v, isZero := f.ValueOf(tx.Statement.Context, reflectValue); !isZero {
 | 
				
			||||||
								if field := tx.Statement.Schema.LookUpField(f.Name); field != nil {
 | 
													if field := tx.Statement.Schema.LookUpField(f.Name); field != nil {
 | 
				
			||||||
									tx.AddError(field.Set(tx.Statement.ReflectValue, v))
 | 
														tx.AddError(field.Set(tx.Statement.Context, tx.Statement.ReflectValue, v))
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
				
			|||||||
@ -40,14 +40,17 @@ type SavePointerDialectorInterface interface {
 | 
				
			|||||||
	RollbackTo(tx *DB, name string) error
 | 
						RollbackTo(tx *DB, name string) error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TxBeginner tx beginner
 | 
				
			||||||
type TxBeginner interface {
 | 
					type TxBeginner interface {
 | 
				
			||||||
	BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
 | 
						BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ConnPoolBeginner conn pool beginner
 | 
				
			||||||
type ConnPoolBeginner interface {
 | 
					type ConnPoolBeginner interface {
 | 
				
			||||||
	BeginTx(ctx context.Context, opts *sql.TxOptions) (ConnPool, error)
 | 
						BeginTx(ctx context.Context, opts *sql.TxOptions) (ConnPool, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TxCommitter tx commiter
 | 
				
			||||||
type TxCommitter interface {
 | 
					type TxCommitter interface {
 | 
				
			||||||
	Commit() error
 | 
						Commit() error
 | 
				
			||||||
	Rollback() error
 | 
						Rollback() error
 | 
				
			||||||
@ -58,6 +61,7 @@ type Valuer interface {
 | 
				
			|||||||
	GormValue(context.Context, *DB) clause.Expr
 | 
						GormValue(context.Context, *DB) clause.Expr
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetDBConnector SQL db connector
 | 
				
			||||||
type GetDBConnector interface {
 | 
					type GetDBConnector interface {
 | 
				
			||||||
	GetDBConn() (*sql.DB, error)
 | 
						GetDBConn() (*sql.DB, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										32
									
								
								scan.go
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								scan.go
									
									
									
									
									
								
							@ -10,6 +10,7 @@ import (
 | 
				
			|||||||
	"gorm.io/gorm/schema"
 | 
						"gorm.io/gorm/schema"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// prepareValues prepare values slice
 | 
				
			||||||
func prepareValues(values []interface{}, db *DB, columnTypes []*sql.ColumnType, columns []string) {
 | 
					func prepareValues(values []interface{}, db *DB, columnTypes []*sql.ColumnType, columns []string) {
 | 
				
			||||||
	if db.Statement.Schema != nil {
 | 
						if db.Statement.Schema != nil {
 | 
				
			||||||
		for idx, name := range columns {
 | 
							for idx, name := range columns {
 | 
				
			||||||
@ -54,11 +55,13 @@ func (db *DB) scanIntoStruct(sch *schema.Schema, rows *sql.Rows, reflectValue re
 | 
				
			|||||||
		if sch == nil {
 | 
							if sch == nil {
 | 
				
			||||||
			values[idx] = reflectValue.Interface()
 | 
								values[idx] = reflectValue.Interface()
 | 
				
			||||||
		} else if field := sch.LookUpField(column); field != nil && field.Readable {
 | 
							} else if field := sch.LookUpField(column); field != nil && field.Readable {
 | 
				
			||||||
			values[idx] = reflect.New(reflect.PtrTo(field.IndirectFieldType)).Interface()
 | 
								values[idx] = field.NewValuePool.Get()
 | 
				
			||||||
 | 
								defer field.NewValuePool.Put(values[idx])
 | 
				
			||||||
		} else if names := strings.Split(column, "__"); len(names) > 1 {
 | 
							} else if names := strings.Split(column, "__"); len(names) > 1 {
 | 
				
			||||||
			if rel, ok := sch.Relationships.Relations[names[0]]; ok {
 | 
								if rel, ok := sch.Relationships.Relations[names[0]]; ok {
 | 
				
			||||||
				if field := rel.FieldSchema.LookUpField(strings.Join(names[1:], "__")); field != nil && field.Readable {
 | 
									if field := rel.FieldSchema.LookUpField(strings.Join(names[1:], "__")); field != nil && field.Readable {
 | 
				
			||||||
					values[idx] = reflect.New(reflect.PtrTo(field.IndirectFieldType)).Interface()
 | 
										values[idx] = field.NewValuePool.Get()
 | 
				
			||||||
 | 
										defer field.NewValuePool.Put(values[idx])
 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -77,21 +80,21 @@ func (db *DB) scanIntoStruct(sch *schema.Schema, rows *sql.Rows, reflectValue re
 | 
				
			|||||||
	if sch != nil {
 | 
						if sch != nil {
 | 
				
			||||||
		for idx, column := range columns {
 | 
							for idx, column := range columns {
 | 
				
			||||||
			if field := sch.LookUpField(column); field != nil && field.Readable {
 | 
								if field := sch.LookUpField(column); field != nil && field.Readable {
 | 
				
			||||||
				field.Set(reflectValue, values[idx])
 | 
									field.Set(db.Statement.Context, reflectValue, values[idx])
 | 
				
			||||||
			} else if names := strings.Split(column, "__"); len(names) > 1 {
 | 
								} else if names := strings.Split(column, "__"); len(names) > 1 {
 | 
				
			||||||
				if rel, ok := sch.Relationships.Relations[names[0]]; ok {
 | 
									if rel, ok := sch.Relationships.Relations[names[0]]; ok {
 | 
				
			||||||
					if field := rel.FieldSchema.LookUpField(strings.Join(names[1:], "__")); field != nil && field.Readable {
 | 
										if field := rel.FieldSchema.LookUpField(strings.Join(names[1:], "__")); field != nil && field.Readable {
 | 
				
			||||||
						relValue := rel.Field.ReflectValueOf(reflectValue)
 | 
											relValue := rel.Field.ReflectValueOf(db.Statement.Context, reflectValue)
 | 
				
			||||||
						value := reflect.ValueOf(values[idx]).Elem()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if relValue.Kind() == reflect.Ptr && relValue.IsNil() {
 | 
											if relValue.Kind() == reflect.Ptr && relValue.IsNil() {
 | 
				
			||||||
							if value.IsNil() {
 | 
												if value := reflect.ValueOf(values[idx]).Elem(); value.Kind() == reflect.Ptr && value.IsNil() {
 | 
				
			||||||
								continue
 | 
													continue
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							relValue.Set(reflect.New(relValue.Type().Elem()))
 | 
												relValue.Set(reflect.New(relValue.Type().Elem()))
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						field.Set(relValue, values[idx])
 | 
											field.Set(db.Statement.Context, relValue, values[idx])
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -99,14 +102,17 @@ func (db *DB) scanIntoStruct(sch *schema.Schema, rows *sql.Rows, reflectValue re
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ScanMode scan data mode
 | 
				
			||||||
type ScanMode uint8
 | 
					type ScanMode uint8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// scan modes
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	ScanInitialized         ScanMode = 1 << 0 // 1
 | 
						ScanInitialized         ScanMode = 1 << 0 // 1
 | 
				
			||||||
	ScanUpdate              ScanMode = 1 << 1 // 2
 | 
						ScanUpdate              ScanMode = 1 << 1 // 2
 | 
				
			||||||
	ScanOnConflictDoNothing ScanMode = 1 << 2 // 4
 | 
						ScanOnConflictDoNothing ScanMode = 1 << 2 // 4
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Scan scan rows into db statement
 | 
				
			||||||
func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 | 
					func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		columns, _          = rows.Columns()
 | 
							columns, _          = rows.Columns()
 | 
				
			||||||
@ -138,7 +144,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			scanIntoMap(mapValue, values, columns)
 | 
								scanIntoMap(mapValue, values, columns)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case *[]map[string]interface{}, []map[string]interface{}:
 | 
						case *[]map[string]interface{}:
 | 
				
			||||||
		columnTypes, _ := rows.ColumnTypes()
 | 
							columnTypes, _ := rows.ColumnTypes()
 | 
				
			||||||
		for initialized || rows.Next() {
 | 
							for initialized || rows.Next() {
 | 
				
			||||||
			prepareValues(values, db, columnTypes, columns)
 | 
								prepareValues(values, db, columnTypes, columns)
 | 
				
			||||||
@ -149,11 +155,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			mapValue := map[string]interface{}{}
 | 
								mapValue := map[string]interface{}{}
 | 
				
			||||||
			scanIntoMap(mapValue, values, columns)
 | 
								scanIntoMap(mapValue, values, columns)
 | 
				
			||||||
			if values, ok := dest.([]map[string]interface{}); ok {
 | 
								*dest = append(*dest, mapValue)
 | 
				
			||||||
				values = append(values, mapValue)
 | 
					 | 
				
			||||||
			} else if values, ok := dest.(*[]map[string]interface{}); ok {
 | 
					 | 
				
			||||||
				*values = append(*values, mapValue)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case *int, *int8, *int16, *int32, *int64,
 | 
						case *int, *int8, *int16, *int32, *int64,
 | 
				
			||||||
		*uint, *uint8, *uint16, *uint32, *uint64, *uintptr,
 | 
							*uint, *uint8, *uint16, *uint32, *uint64, *uintptr,
 | 
				
			||||||
@ -174,7 +176,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 | 
				
			|||||||
			reflectValue = db.Statement.ReflectValue
 | 
								reflectValue = db.Statement.ReflectValue
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if reflectValue.Kind() == reflect.Interface {
 | 
							for reflectValue.Kind() == reflect.Interface {
 | 
				
			||||||
			reflectValue = reflectValue.Elem()
 | 
								reflectValue = reflectValue.Elem()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -244,7 +246,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 | 
				
			|||||||
					elem = reflectValue.Index(int(db.RowsAffected))
 | 
										elem = reflectValue.Index(int(db.RowsAffected))
 | 
				
			||||||
					if onConflictDonothing {
 | 
										if onConflictDonothing {
 | 
				
			||||||
						for _, field := range fields {
 | 
											for _, field := range fields {
 | 
				
			||||||
							if _, ok := field.ValueOf(elem); !ok {
 | 
												if _, ok := field.ValueOf(db.Statement.Context, elem); !ok {
 | 
				
			||||||
								db.RowsAffected++
 | 
													db.RowsAffected++
 | 
				
			||||||
								goto BEGIN
 | 
													goto BEGIN
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										516
									
								
								schema/field.go
									
									
									
									
									
								
							
							
						
						
									
										516
									
								
								schema/field.go
									
									
									
									
									
								
							@ -1,6 +1,7 @@
 | 
				
			|||||||
package schema
 | 
					package schema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
	"database/sql"
 | 
						"database/sql"
 | 
				
			||||||
	"database/sql/driver"
 | 
						"database/sql/driver"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
@ -14,12 +15,21 @@ import (
 | 
				
			|||||||
	"gorm.io/gorm/utils"
 | 
						"gorm.io/gorm/utils"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type DataType string
 | 
					// special types' reflect type
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						TimeReflectType    = reflect.TypeOf(time.Time{})
 | 
				
			||||||
 | 
						TimePtrReflectType = reflect.TypeOf(&time.Time{})
 | 
				
			||||||
 | 
						ByteReflectType    = reflect.TypeOf(uint8(0))
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type TimeType int64
 | 
					type (
 | 
				
			||||||
 | 
						// DataType GORM data type
 | 
				
			||||||
var TimeReflectType = reflect.TypeOf(time.Time{})
 | 
						DataType string
 | 
				
			||||||
 | 
						// TimeType GORM time type
 | 
				
			||||||
 | 
						TimeType int64
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GORM time types
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	UnixTime        TimeType = 1
 | 
						UnixTime        TimeType = 1
 | 
				
			||||||
	UnixSecond      TimeType = 2
 | 
						UnixSecond      TimeType = 2
 | 
				
			||||||
@ -27,6 +37,7 @@ const (
 | 
				
			|||||||
	UnixNanosecond  TimeType = 4
 | 
						UnixNanosecond  TimeType = 4
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GORM fields types
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	Bool   DataType = "bool"
 | 
						Bool   DataType = "bool"
 | 
				
			||||||
	Int    DataType = "int"
 | 
						Int    DataType = "int"
 | 
				
			||||||
@ -37,6 +48,7 @@ const (
 | 
				
			|||||||
	Bytes  DataType = "bytes"
 | 
						Bytes  DataType = "bytes"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Field is the representation of model schema's field
 | 
				
			||||||
type Field struct {
 | 
					type Field struct {
 | 
				
			||||||
	Name                   string
 | 
						Name                   string
 | 
				
			||||||
	DBName                 string
 | 
						DBName                 string
 | 
				
			||||||
@ -49,9 +61,9 @@ type Field struct {
 | 
				
			|||||||
	Creatable              bool
 | 
						Creatable              bool
 | 
				
			||||||
	Updatable              bool
 | 
						Updatable              bool
 | 
				
			||||||
	Readable               bool
 | 
						Readable               bool
 | 
				
			||||||
	HasDefaultValue        bool
 | 
					 | 
				
			||||||
	AutoCreateTime         TimeType
 | 
						AutoCreateTime         TimeType
 | 
				
			||||||
	AutoUpdateTime         TimeType
 | 
						AutoUpdateTime         TimeType
 | 
				
			||||||
 | 
						HasDefaultValue        bool
 | 
				
			||||||
	DefaultValue           string
 | 
						DefaultValue           string
 | 
				
			||||||
	DefaultValueInterface  interface{}
 | 
						DefaultValueInterface  interface{}
 | 
				
			||||||
	NotNull                bool
 | 
						NotNull                bool
 | 
				
			||||||
@ -60,6 +72,7 @@ type Field struct {
 | 
				
			|||||||
	Size                   int
 | 
						Size                   int
 | 
				
			||||||
	Precision              int
 | 
						Precision              int
 | 
				
			||||||
	Scale                  int
 | 
						Scale                  int
 | 
				
			||||||
 | 
						IgnoreMigration        bool
 | 
				
			||||||
	FieldType              reflect.Type
 | 
						FieldType              reflect.Type
 | 
				
			||||||
	IndirectFieldType      reflect.Type
 | 
						IndirectFieldType      reflect.Type
 | 
				
			||||||
	StructField            reflect.StructField
 | 
						StructField            reflect.StructField
 | 
				
			||||||
@ -68,27 +81,39 @@ type Field struct {
 | 
				
			|||||||
	Schema                 *Schema
 | 
						Schema                 *Schema
 | 
				
			||||||
	EmbeddedSchema         *Schema
 | 
						EmbeddedSchema         *Schema
 | 
				
			||||||
	OwnerSchema            *Schema
 | 
						OwnerSchema            *Schema
 | 
				
			||||||
	ReflectValueOf         func(reflect.Value) reflect.Value
 | 
						ReflectValueOf         func(context.Context, reflect.Value) reflect.Value
 | 
				
			||||||
	ValueOf                func(reflect.Value) (value interface{}, zero bool)
 | 
						ValueOf                func(context.Context, reflect.Value) (value interface{}, zero bool)
 | 
				
			||||||
	Set                    func(reflect.Value, interface{}) error
 | 
						Set                    func(context.Context, reflect.Value, interface{}) error
 | 
				
			||||||
	IgnoreMigration        bool
 | 
						Serializer             SerializerInterface
 | 
				
			||||||
 | 
						NewValuePool           FieldNewValuePool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ParseField parses reflect.StructField to Field
 | 
				
			||||||
func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 | 
					func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 | 
				
			||||||
	var err error
 | 
						var (
 | 
				
			||||||
 | 
							err        error
 | 
				
			||||||
 | 
							tagSetting = ParseTagSetting(fieldStruct.Tag.Get("gorm"), ";")
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	field := &Field{
 | 
						field := &Field{
 | 
				
			||||||
		Name:                   fieldStruct.Name,
 | 
							Name:                   fieldStruct.Name,
 | 
				
			||||||
 | 
							DBName:                 tagSetting["COLUMN"],
 | 
				
			||||||
		BindNames:              []string{fieldStruct.Name},
 | 
							BindNames:              []string{fieldStruct.Name},
 | 
				
			||||||
		FieldType:              fieldStruct.Type,
 | 
							FieldType:              fieldStruct.Type,
 | 
				
			||||||
		IndirectFieldType:      fieldStruct.Type,
 | 
							IndirectFieldType:      fieldStruct.Type,
 | 
				
			||||||
		StructField:            fieldStruct,
 | 
							StructField:            fieldStruct,
 | 
				
			||||||
 | 
							Tag:                    fieldStruct.Tag,
 | 
				
			||||||
 | 
							TagSettings:            tagSetting,
 | 
				
			||||||
 | 
							Schema:                 schema,
 | 
				
			||||||
		Creatable:              true,
 | 
							Creatable:              true,
 | 
				
			||||||
		Updatable:              true,
 | 
							Updatable:              true,
 | 
				
			||||||
		Readable:               true,
 | 
							Readable:               true,
 | 
				
			||||||
		Tag:                    fieldStruct.Tag,
 | 
							PrimaryKey:             utils.CheckTruth(tagSetting["PRIMARYKEY"], tagSetting["PRIMARY_KEY"]),
 | 
				
			||||||
		TagSettings:            ParseTagSetting(fieldStruct.Tag.Get("gorm"), ";"),
 | 
							AutoIncrement:          utils.CheckTruth(tagSetting["AUTOINCREMENT"]),
 | 
				
			||||||
		Schema:                 schema,
 | 
							HasDefaultValue:        utils.CheckTruth(tagSetting["AUTOINCREMENT"]),
 | 
				
			||||||
 | 
							NotNull:                utils.CheckTruth(tagSetting["NOT NULL"], tagSetting["NOTNULL"]),
 | 
				
			||||||
 | 
							Unique:                 utils.CheckTruth(tagSetting["UNIQUE"]),
 | 
				
			||||||
 | 
							Comment:                tagSetting["COMMENT"],
 | 
				
			||||||
		AutoIncrementIncrement: 1,
 | 
							AutoIncrementIncrement: 1,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -97,7 +122,7 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fieldValue := reflect.New(field.IndirectFieldType)
 | 
						fieldValue := reflect.New(field.IndirectFieldType)
 | 
				
			||||||
	// if field is valuer, used its value or first fields as data type
 | 
						// if field is valuer, used its value or first field as data type
 | 
				
			||||||
	valuer, isValuer := fieldValue.Interface().(driver.Valuer)
 | 
						valuer, isValuer := fieldValue.Interface().(driver.Valuer)
 | 
				
			||||||
	if isValuer {
 | 
						if isValuer {
 | 
				
			||||||
		if _, ok := fieldValue.Interface().(GormDataTypeInterface); !ok {
 | 
							if _, ok := fieldValue.Interface().(GormDataTypeInterface); !ok {
 | 
				
			||||||
@ -105,31 +130,37 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 | 
				
			|||||||
				fieldValue = reflect.ValueOf(v)
 | 
									fieldValue = reflect.ValueOf(v)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Use the field struct's first field type as data type, e.g: use `string` for sql.NullString
 | 
				
			||||||
			var getRealFieldValue func(reflect.Value)
 | 
								var getRealFieldValue func(reflect.Value)
 | 
				
			||||||
			getRealFieldValue = func(v reflect.Value) {
 | 
								getRealFieldValue = func(v reflect.Value) {
 | 
				
			||||||
				rv := reflect.Indirect(v)
 | 
									var (
 | 
				
			||||||
				if rv.Kind() == reflect.Struct && !rv.Type().ConvertibleTo(TimeReflectType) {
 | 
										rv     = reflect.Indirect(v)
 | 
				
			||||||
					for i := 0; i < rv.Type().NumField(); i++ {
 | 
										rvType = rv.Type()
 | 
				
			||||||
						newFieldType := rv.Type().Field(i).Type
 | 
									)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if rv.Kind() == reflect.Struct && !rvType.ConvertibleTo(TimeReflectType) {
 | 
				
			||||||
 | 
										for i := 0; i < rvType.NumField(); i++ {
 | 
				
			||||||
 | 
											for key, value := range ParseTagSetting(rvType.Field(i).Tag.Get("gorm"), ";") {
 | 
				
			||||||
 | 
												if _, ok := field.TagSettings[key]; !ok {
 | 
				
			||||||
 | 
													field.TagSettings[key] = value
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										for i := 0; i < rvType.NumField(); i++ {
 | 
				
			||||||
 | 
											newFieldType := rvType.Field(i).Type
 | 
				
			||||||
						for newFieldType.Kind() == reflect.Ptr {
 | 
											for newFieldType.Kind() == reflect.Ptr {
 | 
				
			||||||
							newFieldType = newFieldType.Elem()
 | 
												newFieldType = newFieldType.Elem()
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						fieldValue = reflect.New(newFieldType)
 | 
											fieldValue = reflect.New(newFieldType)
 | 
				
			||||||
 | 
											if rvType != reflect.Indirect(fieldValue).Type() {
 | 
				
			||||||
						if rv.Type() != reflect.Indirect(fieldValue).Type() {
 | 
					 | 
				
			||||||
							getRealFieldValue(fieldValue)
 | 
												getRealFieldValue(fieldValue)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if fieldValue.IsValid() {
 | 
											if fieldValue.IsValid() {
 | 
				
			||||||
							return
 | 
												return
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					 | 
				
			||||||
						for key, value := range ParseTagSetting(field.IndirectFieldType.Field(i).Tag.Get("gorm"), ";") {
 | 
					 | 
				
			||||||
							if _, ok := field.TagSettings[key]; !ok {
 | 
					 | 
				
			||||||
								field.TagSettings[key] = value
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -138,19 +169,23 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if dbName, ok := field.TagSettings["COLUMN"]; ok {
 | 
						if v, isSerializer := fieldValue.Interface().(SerializerInterface); isSerializer {
 | 
				
			||||||
		field.DBName = dbName
 | 
							field.DataType = String
 | 
				
			||||||
 | 
							field.Serializer = v
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							var serializerName = field.TagSettings["JSON"]
 | 
				
			||||||
 | 
							if serializerName == "" {
 | 
				
			||||||
 | 
								serializerName = field.TagSettings["SERIALIZER"]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if serializerName != "" {
 | 
				
			||||||
 | 
								if serializer, ok := GetSerializer(serializerName); ok {
 | 
				
			||||||
 | 
									// Set default data type to string for serializer
 | 
				
			||||||
 | 
									field.DataType = String
 | 
				
			||||||
 | 
									field.Serializer = serializer
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									schema.err = fmt.Errorf("invalid serializer type %v", serializerName)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if val, ok := field.TagSettings["PRIMARYKEY"]; ok && utils.CheckTruth(val) {
 | 
					 | 
				
			||||||
		field.PrimaryKey = true
 | 
					 | 
				
			||||||
	} else if val, ok := field.TagSettings["PRIMARY_KEY"]; ok && utils.CheckTruth(val) {
 | 
					 | 
				
			||||||
		field.PrimaryKey = true
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if val, ok := field.TagSettings["AUTOINCREMENT"]; ok && utils.CheckTruth(val) {
 | 
					 | 
				
			||||||
		field.AutoIncrement = true
 | 
					 | 
				
			||||||
		field.HasDefaultValue = true
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if num, ok := field.TagSettings["AUTOINCREMENTINCREMENT"]; ok {
 | 
						if num, ok := field.TagSettings["AUTOINCREMENTINCREMENT"]; ok {
 | 
				
			||||||
@ -176,20 +211,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 | 
				
			|||||||
		field.Scale, _ = strconv.Atoi(s)
 | 
							field.Scale, _ = strconv.Atoi(s)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if val, ok := field.TagSettings["NOT NULL"]; ok && utils.CheckTruth(val) {
 | 
					 | 
				
			||||||
		field.NotNull = true
 | 
					 | 
				
			||||||
	} else if val, ok := field.TagSettings["NOTNULL"]; ok && utils.CheckTruth(val) {
 | 
					 | 
				
			||||||
		field.NotNull = true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if val, ok := field.TagSettings["UNIQUE"]; ok && utils.CheckTruth(val) {
 | 
					 | 
				
			||||||
		field.Unique = true
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if val, ok := field.TagSettings["COMMENT"]; ok {
 | 
					 | 
				
			||||||
		field.Comment = val
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// default value is function or null or blank (primary keys)
 | 
						// default value is function or null or blank (primary keys)
 | 
				
			||||||
	field.DefaultValue = strings.TrimSpace(field.DefaultValue)
 | 
						field.DefaultValue = strings.TrimSpace(field.DefaultValue)
 | 
				
			||||||
	skipParseDefaultValue := strings.Contains(field.DefaultValue, "(") &&
 | 
						skipParseDefaultValue := strings.Contains(field.DefaultValue, "(") &&
 | 
				
			||||||
@ -225,7 +246,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.String:
 | 
						case reflect.String:
 | 
				
			||||||
		field.DataType = String
 | 
							field.DataType = String
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if field.HasDefaultValue && !skipParseDefaultValue {
 | 
							if field.HasDefaultValue && !skipParseDefaultValue {
 | 
				
			||||||
			field.DefaultValue = strings.Trim(field.DefaultValue, "'")
 | 
								field.DefaultValue = strings.Trim(field.DefaultValue, "'")
 | 
				
			||||||
			field.DefaultValue = strings.Trim(field.DefaultValue, `"`)
 | 
								field.DefaultValue = strings.Trim(field.DefaultValue, `"`)
 | 
				
			||||||
@ -236,17 +256,15 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 | 
				
			|||||||
			field.DataType = Time
 | 
								field.DataType = Time
 | 
				
			||||||
		} else if fieldValue.Type().ConvertibleTo(TimeReflectType) {
 | 
							} else if fieldValue.Type().ConvertibleTo(TimeReflectType) {
 | 
				
			||||||
			field.DataType = Time
 | 
								field.DataType = Time
 | 
				
			||||||
		} else if fieldValue.Type().ConvertibleTo(reflect.TypeOf(&time.Time{})) {
 | 
							} else if fieldValue.Type().ConvertibleTo(TimePtrReflectType) {
 | 
				
			||||||
			field.DataType = Time
 | 
								field.DataType = Time
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.Array, reflect.Slice:
 | 
						case reflect.Array, reflect.Slice:
 | 
				
			||||||
		if reflect.Indirect(fieldValue).Type().Elem() == reflect.TypeOf(uint8(0)) {
 | 
							if reflect.Indirect(fieldValue).Type().Elem() == ByteReflectType && field.DataType == "" {
 | 
				
			||||||
			field.DataType = Bytes
 | 
								field.DataType = Bytes
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	field.GORMDataType = field.DataType
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if dataTyper, ok := fieldValue.Interface().(GormDataTypeInterface); ok {
 | 
						if dataTyper, ok := fieldValue.Interface().(GormDataTypeInterface); ok {
 | 
				
			||||||
		field.DataType = DataType(dataTyper.GormDataType())
 | 
							field.DataType = DataType(dataTyper.GormDataType())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -346,8 +364,9 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, ok := field.TagSettings["EMBEDDED"]; field.GORMDataType != Time && field.GORMDataType != Bytes &&
 | 
						// Normal anonymous field or having `EMBEDDED` tag
 | 
				
			||||||
		(ok || (fieldStruct.Anonymous && !isValuer && (field.Creatable || field.Updatable || field.Readable))) {
 | 
						if _, ok := field.TagSettings["EMBEDDED"]; ok || (field.GORMDataType != Time && field.GORMDataType != Bytes && !isValuer &&
 | 
				
			||||||
 | 
							fieldStruct.Anonymous && (field.Creatable || field.Updatable || field.Readable)) {
 | 
				
			||||||
		kind := reflect.Indirect(fieldValue).Kind()
 | 
							kind := reflect.Indirect(fieldValue).Kind()
 | 
				
			||||||
		switch kind {
 | 
							switch kind {
 | 
				
			||||||
		case reflect.Struct:
 | 
							case reflect.Struct:
 | 
				
			||||||
@ -410,31 +429,49 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// create valuer, setter when parse struct
 | 
					// create valuer, setter when parse struct
 | 
				
			||||||
func (field *Field) setupValuerAndSetter() {
 | 
					func (field *Field) setupValuerAndSetter() {
 | 
				
			||||||
	// ValueOf
 | 
						// Setup NewValuePool
 | 
				
			||||||
	switch {
 | 
						var fieldValue = reflect.New(field.FieldType).Interface()
 | 
				
			||||||
	case len(field.StructField.Index) == 1:
 | 
						if field.Serializer != nil {
 | 
				
			||||||
		field.ValueOf = func(value reflect.Value) (interface{}, bool) {
 | 
							field.NewValuePool = &sync.Pool{
 | 
				
			||||||
			fieldValue := reflect.Indirect(value).Field(field.StructField.Index[0])
 | 
								New: func() interface{} {
 | 
				
			||||||
			return fieldValue.Interface(), fieldValue.IsZero()
 | 
									return &serializer{
 | 
				
			||||||
 | 
										Field:      field,
 | 
				
			||||||
 | 
										Serializer: reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface),
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
	case len(field.StructField.Index) == 2 && field.StructField.Index[0] >= 0:
 | 
								},
 | 
				
			||||||
		field.ValueOf = func(value reflect.Value) (interface{}, bool) {
 | 
					 | 
				
			||||||
			fieldValue := reflect.Indirect(value).Field(field.StructField.Index[0]).Field(field.StructField.Index[1])
 | 
					 | 
				
			||||||
			return fieldValue.Interface(), fieldValue.IsZero()
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						} else if _, ok := fieldValue.(sql.Scanner); !ok {
 | 
				
			||||||
 | 
							// set default NewValuePool
 | 
				
			||||||
 | 
							switch field.IndirectFieldType.Kind() {
 | 
				
			||||||
 | 
							case reflect.String:
 | 
				
			||||||
 | 
								field.NewValuePool = stringPool
 | 
				
			||||||
 | 
							case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
				
			||||||
 | 
								field.NewValuePool = intPool
 | 
				
			||||||
 | 
							case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
				
			||||||
 | 
								field.NewValuePool = uintPool
 | 
				
			||||||
 | 
							case reflect.Float32, reflect.Float64:
 | 
				
			||||||
 | 
								field.NewValuePool = floatPool
 | 
				
			||||||
 | 
							case reflect.Bool:
 | 
				
			||||||
 | 
								field.NewValuePool = boolPool
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
		field.ValueOf = func(value reflect.Value) (interface{}, bool) {
 | 
								if field.IndirectFieldType == TimeReflectType {
 | 
				
			||||||
			v := reflect.Indirect(value)
 | 
									field.NewValuePool = timePool
 | 
				
			||||||
 | 
					 | 
				
			||||||
			for _, idx := range field.StructField.Index {
 | 
					 | 
				
			||||||
				if idx >= 0 {
 | 
					 | 
				
			||||||
					v = v.Field(idx)
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					v = v.Field(-idx - 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if v.Type().Elem().Kind() != reflect.Struct {
 | 
					 | 
				
			||||||
						return nil, true
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if field.NewValuePool == nil {
 | 
				
			||||||
 | 
							field.NewValuePool = poolInitializer(reflect.PtrTo(field.IndirectFieldType))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ValueOf returns field's value and if it is zero
 | 
				
			||||||
 | 
						field.ValueOf = func(ctx context.Context, v reflect.Value) (interface{}, bool) {
 | 
				
			||||||
 | 
							v = reflect.Indirect(v)
 | 
				
			||||||
 | 
							for _, fieldIdx := range field.StructField.Index {
 | 
				
			||||||
 | 
								if fieldIdx >= 0 {
 | 
				
			||||||
 | 
									v = v.Field(fieldIdx)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									v = v.Field(-fieldIdx - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if !v.IsNil() {
 | 
									if !v.IsNil() {
 | 
				
			||||||
					v = v.Elem()
 | 
										v = v.Elem()
 | 
				
			||||||
@ -443,36 +480,46 @@ func (field *Field) setupValuerAndSetter() {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
			return v.Interface(), v.IsZero()
 | 
					
 | 
				
			||||||
 | 
							fv, zero := v.Interface(), v.IsZero()
 | 
				
			||||||
 | 
							return fv, zero
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if field.Serializer != nil {
 | 
				
			||||||
 | 
							oldValuerOf := field.ValueOf
 | 
				
			||||||
 | 
							field.ValueOf = func(ctx context.Context, v reflect.Value) (interface{}, bool) {
 | 
				
			||||||
 | 
								value, zero := oldValuerOf(ctx, v)
 | 
				
			||||||
 | 
								if zero {
 | 
				
			||||||
 | 
									return value, zero
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								s, ok := value.(SerializerValuerInterface)
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									s = field.Serializer
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return serializer{
 | 
				
			||||||
 | 
									Field:           field,
 | 
				
			||||||
 | 
									SerializeValuer: s,
 | 
				
			||||||
 | 
									Destination:     v,
 | 
				
			||||||
 | 
									Context:         ctx,
 | 
				
			||||||
 | 
									fieldValue:      value,
 | 
				
			||||||
 | 
								}, false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ReflectValueOf
 | 
						// ReflectValueOf returns field's reflect value
 | 
				
			||||||
	switch {
 | 
						field.ReflectValueOf = func(ctx context.Context, v reflect.Value) reflect.Value {
 | 
				
			||||||
	case len(field.StructField.Index) == 1:
 | 
							v = reflect.Indirect(v)
 | 
				
			||||||
		field.ReflectValueOf = func(value reflect.Value) reflect.Value {
 | 
					 | 
				
			||||||
			return reflect.Indirect(value).Field(field.StructField.Index[0])
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	case len(field.StructField.Index) == 2 && field.StructField.Index[0] >= 0 && field.FieldType.Kind() != reflect.Ptr:
 | 
					 | 
				
			||||||
		field.ReflectValueOf = func(value reflect.Value) reflect.Value {
 | 
					 | 
				
			||||||
			return reflect.Indirect(value).Field(field.StructField.Index[0]).Field(field.StructField.Index[1])
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		field.ReflectValueOf = func(value reflect.Value) reflect.Value {
 | 
					 | 
				
			||||||
			v := reflect.Indirect(value)
 | 
					 | 
				
			||||||
		for idx, fieldIdx := range field.StructField.Index {
 | 
							for idx, fieldIdx := range field.StructField.Index {
 | 
				
			||||||
			if fieldIdx >= 0 {
 | 
								if fieldIdx >= 0 {
 | 
				
			||||||
				v = v.Field(fieldIdx)
 | 
									v = v.Field(fieldIdx)
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				v = v.Field(-fieldIdx - 1)
 | 
									v = v.Field(-fieldIdx - 1)
 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if v.Kind() == reflect.Ptr {
 | 
					 | 
				
			||||||
					if v.Type().Elem().Kind() == reflect.Struct {
 | 
					 | 
				
			||||||
				if v.IsNil() {
 | 
									if v.IsNil() {
 | 
				
			||||||
					v.Set(reflect.New(v.Type().Elem()))
 | 
										v.Set(reflect.New(v.Type().Elem()))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if idx < len(field.StructField.Index)-1 {
 | 
									if idx < len(field.StructField.Index)-1 {
 | 
				
			||||||
					v = v.Elem()
 | 
										v = v.Elem()
 | 
				
			||||||
@ -481,24 +528,23 @@ func (field *Field) setupValuerAndSetter() {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		return v
 | 
							return v
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fallbackSetter := func(value reflect.Value, v interface{}, setter func(reflect.Value, interface{}) error) (err error) {
 | 
						fallbackSetter := func(ctx context.Context, value reflect.Value, v interface{}, setter func(context.Context, reflect.Value, interface{}) error) (err error) {
 | 
				
			||||||
		if v == nil {
 | 
							if v == nil {
 | 
				
			||||||
			field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
 | 
								field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			reflectV := reflect.ValueOf(v)
 | 
								reflectV := reflect.ValueOf(v)
 | 
				
			||||||
			// Optimal value type acquisition for v
 | 
								// Optimal value type acquisition for v
 | 
				
			||||||
			reflectValType := reflectV.Type()
 | 
								reflectValType := reflectV.Type()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if reflectValType.AssignableTo(field.FieldType) {
 | 
								if reflectValType.AssignableTo(field.FieldType) {
 | 
				
			||||||
				field.ReflectValueOf(value).Set(reflectV)
 | 
									field.ReflectValueOf(ctx, value).Set(reflectV)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			} else if reflectValType.ConvertibleTo(field.FieldType) {
 | 
								} else if reflectValType.ConvertibleTo(field.FieldType) {
 | 
				
			||||||
				field.ReflectValueOf(value).Set(reflectV.Convert(field.FieldType))
 | 
									field.ReflectValueOf(ctx, value).Set(reflectV.Convert(field.FieldType))
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			} else if field.FieldType.Kind() == reflect.Ptr {
 | 
								} else if field.FieldType.Kind() == reflect.Ptr {
 | 
				
			||||||
				fieldValue := field.ReflectValueOf(value)
 | 
									fieldValue := field.ReflectValueOf(ctx, value)
 | 
				
			||||||
				fieldType := field.FieldType.Elem()
 | 
									fieldType := field.FieldType.Elem()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if reflectValType.AssignableTo(fieldType) {
 | 
									if reflectValType.AssignableTo(fieldType) {
 | 
				
			||||||
@ -521,13 +567,16 @@ func (field *Field) setupValuerAndSetter() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			if reflectV.Kind() == reflect.Ptr {
 | 
								if reflectV.Kind() == reflect.Ptr {
 | 
				
			||||||
				if reflectV.IsNil() {
 | 
									if reflectV.IsNil() {
 | 
				
			||||||
					field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
 | 
										field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 | 
				
			||||||
 | 
									} else if reflectV.Type().Elem().AssignableTo(field.FieldType) {
 | 
				
			||||||
 | 
										field.ReflectValueOf(ctx, value).Set(reflectV.Elem())
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					err = setter(value, reflectV.Elem().Interface())
 | 
										err = setter(ctx, value, reflectV.Elem().Interface())
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else if valuer, ok := v.(driver.Valuer); ok {
 | 
								} else if valuer, ok := v.(driver.Valuer); ok {
 | 
				
			||||||
				if v, err = valuer.Value(); err == nil {
 | 
									if v, err = valuer.Value(); err == nil {
 | 
				
			||||||
					err = setter(value, v)
 | 
										err = setter(ctx, value, v)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				return fmt.Errorf("failed to set value %+v to field %s", v, field.Name)
 | 
									return fmt.Errorf("failed to set value %+v to field %s", v, field.Name)
 | 
				
			||||||
@ -540,191 +589,201 @@ func (field *Field) setupValuerAndSetter() {
 | 
				
			|||||||
	// Set
 | 
						// Set
 | 
				
			||||||
	switch field.FieldType.Kind() {
 | 
						switch field.FieldType.Kind() {
 | 
				
			||||||
	case reflect.Bool:
 | 
						case reflect.Bool:
 | 
				
			||||||
		field.Set = func(value reflect.Value, v interface{}) error {
 | 
							field.Set = func(ctx context.Context, value reflect.Value, v interface{}) error {
 | 
				
			||||||
			switch data := v.(type) {
 | 
								switch data := v.(type) {
 | 
				
			||||||
 | 
								case **bool:
 | 
				
			||||||
 | 
									if data != nil && *data != nil {
 | 
				
			||||||
 | 
										field.ReflectValueOf(ctx, value).SetBool(**data)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			case bool:
 | 
								case bool:
 | 
				
			||||||
				field.ReflectValueOf(value).SetBool(data)
 | 
									field.ReflectValueOf(ctx, value).SetBool(data)
 | 
				
			||||||
			case *bool:
 | 
					 | 
				
			||||||
				if data != nil {
 | 
					 | 
				
			||||||
					field.ReflectValueOf(value).SetBool(*data)
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					field.ReflectValueOf(value).SetBool(false)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			case int64:
 | 
								case int64:
 | 
				
			||||||
				if data > 0 {
 | 
									field.ReflectValueOf(ctx, value).SetBool(data > 0)
 | 
				
			||||||
					field.ReflectValueOf(value).SetBool(true)
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					field.ReflectValueOf(value).SetBool(false)
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			case string:
 | 
								case string:
 | 
				
			||||||
				b, _ := strconv.ParseBool(data)
 | 
									b, _ := strconv.ParseBool(data)
 | 
				
			||||||
				field.ReflectValueOf(value).SetBool(b)
 | 
									field.ReflectValueOf(ctx, value).SetBool(b)
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return fallbackSetter(value, v, field.Set)
 | 
									return fallbackSetter(ctx, value, v, field.Set)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return nil
 | 
								return nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
						case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
				
			||||||
		field.Set = func(value reflect.Value, v interface{}) (err error) {
 | 
							field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 | 
				
			||||||
			switch data := v.(type) {
 | 
								switch data := v.(type) {
 | 
				
			||||||
 | 
								case **int64:
 | 
				
			||||||
 | 
									if data != nil && *data != nil {
 | 
				
			||||||
 | 
										field.ReflectValueOf(ctx, value).SetInt(**data)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			case int64:
 | 
								case int64:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(data)
 | 
									field.ReflectValueOf(ctx, value).SetInt(data)
 | 
				
			||||||
			case int:
 | 
								case int:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(int64(data))
 | 
									field.ReflectValueOf(ctx, value).SetInt(int64(data))
 | 
				
			||||||
			case int8:
 | 
								case int8:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(int64(data))
 | 
									field.ReflectValueOf(ctx, value).SetInt(int64(data))
 | 
				
			||||||
			case int16:
 | 
								case int16:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(int64(data))
 | 
									field.ReflectValueOf(ctx, value).SetInt(int64(data))
 | 
				
			||||||
			case int32:
 | 
								case int32:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(int64(data))
 | 
									field.ReflectValueOf(ctx, value).SetInt(int64(data))
 | 
				
			||||||
			case uint:
 | 
								case uint:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(int64(data))
 | 
									field.ReflectValueOf(ctx, value).SetInt(int64(data))
 | 
				
			||||||
			case uint8:
 | 
								case uint8:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(int64(data))
 | 
									field.ReflectValueOf(ctx, value).SetInt(int64(data))
 | 
				
			||||||
			case uint16:
 | 
								case uint16:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(int64(data))
 | 
									field.ReflectValueOf(ctx, value).SetInt(int64(data))
 | 
				
			||||||
			case uint32:
 | 
								case uint32:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(int64(data))
 | 
									field.ReflectValueOf(ctx, value).SetInt(int64(data))
 | 
				
			||||||
			case uint64:
 | 
								case uint64:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(int64(data))
 | 
									field.ReflectValueOf(ctx, value).SetInt(int64(data))
 | 
				
			||||||
			case float32:
 | 
								case float32:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(int64(data))
 | 
									field.ReflectValueOf(ctx, value).SetInt(int64(data))
 | 
				
			||||||
			case float64:
 | 
								case float64:
 | 
				
			||||||
				field.ReflectValueOf(value).SetInt(int64(data))
 | 
									field.ReflectValueOf(ctx, value).SetInt(int64(data))
 | 
				
			||||||
			case []byte:
 | 
								case []byte:
 | 
				
			||||||
				return field.Set(value, string(data))
 | 
									return field.Set(ctx, value, string(data))
 | 
				
			||||||
			case string:
 | 
								case string:
 | 
				
			||||||
				if i, err := strconv.ParseInt(data, 0, 64); err == nil {
 | 
									if i, err := strconv.ParseInt(data, 0, 64); err == nil {
 | 
				
			||||||
					field.ReflectValueOf(value).SetInt(i)
 | 
										field.ReflectValueOf(ctx, value).SetInt(i)
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					return err
 | 
										return err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			case time.Time:
 | 
								case time.Time:
 | 
				
			||||||
				if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
 | 
									if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
 | 
				
			||||||
					field.ReflectValueOf(value).SetInt(data.UnixNano())
 | 
										field.ReflectValueOf(ctx, value).SetInt(data.UnixNano())
 | 
				
			||||||
				} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
 | 
									} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
 | 
				
			||||||
					field.ReflectValueOf(value).SetInt(data.UnixNano() / 1e6)
 | 
										field.ReflectValueOf(ctx, value).SetInt(data.UnixNano() / 1e6)
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					field.ReflectValueOf(value).SetInt(data.Unix())
 | 
										field.ReflectValueOf(ctx, value).SetInt(data.Unix())
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			case *time.Time:
 | 
								case *time.Time:
 | 
				
			||||||
				if data != nil {
 | 
									if data != nil {
 | 
				
			||||||
					if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
 | 
										if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
 | 
				
			||||||
						field.ReflectValueOf(value).SetInt(data.UnixNano())
 | 
											field.ReflectValueOf(ctx, value).SetInt(data.UnixNano())
 | 
				
			||||||
					} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
 | 
										} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
 | 
				
			||||||
						field.ReflectValueOf(value).SetInt(data.UnixNano() / 1e6)
 | 
											field.ReflectValueOf(ctx, value).SetInt(data.UnixNano() / 1e6)
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						field.ReflectValueOf(value).SetInt(data.Unix())
 | 
											field.ReflectValueOf(ctx, value).SetInt(data.Unix())
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					field.ReflectValueOf(value).SetInt(0)
 | 
										field.ReflectValueOf(ctx, value).SetInt(0)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return fallbackSetter(value, v, field.Set)
 | 
									return fallbackSetter(ctx, value, v, field.Set)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
						case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
				
			||||||
		field.Set = func(value reflect.Value, v interface{}) (err error) {
 | 
							field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 | 
				
			||||||
			switch data := v.(type) {
 | 
								switch data := v.(type) {
 | 
				
			||||||
 | 
								case **uint64:
 | 
				
			||||||
 | 
									if data != nil && *data != nil {
 | 
				
			||||||
 | 
										field.ReflectValueOf(ctx, value).SetUint(**data)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			case uint64:
 | 
								case uint64:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(data)
 | 
									field.ReflectValueOf(ctx, value).SetUint(data)
 | 
				
			||||||
			case uint:
 | 
								case uint:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(uint64(data))
 | 
									field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 | 
				
			||||||
			case uint8:
 | 
								case uint8:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(uint64(data))
 | 
									field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 | 
				
			||||||
			case uint16:
 | 
								case uint16:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(uint64(data))
 | 
									field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 | 
				
			||||||
			case uint32:
 | 
								case uint32:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(uint64(data))
 | 
									field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 | 
				
			||||||
			case int64:
 | 
								case int64:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(uint64(data))
 | 
									field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 | 
				
			||||||
			case int:
 | 
								case int:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(uint64(data))
 | 
									field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 | 
				
			||||||
			case int8:
 | 
								case int8:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(uint64(data))
 | 
									field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 | 
				
			||||||
			case int16:
 | 
								case int16:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(uint64(data))
 | 
									field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 | 
				
			||||||
			case int32:
 | 
								case int32:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(uint64(data))
 | 
									field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 | 
				
			||||||
			case float32:
 | 
								case float32:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(uint64(data))
 | 
									field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 | 
				
			||||||
			case float64:
 | 
								case float64:
 | 
				
			||||||
				field.ReflectValueOf(value).SetUint(uint64(data))
 | 
									field.ReflectValueOf(ctx, value).SetUint(uint64(data))
 | 
				
			||||||
			case []byte:
 | 
								case []byte:
 | 
				
			||||||
				return field.Set(value, string(data))
 | 
									return field.Set(ctx, value, string(data))
 | 
				
			||||||
			case time.Time:
 | 
								case time.Time:
 | 
				
			||||||
				if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
 | 
									if field.AutoCreateTime == UnixNanosecond || field.AutoUpdateTime == UnixNanosecond {
 | 
				
			||||||
					field.ReflectValueOf(value).SetUint(uint64(data.UnixNano()))
 | 
										field.ReflectValueOf(ctx, value).SetUint(uint64(data.UnixNano()))
 | 
				
			||||||
				} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
 | 
									} else if field.AutoCreateTime == UnixMillisecond || field.AutoUpdateTime == UnixMillisecond {
 | 
				
			||||||
					field.ReflectValueOf(value).SetUint(uint64(data.UnixNano() / 1e6))
 | 
										field.ReflectValueOf(ctx, value).SetUint(uint64(data.UnixNano() / 1e6))
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					field.ReflectValueOf(value).SetUint(uint64(data.Unix()))
 | 
										field.ReflectValueOf(ctx, value).SetUint(uint64(data.Unix()))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			case string:
 | 
								case string:
 | 
				
			||||||
				if i, err := strconv.ParseUint(data, 0, 64); err == nil {
 | 
									if i, err := strconv.ParseUint(data, 0, 64); err == nil {
 | 
				
			||||||
					field.ReflectValueOf(value).SetUint(i)
 | 
										field.ReflectValueOf(ctx, value).SetUint(i)
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					return err
 | 
										return err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return fallbackSetter(value, v, field.Set)
 | 
									return fallbackSetter(ctx, value, v, field.Set)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.Float32, reflect.Float64:
 | 
						case reflect.Float32, reflect.Float64:
 | 
				
			||||||
		field.Set = func(value reflect.Value, v interface{}) (err error) {
 | 
							field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 | 
				
			||||||
			switch data := v.(type) {
 | 
								switch data := v.(type) {
 | 
				
			||||||
 | 
								case **float64:
 | 
				
			||||||
 | 
									if data != nil && *data != nil {
 | 
				
			||||||
 | 
										field.ReflectValueOf(ctx, value).SetFloat(**data)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			case float64:
 | 
								case float64:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(data)
 | 
									field.ReflectValueOf(ctx, value).SetFloat(data)
 | 
				
			||||||
			case float32:
 | 
								case float32:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(float64(data))
 | 
									field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 | 
				
			||||||
			case int64:
 | 
								case int64:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(float64(data))
 | 
									field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 | 
				
			||||||
			case int:
 | 
								case int:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(float64(data))
 | 
									field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 | 
				
			||||||
			case int8:
 | 
								case int8:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(float64(data))
 | 
									field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 | 
				
			||||||
			case int16:
 | 
								case int16:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(float64(data))
 | 
									field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 | 
				
			||||||
			case int32:
 | 
								case int32:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(float64(data))
 | 
									field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 | 
				
			||||||
			case uint:
 | 
								case uint:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(float64(data))
 | 
									field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 | 
				
			||||||
			case uint8:
 | 
								case uint8:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(float64(data))
 | 
									field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 | 
				
			||||||
			case uint16:
 | 
								case uint16:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(float64(data))
 | 
									field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 | 
				
			||||||
			case uint32:
 | 
								case uint32:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(float64(data))
 | 
									field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 | 
				
			||||||
			case uint64:
 | 
								case uint64:
 | 
				
			||||||
				field.ReflectValueOf(value).SetFloat(float64(data))
 | 
									field.ReflectValueOf(ctx, value).SetFloat(float64(data))
 | 
				
			||||||
			case []byte:
 | 
								case []byte:
 | 
				
			||||||
				return field.Set(value, string(data))
 | 
									return field.Set(ctx, value, string(data))
 | 
				
			||||||
			case string:
 | 
								case string:
 | 
				
			||||||
				if i, err := strconv.ParseFloat(data, 64); err == nil {
 | 
									if i, err := strconv.ParseFloat(data, 64); err == nil {
 | 
				
			||||||
					field.ReflectValueOf(value).SetFloat(i)
 | 
										field.ReflectValueOf(ctx, value).SetFloat(i)
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					return err
 | 
										return err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return fallbackSetter(value, v, field.Set)
 | 
									return fallbackSetter(ctx, value, v, field.Set)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.String:
 | 
						case reflect.String:
 | 
				
			||||||
		field.Set = func(value reflect.Value, v interface{}) (err error) {
 | 
							field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 | 
				
			||||||
			switch data := v.(type) {
 | 
								switch data := v.(type) {
 | 
				
			||||||
 | 
								case **string:
 | 
				
			||||||
 | 
									if data != nil && *data != nil {
 | 
				
			||||||
 | 
										field.ReflectValueOf(ctx, value).SetString(**data)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			case string:
 | 
								case string:
 | 
				
			||||||
				field.ReflectValueOf(value).SetString(data)
 | 
									field.ReflectValueOf(ctx, value).SetString(data)
 | 
				
			||||||
			case []byte:
 | 
								case []byte:
 | 
				
			||||||
				field.ReflectValueOf(value).SetString(string(data))
 | 
									field.ReflectValueOf(ctx, value).SetString(string(data))
 | 
				
			||||||
			case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
 | 
								case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
 | 
				
			||||||
				field.ReflectValueOf(value).SetString(utils.ToString(data))
 | 
									field.ReflectValueOf(ctx, value).SetString(utils.ToString(data))
 | 
				
			||||||
			case float64, float32:
 | 
								case float64, float32:
 | 
				
			||||||
				field.ReflectValueOf(value).SetString(fmt.Sprintf("%."+strconv.Itoa(field.Precision)+"f", data))
 | 
									field.ReflectValueOf(ctx, value).SetString(fmt.Sprintf("%."+strconv.Itoa(field.Precision)+"f", data))
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return fallbackSetter(value, v, field.Set)
 | 
									return fallbackSetter(ctx, value, v, field.Set)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -732,41 +791,49 @@ func (field *Field) setupValuerAndSetter() {
 | 
				
			|||||||
		fieldValue := reflect.New(field.FieldType)
 | 
							fieldValue := reflect.New(field.FieldType)
 | 
				
			||||||
		switch fieldValue.Elem().Interface().(type) {
 | 
							switch fieldValue.Elem().Interface().(type) {
 | 
				
			||||||
		case time.Time:
 | 
							case time.Time:
 | 
				
			||||||
			field.Set = func(value reflect.Value, v interface{}) error {
 | 
								field.Set = func(ctx context.Context, value reflect.Value, v interface{}) error {
 | 
				
			||||||
				switch data := v.(type) {
 | 
									switch data := v.(type) {
 | 
				
			||||||
 | 
									case **time.Time:
 | 
				
			||||||
 | 
										if data != nil && *data != nil {
 | 
				
			||||||
 | 
											field.Set(ctx, value, *data)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				case time.Time:
 | 
									case time.Time:
 | 
				
			||||||
					field.ReflectValueOf(value).Set(reflect.ValueOf(v))
 | 
										field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(v))
 | 
				
			||||||
				case *time.Time:
 | 
									case *time.Time:
 | 
				
			||||||
					if data != nil {
 | 
										if data != nil {
 | 
				
			||||||
						field.ReflectValueOf(value).Set(reflect.ValueOf(data).Elem())
 | 
											field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(data).Elem())
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						field.ReflectValueOf(value).Set(reflect.ValueOf(time.Time{}))
 | 
											field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(time.Time{}))
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				case string:
 | 
									case string:
 | 
				
			||||||
					if t, err := now.Parse(data); err == nil {
 | 
										if t, err := now.Parse(data); err == nil {
 | 
				
			||||||
						field.ReflectValueOf(value).Set(reflect.ValueOf(t))
 | 
											field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(t))
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %v", v, field.Name, err)
 | 
											return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %v", v, field.Name, err)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					return fallbackSetter(value, v, field.Set)
 | 
										return fallbackSetter(ctx, value, v, field.Set)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return nil
 | 
									return nil
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case *time.Time:
 | 
							case *time.Time:
 | 
				
			||||||
			field.Set = func(value reflect.Value, v interface{}) error {
 | 
								field.Set = func(ctx context.Context, value reflect.Value, v interface{}) error {
 | 
				
			||||||
				switch data := v.(type) {
 | 
									switch data := v.(type) {
 | 
				
			||||||
 | 
									case **time.Time:
 | 
				
			||||||
 | 
										if data != nil {
 | 
				
			||||||
 | 
											field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(*data))
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				case time.Time:
 | 
									case time.Time:
 | 
				
			||||||
					fieldValue := field.ReflectValueOf(value)
 | 
										fieldValue := field.ReflectValueOf(ctx, value)
 | 
				
			||||||
					if fieldValue.IsNil() {
 | 
										if fieldValue.IsNil() {
 | 
				
			||||||
						fieldValue.Set(reflect.New(field.FieldType.Elem()))
 | 
											fieldValue.Set(reflect.New(field.FieldType.Elem()))
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					fieldValue.Elem().Set(reflect.ValueOf(v))
 | 
										fieldValue.Elem().Set(reflect.ValueOf(v))
 | 
				
			||||||
				case *time.Time:
 | 
									case *time.Time:
 | 
				
			||||||
					field.ReflectValueOf(value).Set(reflect.ValueOf(v))
 | 
										field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(v))
 | 
				
			||||||
				case string:
 | 
									case string:
 | 
				
			||||||
					if t, err := now.Parse(data); err == nil {
 | 
										if t, err := now.Parse(data); err == nil {
 | 
				
			||||||
						fieldValue := field.ReflectValueOf(value)
 | 
											fieldValue := field.ReflectValueOf(ctx, value)
 | 
				
			||||||
						if fieldValue.IsNil() {
 | 
											if fieldValue.IsNil() {
 | 
				
			||||||
							if v == "" {
 | 
												if v == "" {
 | 
				
			||||||
								return nil
 | 
													return nil
 | 
				
			||||||
@ -778,27 +845,27 @@ func (field *Field) setupValuerAndSetter() {
 | 
				
			|||||||
						return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %v", v, field.Name, err)
 | 
											return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %v", v, field.Name, err)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					return fallbackSetter(value, v, field.Set)
 | 
										return fallbackSetter(ctx, value, v, field.Set)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return nil
 | 
									return nil
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			if _, ok := fieldValue.Elem().Interface().(sql.Scanner); ok {
 | 
								if _, ok := fieldValue.Elem().Interface().(sql.Scanner); ok {
 | 
				
			||||||
				// pointer scanner
 | 
									// pointer scanner
 | 
				
			||||||
				field.Set = func(value reflect.Value, v interface{}) (err error) {
 | 
									field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 | 
				
			||||||
					reflectV := reflect.ValueOf(v)
 | 
										reflectV := reflect.ValueOf(v)
 | 
				
			||||||
					if !reflectV.IsValid() {
 | 
										if !reflectV.IsValid() {
 | 
				
			||||||
						field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
 | 
											field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 | 
				
			||||||
					} else if reflectV.Type().AssignableTo(field.FieldType) {
 | 
										} else if reflectV.Type().AssignableTo(field.FieldType) {
 | 
				
			||||||
						field.ReflectValueOf(value).Set(reflectV)
 | 
											field.ReflectValueOf(ctx, value).Set(reflectV)
 | 
				
			||||||
					} else if reflectV.Kind() == reflect.Ptr {
 | 
										} else if reflectV.Kind() == reflect.Ptr {
 | 
				
			||||||
						if reflectV.IsNil() || !reflectV.IsValid() {
 | 
											if reflectV.IsNil() || !reflectV.IsValid() {
 | 
				
			||||||
							field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
 | 
												field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 | 
				
			||||||
						} else {
 | 
											} else {
 | 
				
			||||||
							return field.Set(value, reflectV.Elem().Interface())
 | 
												return field.Set(ctx, value, reflectV.Elem().Interface())
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						fieldValue := field.ReflectValueOf(value)
 | 
											fieldValue := field.ReflectValueOf(ctx, value)
 | 
				
			||||||
						if fieldValue.IsNil() {
 | 
											if fieldValue.IsNil() {
 | 
				
			||||||
							fieldValue.Set(reflect.New(field.FieldType.Elem()))
 | 
												fieldValue.Set(reflect.New(field.FieldType.Elem()))
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
@ -813,32 +880,61 @@ func (field *Field) setupValuerAndSetter() {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			} else if _, ok := fieldValue.Interface().(sql.Scanner); ok {
 | 
								} else if _, ok := fieldValue.Interface().(sql.Scanner); ok {
 | 
				
			||||||
				// struct scanner
 | 
									// struct scanner
 | 
				
			||||||
				field.Set = func(value reflect.Value, v interface{}) (err error) {
 | 
									field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 | 
				
			||||||
					reflectV := reflect.ValueOf(v)
 | 
										reflectV := reflect.ValueOf(v)
 | 
				
			||||||
					if !reflectV.IsValid() {
 | 
										if !reflectV.IsValid() {
 | 
				
			||||||
						field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
 | 
											field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 | 
				
			||||||
					} else if reflectV.Type().AssignableTo(field.FieldType) {
 | 
										} else if reflectV.Type().AssignableTo(field.FieldType) {
 | 
				
			||||||
						field.ReflectValueOf(value).Set(reflectV)
 | 
											field.ReflectValueOf(ctx, value).Set(reflectV)
 | 
				
			||||||
					} else if reflectV.Kind() == reflect.Ptr {
 | 
										} else if reflectV.Kind() == reflect.Ptr {
 | 
				
			||||||
						if reflectV.IsNil() || !reflectV.IsValid() {
 | 
											if reflectV.IsNil() || !reflectV.IsValid() {
 | 
				
			||||||
							field.ReflectValueOf(value).Set(reflect.New(field.FieldType).Elem())
 | 
												field.ReflectValueOf(ctx, value).Set(reflect.New(field.FieldType).Elem())
 | 
				
			||||||
						} else {
 | 
											} else {
 | 
				
			||||||
							return field.Set(value, reflectV.Elem().Interface())
 | 
												return field.Set(ctx, value, reflectV.Elem().Interface())
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						if valuer, ok := v.(driver.Valuer); ok {
 | 
											if valuer, ok := v.(driver.Valuer); ok {
 | 
				
			||||||
							v, _ = valuer.Value()
 | 
												v, _ = valuer.Value()
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						err = field.ReflectValueOf(value).Addr().Interface().(sql.Scanner).Scan(v)
 | 
											err = field.ReflectValueOf(ctx, value).Addr().Interface().(sql.Scanner).Scan(v)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				field.Set = func(value reflect.Value, v interface{}) (err error) {
 | 
									field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 | 
				
			||||||
					return fallbackSetter(value, v, field.Set)
 | 
										return fallbackSetter(ctx, value, v, field.Set)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if field.Serializer != nil {
 | 
				
			||||||
 | 
							var (
 | 
				
			||||||
 | 
								oldFieldSetter = field.Set
 | 
				
			||||||
 | 
								sameElemType   bool
 | 
				
			||||||
 | 
								sameType       = field.FieldType == reflect.ValueOf(field.Serializer).Type()
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if reflect.ValueOf(field.Serializer).Kind() == reflect.Ptr {
 | 
				
			||||||
 | 
								sameElemType = field.FieldType == reflect.ValueOf(field.Serializer).Type().Elem()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							field.Set = func(ctx context.Context, value reflect.Value, v interface{}) (err error) {
 | 
				
			||||||
 | 
								if s, ok := v.(*serializer); ok {
 | 
				
			||||||
 | 
									if err = s.Serializer.Scan(ctx, field, value, s.value); err == nil {
 | 
				
			||||||
 | 
										if sameElemType {
 | 
				
			||||||
 | 
											field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(s.Serializer).Elem())
 | 
				
			||||||
 | 
											s.Serializer = reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface)
 | 
				
			||||||
 | 
										} else if sameType {
 | 
				
			||||||
 | 
											field.ReflectValueOf(ctx, value).Set(reflect.ValueOf(s.Serializer))
 | 
				
			||||||
 | 
											s.Serializer = reflect.New(reflect.Indirect(reflect.ValueOf(field.Serializer)).Type()).Interface().(SerializerInterface)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									err = oldFieldSetter(ctx, value, v)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package schema_test
 | 
					package schema_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
	"database/sql"
 | 
						"database/sql"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@ -57,7 +58,7 @@ func TestFieldValuerAndSetter(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for k, v := range newValues {
 | 
						for k, v := range newValues {
 | 
				
			||||||
		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
 | 
							if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 | 
				
			||||||
			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
								t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -80,7 +81,7 @@ func TestFieldValuerAndSetter(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for k, v := range newValues2 {
 | 
						for k, v := range newValues2 {
 | 
				
			||||||
		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
 | 
							if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 | 
				
			||||||
			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
								t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -132,7 +133,7 @@ func TestPointerFieldValuerAndSetter(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for k, v := range newValues {
 | 
						for k, v := range newValues {
 | 
				
			||||||
		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
 | 
							if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 | 
				
			||||||
			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
								t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -151,7 +152,7 @@ func TestPointerFieldValuerAndSetter(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for k, v := range newValues2 {
 | 
						for k, v := range newValues2 {
 | 
				
			||||||
		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
 | 
							if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 | 
				
			||||||
			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
								t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -202,7 +203,7 @@ func TestAdvancedDataTypeValuerAndSetter(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for k, v := range newValues {
 | 
						for k, v := range newValues {
 | 
				
			||||||
		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
 | 
							if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 | 
				
			||||||
			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
								t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -219,7 +220,7 @@ func TestAdvancedDataTypeValuerAndSetter(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for k, v := range newValues2 {
 | 
						for k, v := range newValues2 {
 | 
				
			||||||
		if err := userSchema.FieldsByDBName[k].Set(reflectValue, v); err != nil {
 | 
							if err := userSchema.FieldsByDBName[k].Set(context.Background(), reflectValue, v); err != nil {
 | 
				
			||||||
			t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
								t.Errorf("no error should happen when assign value to field %v, but got %v", k, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,22 +4,33 @@ import (
 | 
				
			|||||||
	"gorm.io/gorm/clause"
 | 
						"gorm.io/gorm/clause"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GormDataTypeInterface gorm data type interface
 | 
				
			||||||
type GormDataTypeInterface interface {
 | 
					type GormDataTypeInterface interface {
 | 
				
			||||||
	GormDataType() string
 | 
						GormDataType() string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FieldNewValuePool field new scan value pool
 | 
				
			||||||
 | 
					type FieldNewValuePool interface {
 | 
				
			||||||
 | 
						Get() interface{}
 | 
				
			||||||
 | 
						Put(interface{})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CreateClausesInterface create clauses interface
 | 
				
			||||||
type CreateClausesInterface interface {
 | 
					type CreateClausesInterface interface {
 | 
				
			||||||
	CreateClauses(*Field) []clause.Interface
 | 
						CreateClauses(*Field) []clause.Interface
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// QueryClausesInterface query clauses interface
 | 
				
			||||||
type QueryClausesInterface interface {
 | 
					type QueryClausesInterface interface {
 | 
				
			||||||
	QueryClauses(*Field) []clause.Interface
 | 
						QueryClauses(*Field) []clause.Interface
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateClausesInterface update clauses interface
 | 
				
			||||||
type UpdateClausesInterface interface {
 | 
					type UpdateClausesInterface interface {
 | 
				
			||||||
	UpdateClauses(*Field) []clause.Interface
 | 
						UpdateClauses(*Field) []clause.Interface
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DeleteClausesInterface delete clauses interface
 | 
				
			||||||
type DeleteClausesInterface interface {
 | 
					type DeleteClausesInterface interface {
 | 
				
			||||||
	DeleteClauses(*Field) []clause.Interface
 | 
						DeleteClauses(*Field) []clause.Interface
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										62
									
								
								schema/pool.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								schema/pool.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					package schema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// sync pools
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						normalPool sync.Map
 | 
				
			||||||
 | 
						stringPool = &sync.Pool{
 | 
				
			||||||
 | 
							New: func() interface{} {
 | 
				
			||||||
 | 
								var v string
 | 
				
			||||||
 | 
								ptrV := &v
 | 
				
			||||||
 | 
								return &ptrV
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						intPool = &sync.Pool{
 | 
				
			||||||
 | 
							New: func() interface{} {
 | 
				
			||||||
 | 
								var v int64
 | 
				
			||||||
 | 
								ptrV := &v
 | 
				
			||||||
 | 
								return &ptrV
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						uintPool = &sync.Pool{
 | 
				
			||||||
 | 
							New: func() interface{} {
 | 
				
			||||||
 | 
								var v uint64
 | 
				
			||||||
 | 
								ptrV := &v
 | 
				
			||||||
 | 
								return &ptrV
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						floatPool = &sync.Pool{
 | 
				
			||||||
 | 
							New: func() interface{} {
 | 
				
			||||||
 | 
								var v float64
 | 
				
			||||||
 | 
								ptrV := &v
 | 
				
			||||||
 | 
								return &ptrV
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						boolPool = &sync.Pool{
 | 
				
			||||||
 | 
							New: func() interface{} {
 | 
				
			||||||
 | 
								var v bool
 | 
				
			||||||
 | 
								ptrV := &v
 | 
				
			||||||
 | 
								return &ptrV
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						timePool = &sync.Pool{
 | 
				
			||||||
 | 
							New: func() interface{} {
 | 
				
			||||||
 | 
								var v time.Time
 | 
				
			||||||
 | 
								ptrV := &v
 | 
				
			||||||
 | 
								return &ptrV
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						poolInitializer = func(reflectType reflect.Type) FieldNewValuePool {
 | 
				
			||||||
 | 
							v, _ := normalPool.LoadOrStore(reflectType, &sync.Pool{
 | 
				
			||||||
 | 
								New: func() interface{} {
 | 
				
			||||||
 | 
									return reflect.New(reflectType).Interface()
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							return v.(FieldNewValuePool)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package schema
 | 
					package schema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@ -576,7 +577,7 @@ func (rel *Relationship) ParseConstraint() *Constraint {
 | 
				
			|||||||
	return &constraint
 | 
						return &constraint
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (rel *Relationship) ToQueryConditions(reflectValue reflect.Value) (conds []clause.Expression) {
 | 
					func (rel *Relationship) ToQueryConditions(ctx context.Context, reflectValue reflect.Value) (conds []clause.Expression) {
 | 
				
			||||||
	table := rel.FieldSchema.Table
 | 
						table := rel.FieldSchema.Table
 | 
				
			||||||
	foreignFields := []*Field{}
 | 
						foreignFields := []*Field{}
 | 
				
			||||||
	relForeignKeys := []string{}
 | 
						relForeignKeys := []string{}
 | 
				
			||||||
@ -616,7 +617,7 @@ func (rel *Relationship) ToQueryConditions(reflectValue reflect.Value) (conds []
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, foreignValues := GetIdentityFieldValuesMap(reflectValue, foreignFields)
 | 
						_, foreignValues := GetIdentityFieldValuesMap(ctx, reflectValue, foreignFields)
 | 
				
			||||||
	column, values := ToQueryValues(table, relForeignKeys, foreignValues)
 | 
						column, values := ToQueryValues(table, relForeignKeys, foreignValues)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conds = append(conds, clause.IN{Column: column, Values: values})
 | 
						conds = append(conds, clause.IN{Column: column, Values: values})
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package schema_test
 | 
					package schema_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@ -203,7 +204,7 @@ func checkSchemaRelation(t *testing.T, s *schema.Schema, relation Relation) {
 | 
				
			|||||||
func checkField(t *testing.T, s *schema.Schema, value reflect.Value, values map[string]interface{}) {
 | 
					func checkField(t *testing.T, s *schema.Schema, value reflect.Value, values map[string]interface{}) {
 | 
				
			||||||
	for k, v := range values {
 | 
						for k, v := range values {
 | 
				
			||||||
		t.Run("CheckField/"+k, func(t *testing.T) {
 | 
							t.Run("CheckField/"+k, func(t *testing.T) {
 | 
				
			||||||
			fv, _ := s.FieldsByDBName[k].ValueOf(value)
 | 
								fv, _ := s.FieldsByDBName[k].ValueOf(context.Background(), value)
 | 
				
			||||||
			tests.AssertEqual(t, v, fv)
 | 
								tests.AssertEqual(t, v, fv)
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										125
									
								
								schema/serializer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								schema/serializer.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,125 @@
 | 
				
			|||||||
 | 
					package schema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"database/sql"
 | 
				
			||||||
 | 
						"database/sql/driver"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var serializerMap = sync.Map{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RegisterSerializer register serializer
 | 
				
			||||||
 | 
					func RegisterSerializer(name string, serializer SerializerInterface) {
 | 
				
			||||||
 | 
						serializerMap.Store(strings.ToLower(name), serializer)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetSerializer get serializer
 | 
				
			||||||
 | 
					func GetSerializer(name string) (serializer SerializerInterface, ok bool) {
 | 
				
			||||||
 | 
						v, ok := serializerMap.Load(strings.ToLower(name))
 | 
				
			||||||
 | 
						if ok {
 | 
				
			||||||
 | 
							serializer, ok = v.(SerializerInterface)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return serializer, ok
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						RegisterSerializer("json", JSONSerializer{})
 | 
				
			||||||
 | 
						RegisterSerializer("unixtime", UnixSecondSerializer{})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Serializer field value serializer
 | 
				
			||||||
 | 
					type serializer struct {
 | 
				
			||||||
 | 
						Field           *Field
 | 
				
			||||||
 | 
						Serializer      SerializerInterface
 | 
				
			||||||
 | 
						SerializeValuer SerializerValuerInterface
 | 
				
			||||||
 | 
						Destination     reflect.Value
 | 
				
			||||||
 | 
						Context         context.Context
 | 
				
			||||||
 | 
						value           interface{}
 | 
				
			||||||
 | 
						fieldValue      interface{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Scan implements sql.Scanner interface
 | 
				
			||||||
 | 
					func (s *serializer) Scan(value interface{}) error {
 | 
				
			||||||
 | 
						s.value = value
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Value implements driver.Valuer interface
 | 
				
			||||||
 | 
					func (s serializer) Value() (driver.Value, error) {
 | 
				
			||||||
 | 
						return s.SerializeValuer.Value(s.Context, s.Field, s.Destination, s.fieldValue)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SerializerInterface serializer interface
 | 
				
			||||||
 | 
					type SerializerInterface interface {
 | 
				
			||||||
 | 
						Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) error
 | 
				
			||||||
 | 
						SerializerValuerInterface
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SerializerValuerInterface serializer valuer interface
 | 
				
			||||||
 | 
					type SerializerValuerInterface interface {
 | 
				
			||||||
 | 
						Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// JSONSerializer json serializer
 | 
				
			||||||
 | 
					type JSONSerializer struct {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Scan implements serializer interface
 | 
				
			||||||
 | 
					func (JSONSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) (err error) {
 | 
				
			||||||
 | 
						fieldValue := reflect.New(field.FieldType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if dbValue != nil {
 | 
				
			||||||
 | 
							var bytes []byte
 | 
				
			||||||
 | 
							switch v := dbValue.(type) {
 | 
				
			||||||
 | 
							case []byte:
 | 
				
			||||||
 | 
								bytes = v
 | 
				
			||||||
 | 
							case string:
 | 
				
			||||||
 | 
								bytes = []byte(v)
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", dbValue))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = json.Unmarshal(bytes, fieldValue.Interface())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem())
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Value implements serializer interface
 | 
				
			||||||
 | 
					func (JSONSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
						result, err := json.Marshal(fieldValue)
 | 
				
			||||||
 | 
						return string(result), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UnixSecondSerializer json serializer
 | 
				
			||||||
 | 
					type UnixSecondSerializer struct {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Scan implements serializer interface
 | 
				
			||||||
 | 
					func (UnixSecondSerializer) Scan(ctx context.Context, field *Field, dst reflect.Value, dbValue interface{}) (err error) {
 | 
				
			||||||
 | 
						t := sql.NullTime{}
 | 
				
			||||||
 | 
						if err = t.Scan(dbValue); err == nil {
 | 
				
			||||||
 | 
							err = field.Set(ctx, dst, t.Time)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Value implements serializer interface
 | 
				
			||||||
 | 
					func (UnixSecondSerializer) Value(ctx context.Context, field *Field, dst reflect.Value, fieldValue interface{}) (result interface{}, err error) {
 | 
				
			||||||
 | 
						switch v := fieldValue.(type) {
 | 
				
			||||||
 | 
						case int64, int, uint, uint64, int32, uint32, int16, uint16:
 | 
				
			||||||
 | 
							result = time.Unix(reflect.ValueOf(v).Int(), 0)
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							err = fmt.Errorf("invalid field type %#v for UnixSecondSerializer, only int, uint supported", v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package schema
 | 
					package schema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@ -59,13 +60,13 @@ func removeSettingFromTag(tag reflect.StructTag, names ...string) reflect.Struct
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetRelationsValues get relations's values from a reflect value
 | 
					// GetRelationsValues get relations's values from a reflect value
 | 
				
			||||||
func GetRelationsValues(reflectValue reflect.Value, rels []*Relationship) (reflectResults reflect.Value) {
 | 
					func GetRelationsValues(ctx context.Context, reflectValue reflect.Value, rels []*Relationship) (reflectResults reflect.Value) {
 | 
				
			||||||
	for _, rel := range rels {
 | 
						for _, rel := range rels {
 | 
				
			||||||
		reflectResults = reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(rel.FieldSchema.ModelType)), 0, 1)
 | 
							reflectResults = reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(rel.FieldSchema.ModelType)), 0, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		appendToResults := func(value reflect.Value) {
 | 
							appendToResults := func(value reflect.Value) {
 | 
				
			||||||
			if _, isZero := rel.Field.ValueOf(value); !isZero {
 | 
								if _, isZero := rel.Field.ValueOf(ctx, value); !isZero {
 | 
				
			||||||
				result := reflect.Indirect(rel.Field.ReflectValueOf(value))
 | 
									result := reflect.Indirect(rel.Field.ReflectValueOf(ctx, value))
 | 
				
			||||||
				switch result.Kind() {
 | 
									switch result.Kind() {
 | 
				
			||||||
				case reflect.Struct:
 | 
									case reflect.Struct:
 | 
				
			||||||
					reflectResults = reflect.Append(reflectResults, result.Addr())
 | 
										reflectResults = reflect.Append(reflectResults, result.Addr())
 | 
				
			||||||
@ -97,7 +98,7 @@ func GetRelationsValues(reflectValue reflect.Value, rels []*Relationship) (refle
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetIdentityFieldValuesMap get identity map from fields
 | 
					// GetIdentityFieldValuesMap get identity map from fields
 | 
				
			||||||
func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
 | 
					func GetIdentityFieldValuesMap(ctx context.Context, reflectValue reflect.Value, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		results       = [][]interface{}{}
 | 
							results       = [][]interface{}{}
 | 
				
			||||||
		dataResults   = map[string][]reflect.Value{}
 | 
							dataResults   = map[string][]reflect.Value{}
 | 
				
			||||||
@ -110,7 +111,7 @@ func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map
 | 
				
			|||||||
		results = [][]interface{}{make([]interface{}, len(fields))}
 | 
							results = [][]interface{}{make([]interface{}, len(fields))}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for idx, field := range fields {
 | 
							for idx, field := range fields {
 | 
				
			||||||
			results[0][idx], zero = field.ValueOf(reflectValue)
 | 
								results[0][idx], zero = field.ValueOf(ctx, reflectValue)
 | 
				
			||||||
			notZero = notZero || !zero
 | 
								notZero = notZero || !zero
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -135,7 +136,7 @@ func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map
 | 
				
			|||||||
			fieldValues := make([]interface{}, len(fields))
 | 
								fieldValues := make([]interface{}, len(fields))
 | 
				
			||||||
			notZero = false
 | 
								notZero = false
 | 
				
			||||||
			for idx, field := range fields {
 | 
								for idx, field := range fields {
 | 
				
			||||||
				fieldValues[idx], zero = field.ValueOf(elem)
 | 
									fieldValues[idx], zero = field.ValueOf(ctx, elem)
 | 
				
			||||||
				notZero = notZero || !zero
 | 
									notZero = notZero || !zero
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -155,12 +156,12 @@ func GetIdentityFieldValuesMap(reflectValue reflect.Value, fields []*Field) (map
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetIdentityFieldValuesMapFromValues get identity map from fields
 | 
					// GetIdentityFieldValuesMapFromValues get identity map from fields
 | 
				
			||||||
func GetIdentityFieldValuesMapFromValues(values []interface{}, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
 | 
					func GetIdentityFieldValuesMapFromValues(ctx context.Context, values []interface{}, fields []*Field) (map[string][]reflect.Value, [][]interface{}) {
 | 
				
			||||||
	resultsMap := map[string][]reflect.Value{}
 | 
						resultsMap := map[string][]reflect.Value{}
 | 
				
			||||||
	results := [][]interface{}{}
 | 
						results := [][]interface{}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, v := range values {
 | 
						for _, v := range values {
 | 
				
			||||||
		rm, rs := GetIdentityFieldValuesMap(reflect.Indirect(reflect.ValueOf(v)), fields)
 | 
							rm, rs := GetIdentityFieldValuesMap(ctx, reflect.Indirect(reflect.ValueOf(v)), fields)
 | 
				
			||||||
		for k, v := range rm {
 | 
							for k, v := range rm {
 | 
				
			||||||
			resultsMap[k] = append(resultsMap[k], v...)
 | 
								resultsMap[k] = append(resultsMap[k], v...)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -135,7 +135,7 @@ func (sd SoftDeleteDeleteClause) ModifyStatement(stmt *Statement) {
 | 
				
			|||||||
		stmt.SetColumn(sd.Field.DBName, curTime, true)
 | 
							stmt.SetColumn(sd.Field.DBName, curTime, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if stmt.Schema != nil {
 | 
							if stmt.Schema != nil {
 | 
				
			||||||
			_, queryValues := schema.GetIdentityFieldValuesMap(stmt.ReflectValue, stmt.Schema.PrimaryFields)
 | 
								_, queryValues := schema.GetIdentityFieldValuesMap(stmt.Context, stmt.ReflectValue, stmt.Schema.PrimaryFields)
 | 
				
			||||||
			column, values := schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
 | 
								column, values := schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if len(values) > 0 {
 | 
								if len(values) > 0 {
 | 
				
			||||||
@ -143,7 +143,7 @@ func (sd SoftDeleteDeleteClause) ModifyStatement(stmt *Statement) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if stmt.ReflectValue.CanAddr() && stmt.Dest != stmt.Model && stmt.Model != nil {
 | 
								if stmt.ReflectValue.CanAddr() && stmt.Dest != stmt.Model && stmt.Model != nil {
 | 
				
			||||||
				_, queryValues = schema.GetIdentityFieldValuesMap(reflect.ValueOf(stmt.Model), stmt.Schema.PrimaryFields)
 | 
									_, queryValues = schema.GetIdentityFieldValuesMap(stmt.Context, reflect.ValueOf(stmt.Model), stmt.Schema.PrimaryFields)
 | 
				
			||||||
				column, values = schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
 | 
									column, values = schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if len(values) > 0 {
 | 
									if len(values) > 0 {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								statement.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								statement.go
									
									
									
									
									
								
							@ -389,7 +389,7 @@ func (stmt *Statement) BuildCondition(query interface{}, args ...interface{}) []
 | 
				
			|||||||
					for _, field := range s.Fields {
 | 
										for _, field := range s.Fields {
 | 
				
			||||||
						selected := selectedColumns[field.DBName] || selectedColumns[field.Name]
 | 
											selected := selectedColumns[field.DBName] || selectedColumns[field.Name]
 | 
				
			||||||
						if selected || (!restricted && field.Readable) {
 | 
											if selected || (!restricted && field.Readable) {
 | 
				
			||||||
							if v, isZero := field.ValueOf(reflectValue); !isZero || selected {
 | 
												if v, isZero := field.ValueOf(stmt.Context, reflectValue); !isZero || selected {
 | 
				
			||||||
								if field.DBName != "" {
 | 
													if field.DBName != "" {
 | 
				
			||||||
									conds = append(conds, clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: field.DBName}, Value: v})
 | 
														conds = append(conds, clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: field.DBName}, Value: v})
 | 
				
			||||||
								} else if field.DataType != "" {
 | 
													} else if field.DataType != "" {
 | 
				
			||||||
@ -403,7 +403,7 @@ func (stmt *Statement) BuildCondition(query interface{}, args ...interface{}) []
 | 
				
			|||||||
						for _, field := range s.Fields {
 | 
											for _, field := range s.Fields {
 | 
				
			||||||
							selected := selectedColumns[field.DBName] || selectedColumns[field.Name]
 | 
												selected := selectedColumns[field.DBName] || selectedColumns[field.Name]
 | 
				
			||||||
							if selected || (!restricted && field.Readable) {
 | 
												if selected || (!restricted && field.Readable) {
 | 
				
			||||||
								if v, isZero := field.ValueOf(reflectValue.Index(i)); !isZero || selected {
 | 
													if v, isZero := field.ValueOf(stmt.Context, reflectValue.Index(i)); !isZero || selected {
 | 
				
			||||||
									if field.DBName != "" {
 | 
														if field.DBName != "" {
 | 
				
			||||||
										conds = append(conds, clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: field.DBName}, Value: v})
 | 
															conds = append(conds, clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: field.DBName}, Value: v})
 | 
				
			||||||
									} else if field.DataType != "" {
 | 
														} else if field.DataType != "" {
 | 
				
			||||||
@ -562,7 +562,7 @@ func (stmt *Statement) SetColumn(name string, value interface{}, fromCallbacks .
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				switch destValue.Kind() {
 | 
									switch destValue.Kind() {
 | 
				
			||||||
				case reflect.Struct:
 | 
									case reflect.Struct:
 | 
				
			||||||
					field.Set(destValue, value)
 | 
										field.Set(stmt.Context, destValue, value)
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					stmt.AddError(ErrInvalidData)
 | 
										stmt.AddError(ErrInvalidData)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@ -572,10 +572,10 @@ func (stmt *Statement) SetColumn(name string, value interface{}, fromCallbacks .
 | 
				
			|||||||
			case reflect.Slice, reflect.Array:
 | 
								case reflect.Slice, reflect.Array:
 | 
				
			||||||
				if len(fromCallbacks) > 0 {
 | 
									if len(fromCallbacks) > 0 {
 | 
				
			||||||
					for i := 0; i < stmt.ReflectValue.Len(); i++ {
 | 
										for i := 0; i < stmt.ReflectValue.Len(); i++ {
 | 
				
			||||||
						field.Set(stmt.ReflectValue.Index(i), value)
 | 
											field.Set(stmt.Context, stmt.ReflectValue.Index(i), value)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					field.Set(stmt.ReflectValue.Index(stmt.CurDestIndex), value)
 | 
										field.Set(stmt.Context, stmt.ReflectValue.Index(stmt.CurDestIndex), value)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			case reflect.Struct:
 | 
								case reflect.Struct:
 | 
				
			||||||
				if !stmt.ReflectValue.CanAddr() {
 | 
									if !stmt.ReflectValue.CanAddr() {
 | 
				
			||||||
@ -583,7 +583,7 @@ func (stmt *Statement) SetColumn(name string, value interface{}, fromCallbacks .
 | 
				
			|||||||
					return
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				field.Set(stmt.ReflectValue, value)
 | 
									field.Set(stmt.Context, stmt.ReflectValue, value)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			stmt.AddError(ErrInvalidField)
 | 
								stmt.AddError(ErrInvalidField)
 | 
				
			||||||
@ -603,7 +603,7 @@ func (stmt *Statement) Changed(fields ...string) bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	selectColumns, restricted := stmt.SelectAndOmitColumns(false, true)
 | 
						selectColumns, restricted := stmt.SelectAndOmitColumns(false, true)
 | 
				
			||||||
	changed := func(field *schema.Field) bool {
 | 
						changed := func(field *schema.Field) bool {
 | 
				
			||||||
		fieldValue, _ := field.ValueOf(modelValue)
 | 
							fieldValue, _ := field.ValueOf(stmt.Context, modelValue)
 | 
				
			||||||
		if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
 | 
							if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && !restricted) {
 | 
				
			||||||
			if v, ok := stmt.Dest.(map[string]interface{}); ok {
 | 
								if v, ok := stmt.Dest.(map[string]interface{}); ok {
 | 
				
			||||||
				if fv, ok := v[field.Name]; ok {
 | 
									if fv, ok := v[field.Name]; ok {
 | 
				
			||||||
@ -617,7 +617,7 @@ func (stmt *Statement) Changed(fields ...string) bool {
 | 
				
			|||||||
					destValue = destValue.Elem()
 | 
										destValue = destValue.Elem()
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				changedValue, zero := field.ValueOf(destValue)
 | 
									changedValue, zero := field.ValueOf(stmt.Context, destValue)
 | 
				
			||||||
				return !zero && !utils.AssertEqual(changedValue, fieldValue)
 | 
									return !zero && !utils.AssertEqual(changedValue, fieldValue)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -123,7 +123,7 @@ func TestCreateFromMap(t *testing.T) {
 | 
				
			|||||||
		{"name": "create_from_map_3", "Age": 20},
 | 
							{"name": "create_from_map_3", "Age": 20},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&User{}).Create(datas).Error; err != nil {
 | 
						if err := DB.Model(&User{}).Create(&datas).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("failed to create data from slice of map, got error: %v", err)
 | 
							t.Fatalf("failed to create data from slice of map, got error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,7 @@ require (
 | 
				
			|||||||
	github.com/jinzhu/now v1.1.4
 | 
						github.com/jinzhu/now v1.1.4
 | 
				
			||||||
	github.com/lib/pq v1.10.4
 | 
						github.com/lib/pq v1.10.4
 | 
				
			||||||
	github.com/mattn/go-sqlite3 v1.14.11 // indirect
 | 
						github.com/mattn/go-sqlite3 v1.14.11 // indirect
 | 
				
			||||||
	golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 // indirect
 | 
						golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
 | 
				
			||||||
	gorm.io/driver/mysql v1.2.3
 | 
						gorm.io/driver/mysql v1.2.3
 | 
				
			||||||
	gorm.io/driver/postgres v1.2.3
 | 
						gorm.io/driver/postgres v1.2.3
 | 
				
			||||||
	gorm.io/driver/sqlite v1.2.6
 | 
						gorm.io/driver/sqlite v1.2.6
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										71
									
								
								tests/serializer_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								tests/serializer_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					package tests_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"gorm.io/gorm"
 | 
				
			||||||
 | 
						"gorm.io/gorm/schema"
 | 
				
			||||||
 | 
						. "gorm.io/gorm/utils/tests"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SerializerStruct struct {
 | 
				
			||||||
 | 
						gorm.Model
 | 
				
			||||||
 | 
						Name            []byte                 `gorm:"json"`
 | 
				
			||||||
 | 
						Roles           Roles                  `gorm:"serializer:json"`
 | 
				
			||||||
 | 
						Contracts       map[string]interface{} `gorm:"serializer:json"`
 | 
				
			||||||
 | 
						CreatedTime     int64                  `gorm:"serializer:unixtime;type:time"` // store time in db, use int as field type
 | 
				
			||||||
 | 
						EncryptedString EncryptedString
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Roles []string
 | 
				
			||||||
 | 
					type EncryptedString string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (es *EncryptedString) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) (err error) {
 | 
				
			||||||
 | 
						switch value := dbValue.(type) {
 | 
				
			||||||
 | 
						case []byte:
 | 
				
			||||||
 | 
							*es = EncryptedString(bytes.TrimPrefix(value, []byte("hello")))
 | 
				
			||||||
 | 
						case string:
 | 
				
			||||||
 | 
							*es = EncryptedString(strings.TrimPrefix(value, "hello"))
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return fmt.Errorf("unsupported data %v", dbValue)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (es EncryptedString) Value(ctx context.Context, field *schema.Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
 | 
				
			||||||
 | 
						return "hello" + string(es), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSerializer(t *testing.T) {
 | 
				
			||||||
 | 
						DB.Migrator().DropTable(&SerializerStruct{})
 | 
				
			||||||
 | 
						if err := DB.Migrator().AutoMigrate(&SerializerStruct{}); err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("no error should happen when migrate scanner, valuer struct, got error %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						createdAt := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data := SerializerStruct{
 | 
				
			||||||
 | 
							Name:            []byte("jinzhu"),
 | 
				
			||||||
 | 
							Roles:           []string{"r1", "r2"},
 | 
				
			||||||
 | 
							Contracts:       map[string]interface{}{"name": "jinzhu", "age": 10},
 | 
				
			||||||
 | 
							EncryptedString: EncryptedString("pass"),
 | 
				
			||||||
 | 
							CreatedTime:     createdAt.Unix(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := DB.Create(&data).Error; err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("failed to create data, got error %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var result SerializerStruct
 | 
				
			||||||
 | 
						if err := DB.First(&result, data.ID).Error; err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("failed to query data, got error %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AssertEqual(t, result, data)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -36,17 +36,14 @@ func IsValidDBNameChar(c rune) bool {
 | 
				
			|||||||
	return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '*' && c != '_' && c != '$' && c != '@'
 | 
						return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '.' && c != '*' && c != '_' && c != '$' && c != '@'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func CheckTruth(val interface{}) bool {
 | 
					// CheckTruth check string true or not
 | 
				
			||||||
	if v, ok := val.(bool); ok {
 | 
					func CheckTruth(vals ...string) bool {
 | 
				
			||||||
		return v
 | 
						for _, val := range vals {
 | 
				
			||||||
 | 
							if !strings.EqualFold(val, "false") && val != "" {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if v, ok := val.(string); ok {
 | 
					 | 
				
			||||||
		v = strings.ToLower(v)
 | 
					 | 
				
			||||||
		return v != "false"
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
	return !reflect.ValueOf(val).IsZero()
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ToStringKey(values ...interface{}) string {
 | 
					func ToStringKey(values ...interface{}) string {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user