summaryrefslogtreecommitdiff
path: root/vendor/github.com/uptrace/bun/schema
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/uptrace/bun/schema')
-rw-r--r--vendor/github.com/uptrace/bun/schema/field.go1
-rw-r--r--vendor/github.com/uptrace/bun/schema/relation.go51
-rw-r--r--vendor/github.com/uptrace/bun/schema/sqlfmt.go1
-rw-r--r--vendor/github.com/uptrace/bun/schema/table.go44
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 }