mirror of https://github.com/go-gorm/gorm.git
Implement guess relation
This commit is contained in:
parent
eea78f3f30
commit
a9c20291e4
|
@ -33,7 +33,7 @@ type Relationship struct {
|
||||||
Schema *Schema
|
Schema *Schema
|
||||||
FieldSchema *Schema
|
FieldSchema *Schema
|
||||||
JoinTable *Schema
|
JoinTable *Schema
|
||||||
ForeignKeys, AssociationForeignKeys []string
|
ForeignKeys, PrimaryKeys []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Polymorphic struct {
|
type Polymorphic struct {
|
||||||
|
@ -56,9 +56,8 @@ func (schema *Schema) parseRelation(field *Field) {
|
||||||
Name: field.Name,
|
Name: field.Name,
|
||||||
Field: field,
|
Field: field,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Type: RelationshipType(strings.ToLower(strings.TrimSpace(field.TagSettings["REL"]))),
|
|
||||||
ForeignKeys: toColumns(field.TagSettings["FOREIGNKEY"]),
|
ForeignKeys: toColumns(field.TagSettings["FOREIGNKEY"]),
|
||||||
AssociationForeignKeys: toColumns(field.TagSettings["ASSOCIATION_FOREIGNKEY"]),
|
PrimaryKeys: toColumns(field.TagSettings["PRIMARYKEY"]),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -66,6 +65,8 @@ func (schema *Schema) parseRelation(field *Field) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse Polymorphic relations
|
||||||
|
//
|
||||||
// User has many Toys, its `Polymorphic` is `Owner`, Pet has one Toy, its `Polymorphic` is `Owner`
|
// User has many Toys, its `Polymorphic` is `Owner`, Pet has one Toy, its `Polymorphic` is `Owner`
|
||||||
// type User struct {
|
// type User struct {
|
||||||
// Toys []Toy `gorm:"polymorphic:Owner;"`
|
// Toys []Toy `gorm:"polymorphic:Owner;"`
|
||||||
|
@ -89,11 +90,11 @@ func (schema *Schema) parseRelation(field *Field) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if relation.Polymorphic.PolymorphicType == nil {
|
if relation.Polymorphic.PolymorphicType == nil {
|
||||||
schema.err = fmt.Errorf("invalid polymorphic type: %v for %v on field %v, missing field %v", relation.FieldSchema, schema, field.Name, polymorphic+"Type")
|
schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %v, missing field %v", relation.FieldSchema, schema, field.Name, polymorphic+"Type")
|
||||||
}
|
}
|
||||||
|
|
||||||
if relation.Polymorphic.PolymorphicID == nil {
|
if relation.Polymorphic.PolymorphicID == nil {
|
||||||
schema.err = fmt.Errorf("invalid polymorphic type: %v for %v on field %v, missing field %v", relation.FieldSchema, schema, field.Name, polymorphic+"ID")
|
schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %v, missing field %v", relation.FieldSchema, schema, field.Name, polymorphic+"ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
if schema.err == nil {
|
if schema.err == nil {
|
||||||
|
@ -105,7 +106,7 @@ func (schema *Schema) parseRelation(field *Field) {
|
||||||
primaryKeyField := schema.PrioritizedPrimaryField
|
primaryKeyField := schema.PrioritizedPrimaryField
|
||||||
if len(relation.ForeignKeys) > 0 {
|
if len(relation.ForeignKeys) > 0 {
|
||||||
if primaryKeyField = schema.LookUpField(relation.ForeignKeys[0]); primaryKeyField == nil || len(relation.ForeignKeys) > 1 {
|
if primaryKeyField = schema.LookUpField(relation.ForeignKeys[0]); primaryKeyField == nil || len(relation.ForeignKeys) > 1 {
|
||||||
schema.err = fmt.Errorf("invalid polymorphic foreign key: %+v for %v on field %v", relation.ForeignKeys, schema, field.Name)
|
schema.err = fmt.Errorf("invalid polymorphic foreign keys %+v for %v on field %v", relation.ForeignKeys, schema, field.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
relation.References = append(relation.References, Reference{
|
relation.References = append(relation.References, Reference{
|
||||||
|
@ -115,29 +116,108 @@ func (schema *Schema) parseRelation(field *Field) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
relation.Type = "has"
|
||||||
|
} else {
|
||||||
|
switch field.FieldType.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
schema.guessRelation(relation, field, true)
|
||||||
|
case reflect.Slice:
|
||||||
|
schema.guessRelation(relation, field, true)
|
||||||
|
default:
|
||||||
|
schema.err = fmt.Errorf("unsupported data type %v for %v on field %v", relation.FieldSchema, schema, field.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if relation.Type == "has" {
|
||||||
switch field.FieldType.Kind() {
|
switch field.FieldType.Kind() {
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
relation.Type = HasOne
|
relation.Type = HasOne
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
relation.Type = HasMany
|
relation.Type = HasMany
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (schema *Schema) guessRelation(relation *Relationship, field *Field, guessHas bool) {
|
||||||
|
var (
|
||||||
|
primaryFields, foreignFields []*Field
|
||||||
|
primarySchema, foreignSchema = schema, relation.FieldSchema
|
||||||
|
)
|
||||||
|
|
||||||
|
if !guessHas {
|
||||||
|
primarySchema, foreignSchema = relation.FieldSchema, schema
|
||||||
|
}
|
||||||
|
|
||||||
|
reguessOrErr := func(err string, args ...interface{}) {
|
||||||
|
if guessHas {
|
||||||
|
schema.guessRelation(relation, field, false)
|
||||||
|
} else {
|
||||||
|
schema.err = fmt.Errorf(err, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(relation.ForeignKeys) > 0 {
|
||||||
|
for _, foreignKey := range relation.ForeignKeys {
|
||||||
|
if f := foreignSchema.LookUpField(foreignKey); f != nil {
|
||||||
|
foreignFields = append(foreignFields, f)
|
||||||
|
} else {
|
||||||
|
reguessOrErr("unsupported relations %v for %v on field %v with foreign keys %v", relation.FieldSchema, schema, field.Name, relation.ForeignKeys)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
switch field.FieldType.Kind() {
|
} else {
|
||||||
case reflect.Struct:
|
for _, primaryField := range primarySchema.PrimaryFields {
|
||||||
schema.parseStructRelation(relation, field)
|
if f := foreignSchema.LookUpField(field.Name + primaryField.Name); f != nil {
|
||||||
case reflect.Slice:
|
foreignFields = append(foreignFields, f)
|
||||||
schema.parseSliceRelation(relation, field)
|
primaryFields = append(primaryFields, primaryField)
|
||||||
default:
|
}
|
||||||
schema.err = fmt.Errorf("unsupported data type: %v (in %v#%v ", field.FieldType.PkgPath(), schema, field.Name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (schema *Schema) parseStructRelation(relation *Relationship, field *Field) error {
|
if len(foreignFields) == 0 {
|
||||||
return nil
|
reguessOrErr("failed to guess %v's relations with %v's field %v", relation.FieldSchema, schema, field.Name)
|
||||||
}
|
return
|
||||||
|
} else if len(relation.PrimaryKeys) > 0 {
|
||||||
func (schema *Schema) parseSliceRelation(relation *Relationship, field *Field) error {
|
for idx, primaryKey := range relation.PrimaryKeys {
|
||||||
|
if f := primarySchema.LookUpField(primaryKey); f != nil {
|
||||||
|
if len(primaryFields) < idx+1 {
|
||||||
|
primaryFields = append(primaryFields, f)
|
||||||
|
} else if f != primaryFields[idx] {
|
||||||
|
reguessOrErr("unsupported relations %v for %v on field %v with primary keys %v", relation.FieldSchema, schema, field.Name, relation.PrimaryKeys)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reguessOrErr("unsupported relations %v for %v on field %v with primary keys %v", relation.FieldSchema, schema, field.Name, relation.PrimaryKeys)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if len(primaryFields) == 0 {
|
||||||
|
if len(foreignFields) == 1 {
|
||||||
|
primaryFields = append(primaryFields, primarySchema.PrioritizedPrimaryField)
|
||||||
|
} else if len(primarySchema.PrimaryFields) == len(foreignFields) {
|
||||||
|
primaryFields = append(primaryFields, primarySchema.PrimaryFields...)
|
||||||
|
} else {
|
||||||
|
reguessOrErr("unsupported relations %v for %v on field %v", relation.FieldSchema, schema, field.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build references
|
||||||
|
for idx, foreignField := range foreignFields {
|
||||||
|
relation.References = append(relation.References, Reference{
|
||||||
|
PriamryKey: primaryFields[idx],
|
||||||
|
ForeignKey: foreignField,
|
||||||
|
OwnPriamryKey: schema == primarySchema,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if guessHas {
|
||||||
|
relation.Type = "has"
|
||||||
|
} else {
|
||||||
|
relation.Type = "belongs_to"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (schema *Schema) parseMany2ManyRelation(relation *Relationship, field *Field) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue