diff --git a/model/field.go b/model/field.go new file mode 100644 index 00000000..714170b6 --- /dev/null +++ b/model/field.go @@ -0,0 +1,78 @@ +package model + +import ( + "reflect" + + "github.com/jinzhu/gorm" + "github.com/jinzhu/gorm/schema" +) + +// Field GORM model field +type Field struct { + *schema.Field + IsBlank bool + Value reflect.Value +} + +// GetCreatingAssignments get creating assignments +func GetCreatingAssignments(tx *gorm.DB) chan [][]*Field { + fieldChan := make(chan [][]*Field) + + go func() { + // TODO handle select, omit, protected + switch dest := tx.Statement.Dest.(type) { + case map[string]interface{}: + fieldChan <- [][]*Field{mapToFields(dest, schema.Parse(tx.Statement.Table))} + case []map[string]interface{}: + fields := [][]*Field{} + tableSchema := schema.Parse(tx.Statement.Table) + + for _, v := range dest { + fields = append(fields, mapToFields(v, tableSchema)) + } + fieldChan <- fields + default: + if s := schema.Parse(tx.Statement.Dest); s != nil { + results := indirect(reflect.ValueOf(tx.Statement.Dest)) + + switch results.Kind() { + case reflect.Slice: + fields := [][]*Field{} + for i := 0; i < results.Len(); i++ { + fields = append(fields, structToField(results.Index(i), s)) + } + fieldChan <- fields + case reflect.Struct: + fieldChan <- [][]*Field{structToField(results, s)} + } + } + } + }() + + return fieldChan +} + +func mapToFields(value map[string]interface{}, s *schema.Schema) (fields []*Field) { + for k, v := range value { + if s != nil { + if f := s.FieldByName(k); f != nil { + fields = append(fields, &Field{Field: f, Value: reflect.ValueOf(v)}) + continue + } + } + + fields = append(fields, &Field{Field: &schema.Field{DBName: k}, Value: reflect.ValueOf(v)}) + } + return +} + +func structToField(value reflect.Value, s *schema.Schema) (fields []*Field) { + for _, sf := range s.Fields { + obj := value + for _, bn := range sf.BindNames { + obj = value.FieldByName(bn) + } + fields = append(fields, &Field{Field: sf, Value: obj}) + } + return +} diff --git a/model/model.go b/model/model.go index 878d4c90..86aad30c 100644 --- a/model/model.go +++ b/model/model.go @@ -12,11 +12,6 @@ import ( // } var DefaultTableNameHandler func(tx *gorm.DB, tableName string) string -// GetCreatingAssignments get creating assignments -func GetCreatingAssignments(tx *gorm.DB) chan []schema.Field { - return nil -} - // GetTable get table name for current db operation func GetTable(tx *gorm.DB) chan string { tableChan := make(chan string) diff --git a/model/utils.go b/model/utils.go index edd67a0a..dfeba195 100644 --- a/model/utils.go +++ b/model/utils.go @@ -1,5 +1,7 @@ package model +import "reflect" + // ToSearchableMap convert attrs to searchable map func ToSearchableMap(attrs ...interface{}) (result interface{}) { if len(attrs) > 1 { @@ -17,3 +19,10 @@ func ToSearchableMap(attrs ...interface{}) (result interface{}) { } return } + +func indirect(reflectValue reflect.Value) reflect.Value { + for reflectValue.Kind() == reflect.Ptr { + reflectValue = reflectValue.Elem() + } + return reflectValue +} diff --git a/schema/schema.go b/schema/schema.go index ee5f5c54..6c295b97 100644 --- a/schema/schema.go +++ b/schema/schema.go @@ -255,6 +255,11 @@ func (schema *Schema) MainPrimaryField() *Field { return nil } +// FieldByName get schema's field by name +func (schema *Schema) FieldByName(name string) *Field { + return getSchemaField(name, schema.Fields) +} + func (schemaField *Field) clone() *Field { clone := *schemaField