package repository import ( "context" "permission/reborn/domain/entity" "permission/reborn/domain/errors" "permission/reborn/domain/repository" "gorm.io/gorm" ) type roleRepository struct { db *gorm.DB } // NewRoleRepository 建立角色 Repository func NewRoleRepository(db *gorm.DB) repository.RoleRepository { return &roleRepository{db: db} } func (r *roleRepository) Create(ctx context.Context, role *entity.Role) error { if err := role.Validate(); err != nil { return errors.Wrap(errors.ErrCodeInvalidInput, "invalid role data", err) } if err := r.db.WithContext(ctx).Create(role).Error; err != nil { return errors.Wrap(errors.ErrCodeDBQuery, "failed to create role", err) } return nil } func (r *roleRepository) Update(ctx context.Context, role *entity.Role) error { if err := role.Validate(); err != nil { return errors.Wrap(errors.ErrCodeInvalidInput, "invalid role data", err) } result := r.db.WithContext(ctx). Model(&entity.Role{}). Where("uid = ? AND status != ?", role.UID, entity.StatusDeleted). Updates(map[string]interface{}{ "name": role.Name, "status": role.Status, }) if result.Error != nil { return errors.Wrap(errors.ErrCodeDBQuery, "failed to update role", result.Error) } if result.RowsAffected == 0 { return errors.ErrRoleNotFound } return nil } func (r *roleRepository) Delete(ctx context.Context, uid string) error { result := r.db.WithContext(ctx). Model(&entity.Role{}). Where("uid = ?", uid). Update("status", entity.StatusDeleted) if result.Error != nil { return errors.Wrap(errors.ErrCodeDBQuery, "failed to delete role", result.Error) } if result.RowsAffected == 0 { return errors.ErrRoleNotFound } return nil } func (r *roleRepository) Get(ctx context.Context, id int64) (*entity.Role, error) { var role entity.Role err := r.db.WithContext(ctx). Where("id = ? AND status != ?", id, entity.StatusDeleted). First(&role).Error if err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.ErrRoleNotFound } return nil, errors.Wrap(errors.ErrCodeDBQuery, "failed to get role", err) } return &role, nil } func (r *roleRepository) GetByUID(ctx context.Context, uid string) (*entity.Role, error) { var role entity.Role err := r.db.WithContext(ctx). Where("uid = ? AND status != ?", uid, entity.StatusDeleted). First(&role).Error if err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.ErrRoleNotFound } return nil, errors.Wrap(errors.ErrCodeDBQuery, "failed to get role by uid", err) } return &role, nil } func (r *roleRepository) GetByUIDs(ctx context.Context, uids []string) ([]*entity.Role, error) { if len(uids) == 0 { return []*entity.Role{}, nil } var roles []*entity.Role err := r.db.WithContext(ctx). Where("uid IN ? AND status != ?", uids, entity.StatusDeleted). Find(&roles).Error if err != nil { return nil, errors.Wrap(errors.ErrCodeDBQuery, "failed to get roles by uids", err) } return roles, nil } func (r *roleRepository) List(ctx context.Context, filter repository.RoleFilter) ([]*entity.Role, error) { query := r.buildQuery(ctx, filter) var roles []*entity.Role if err := query.Find(&roles).Error; err != nil { return nil, errors.Wrap(errors.ErrCodeDBQuery, "failed to list roles", err) } return roles, nil } func (r *roleRepository) Page(ctx context.Context, filter repository.RoleFilter, page, size int) ([]*entity.Role, int64, error) { query := r.buildQuery(ctx, filter) // 計算總數 var total int64 if err := query.Count(&total).Error; err != nil { return nil, 0, errors.Wrap(errors.ErrCodeDBQuery, "failed to count roles", err) } // 分頁查詢 var roles []*entity.Role offset := (page - 1) * size if err := query.Offset(offset).Limit(size).Find(&roles).Error; err != nil { return nil, 0, errors.Wrap(errors.ErrCodeDBQuery, "failed to page roles", err) } return roles, total, nil } func (r *roleRepository) Exists(ctx context.Context, uid string) (bool, error) { var count int64 err := r.db.WithContext(ctx). Model(&entity.Role{}). Where("uid = ? AND status != ?", uid, entity.StatusDeleted). Count(&count).Error if err != nil { return false, errors.Wrap(errors.ErrCodeDBQuery, "failed to check role exists", err) } return count > 0, nil } func (r *roleRepository) NextID(ctx context.Context) (int64, error) { var role entity.Role err := r.db.WithContext(ctx). Order("id DESC"). Limit(1). First(&role).Error if err != nil { if err == gorm.ErrRecordNotFound { return 1, nil } return 0, errors.Wrap(errors.ErrCodeDBQuery, "failed to get next id", err) } return role.ID + 1, nil } func (r *roleRepository) buildQuery(ctx context.Context, filter repository.RoleFilter) *gorm.DB { query := r.db.WithContext(ctx). Model(&entity.Role{}). Where("status != ?", entity.StatusDeleted) if filter.ClientID > 0 { query = query.Where("client_id = ?", filter.ClientID) } if filter.UID != "" { query = query.Where("uid = ?", filter.UID) } if filter.Name != "" { query = query.Where("name LIKE ?", "%"+filter.Name+"%") } if filter.Status != nil { query = query.Where("status = ?", *filter.Status) } return query }