package repository import ( "context" "time" libmongo "gateway/internal/library/mongo" permission "gateway/internal/model/permission/domain" "gateway/internal/model/permission/domain/entity" "gateway/internal/model/permission/domain/enum" domrepo "gateway/internal/model/permission/domain/repository" "go.mongodb.org/mongo-driver/v2/bson" mongodriver "go.mongodb.org/mongo-driver/v2/mongo" ) // UserRoleRepositoryParam configures the Mongo user-role repository. type UserRoleRepositoryParam struct { Conf *libmongo.Conf } type userRoleRepository struct { db libmongo.DocumentDBUseCase } // NewUserRoleRepository creates a Mongo-backed UserRoleRepository. func NewUserRoleRepository(param UserRoleRepositoryParam) domrepo.UserRoleRepository { documentDB, err := libmongo.NewDocumentDB(param.Conf, entity.UserRole{}.CollectionName()) if err != nil { panic(err) } return &userRoleRepository{db: documentDB} } func (r *userRoleRepository) Insert(ctx context.Context, ur *entity.UserRole) error { now := time.Now().UTC().UnixMilli() if ur.ID.IsZero() { ur.ID = bson.NewObjectID() } if ur.Source == "" { ur.Source = enum.RoleSourceManual } if ur.CreateAt == 0 { ur.CreateAt = now } if ur.UpdateAt == 0 { ur.UpdateAt = now } _, err := r.db.GetClient().InsertOne(ctx, ur) if err != nil { if mongodriver.IsDuplicateKeyError(err) { return permission.ErrUserRoleDuplicate } return err } return nil } func (r *userRoleRepository) BulkInsert(ctx context.Context, urs []*entity.UserRole) error { if len(urs) == 0 { return nil } now := time.Now().UTC().UnixMilli() docs := make([]any, 0, len(urs)) for _, ur := range urs { if ur.ID.IsZero() { ur.ID = bson.NewObjectID() } if ur.Source == "" { ur.Source = enum.RoleSourceManual } if ur.CreateAt == 0 { ur.CreateAt = now } if ur.UpdateAt == 0 { ur.UpdateAt = now } docs = append(docs, ur) } _, err := r.db.GetClient().InsertMany(ctx, docs) if err != nil && !mongodriver.IsDuplicateKeyError(err) { return err } return nil } func (r *userRoleRepository) Delete(ctx context.Context, tenantID, uid, roleID string) error { filter := bson.M{ permission.BSONFieldTenantID: tenantID, permission.BSONFieldUID: uid, permission.BSONFieldRoleID: roleID, } res, err := r.db.GetClient().DeleteOne(ctx, filter) if err != nil { return err } if res == 0 { return permission.ErrUserRoleNotFound } return nil } func (r *userRoleRepository) DeleteByRole(ctx context.Context, tenantID, roleID string) (int64, error) { filter := bson.M{ permission.BSONFieldTenantID: tenantID, permission.BSONFieldRoleID: roleID, } return r.db.GetClient().DeleteMany(ctx, filter) } func (r *userRoleRepository) ReplaceForSource( ctx context.Context, tenantID, uid string, source enum.RoleSource, roleIDs []string, ) error { filter := bson.M{ permission.BSONFieldTenantID: tenantID, permission.BSONFieldUID: uid, permission.BSONFieldSource: source, } if _, err := r.db.GetClient().DeleteMany(ctx, filter); err != nil { return err } if len(roleIDs) == 0 { return nil } now := time.Now().UTC().UnixMilli() rows := make([]*entity.UserRole, 0, len(roleIDs)) for _, rid := range roleIDs { rows = append(rows, &entity.UserRole{ ID: bson.NewObjectID(), TenantID: tenantID, UID: uid, RoleID: rid, Source: source, CreateAt: now, UpdateAt: now, }) } return r.BulkInsert(ctx, rows) } func (r *userRoleRepository) ListByUser(ctx context.Context, tenantID, uid string) ([]*entity.UserRole, error) { q := bson.M{ permission.BSONFieldTenantID: tenantID, permission.BSONFieldUID: uid, } var docs []*entity.UserRole if err := r.db.GetClient().Find(ctx, &docs, q); err != nil { return nil, err } return docs, nil } func (r *userRoleRepository) ListByRole(ctx context.Context, tenantID, roleID string) ([]*entity.UserRole, error) { q := bson.M{ permission.BSONFieldTenantID: tenantID, permission.BSONFieldRoleID: roleID, } var docs []*entity.UserRole if err := r.db.GetClient().Find(ctx, &docs, q); err != nil { return nil, err } return docs, nil } // Index20260521001UP ensures user_roles collection indexes exist. func (r *userRoleRepository) Index20260521001UP(ctx context.Context) error { if err := r.db.PopulateMultiIndex(ctx, []string{permission.BSONFieldTenantID, permission.BSONFieldUID, permission.BSONFieldRoleID}, []int32{1, 1, 1}, true); err != nil { return err } if err := r.db.PopulateMultiIndex(ctx, []string{permission.BSONFieldTenantID, permission.BSONFieldRoleID}, []int32{1, 1}, false); err != nil { return err } return r.db.PopulateMultiIndex(ctx, []string{permission.BSONFieldTenantID, permission.BSONFieldUID, permission.BSONFieldSource}, []int32{1, 1, 1}, false) } var _ domrepo.UserRoleRepository = (*userRoleRepository)(nil)