github.com/unionj-cloud/go-doudou/v2@v2.3.5/toolkit/gormgen/field/association.go (about) 1 package field 2 3 import ( 4 "fmt" 5 "strings" 6 7 "gorm.io/gorm" 8 "gorm.io/gorm/clause" 9 "gorm.io/gorm/schema" 10 ) 11 12 // RelationshipType table relationship 13 type RelationshipType schema.RelationshipType 14 15 const ( 16 // HasOne a has one association sets up a one-to-one connection with another model. Reference https://gorm.io/docs/has_one.html 17 HasOne RelationshipType = RelationshipType(schema.HasOne) // HasOneRel has one relationship 18 // HasMany a has many association sets up a one-to-many connection with another model. Reference https://gorm.io/docs/has_many.html 19 HasMany RelationshipType = RelationshipType(schema.HasMany) // HasManyRel has many relationships 20 // BelongsTo A belongs to association sets up a one-to-one connection with another model. Reference https://gorm.io/docs/belongs_to.html 21 BelongsTo RelationshipType = RelationshipType(schema.BelongsTo) // BelongsToRel belongs to relationship 22 // Many2Many Many to Many add a join table between two models. Reference https://gorm.io/docs/many2many.html 23 Many2Many RelationshipType = RelationshipType(schema.Many2Many) // Many2ManyRel many to many relationship 24 ) 25 26 type relationScope func(*gorm.DB) *gorm.DB 27 28 var ( 29 // RelationFieldUnscoped relation fild unscoped 30 RelationFieldUnscoped relationScope = func(tx *gorm.DB) *gorm.DB { 31 return tx.Unscoped() 32 } 33 ) 34 35 var ns = schema.NamingStrategy{} 36 37 // RelationField interface for relation field 38 type RelationField interface { 39 Name() string 40 Path() string 41 // Field return expr for Select 42 // Field() return "<self>" field name in struct 43 // Field("RelateField") return "<self>.RelateField" for Select 44 // Field("RelateField", "RelateRelateField") return "<self>.RelateField.RelateRelateField" for Select 45 // ex: 46 // Select(u.CreditCards.Field()) equals to GORM: Select("CreditCards") 47 // Select(u.CreditCards.Field("Bank")) equals to GORM: Select("CreditCards.Bank") 48 // Select(u.CreditCards.Field("Bank","Owner")) equals to GORM: Select("CreditCards.Bank.Owner") 49 Field(fields ...string) Expr 50 51 On(conds ...Expr) RelationField 52 Select(conds ...Expr) RelationField 53 Order(columns ...Expr) RelationField 54 Clauses(hints ...clause.Expression) RelationField 55 Scopes(funcs ...relationScope) RelationField 56 Offset(offset int) RelationField 57 Limit(limit int) RelationField 58 59 GetConds() []Expr 60 GetSelects() []Expr 61 GetOrderCol() []Expr 62 GetClauses() []clause.Expression 63 GetScopes() []relationScope 64 GetPage() (offset, limit int) 65 } 66 67 // Relation relation meta info 68 type Relation struct { 69 relationship RelationshipType 70 71 fieldName string 72 fieldType string 73 fieldPath string 74 fieldModel interface{} // store relaiton model 75 76 childRelations []Relation 77 78 conds []Expr 79 selects []Expr 80 order []Expr 81 clauses []clause.Expression 82 scopes []relationScope 83 limit, offset int 84 } 85 86 // Name relation field' name 87 func (r Relation) Name() string { return r.fieldName } 88 89 // Path relation field's path 90 func (r Relation) Path() string { return r.fieldPath } 91 92 // Type relation field's type 93 func (r Relation) Type() string { return r.fieldType } 94 95 // Model relation field's model 96 func (r Relation) Model() interface{} { return r.fieldModel } 97 98 // Relationship relationship between field and table struct 99 func (r Relation) Relationship() RelationshipType { return r.relationship } 100 101 // RelationshipName relationship's name 102 func (r Relation) RelationshipName() string { return ns.SchemaName(string(r.relationship)) } 103 104 // ChildRelations return child relations 105 func (r Relation) ChildRelations() []Relation { return r.childRelations } 106 107 // Field build field 108 func (r Relation) Field(fields ...string) Expr { 109 if len(fields) > 0 { 110 return NewString("", r.fieldName+"."+strings.Join(fields, ".")).appendBuildOpts(WithoutQuote) 111 } 112 return NewString("", r.fieldName).appendBuildOpts(WithoutQuote) 113 } 114 115 // AppendChildRelation append child relationship 116 func (r *Relation) AppendChildRelation(relations ...Relation) { 117 r.childRelations = append(r.childRelations, wrapPath(r.fieldPath, relations)...) 118 } 119 120 // On relation condition 121 func (r Relation) On(conds ...Expr) RelationField { 122 r.conds = append(r.conds, conds...) 123 return &r 124 } 125 126 // Select relation select columns 127 func (r Relation) Select(columns ...Expr) RelationField { 128 r.selects = append(r.selects, columns...) 129 return &r 130 } 131 132 // Order relation order columns 133 func (r Relation) Order(columns ...Expr) RelationField { 134 r.order = append(r.order, columns...) 135 return &r 136 } 137 138 // Clauses set relation clauses 139 func (r Relation) Clauses(hints ...clause.Expression) RelationField { 140 r.clauses = append(r.clauses, hints...) 141 return &r 142 } 143 144 // Scopes set scopes func 145 func (r Relation) Scopes(funcs ...relationScope) RelationField { 146 r.scopes = append(r.scopes, funcs...) 147 return &r 148 } 149 150 // Offset set relation offset 151 func (r Relation) Offset(offset int) RelationField { 152 r.offset = offset 153 return &r 154 } 155 156 // Limit set relation limit 157 func (r Relation) Limit(limit int) RelationField { 158 r.limit = limit 159 return &r 160 } 161 162 // GetConds get query conditions 163 func (r *Relation) GetConds() []Expr { return r.conds } 164 165 // GetSelects get select columns 166 func (r *Relation) GetSelects() []Expr { return r.selects } 167 168 // GetOrderCol get order columns 169 func (r *Relation) GetOrderCol() []Expr { return r.order } 170 171 // GetClauses get clauses 172 func (r *Relation) GetClauses() []clause.Expression { return r.clauses } 173 174 // GetScopes get scope functions 175 func (r *Relation) GetScopes() []relationScope { return r.scopes } // nolint 176 177 // GetPage get offset and limit 178 func (r *Relation) GetPage() (offset, limit int) { return r.offset, r.limit } 179 180 // StructField return struct field code 181 func (r *Relation) StructField() (fieldStr string) { 182 for _, relation := range r.childRelations { 183 fieldStr += relation.fieldName + " struct {\nfield.RelationField\n" + relation.StructField() + "}\n" 184 } 185 return fieldStr 186 } 187 188 // StructFieldInit return field initialize code 189 func (r *Relation) StructFieldInit() string { 190 initStr := fmt.Sprintf("RelationField: field.NewRelation(%q, %q),\n", r.fieldPath, r.fieldType) 191 for _, relation := range r.childRelations { 192 initStr += relation.fieldName + ": struct {\nfield.RelationField\n" + strings.TrimSpace(relation.StructField()) + "}" 193 initStr += "{\n" + relation.StructFieldInit() + "},\n" 194 } 195 return initStr 196 } 197 198 func wrapPath(root string, rs []Relation) []Relation { 199 result := make([]Relation, len(rs)) 200 for i, r := range rs { 201 r.fieldPath = root + "." + r.fieldPath 202 r.childRelations = wrapPath(root, r.childRelations) 203 result[i] = r 204 } 205 return result 206 } 207 208 var defaultRelationshipPrefix = map[RelationshipType]string{ 209 // HasOne: "", 210 // BelongsTo: "", 211 HasMany: "[]", 212 Many2Many: "[]", 213 } 214 215 // RelateConfig config for relationship 216 type RelateConfig struct { 217 RelatePointer bool 218 RelateSlice bool 219 RelateSlicePointer bool 220 221 JSONTag string 222 GORMTag GormTag 223 Tag Tag 224 OverwriteTag Tag 225 } 226 227 // RelateFieldPrefix return generated relation field's type 228 func (c *RelateConfig) RelateFieldPrefix(relationshipType RelationshipType) string { 229 switch { 230 case c.RelatePointer: 231 return "*" 232 case c.RelateSlice: 233 return "[]" 234 case c.RelateSlicePointer: 235 return "[]*" 236 default: 237 return defaultRelationshipPrefix[relationshipType] 238 } 239 } 240 func (c *RelateConfig) GetTag(fieldName string) Tag { 241 if c == nil { 242 return Tag{} 243 } 244 if c.OverwriteTag != nil { 245 return c.OverwriteTag 246 } 247 if c.Tag == nil { 248 c.Tag = Tag{} 249 } 250 if c.JSONTag == "" { 251 c.JSONTag = ns.ColumnName("", fieldName) 252 } 253 c.Tag.Set(TagKeyJson, c.JSONTag) 254 return c.Tag 255 }