diff options
Diffstat (limited to 'vendor/github.com/uptrace/bun/schema')
| -rw-r--r-- | vendor/github.com/uptrace/bun/schema/field.go | 1 | ||||
| -rw-r--r-- | vendor/github.com/uptrace/bun/schema/relation.go | 51 | ||||
| -rw-r--r-- | vendor/github.com/uptrace/bun/schema/sqlfmt.go | 1 | ||||
| -rw-r--r-- | vendor/github.com/uptrace/bun/schema/table.go | 44 |
4 files changed, 89 insertions, 8 deletions
diff --git a/vendor/github.com/uptrace/bun/schema/field.go b/vendor/github.com/uptrace/bun/schema/field.go index 06d0a5094..09949dd72 100644 --- a/vendor/github.com/uptrace/bun/schema/field.go +++ b/vendor/github.com/uptrace/bun/schema/field.go @@ -10,6 +10,7 @@ import ( ) type Field struct { + Table *Table // Contains this field StructField reflect.StructField IsPtr bool diff --git a/vendor/github.com/uptrace/bun/schema/relation.go b/vendor/github.com/uptrace/bun/schema/relation.go index f653cd7a3..0711635f5 100644 --- a/vendor/github.com/uptrace/bun/schema/relation.go +++ b/vendor/github.com/uptrace/bun/schema/relation.go @@ -13,12 +13,12 @@ const ( ) type Relation struct { + Type int + Field *Field // Has the bun tag defining this relation. + // Base and Join can be explained with this query: // // SELECT * FROM base_table JOIN join_table - - Type int - Field *Field JoinTable *Table BasePKs []*Field JoinPKs []*Field @@ -34,10 +34,49 @@ type Relation struct { M2MJoinPKs []*Field } -// References returns true if the table to which the Relation belongs needs to declare a foreign key constraint to create the relation. -// For other relations, the constraint is created in either the referencing table (1:N, 'has-many' relations) or a mapping table (N:N, 'm2m' relations). +// References returns true if the table which defines this Relation +// needs to declare a foreign key constraint, as is the case +// for 'has-one' and 'belongs-to' relations. For other relations, +// the constraint is created either in the referencing table (1:N, 'has-many' relations) +// or the junction table (N:N, 'm2m' relations). +// +// Usage of `rel:` tag does not always imply creation of foreign keys (when WithForeignKeys() is not set) +// and can be used exclusively for joining tables at query time. For example: +// +// type User struct { +// ID int64 `bun:",pk"` +// Profile *Profile `bun:",rel:has-one,join:id=user_id"` +// } +// +// Creating a FK users.id -> profiles.user_id would be confusing and incorrect, +// so for such cases References() returns false. One notable exception to this rule +// is when a Relation is defined in a junction table, in which case it is perfectly +// fine for its primary keys to reference other tables. Consider: +// +// // UsersToGroups maps users to groups they follow. +// type UsersToGroups struct { +// UserID string `bun:"user_id,pk"` // Needs FK to users.id +// GroupID string `bun:"group_id,pk"` // Needs FK to groups.id +// +// User *User `bun:"rel:belongs-to,join:user_id=id"` +// Group *Group `bun:"rel:belongs-to,join:group_id=id"` +// } +// +// Here BooksToReaders has a composite primary key, composed of other primary keys. func (r *Relation) References() bool { - return r.Type == HasOneRelation || r.Type == BelongsToRelation + allPK := true + nonePK := true + for _, f := range r.BasePKs { + allPK = allPK && f.IsPK + nonePK = nonePK && !f.IsPK + } + + // Erring on the side of caution, only create foreign keys + // if the referencing columns are part of a composite PK + // in the junction table of the m2m relationship. + effectsM2M := r.Field.Table.IsM2MTable && allPK + + return (r.Type == HasOneRelation || r.Type == BelongsToRelation) && (effectsM2M || nonePK) } func (r *Relation) String() string { diff --git a/vendor/github.com/uptrace/bun/schema/sqlfmt.go b/vendor/github.com/uptrace/bun/schema/sqlfmt.go index 7b4a9493f..5a9d70460 100644 --- a/vendor/github.com/uptrace/bun/schema/sqlfmt.go +++ b/vendor/github.com/uptrace/bun/schema/sqlfmt.go @@ -50,6 +50,7 @@ func (s Ident) AppendQuery(fmter Formatter, b []byte) ([]byte, error) { //------------------------------------------------------------------------------ +// NOTE: It should not be modified after creation. type QueryWithArgs struct { Query string Args []interface{} diff --git a/vendor/github.com/uptrace/bun/schema/table.go b/vendor/github.com/uptrace/bun/schema/table.go index 13b989e4d..cf9f49197 100644 --- a/vendor/github.com/uptrace/bun/schema/table.go +++ b/vendor/github.com/uptrace/bun/schema/table.go @@ -62,8 +62,9 @@ type Table struct { FieldMap map[string]*Field StructMap map[string]*structField - Relations map[string]*Relation - Unique map[string][]*Field + IsM2MTable bool // If true, this table is the "junction table" of an m2m relation. + Relations map[string]*Relation + Unique map[string][]*Field SoftDeleteField *Field UpdateSoftDeleteField func(fv reflect.Value, tm time.Time) error @@ -122,6 +123,7 @@ func (t *Table) processFields(typ reflect.Type) { names := make(map[string]struct{}) embedded := make([]embeddedField, 0, 10) + ebdStructs := make(map[string]*structField, 0) for i, n := 0, typ.NumField(); i < n; i++ { sf := typ.Field(i) @@ -163,6 +165,17 @@ func (t *Table) processFields(typ reflect.Type) { subfield: subfield, }) } + if len(subtable.StructMap) > 0 { + for k, v := range subtable.StructMap { + // NOTE: conflict Struct name + if _, ok := ebdStructs[k]; !ok { + ebdStructs[k] = &structField{ + Index: makeIndex(sf.Index, v.Index), + Table: subtable, + } + } + } + } if tagstr != "" { tag := tagparser.Parse(tagstr) @@ -197,6 +210,18 @@ func (t *Table) processFields(typ reflect.Type) { subfield: subfield, }) } + if len(subtable.StructMap) > 0 { + for k, v := range subtable.StructMap { + // NOTE: conflict Struct name + k = prefix + k + if _, ok := ebdStructs[k]; !ok { + ebdStructs[k] = &structField{ + Index: makeIndex(sf.Index, v.Index), + Table: subtable, + } + } + } + } continue } @@ -252,6 +277,15 @@ func (t *Table) processFields(typ reflect.Type) { } } + if len(ebdStructs) > 0 && t.StructMap == nil { + t.StructMap = make(map[string]*structField) + } + for name, sfield := range ebdStructs { + if _, ok := t.StructMap[name]; !ok { + t.StructMap[name] = sfield + } + } + if len(embedded) > 0 { // https://github.com/uptrace/bun/issues/1095 // < v1.2, all fields follow the order corresponding to the struct @@ -483,6 +517,7 @@ func (t *Table) newField(sf reflect.StructField, tag tagparser.Tag) *Field { } field := &Field{ + Table: t, StructField: sf, IsPtr: sf.Type.Kind() == reflect.Ptr, @@ -862,6 +897,7 @@ func (t *Table) m2mRelation(field *Field) *Relation { JoinTable: joinTable, M2MTable: m2mTable, } + m2mTable.markM2M() if field.Tag.HasOption("join_on") { rel.Condition = field.Tag.Options["join_on"] @@ -907,6 +943,10 @@ func (t *Table) m2mRelation(field *Field) *Relation { return rel } +func (t *Table) markM2M() { + t.IsM2MTable = true +} + //------------------------------------------------------------------------------ func (t *Table) Dialect() Dialect { return t.dialect } |
