func NewModel(vi interface{}) (Model, error) { v := reflect.ValueOf(vi) if !v.IsValid() { return nil, errors.New("pg: NewModel(nil)") } v = reflect.Indirect(v) if v.Kind() == reflect.Slice { elType := indirectType(v.Type().Elem()) if elType == timeType || elType.Kind() != reflect.Struct { return &sliceModel{ slice: v, decoder: types.Decoder(elType), }, nil } } return newTableModelValue(v) }
func (t *Table) newField(typ reflect.Type, f reflect.StructField) *Field { sqlName, sqlOpt := parseTag(f.Tag.Get("sql")) if f.Name == "TableName" { t.Name = sqlName return nil } skip := sqlName == "-" if skip || sqlName == "" { sqlName = Underscore(f.Name) } if field, ok := t.FieldsMap[sqlName]; ok { return field } _, pgOpt := parseTag(f.Tag.Get("pg")) ftype := indirectType(f.Type) field := Field{ GoName: f.Name, SQLName: sqlName, Index: f.Index, append: types.Appender(ftype), decode: types.Decoder(ftype), isEmpty: isEmptier(ftype.Kind()), equal: equaler(ftype.Kind()), } if skip { t.FieldsMap[field.SQLName] = &field return nil } if _, ok := pgOpt.Get("nullempty"); ok { field.flags |= NullEmptyFlag } if field.SQLName == "id" { field.flags |= PrimaryKeyFlag t.PKs = append(t.PKs, &field) } else if _, ok := sqlOpt.Get("pk"); ok { field.flags |= PrimaryKeyFlag t.PKs = append(t.PKs, &field) } else if strings.HasSuffix(field.SQLName, "_id") { field.flags |= ForeignKeyFlag } var polymorphic string if s, _ := pgOpt.Get("polymorphic:"); s != "" { polymorphic = Underscore(s) + "_" } switch ftype.Kind() { case reflect.Slice: if ftype.Elem().Kind() == reflect.Struct { joinTable := newTable(ftype.Elem()) if m2mName, _ := pgOpt.Get("many2many:"); m2mName != "" { if m2mSlice, ok := typ.FieldByName(m2mName); ok { t.addRelation(&Relation{ Field: &field, Join: joinTable, M2M: newTable(m2mSlice.Type.Elem()), }) } return nil } var fks []*Field var prefix string if polymorphic != "" { prefix = polymorphic } else { prefix = t.ModelName + "_" } for _, pk := range t.PKs { fkName := prefix + pk.SQLName fk, ok := joinTable.FieldsMap[fkName] if ok { fks = append(fks, fk) } } if len(fks) > 0 { t.addRelation(&Relation{ Polymorphic: polymorphic, Field: &field, FKs: fks, Join: joinTable, }) return nil } } case reflect.Struct: joinTable := newTable(ftype) if len(joinTable.Fields) == 0 { break } for _, ff := range joinTable.Fields { ff = ff.Copy() ff.SQLName = field.SQLName + "__" + ff.SQLName ff.Index = append(field.Index, ff.Index...) t.FieldsMap[ff.SQLName] = ff } var fks []*Field for _, pk := range joinTable.PKs { fkName := field.SQLName + "_" + pk.SQLName fk, ok := t.FieldsMap[fkName] if ok { fks = append(fks, fk) } } if len(fks) > 0 { t.addRelation(&Relation{ One: true, Field: &field, FKs: fks, Join: joinTable, }) } t.FieldsMap[field.SQLName] = &field return nil } return &field }