forked from mirror/gorm
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
39d84cba5f
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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…
Reference in New Issue