func TestPlural(t *testing.T) { for key, value := range inflections { if v := inflection.Plural(strings.ToUpper(key)); v != strings.ToUpper(value) { t.Errorf("%v's plural should be %v, but got %v", strings.ToUpper(key), strings.ToUpper(value), v) } if v := inflection.Plural(strings.Title(key)); v != strings.Title(value) { t.Errorf("%v's plural should be %v, but got %v", strings.Title(key), strings.Title(value), v) } if v := inflection.Plural(key); v != value { t.Errorf("%v's plural should be %v, but got %v", key, value, v) } } }
func (scope *Scope) GetModelStruct() *ModelStruct { var modelStruct ModelStruct reflectValue := reflect.Indirect(reflect.ValueOf(scope.Value)) if !reflectValue.IsValid() { return &modelStruct } if reflectValue.Kind() == reflect.Slice { reflectValue = reflect.Indirect(reflect.New(reflectValue.Type().Elem())) } scopeType := reflectValue.Type() if scopeType.Kind() == reflect.Ptr { scopeType = scopeType.Elem() } if value := modelStructsMap.Get(scopeType); value != nil { return value } modelStruct.ModelType = scopeType if scopeType.Kind() != reflect.Struct { return &modelStruct } if tabler, ok := reflect.New(scopeType).Interface().(interface { TableName() string }); ok { modelStruct.defaultTableName = tabler.TableName() } else { name := ToDBName(scopeType.Name()) if scope.db == nil || !scope.db.parent.singularTable { name = inflection.Plural(name) } modelStruct.defaultTableName = name } // Get all fields fields := []*StructField{} for i := 0; i < scopeType.NumField(); i++ { if fieldStruct := scopeType.Field(i); ast.IsExported(fieldStruct.Name) { field := &StructField{ Struct: fieldStruct, Name: fieldStruct.Name, Names: []string{fieldStruct.Name}, Tag: fieldStruct.Tag, } if fieldStruct.Tag.Get("sql") == "-" { field.IsIgnored = true } else { sqlSettings := parseTagSetting(field.Tag.Get("sql")) gormSettings := parseTagSetting(field.Tag.Get("gorm")) if _, ok := gormSettings["PRIMARY_KEY"]; ok { field.IsPrimaryKey = true modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, field) } if _, ok := sqlSettings["DEFAULT"]; ok { field.HasDefaultValue = true } if value, ok := gormSettings["COLUMN"]; ok { field.DBName = value } else { field.DBName = ToDBName(fieldStruct.Name) } } fields = append(fields, field) } } var finished = make(chan bool) go func(finished chan bool) { for _, field := range fields { if !field.IsIgnored { fieldStruct := field.Struct indirectType := fieldStruct.Type if indirectType.Kind() == reflect.Ptr { indirectType = indirectType.Elem() } if _, isScanner := reflect.New(indirectType).Interface().(sql.Scanner); isScanner { field.IsScanner, field.IsNormal = true, true } if _, isTime := reflect.New(indirectType).Interface().(*time.Time); isTime { field.IsNormal = true } if !field.IsNormal { gormSettings := parseTagSetting(field.Tag.Get("gorm")) toScope := scope.New(reflect.New(fieldStruct.Type).Interface()) getForeignField := func(column string, fields []*StructField) *StructField { for _, field := range fields { if field.Name == column || field.DBName == ToDBName(column) { return field } } return nil } var relationship = &Relationship{} if polymorphic := gormSettings["POLYMORPHIC"]; polymorphic != "" { if polymorphicField := getForeignField(polymorphic+"Id", toScope.GetStructFields()); polymorphicField != nil { if polymorphicType := getForeignField(polymorphic+"Type", toScope.GetStructFields()); polymorphicType != nil { relationship.ForeignFieldNames = []string{polymorphicField.Name} relationship.ForeignDBNames = []string{polymorphicField.DBName} relationship.AssociationForeignFieldNames = []string{scope.PrimaryField().Name} relationship.AssociationForeignDBNames = []string{scope.PrimaryField().DBName} relationship.PolymorphicType = polymorphicType.Name relationship.PolymorphicDBName = polymorphicType.DBName polymorphicType.IsForeignKey = true polymorphicField.IsForeignKey = true } } } var foreignKeys []string if foreignKey, ok := gormSettings["FOREIGNKEY"]; ok { foreignKeys = append(foreignKeys, foreignKey) } switch indirectType.Kind() { case reflect.Slice: elemType := indirectType.Elem() if elemType.Kind() == reflect.Ptr { elemType = elemType.Elem() } if elemType.Kind() == reflect.Struct { if many2many := gormSettings["MANY2MANY"]; many2many != "" { relationship.Kind = "many_to_many" // foreign keys if len(foreignKeys) == 0 { for _, field := range scope.PrimaryFields() { foreignKeys = append(foreignKeys, field.DBName) } } for _, foreignKey := range foreignKeys { if field, ok := scope.FieldByName(foreignKey); ok { relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, field.DBName) joinTableDBName := ToDBName(scopeType.Name()) + "_" + field.DBName relationship.ForeignDBNames = append(relationship.ForeignDBNames, joinTableDBName) } } // association foreign keys var associationForeignKeys []string if foreignKey := gormSettings["ASSOCIATIONFOREIGNKEY"]; foreignKey != "" { associationForeignKeys = []string{gormSettings["ASSOCIATIONFOREIGNKEY"]} } else { for _, field := range toScope.PrimaryFields() { associationForeignKeys = append(associationForeignKeys, field.DBName) } } for _, name := range associationForeignKeys { if field, ok := toScope.FieldByName(name); ok { relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, field.DBName) relationship.AssociationForeignStructFieldNames = append(relationship.AssociationForeignFieldNames, field.Name) joinTableDBName := ToDBName(elemType.Name()) + "_" + field.DBName relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, joinTableDBName) } } joinTableHandler := JoinTableHandler{} joinTableHandler.Setup(relationship, many2many, scopeType, elemType) relationship.JoinTableHandler = &joinTableHandler field.Relationship = relationship } else { relationship.Kind = "has_many" if len(foreignKeys) == 0 { for _, field := range scope.PrimaryFields() { if foreignField := getForeignField(scopeType.Name()+field.Name, toScope.GetStructFields()); foreignField != nil { relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, field.Name) relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, field.DBName) relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name) relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName) foreignField.IsForeignKey = true } } } else { for _, foreignKey := range foreignKeys { if foreignField := getForeignField(foreignKey, toScope.GetStructFields()); foreignField != nil { relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, scope.PrimaryField().Name) relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, scope.PrimaryField().DBName) relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name) relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName) foreignField.IsForeignKey = true } } } if len(relationship.ForeignFieldNames) != 0 { field.Relationship = relationship } } } else { field.IsNormal = true } case reflect.Struct: if _, ok := gormSettings["EMBEDDED"]; ok || fieldStruct.Anonymous { for _, toField := range toScope.GetStructFields() { toField = toField.clone() toField.Names = append([]string{fieldStruct.Name}, toField.Names...) modelStruct.StructFields = append(modelStruct.StructFields, toField) if toField.IsPrimaryKey { modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, toField) } } continue } else { if len(foreignKeys) == 0 { for _, f := range scope.PrimaryFields() { if foreignField := getForeignField(modelStruct.ModelType.Name()+f.Name, toScope.GetStructFields()); foreignField != nil { relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, f.Name) relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, f.DBName) relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name) relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName) foreignField.IsForeignKey = true } } } else { for _, foreignKey := range foreignKeys { if foreignField := getForeignField(foreignKey, toScope.GetStructFields()); foreignField != nil { relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, scope.PrimaryField().Name) relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, scope.PrimaryField().DBName) relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name) relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName) foreignField.IsForeignKey = true } } } if len(relationship.ForeignFieldNames) != 0 { relationship.Kind = "has_one" field.Relationship = relationship } else { if len(foreignKeys) == 0 { for _, f := range toScope.PrimaryFields() { if foreignField := getForeignField(field.Name+f.Name, fields); foreignField != nil { relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, f.Name) relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, f.DBName) relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name) relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName) foreignField.IsForeignKey = true } } } else { for _, foreignKey := range foreignKeys { if foreignField := getForeignField(foreignKey, fields); foreignField != nil { relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, toScope.PrimaryField().Name) relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, toScope.PrimaryField().DBName) relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name) relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName) foreignField.IsForeignKey = true } } } if len(relationship.ForeignFieldNames) != 0 { relationship.Kind = "belongs_to" field.Relationship = relationship } } } default: field.IsNormal = true } } if field.IsNormal { if len(modelStruct.PrimaryFields) == 0 && field.DBName == "id" { field.IsPrimaryKey = true modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, field) } } } modelStruct.StructFields = append(modelStruct.StructFields, field) } finished <- true }(finished) modelStructsMap.Set(scopeType, &modelStruct) <-finished modelStruct.cached = true return &modelStruct }