relationship.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  1. package schema
  2. import (
  3. "context"
  4. "fmt"
  5. "reflect"
  6. "strings"
  7. "sync"
  8. "github.com/jinzhu/inflection"
  9. "golang.org/x/text/cases"
  10. "golang.org/x/text/language"
  11. "gorm.io/gorm/clause"
  12. )
  13. // RelationshipType relationship type
  14. type RelationshipType string
  15. const (
  16. HasOne RelationshipType = "has_one" // HasOneRel has one relationship
  17. HasMany RelationshipType = "has_many" // HasManyRel has many relationship
  18. BelongsTo RelationshipType = "belongs_to" // BelongsToRel belongs to relationship
  19. Many2Many RelationshipType = "many_to_many" // Many2ManyRel many to many relationship
  20. has RelationshipType = "has"
  21. )
  22. type Relationships struct {
  23. HasOne []*Relationship
  24. BelongsTo []*Relationship
  25. HasMany []*Relationship
  26. Many2Many []*Relationship
  27. Relations map[string]*Relationship
  28. EmbeddedRelations map[string]*Relationships
  29. Mux sync.RWMutex
  30. }
  31. type Relationship struct {
  32. Name string
  33. Type RelationshipType
  34. Field *Field
  35. Polymorphic *Polymorphic
  36. References []*Reference
  37. Schema *Schema
  38. FieldSchema *Schema
  39. JoinTable *Schema
  40. foreignKeys, primaryKeys []string
  41. }
  42. type Polymorphic struct {
  43. PolymorphicID *Field
  44. PolymorphicType *Field
  45. Value string
  46. }
  47. type Reference struct {
  48. PrimaryKey *Field
  49. PrimaryValue string
  50. ForeignKey *Field
  51. OwnPrimaryKey bool
  52. }
  53. func (schema *Schema) parseRelation(field *Field) *Relationship {
  54. var (
  55. err error
  56. fieldValue = reflect.New(field.IndirectFieldType).Interface()
  57. relation = &Relationship{
  58. Name: field.Name,
  59. Field: field,
  60. Schema: schema,
  61. foreignKeys: toColumns(field.TagSettings["FOREIGNKEY"]),
  62. primaryKeys: toColumns(field.TagSettings["REFERENCES"]),
  63. }
  64. )
  65. cacheStore := schema.cacheStore
  66. if relation.FieldSchema, err = getOrParse(fieldValue, cacheStore, schema.namer); err != nil {
  67. schema.err = err
  68. return nil
  69. }
  70. if hasPolymorphicRelation(field.TagSettings) {
  71. schema.buildPolymorphicRelation(relation, field)
  72. } else if many2many := field.TagSettings["MANY2MANY"]; many2many != "" {
  73. schema.buildMany2ManyRelation(relation, field, many2many)
  74. } else if belongsTo := field.TagSettings["BELONGSTO"]; belongsTo != "" {
  75. schema.guessRelation(relation, field, guessBelongs)
  76. } else {
  77. switch field.IndirectFieldType.Kind() {
  78. case reflect.Struct:
  79. schema.guessRelation(relation, field, guessGuess)
  80. case reflect.Slice:
  81. schema.guessRelation(relation, field, guessHas)
  82. default:
  83. schema.err = fmt.Errorf("unsupported data type %v for %v on field %s", relation.FieldSchema, schema,
  84. field.Name)
  85. }
  86. }
  87. if relation.Type == has {
  88. if relation.FieldSchema != relation.Schema && relation.Polymorphic == nil && field.OwnerSchema == nil {
  89. relation.FieldSchema.Relationships.Mux.Lock()
  90. relation.FieldSchema.Relationships.Relations["_"+relation.Schema.Name+"_"+relation.Name] = relation
  91. relation.FieldSchema.Relationships.Mux.Unlock()
  92. }
  93. switch field.IndirectFieldType.Kind() {
  94. case reflect.Struct:
  95. relation.Type = HasOne
  96. case reflect.Slice:
  97. relation.Type = HasMany
  98. }
  99. }
  100. if schema.err == nil {
  101. schema.setRelation(relation)
  102. switch relation.Type {
  103. case HasOne:
  104. schema.Relationships.HasOne = append(schema.Relationships.HasOne, relation)
  105. case HasMany:
  106. schema.Relationships.HasMany = append(schema.Relationships.HasMany, relation)
  107. case BelongsTo:
  108. schema.Relationships.BelongsTo = append(schema.Relationships.BelongsTo, relation)
  109. case Many2Many:
  110. schema.Relationships.Many2Many = append(schema.Relationships.Many2Many, relation)
  111. }
  112. }
  113. return relation
  114. }
  115. // hasPolymorphicRelation check if has polymorphic relation
  116. // 1. `POLYMORPHIC` tag
  117. // 2. `POLYMORPHICTYPE` and `POLYMORPHICID` tag
  118. func hasPolymorphicRelation(tagSettings map[string]string) bool {
  119. if _, ok := tagSettings["POLYMORPHIC"]; ok {
  120. return true
  121. }
  122. _, hasType := tagSettings["POLYMORPHICTYPE"]
  123. _, hasId := tagSettings["POLYMORPHICID"]
  124. return hasType && hasId
  125. }
  126. func (schema *Schema) setRelation(relation *Relationship) {
  127. // set non-embedded relation
  128. if rel := schema.Relationships.Relations[relation.Name]; rel != nil {
  129. if len(rel.Field.BindNames) > 1 {
  130. schema.Relationships.Relations[relation.Name] = relation
  131. }
  132. } else {
  133. schema.Relationships.Relations[relation.Name] = relation
  134. }
  135. // set embedded relation
  136. if len(relation.Field.EmbeddedBindNames) <= 1 {
  137. return
  138. }
  139. relationships := &schema.Relationships
  140. for i, name := range relation.Field.EmbeddedBindNames {
  141. if i < len(relation.Field.EmbeddedBindNames)-1 {
  142. if relationships.EmbeddedRelations == nil {
  143. relationships.EmbeddedRelations = map[string]*Relationships{}
  144. }
  145. if r := relationships.EmbeddedRelations[name]; r == nil {
  146. relationships.EmbeddedRelations[name] = &Relationships{}
  147. }
  148. relationships = relationships.EmbeddedRelations[name]
  149. } else {
  150. if relationships.Relations == nil {
  151. relationships.Relations = map[string]*Relationship{}
  152. }
  153. relationships.Relations[relation.Name] = relation
  154. }
  155. }
  156. }
  157. // User has many Toys, its `Polymorphic` is `Owner`, Pet has one Toy, its `Polymorphic` is `Owner`
  158. //
  159. // type User struct {
  160. // Toys []Toy `gorm:"polymorphic:Owner;"`
  161. // }
  162. // type Pet struct {
  163. // Toy Toy `gorm:"polymorphic:Owner;"`
  164. // }
  165. // type Toy struct {
  166. // OwnerID int
  167. // OwnerType string
  168. // }
  169. func (schema *Schema) buildPolymorphicRelation(relation *Relationship, field *Field) {
  170. polymorphic := field.TagSettings["POLYMORPHIC"]
  171. relation.Polymorphic = &Polymorphic{
  172. Value: schema.Table,
  173. }
  174. var (
  175. typeName = polymorphic + "Type"
  176. typeId = polymorphic + "ID"
  177. )
  178. if value, ok := field.TagSettings["POLYMORPHICTYPE"]; ok {
  179. typeName = strings.TrimSpace(value)
  180. }
  181. if value, ok := field.TagSettings["POLYMORPHICID"]; ok {
  182. typeId = strings.TrimSpace(value)
  183. }
  184. relation.Polymorphic.PolymorphicType = relation.FieldSchema.FieldsByName[typeName]
  185. relation.Polymorphic.PolymorphicID = relation.FieldSchema.FieldsByName[typeId]
  186. if value, ok := field.TagSettings["POLYMORPHICVALUE"]; ok {
  187. relation.Polymorphic.Value = strings.TrimSpace(value)
  188. }
  189. if relation.Polymorphic.PolymorphicType == nil {
  190. schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %s, missing field %s",
  191. relation.FieldSchema, schema, field.Name, polymorphic+"Type")
  192. }
  193. if relation.Polymorphic.PolymorphicID == nil {
  194. schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %s, missing field %s",
  195. relation.FieldSchema, schema, field.Name, polymorphic+"ID")
  196. }
  197. if schema.err == nil {
  198. relation.References = append(relation.References, &Reference{
  199. PrimaryValue: relation.Polymorphic.Value,
  200. ForeignKey: relation.Polymorphic.PolymorphicType,
  201. })
  202. primaryKeyField := schema.PrioritizedPrimaryField
  203. if len(relation.foreignKeys) > 0 {
  204. if primaryKeyField = schema.LookUpField(relation.foreignKeys[0]); primaryKeyField == nil || len(relation.foreignKeys) > 1 {
  205. schema.err = fmt.Errorf("invalid polymorphic foreign keys %+v for %v on field %s", relation.foreignKeys,
  206. schema, field.Name)
  207. }
  208. }
  209. if primaryKeyField == nil {
  210. schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %s, missing primaryKey field",
  211. relation.FieldSchema, schema, field.Name)
  212. return
  213. }
  214. // use same data type for foreign keys
  215. if copyableDataType(primaryKeyField.DataType) {
  216. relation.Polymorphic.PolymorphicID.DataType = primaryKeyField.DataType
  217. }
  218. relation.Polymorphic.PolymorphicID.GORMDataType = primaryKeyField.GORMDataType
  219. if relation.Polymorphic.PolymorphicID.Size == 0 {
  220. relation.Polymorphic.PolymorphicID.Size = primaryKeyField.Size
  221. }
  222. relation.References = append(relation.References, &Reference{
  223. PrimaryKey: primaryKeyField,
  224. ForeignKey: relation.Polymorphic.PolymorphicID,
  225. OwnPrimaryKey: true,
  226. })
  227. }
  228. relation.Type = has
  229. }
  230. func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Field, many2many string) {
  231. relation.Type = Many2Many
  232. var (
  233. err error
  234. joinTableFields []reflect.StructField
  235. fieldsMap = map[string]*Field{}
  236. ownFieldsMap = map[string]*Field{} // fix self join many2many
  237. referFieldsMap = map[string]*Field{}
  238. joinForeignKeys = toColumns(field.TagSettings["JOINFOREIGNKEY"])
  239. joinReferences = toColumns(field.TagSettings["JOINREFERENCES"])
  240. )
  241. ownForeignFields := schema.PrimaryFields
  242. refForeignFields := relation.FieldSchema.PrimaryFields
  243. if len(relation.foreignKeys) > 0 {
  244. ownForeignFields = []*Field{}
  245. for _, foreignKey := range relation.foreignKeys {
  246. if field := schema.LookUpField(foreignKey); field != nil {
  247. ownForeignFields = append(ownForeignFields, field)
  248. } else {
  249. schema.err = fmt.Errorf("invalid foreign key: %s", foreignKey)
  250. return
  251. }
  252. }
  253. }
  254. if len(relation.primaryKeys) > 0 {
  255. refForeignFields = []*Field{}
  256. for _, foreignKey := range relation.primaryKeys {
  257. if field := relation.FieldSchema.LookUpField(foreignKey); field != nil {
  258. refForeignFields = append(refForeignFields, field)
  259. } else {
  260. schema.err = fmt.Errorf("invalid foreign key: %s", foreignKey)
  261. return
  262. }
  263. }
  264. }
  265. for idx, ownField := range ownForeignFields {
  266. joinFieldName := cases.Title(language.Und, cases.NoLower).String(schema.Name) + ownField.Name
  267. if len(joinForeignKeys) > idx {
  268. joinFieldName = cases.Title(language.Und, cases.NoLower).String(joinForeignKeys[idx])
  269. }
  270. ownFieldsMap[joinFieldName] = ownField
  271. fieldsMap[joinFieldName] = ownField
  272. joinTableFields = append(joinTableFields, reflect.StructField{
  273. Name: joinFieldName,
  274. PkgPath: ownField.StructField.PkgPath,
  275. Type: ownField.StructField.Type,
  276. Tag: removeSettingFromTag(appendSettingFromTag(ownField.StructField.Tag, "primaryKey"),
  277. "column", "autoincrement", "index", "unique", "uniqueindex"),
  278. })
  279. }
  280. for idx, relField := range refForeignFields {
  281. joinFieldName := cases.Title(language.Und, cases.NoLower).String(relation.FieldSchema.Name) + relField.Name
  282. if _, ok := ownFieldsMap[joinFieldName]; ok {
  283. if field.Name != relation.FieldSchema.Name {
  284. joinFieldName = inflection.Singular(field.Name) + relField.Name
  285. } else {
  286. joinFieldName += "Reference"
  287. }
  288. }
  289. if len(joinReferences) > idx {
  290. joinFieldName = cases.Title(language.Und, cases.NoLower).String(joinReferences[idx])
  291. }
  292. referFieldsMap[joinFieldName] = relField
  293. if _, ok := fieldsMap[joinFieldName]; !ok {
  294. fieldsMap[joinFieldName] = relField
  295. joinTableFields = append(joinTableFields, reflect.StructField{
  296. Name: joinFieldName,
  297. PkgPath: relField.StructField.PkgPath,
  298. Type: relField.StructField.Type,
  299. Tag: removeSettingFromTag(appendSettingFromTag(relField.StructField.Tag, "primaryKey"),
  300. "column", "autoincrement", "index", "unique", "uniqueindex"),
  301. })
  302. }
  303. }
  304. joinTableFields = append(joinTableFields, reflect.StructField{
  305. Name: cases.Title(language.Und, cases.NoLower).String(schema.Name) + field.Name,
  306. Type: schema.ModelType,
  307. Tag: `gorm:"-"`,
  308. })
  309. if relation.JoinTable, err = Parse(reflect.New(reflect.StructOf(joinTableFields)).Interface(), schema.cacheStore,
  310. schema.namer); err != nil {
  311. schema.err = err
  312. }
  313. relation.JoinTable.Name = many2many
  314. relation.JoinTable.Table = schema.namer.JoinTableName(many2many)
  315. relation.JoinTable.PrimaryFields = make([]*Field, 0, len(relation.JoinTable.Fields))
  316. relName := relation.Schema.Name
  317. relRefName := relation.FieldSchema.Name
  318. if relName == relRefName {
  319. relRefName = relation.Field.Name
  320. }
  321. if _, ok := relation.JoinTable.Relationships.Relations[relName]; !ok {
  322. relation.JoinTable.Relationships.Relations[relName] = &Relationship{
  323. Name: relName,
  324. Type: BelongsTo,
  325. Schema: relation.JoinTable,
  326. FieldSchema: relation.Schema,
  327. }
  328. } else {
  329. relation.JoinTable.Relationships.Relations[relName].References = []*Reference{}
  330. }
  331. if _, ok := relation.JoinTable.Relationships.Relations[relRefName]; !ok {
  332. relation.JoinTable.Relationships.Relations[relRefName] = &Relationship{
  333. Name: relRefName,
  334. Type: BelongsTo,
  335. Schema: relation.JoinTable,
  336. FieldSchema: relation.FieldSchema,
  337. }
  338. } else {
  339. relation.JoinTable.Relationships.Relations[relRefName].References = []*Reference{}
  340. }
  341. // build references
  342. for _, f := range relation.JoinTable.Fields {
  343. if f.Creatable || f.Readable || f.Updatable {
  344. // use same data type for foreign keys
  345. if copyableDataType(fieldsMap[f.Name].DataType) {
  346. f.DataType = fieldsMap[f.Name].DataType
  347. }
  348. f.GORMDataType = fieldsMap[f.Name].GORMDataType
  349. if f.Size == 0 {
  350. f.Size = fieldsMap[f.Name].Size
  351. }
  352. relation.JoinTable.PrimaryFields = append(relation.JoinTable.PrimaryFields, f)
  353. if of, ok := ownFieldsMap[f.Name]; ok {
  354. joinRel := relation.JoinTable.Relationships.Relations[relName]
  355. joinRel.Field = relation.Field
  356. joinRel.References = append(joinRel.References, &Reference{
  357. PrimaryKey: of,
  358. ForeignKey: f,
  359. })
  360. relation.References = append(relation.References, &Reference{
  361. PrimaryKey: of,
  362. ForeignKey: f,
  363. OwnPrimaryKey: true,
  364. })
  365. }
  366. if rf, ok := referFieldsMap[f.Name]; ok {
  367. joinRefRel := relation.JoinTable.Relationships.Relations[relRefName]
  368. if joinRefRel.Field == nil {
  369. joinRefRel.Field = relation.Field
  370. }
  371. joinRefRel.References = append(joinRefRel.References, &Reference{
  372. PrimaryKey: rf,
  373. ForeignKey: f,
  374. })
  375. relation.References = append(relation.References, &Reference{
  376. PrimaryKey: rf,
  377. ForeignKey: f,
  378. })
  379. }
  380. }
  381. }
  382. }
  383. type guessLevel int
  384. const (
  385. guessGuess guessLevel = iota
  386. guessBelongs
  387. guessEmbeddedBelongs
  388. guessHas
  389. guessEmbeddedHas
  390. )
  391. func (schema *Schema) guessRelation(relation *Relationship, field *Field, cgl guessLevel) {
  392. var (
  393. primaryFields, foreignFields []*Field
  394. primarySchema, foreignSchema = schema, relation.FieldSchema
  395. gl = cgl
  396. )
  397. if gl == guessGuess {
  398. if field.Schema == relation.FieldSchema {
  399. gl = guessBelongs
  400. } else {
  401. gl = guessHas
  402. }
  403. }
  404. reguessOrErr := func() {
  405. switch cgl {
  406. case guessGuess:
  407. schema.guessRelation(relation, field, guessBelongs)
  408. case guessBelongs:
  409. schema.guessRelation(relation, field, guessEmbeddedBelongs)
  410. case guessEmbeddedBelongs:
  411. schema.guessRelation(relation, field, guessHas)
  412. case guessHas:
  413. schema.guessRelation(relation, field, guessEmbeddedHas)
  414. // case guessEmbeddedHas:
  415. default:
  416. schema.err = fmt.Errorf("invalid field found for struct %v's field %s: define a valid foreign key for relations or implement the Valuer/Scanner interface",
  417. schema, field.Name)
  418. }
  419. }
  420. switch gl {
  421. case guessBelongs:
  422. primarySchema, foreignSchema = relation.FieldSchema, schema
  423. case guessEmbeddedBelongs:
  424. if field.OwnerSchema == nil {
  425. reguessOrErr()
  426. return
  427. }
  428. primarySchema, foreignSchema = relation.FieldSchema, field.OwnerSchema
  429. case guessHas:
  430. case guessEmbeddedHas:
  431. if field.OwnerSchema == nil {
  432. reguessOrErr()
  433. return
  434. }
  435. primarySchema, foreignSchema = field.OwnerSchema, relation.FieldSchema
  436. }
  437. if len(relation.foreignKeys) > 0 {
  438. for _, foreignKey := range relation.foreignKeys {
  439. f := foreignSchema.LookUpField(foreignKey)
  440. if f == nil {
  441. reguessOrErr()
  442. return
  443. }
  444. foreignFields = append(foreignFields, f)
  445. }
  446. } else {
  447. primarySchemaName := primarySchema.Name
  448. if primarySchemaName == "" {
  449. primarySchemaName = relation.FieldSchema.Name
  450. }
  451. if len(relation.primaryKeys) > 0 {
  452. for _, primaryKey := range relation.primaryKeys {
  453. if f := primarySchema.LookUpField(primaryKey); f != nil {
  454. primaryFields = append(primaryFields, f)
  455. }
  456. }
  457. } else {
  458. primaryFields = primarySchema.PrimaryFields
  459. }
  460. primaryFieldLoop:
  461. for _, primaryField := range primaryFields {
  462. lookUpName := primarySchemaName + primaryField.Name
  463. if gl == guessBelongs {
  464. lookUpName = field.Name + primaryField.Name
  465. }
  466. lookUpNames := []string{lookUpName}
  467. if len(primaryFields) == 1 {
  468. lookUpNames = append(lookUpNames, strings.TrimSuffix(lookUpName, primaryField.Name)+"ID",
  469. strings.TrimSuffix(lookUpName, primaryField.Name)+"Id", schema.namer.ColumnName(foreignSchema.Table,
  470. strings.TrimSuffix(lookUpName, primaryField.Name)+"ID"))
  471. }
  472. for _, name := range lookUpNames {
  473. if f := foreignSchema.LookUpFieldByBindName(field.BindNames, name); f != nil {
  474. foreignFields = append(foreignFields, f)
  475. primaryFields = append(primaryFields, primaryField)
  476. continue primaryFieldLoop
  477. }
  478. }
  479. for _, name := range lookUpNames {
  480. if f := foreignSchema.LookUpField(name); f != nil {
  481. foreignFields = append(foreignFields, f)
  482. primaryFields = append(primaryFields, primaryField)
  483. continue primaryFieldLoop
  484. }
  485. }
  486. }
  487. }
  488. switch {
  489. case len(foreignFields) == 0:
  490. reguessOrErr()
  491. return
  492. case len(relation.primaryKeys) > 0:
  493. for idx, primaryKey := range relation.primaryKeys {
  494. if f := primarySchema.LookUpField(primaryKey); f != nil {
  495. if len(primaryFields) < idx+1 {
  496. primaryFields = append(primaryFields, f)
  497. } else if f != primaryFields[idx] {
  498. reguessOrErr()
  499. return
  500. }
  501. } else {
  502. reguessOrErr()
  503. return
  504. }
  505. }
  506. case len(primaryFields) == 0:
  507. if len(foreignFields) == 1 && primarySchema.PrioritizedPrimaryField != nil {
  508. primaryFields = append(primaryFields, primarySchema.PrioritizedPrimaryField)
  509. } else if len(primarySchema.PrimaryFields) == len(foreignFields) {
  510. primaryFields = append(primaryFields, primarySchema.PrimaryFields...)
  511. } else {
  512. reguessOrErr()
  513. return
  514. }
  515. }
  516. // build references
  517. for idx, foreignField := range foreignFields {
  518. // use same data type for foreign keys
  519. if copyableDataType(primaryFields[idx].DataType) {
  520. foreignField.DataType = primaryFields[idx].DataType
  521. }
  522. foreignField.GORMDataType = primaryFields[idx].GORMDataType
  523. if foreignField.Size == 0 {
  524. foreignField.Size = primaryFields[idx].Size
  525. }
  526. relation.References = append(relation.References, &Reference{
  527. PrimaryKey: primaryFields[idx],
  528. ForeignKey: foreignField,
  529. OwnPrimaryKey: (schema == primarySchema && gl == guessHas) || (field.OwnerSchema == primarySchema && gl == guessEmbeddedHas),
  530. })
  531. }
  532. if gl == guessHas || gl == guessEmbeddedHas {
  533. relation.Type = has
  534. } else {
  535. relation.Type = BelongsTo
  536. }
  537. }
  538. // Constraint is ForeignKey Constraint
  539. type Constraint struct {
  540. Name string
  541. Field *Field
  542. Schema *Schema
  543. ForeignKeys []*Field
  544. ReferenceSchema *Schema
  545. References []*Field
  546. OnDelete string
  547. OnUpdate string
  548. }
  549. func (constraint *Constraint) GetName() string { return constraint.Name }
  550. func (constraint *Constraint) Build() (sql string, vars []interface{}) {
  551. sql = "CONSTRAINT ? FOREIGN KEY ? REFERENCES ??"
  552. if constraint.OnDelete != "" {
  553. sql += " ON DELETE " + constraint.OnDelete
  554. }
  555. if constraint.OnUpdate != "" {
  556. sql += " ON UPDATE " + constraint.OnUpdate
  557. }
  558. foreignKeys := make([]interface{}, 0, len(constraint.ForeignKeys))
  559. for _, field := range constraint.ForeignKeys {
  560. foreignKeys = append(foreignKeys, clause.Column{Name: field.DBName})
  561. }
  562. references := make([]interface{}, 0, len(constraint.References))
  563. for _, field := range constraint.References {
  564. references = append(references, clause.Column{Name: field.DBName})
  565. }
  566. vars = append(vars, clause.Table{Name: constraint.Name}, foreignKeys, clause.Table{Name: constraint.ReferenceSchema.Table}, references)
  567. return
  568. }
  569. func (rel *Relationship) ParseConstraint() *Constraint {
  570. str := rel.Field.TagSettings["CONSTRAINT"]
  571. if str == "-" {
  572. return nil
  573. }
  574. if rel.Type == BelongsTo {
  575. for _, r := range rel.FieldSchema.Relationships.Relations {
  576. if r != rel && r.FieldSchema == rel.Schema && len(rel.References) == len(r.References) {
  577. matched := true
  578. for idx, ref := range r.References {
  579. if !(rel.References[idx].PrimaryKey == ref.PrimaryKey && rel.References[idx].ForeignKey == ref.ForeignKey &&
  580. rel.References[idx].PrimaryValue == ref.PrimaryValue) {
  581. matched = false
  582. }
  583. }
  584. if matched {
  585. return nil
  586. }
  587. }
  588. }
  589. }
  590. var (
  591. name string
  592. idx = strings.Index(str, ",")
  593. settings = ParseTagSetting(str, ",")
  594. )
  595. // optimize match english letters and midline
  596. // The following code is basically called in for.
  597. // In order to avoid the performance problems caused by repeated compilation of regular expressions,
  598. // it only needs to be done once outside, so optimization is done here.
  599. if idx != -1 && regEnLetterAndMidline.MatchString(str[0:idx]) {
  600. name = str[0:idx]
  601. } else {
  602. name = rel.Schema.namer.RelationshipFKName(*rel)
  603. }
  604. constraint := Constraint{
  605. Name: name,
  606. Field: rel.Field,
  607. OnUpdate: settings["ONUPDATE"],
  608. OnDelete: settings["ONDELETE"],
  609. }
  610. for _, ref := range rel.References {
  611. if ref.PrimaryKey != nil && (rel.JoinTable == nil || ref.OwnPrimaryKey) {
  612. constraint.ForeignKeys = append(constraint.ForeignKeys, ref.ForeignKey)
  613. constraint.References = append(constraint.References, ref.PrimaryKey)
  614. if ref.OwnPrimaryKey {
  615. constraint.Schema = ref.ForeignKey.Schema
  616. constraint.ReferenceSchema = rel.Schema
  617. } else {
  618. constraint.Schema = rel.Schema
  619. constraint.ReferenceSchema = ref.PrimaryKey.Schema
  620. }
  621. }
  622. }
  623. return &constraint
  624. }
  625. func (rel *Relationship) ToQueryConditions(ctx context.Context, reflectValue reflect.Value) (conds []clause.Expression) {
  626. table := rel.FieldSchema.Table
  627. foreignFields := []*Field{}
  628. relForeignKeys := []string{}
  629. if rel.JoinTable != nil {
  630. table = rel.JoinTable.Table
  631. for _, ref := range rel.References {
  632. if ref.OwnPrimaryKey {
  633. foreignFields = append(foreignFields, ref.PrimaryKey)
  634. relForeignKeys = append(relForeignKeys, ref.ForeignKey.DBName)
  635. } else if ref.PrimaryValue != "" {
  636. conds = append(conds, clause.Eq{
  637. Column: clause.Column{Table: rel.JoinTable.Table, Name: ref.ForeignKey.DBName},
  638. Value: ref.PrimaryValue,
  639. })
  640. } else {
  641. conds = append(conds, clause.Eq{
  642. Column: clause.Column{Table: rel.JoinTable.Table, Name: ref.ForeignKey.DBName},
  643. Value: clause.Column{Table: rel.FieldSchema.Table, Name: ref.PrimaryKey.DBName},
  644. })
  645. }
  646. }
  647. } else {
  648. for _, ref := range rel.References {
  649. if ref.OwnPrimaryKey {
  650. relForeignKeys = append(relForeignKeys, ref.ForeignKey.DBName)
  651. foreignFields = append(foreignFields, ref.PrimaryKey)
  652. } else if ref.PrimaryValue != "" {
  653. conds = append(conds, clause.Eq{
  654. Column: clause.Column{Table: rel.FieldSchema.Table, Name: ref.ForeignKey.DBName},
  655. Value: ref.PrimaryValue,
  656. })
  657. } else {
  658. relForeignKeys = append(relForeignKeys, ref.PrimaryKey.DBName)
  659. foreignFields = append(foreignFields, ref.ForeignKey)
  660. }
  661. }
  662. }
  663. _, foreignValues := GetIdentityFieldValuesMap(ctx, reflectValue, foreignFields)
  664. column, values := ToQueryValues(table, relForeignKeys, foreignValues)
  665. conds = append(conds, clause.IN{Column: column, Values: values})
  666. return
  667. }
  668. func copyableDataType(str DataType) bool {
  669. for _, s := range []string{"auto_increment", "primary key"} {
  670. if strings.Contains(strings.ToLower(string(str)), s) {
  671. return false
  672. }
  673. }
  674. return true
  675. }