feat: add user_tenant associations

This commit is contained in:
2025-12-16 14:14:58 +08:00
parent d058b7ffda
commit 4722eef72c
9 changed files with 391 additions and 24 deletions

View File

@@ -20,3 +20,23 @@ field_type:
role: types.Array[consts.TenantUserRole]
status: consts.UserStatus
field_relate:
users:
OwnedTenant:
relation: belongs_to
table: tenants
json: owned
Tenants:
json: tenants
relation: many_to_many
table: tenants
pivot: tenant_users
# foreign_key: user_id # 当前表users用于关联的键转为结构体字段名 user_id
join_foreign_key: user_id # 中间表中指向当前表的列tenant_users.user_id
# references: id # 关联表tenants被引用的列转为结构体字段名 ID
join_references: tenant_id # 中间表中指向关联表的列tenant_users.tenant_id
tenants:
Users:
relation: many_to_many
table: users
pivot: tenant_users
json: users

View File

@@ -28,6 +28,7 @@ type Tenant struct {
ExpiredAt time.Time `gorm:"column:expired_at;type:timestamp with time zone" json:"expired_at"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamp with time zone;not null;default:now()" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp with time zone;not null;default:now()" json:"updated_at"`
Users []*User `gorm:"many2many:tenant_users" json:"users,omitempty"`
}
// Quick operations without importing query package

View File

