package repository import ( "context" "errors" "time" libmongo "gateway/internal/library/mongo" permission "gateway/internal/model/permission/domain" "gateway/internal/model/permission/domain/entity" domrepo "gateway/internal/model/permission/domain/repository" "go.mongodb.org/mongo-driver/v2/bson" mongodriver "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" ) // RoleRepositoryParam configures the Mongo role repository. type RoleRepositoryParam struct { Conf *libmongo.Conf } type roleRepository struct { db libmongo.DocumentDBUseCase } // NewRoleRepository creates a Mongo-backed RoleRepository. func NewRoleRepository(param RoleRepositoryParam) domrepo.RoleRepository { documentDB, err := libmongo.NewDocumentDB(param.Conf, entity.Role{}.CollectionName()) if err != nil { panic(err) } return &roleRepository{db: documentDB} } func (r *roleRepository) Insert(ctx context.Context, role *entity.Role) error { now := time.Now().UTC().UnixMilli() if role.ID.IsZero() { role.ID = bson.NewObjectID() } if role.CreateAt == 0 { role.CreateAt = now } if role.UpdateAt == 0 { role.UpdateAt = now } _, err := r.db.GetClient().InsertOne(ctx, role) if err != nil { if mongodriver.IsDuplicateKeyError(err) { return permission.ErrRoleDuplicate } return err } return nil } func (r *roleRepository) GetByID(ctx context.Context, tenantID, id string) (*entity.Role, error) { objID, err := bson.ObjectIDFromHex(id) if err != nil { return nil, permission.ErrRoleNotFound } var doc entity.Role filter := bson.M{ permission.BSONFieldID: objID, permission.BSONFieldTenantID: tenantID, } if err := r.db.GetClient().FindOne(ctx, &doc, filter); err != nil { if errors.Is(err, mongodriver.ErrNoDocuments) { return nil, permission.ErrRoleNotFound } return nil, err } return &doc, nil } func (r *roleRepository) GetByKey(ctx context.Context, tenantID, key string) (*entity.Role, error) { var doc entity.Role filter := bson.M{ permission.BSONFieldTenantID: tenantID, permission.BSONFieldKey: key, } if err := r.db.GetClient().FindOne(ctx, &doc, filter); err != nil { if errors.Is(err, mongodriver.ErrNoDocuments) { return nil, permission.ErrRoleNotFound } return nil, err } return &doc, nil } func (r *roleRepository) ListByTenant(ctx context.Context, tenantID string) ([]*entity.Role, error) { q := bson.M{permission.BSONFieldTenantID: tenantID} opts := options.Find().SetSort(bson.D{ {Key: permission.BSONFieldIsSystem, Value: -1}, {Key: permission.BSONFieldKey, Value: 1}, }) var docs []*entity.Role if err := r.db.GetClient().Find(ctx, &docs, q, opts); err != nil { return nil, err } return docs, nil } func (r *roleRepository) ListByTenantAndIDs(ctx context.Context, tenantID string, ids []string) ([]*entity.Role, error) { if len(ids) == 0 { return nil, nil } objIDs := make([]bson.ObjectID, 0, len(ids)) for _, id := range ids { objID, err := bson.ObjectIDFromHex(id) if err != nil { continue } objIDs = append(objIDs, objID) } if len(objIDs) == 0 { return nil, nil } q := bson.M{ permission.BSONFieldTenantID: tenantID, permission.BSONFieldID: bson.M{bsonOpIn: objIDs}, } var docs []*entity.Role if err := r.db.GetClient().Find(ctx, &docs, q); err != nil { return nil, err } return docs, nil } func (r *roleRepository) Update(ctx context.Context, tenantID, id string, update *domrepo.RoleUpdate) (*entity.Role, error) { if update == nil { return r.GetByID(ctx, tenantID, id) } objID, err := bson.ObjectIDFromHex(id) if err != nil { return nil, permission.ErrRoleNotFound } now := time.Now().UTC().UnixMilli() set := bson.M{permission.BSONFieldUpdateAt: now} if update.DisplayName != nil { set[permission.BSONFieldDisplayName] = *update.DisplayName } if update.Status != nil { set[permission.BSONFieldStatus] = *update.Status } filter := bson.M{ permission.BSONFieldID: objID, permission.BSONFieldTenantID: tenantID, } var doc entity.Role opts := options.FindOneAndUpdate().SetReturnDocument(options.After) if err := r.db.GetClient().FindOneAndUpdate(ctx, &doc, filter, bson.M{bsonOpSet: set}, opts); err != nil { if errors.Is(err, mongodriver.ErrNoDocuments) { return nil, permission.ErrRoleNotFound } return nil, err } return &doc, nil } func (r *roleRepository) Delete(ctx context.Context, tenantID, id string) error { objID, err := bson.ObjectIDFromHex(id) if err != nil { return permission.ErrRoleNotFound } filter := bson.M{ permission.BSONFieldID: objID, permission.BSONFieldTenantID: tenantID, } res, err := r.db.GetClient().DeleteOne(ctx, filter) if err != nil { return err } if res == 0 { return permission.ErrRoleNotFound } return nil } // Index20260521001UP ensures roles collection indexes exist. func (r *roleRepository) Index20260521001UP(ctx context.Context) error { if err := r.db.PopulateMultiIndex(ctx, []string{permission.BSONFieldTenantID, permission.BSONFieldKey}, []int32{1, 1}, true); err != nil { return err } return r.db.PopulateMultiIndex(ctx, []string{permission.BSONFieldTenantID, permission.BSONFieldIsSystem}, []int32{1, 1}, false) } var _ domrepo.RoleRepository = (*roleRepository)(nil)