Implement guess relation
This commit is contained in:
		
							parent
							
								
									eea78f3f30
								
							
						
					
					
						commit
						a9c20291e4
					
				| @ -25,15 +25,15 @@ type Relationships struct { | ||||
| } | ||||
| 
 | ||||
| type Relationship struct { | ||||
| 	Name                                string | ||||
| 	Type                                RelationshipType | ||||
| 	Field                               *Field | ||||
| 	Polymorphic                         *Polymorphic | ||||
| 	References                          []Reference | ||||
| 	Schema                              *Schema | ||||
| 	FieldSchema                         *Schema | ||||
| 	JoinTable                           *Schema | ||||
| 	ForeignKeys, AssociationForeignKeys []string | ||||
| 	Name                     string | ||||
| 	Type                     RelationshipType | ||||
| 	Field                    *Field | ||||
| 	Polymorphic              *Polymorphic | ||||
| 	References               []Reference | ||||
| 	Schema                   *Schema | ||||
| 	FieldSchema              *Schema | ||||
| 	JoinTable                *Schema | ||||
| 	ForeignKeys, PrimaryKeys []string | ||||
| } | ||||
| 
 | ||||
| type Polymorphic struct { | ||||
| @ -53,12 +53,11 @@ func (schema *Schema) parseRelation(field *Field) { | ||||
| 	var ( | ||||
| 		fieldValue = reflect.New(field.FieldType).Interface() | ||||
| 		relation   = &Relationship{ | ||||
| 			Name:                   field.Name, | ||||
| 			Field:                  field, | ||||
| 			Schema:                 schema, | ||||
| 			Type:                   RelationshipType(strings.ToLower(strings.TrimSpace(field.TagSettings["REL"]))), | ||||
| 			ForeignKeys:            toColumns(field.TagSettings["FOREIGNKEY"]), | ||||
| 			AssociationForeignKeys: toColumns(field.TagSettings["ASSOCIATION_FOREIGNKEY"]), | ||||
| 			Name:        field.Name, | ||||
| 			Field:       field, | ||||
| 			Schema:      schema, | ||||
| 			ForeignKeys: toColumns(field.TagSettings["FOREIGNKEY"]), | ||||
| 			PrimaryKeys: toColumns(field.TagSettings["PRIMARYKEY"]), | ||||
| 		} | ||||
| 	) | ||||
| 
 | ||||
| @ -66,6 +65,8 @@ func (schema *Schema) parseRelation(field *Field) { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// Parse Polymorphic relations
 | ||||
| 	//
 | ||||
| 	// User has many Toys, its `Polymorphic` is `Owner`, Pet has one Toy, its `Polymorphic` is `Owner`
 | ||||
| 	//     type User struct {
 | ||||
| 	//       Toys []Toy `gorm:"polymorphic:Owner;"`
 | ||||
| @ -89,11 +90,11 @@ func (schema *Schema) parseRelation(field *Field) { | ||||
| 		} | ||||
| 
 | ||||
| 		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 { | ||||
| 			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 { | ||||
| @ -105,7 +106,7 @@ func (schema *Schema) parseRelation(field *Field) { | ||||
| 			primaryKeyField := schema.PrioritizedPrimaryField | ||||
| 			if len(relation.ForeignKeys) > 0 { | ||||
| 				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{ | ||||
| @ -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() { | ||||
| 		case reflect.Struct: | ||||
| 			relation.Type = HasOne | ||||
| 		case reflect.Slice: | ||||
| 			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 | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		for _, primaryField := range primarySchema.PrimaryFields { | ||||
| 			if f := foreignSchema.LookUpField(field.Name + primaryField.Name); f != nil { | ||||
| 				foreignFields = append(foreignFields, f) | ||||
| 				primaryFields = append(primaryFields, primaryField) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if len(foreignFields) == 0 { | ||||
| 		reguessOrErr("failed to guess %v's relations with %v's field %v", relation.FieldSchema, schema, field.Name) | ||||
| 		return | ||||
| 	} else if len(relation.PrimaryKeys) > 0 { | ||||
| 		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 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	switch field.FieldType.Kind() { | ||||
| 	case reflect.Struct: | ||||
| 		schema.parseStructRelation(relation, field) | ||||
| 	case reflect.Slice: | ||||
| 		schema.parseSliceRelation(relation, field) | ||||
| 	default: | ||||
| 		schema.err = fmt.Errorf("unsupported data type: %v (in %v#%v ", field.FieldType.PkgPath(), schema, field.Name) | ||||
| 	// 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) parseStructRelation(relation *Relationship, field *Field) error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (schema *Schema) parseSliceRelation(relation *Relationship, field *Field) error { | ||||
| func (schema *Schema) parseMany2ManyRelation(relation *Relationship, field *Field) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jinzhu
						Jinzhu