@@ -35,6 +35,11 @@ func newTenant(db *gorm.DB, opts ...gen.DOOption) tenantQuery {
_tenantQuery.ExpiredAt = field.NewTime(tableName, "expired_at")
_tenantQuery.CreatedAt = field.NewTime(tableName, "created_at")
_tenantQuery.UpdatedAt = field.NewTime(tableName, "updated_at")
_tenantQuery.Users = tenantQueryManyToManyUsers{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Users", "User"),
}
_tenantQuery.fillFieldMap()
@@ -55,6 +60,7 @@ type tenantQuery struct {
ExpiredAt field.Time
CreatedAt field.Time
UpdatedAt field.Time
Users tenantQueryManyToManyUsers
fieldMap map[string]field.Expr
}
@@ -111,7 +117,7 @@ func (t *tenantQuery) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
}
func (t *tenantQuery) fillFieldMap() {
t.fieldMap = make(map[string]field.Expr, 10)
t.fieldMap = make(map[string]field.Expr, 11)
t.fieldMap["id"] = t.ID
t.fieldMap["user_id"] = t.UserID
t.fieldMap["code"] = t.Code
@@ -122,18 +128,103 @@ func (t *tenantQuery) fillFieldMap() {
t.fieldMap["expired_at"] = t.ExpiredAt
t.fieldMap["created_at"] = t.CreatedAt
t.fieldMap["updated_at"] = t.UpdatedAt
}
func (t tenantQuery) clone(db *gorm.DB) tenantQuery {
t.tenantQueryDo.ReplaceConnPool(db.Statement.ConnPool)
t.Users.db = db.Session(&gorm.Session{Initialized: true})
t.Users.db.Statement.ConnPool = db.Statement.ConnPool
return t
}
func (t tenantQuery) replaceDB(db *gorm.DB) tenantQuery {
t.tenantQueryDo.ReplaceDB(db)
t.Users.db = db.Session(&gorm.Session{})
return t
}
type tenantQueryManyToManyUsers struct {
db *gorm.DB
field.RelationField
}
func (a tenantQueryManyToManyUsers) Where(conds ...field.Expr) *tenantQueryManyToManyUsers {
if len(conds) == 0 {
return &a
}
exprs := make([]clause.Expression, 0, len(conds))
for _, cond := range conds {
exprs = append(exprs, cond.BeCond().(clause.Expression))
}
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
return &a
}
func (a tenantQueryManyToManyUsers) WithContext(ctx context.Context) *tenantQueryManyToManyUsers {
a.db = a.db.WithContext(ctx)
return &a
}
func (a tenantQueryManyToManyUsers) Session(session *gorm.Session) *tenantQueryManyToManyUsers {
a.db = a.db.Session(session)
return &a
}
func (a tenantQueryManyToManyUsers) Model(m *Tenant) *tenantQueryManyToManyUsersTx {
return &tenantQueryManyToManyUsersTx{a.db.Model(m).Association(a.Name())}
}
func (a tenantQueryManyToManyUsers) Unscoped() *tenantQueryManyToManyUsers {
a.db = a.db.Unscoped()
return &a
}
type tenantQueryManyToManyUsersTx struct{ tx *gorm.Association }
func (a tenantQueryManyToManyUsersTx) Find() (result []*User, err error) {
return result, a.tx.Find(&result)
}
func (a tenantQueryManyToManyUsersTx) Append(values ...*User) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a tenantQueryManyToManyUsersTx) Replace(values ...*User) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a tenantQueryManyToManyUsersTx) Delete(values ...*User) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a tenantQueryManyToManyUsersTx) Clear() error {
return a.tx.Clear()
}
func (a tenantQueryManyToManyUsersTx) Count() int64 {
return a.tx.Count()
}
func (a tenantQueryManyToManyUsersTx) Unscoped() *tenantQueryManyToManyUsersTx {
a.tx = a.tx.Unscoped()
return &a
}
type tenantQueryDo struct{ gen.DO }
func (t tenantQueryDo) Debug() *tenantQueryDo {

View File

@@ -19,16 +19,18 @@ const TableNameUser = "users"
// User mapped from table <users>
type User struct {
ID int64 `gorm:"column:id;type:bigint;primaryKey;autoIncrement:true" json:"id"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamp with time zone;not null;default:now()" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp with time zone;not null;default:now()" json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp with time zone" json:"deleted_at"`
Username string `gorm:"column:username;type:character varying(255);not null" json:"username"`
Password string `gorm:"column:password;type:character varying(255);not null" json:"password"`
Roles types.Array[consts.Role] `gorm:"column:roles;type:text[];not null;default:ARRAY['user" json:"roles"`
Status consts.UserStatus `gorm:"column:status;type:character varying(50);not null;default:active" json:"status"`
Metas types.JSON `gorm:"column:metas;type:jsonb;not null;default:{}" json:"metas"`
VerifiedAt time.Time `gorm:"column:verified_at;type:timestamp with time zone" json:"verified_at"`
ID int64 `gorm:"column:id;type:bigint;primaryKey;autoIncrement:true" json:"id"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamp with time zone;not null;default:now()" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp with time zone;not null;default:now()" json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp with time zone" json:"deleted_at"`
Username string `gorm:"column:username;type:character varying(255);not null" json:"username"`
Password string `gorm:"column:password;type:character varying(255);not null" json:"password"`
Roles types.Array[consts.Role] `gorm:"column:roles;type:text[];not null;default:ARRAY['user" json:"roles"`
Status consts.UserStatus `gorm:"column:status;type:character varying(50);not null;default:active" json:"status"`
Metas types.JSON `gorm:"column:metas;type:jsonb;not null;default:{}" json:"metas"`
VerifiedAt time.Time `gorm:"column:verified_at;type:timestamp with time zone" json:"verified_at"`
OwnedTenant *Tenant `json:"owned,omitempty"`
Tenants []*Tenant `gorm:"joinForeignKey:UserID;joinReferences:TenantID;many2many:tenant_users" json:"tenants,omitempty"`
}
// Quick operations without importing query package

View File

@@ -35,6 +35,17 @@ func newUser(db *gorm.DB, opts ...gen.DOOption) userQuery {
_userQuery.Status = field.NewField(tableName, "status")
_userQuery.Metas = field.NewJSONB(tableName, "metas")
_userQuery.VerifiedAt = field.NewTime(tableName, "verified_at")
_userQuery.OwnedTenant = userQueryBelongsToOwnedTenant{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("OwnedTenant", "Tenant"),
}
_userQuery.Tenants = userQueryManyToManyTenants{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Tenants", "Tenant"),
}
_userQuery.fillFieldMap()
@@ -44,17 +55,20 @@ func newUser(db *gorm.DB, opts ...gen.DOOption) userQuery {
type userQuery struct {
userQueryDo userQueryDo
ALL field.Asterisk
ID field.Int64
CreatedAt field.Time
UpdatedAt field.Time
DeletedAt field.Field
Username field.String
Password field.String
Roles field.Array
Status field.Field
Metas field.JSONB
VerifiedAt field.Time
ALL field.Asterisk
ID field.Int64
CreatedAt field.Time
UpdatedAt field.Time
DeletedAt field.Field
Username field.String
Password field.String
Roles field.Array
Status field.Field
Metas field.JSONB
VerifiedAt field.Time
OwnedTenant userQueryBelongsToOwnedTenant
Tenants userQueryManyToManyTenants
fieldMap map[string]field.Expr
}
@@ -111,7 +125,7 @@ func (u *userQuery) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
}
func (u *userQuery) fillFieldMap() {
u.fieldMap = make(map[string]field.Expr, 10)
u.fieldMap = make(map[string]field.Expr, 12)
u.fieldMap["id"] = u.ID
u.fieldMap["created_at"] = u.CreatedAt
u.fieldMap["updated_at"] = u.UpdatedAt
@@ -122,18 +136,187 @@ func (u *userQuery) fillFieldMap() {
u.fieldMap["status"] = u.Status
u.fieldMap["metas"] = u.Metas
u.fieldMap["verified_at"] = u.VerifiedAt
}
func (u userQuery) clone(db *gorm.DB) userQuery {
u.userQueryDo.ReplaceConnPool(db.Statement.ConnPool)
u.OwnedTenant.db = db.Session(&gorm.Session{Initialized: true})
u.OwnedTenant.db.Statement.ConnPool = db.Statement.ConnPool
u.Tenants.db = db.Session(&gorm.Session{Initialized: true})
u.Tenants.db.Statement.ConnPool = db.Statement.ConnPool
return u
}
func (u userQuery) replaceDB(db *gorm.DB) userQuery {
u.userQueryDo.ReplaceDB(db)
u.OwnedTenant.db = db.Session(&gorm.Session{})
u.Tenants.db = db.Session(&gorm.Session{})
return u
}
type userQueryBelongsToOwnedTenant struct {
db *gorm.DB
field.RelationField
}
func (a userQueryBelongsToOwnedTenant) Where(conds ...field.Expr) *userQueryBelongsToOwnedTenant {
if len(conds) == 0 {
return &a
}
exprs := make([]clause.Expression, 0, len(conds))
for _, cond := range conds {
exprs = append(exprs, cond.BeCond().(clause.Expression))
}
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
return &a
}
func (a userQueryBelongsToOwnedTenant) WithContext(ctx context.Context) *userQueryBelongsToOwnedTenant {
a.db = a.db.WithContext(ctx)
return &a
}
func (a userQueryBelongsToOwnedTenant) Session(session *gorm.Session) *userQueryBelongsToOwnedTenant {
a.db = a.db.Session(session)
return &a
}
func (a userQueryBelongsToOwnedTenant) Model(m *User) *userQueryBelongsToOwnedTenantTx {
return &userQueryBelongsToOwnedTenantTx{a.db.Model(m).Association(a.Name())}
}
func (a userQueryBelongsToOwnedTenant) Unscoped() *userQueryBelongsToOwnedTenant {
a.db = a.db.Unscoped()
return &a
}
type userQueryBelongsToOwnedTenantTx struct{ tx *gorm.Association }
func (a userQueryBelongsToOwnedTenantTx) Find() (result *Tenant, err error) {
return result, a.tx.Find(&result)
}
func (a userQueryBelongsToOwnedTenantTx) Append(values ...*Tenant) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a userQueryBelongsToOwnedTenantTx) Replace(values ...*Tenant) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a userQueryBelongsToOwnedTenantTx) Delete(values ...*Tenant) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a userQueryBelongsToOwnedTenantTx) Clear() error {
return a.tx.Clear()
}
func (a userQueryBelongsToOwnedTenantTx) Count() int64 {
return a.tx.Count()
}
func (a userQueryBelongsToOwnedTenantTx) Unscoped() *userQueryBelongsToOwnedTenantTx {
a.tx = a.tx.Unscoped()
return &a
}
type userQueryManyToManyTenants struct {
db *gorm.DB
field.RelationField
}
func (a userQueryManyToManyTenants) Where(conds ...field.Expr) *userQueryManyToManyTenants {
if len(conds) == 0 {
return &a
}
exprs := make([]clause.Expression, 0, len(conds))
for _, cond := range conds {
exprs = append(exprs, cond.BeCond().(clause.Expression))
}
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
return &a
}
func (a userQueryManyToManyTenants) WithContext(ctx context.Context) *userQueryManyToManyTenants {
a.db = a.db.WithContext(ctx)
return &a
}
func (a userQueryManyToManyTenants) Session(session *gorm.Session) *userQueryManyToManyTenants {
a.db = a.db.Session(session)
return &a
}
func (a userQueryManyToManyTenants) Model(m *User) *userQueryManyToManyTenantsTx {
return &userQueryManyToManyTenantsTx{a.db.Model(m).Association(a.Name())}
}
func (a userQueryManyToManyTenants) Unscoped() *userQueryManyToManyTenants {
a.db = a.db.Unscoped()
return &a
}
type userQueryManyToManyTenantsTx struct{ tx *gorm.Association }
func (a userQueryManyToManyTenantsTx) Find() (result []*Tenant, err error) {
return result, a.tx.Find(&result)
}
func (a userQueryManyToManyTenantsTx) Append(values ...*Tenant) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a userQueryManyToManyTenantsTx) Replace(values ...*Tenant) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a userQueryManyToManyTenantsTx) Delete(values ...*Tenant) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a userQueryManyToManyTenantsTx) Clear() error {
return a.tx.Clear()
}
func (a userQueryManyToManyTenantsTx) Count() int64 {
return a.tx.Count()
}
func (a userQueryManyToManyTenantsTx) Unscoped() *userQueryManyToManyTenantsTx {
a.tx = a.tx.Unscoped()
return &a
}
type userQueryDo struct{ gen.DO }
func (u userQueryDo) Debug() *userQueryDo {