Handle SelectAttrs, OmitAttrs when generate assignable attrs
This commit is contained in:
parent
6c8ab4dd0d
commit
0a35abb59f
132
model/field.go
132
model/field.go
@ -20,44 +20,6 @@ type Field struct {
|
||||
Value reflect.Value
|
||||
}
|
||||
|
||||
// GetAssignments get assignments
|
||||
func GetAssignments(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, tx.Statement, 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, tx.Statement, 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), tx.Statement, s))
|
||||
}
|
||||
fieldChan <- fields
|
||||
case reflect.Struct:
|
||||
fieldChan <- [][]*Field{structToField(results, tx.Statement, s)}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return fieldChan
|
||||
}
|
||||
|
||||
// Set set a value to the field
|
||||
func (field *Field) Set(value interface{}) (err error) {
|
||||
if !field.Value.IsValid() {
|
||||
@ -101,18 +63,62 @@ func (field *Field) Set(value interface{}) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func mapToFields(value map[string]interface{}, stmt *builder.Statement, s *schema.Schema) (fields []*Field) {
|
||||
// sort
|
||||
// GetAssignments get assignments
|
||||
func GetAssignments(tx *gorm.DB) chan [][]*Field {
|
||||
fieldChan := make(chan [][]*Field)
|
||||
|
||||
go func() {
|
||||
assignableChecker := generateAssignableChecker(selectAttrs(tx.Statement), omitAttrs(tx.Statement))
|
||||
|
||||
switch dest := tx.Statement.Dest.(type) {
|
||||
case map[string]interface{}:
|
||||
fieldChan <- [][]*Field{mapToFields(dest, schema.Parse(tx.Statement.Table), assignableChecker)}
|
||||
case []map[string]interface{}:
|
||||
fields := [][]*Field{}
|
||||
tableSchema := schema.Parse(tx.Statement.Table)
|
||||
|
||||
for _, v := range dest {
|
||||
fields = append(fields, mapToFields(v, tableSchema, assignableChecker))
|
||||
}
|
||||
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, assignableChecker))
|
||||
}
|
||||
fieldChan <- fields
|
||||
case reflect.Struct:
|
||||
fieldChan <- [][]*Field{structToField(results, s, assignableChecker)}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return fieldChan
|
||||
}
|
||||
|
||||
func mapToFields(value map[string]interface{}, s *schema.Schema, assignableChecker func(*Field) bool) (fields []*Field) {
|
||||
// TODO assign those value to dest
|
||||
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)})
|
||||
field := &Field{Field: f, Value: reflect.ValueOf(v)}
|
||||
if assignableChecker(field) {
|
||||
fields = append(fields, field)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
fields = append(fields, &Field{Field: &schema.Field{DBName: k}, Value: reflect.ValueOf(v)})
|
||||
field := &Field{Field: &schema.Field{DBName: k}, Value: reflect.ValueOf(v)}
|
||||
if assignableChecker(field) {
|
||||
fields = append(fields, field)
|
||||
}
|
||||
}
|
||||
|
||||
sort.SliceStable(fields, func(i, j int) bool {
|
||||
@ -121,14 +127,52 @@ func mapToFields(value map[string]interface{}, stmt *builder.Statement, s *schem
|
||||
return
|
||||
}
|
||||
|
||||
func structToField(value reflect.Value, stmt *builder.Statement, s *schema.Schema) (fields []*Field) {
|
||||
func structToField(value reflect.Value, s *schema.Schema, assignableChecker func(*Field) bool) (fields []*Field) {
|
||||
// TODO use Offset to replace FieldByName?
|
||||
for _, sf := range s.Fields {
|
||||
obj := value
|
||||
for _, bn := range sf.BindNames {
|
||||
obj = value.FieldByName(bn)
|
||||
}
|
||||
fields = append(fields, &Field{Field: sf, Value: obj, IsBlank: isBlank(obj)})
|
||||
field := &Field{Field: sf, Value: obj, IsBlank: isBlank(obj)}
|
||||
if assignableChecker(field) {
|
||||
fields = append(fields, field)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// generateAssignableChecker generate checker to check if field is assignable or not
|
||||
func generateAssignableChecker(selectAttrs []string, omitAttrs []string) func(*Field) bool {
|
||||
return func(field *Field) bool {
|
||||
if len(selectAttrs) > 0 {
|
||||
for _, attr := range selectAttrs {
|
||||
if field.Name == attr || field.DBName == attr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for _, attr := range omitAttrs {
|
||||
if field.Name == attr || field.DBName == attr {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// omitAttrs return selected attributes of stmt
|
||||
func selectAttrs(stmt *builder.Statement) []string {
|
||||
columns := stmt.Select.Columns
|
||||
for _, arg := range stmt.Select.Args {
|
||||
columns = append(columns, fmt.Sprint(arg))
|
||||
}
|
||||
return columns
|
||||
}
|
||||
|
||||
// omitAttrs return omitted attributes of stmt
|
||||
func omitAttrs(stmt *builder.Statement) []string {
|
||||
return stmt.Omit
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user