package repository import ( "context" "permission/reborn/domain/entity" "permission/reborn/domain/errors" "permission/reborn/domain/repository" "gorm.io/gorm" ) type userRoleRepository struct { db *gorm.DB } // NewUserRoleRepository 建立使用者角色 Repository func NewUserRoleRepository(db *gorm.DB) repository.UserRoleRepository { return &userRoleRepository{db: db} } func (r *userRoleRepository) Create(ctx context.Context, userRole *entity.UserRole) error { if err := userRole.Validate(); err != nil { return errors.Wrap(errors.ErrCodeInvalidInput, "invalid user role data", err) } if err := r.db.WithContext(ctx).Create(userRole).Error; err != nil { return errors.Wrap(errors.ErrCodeDBQuery, "failed to create user role", err) } return nil } func (r *userRoleRepository) Update(ctx context.Context, uid, roleID string) (*entity.UserRole, error) { var userRole entity.UserRole result := r.db.WithContext(ctx). Model(&userRole). Where("uid = ? AND status != ?", uid, entity.StatusDeleted). Update("role_id", roleID) if result.Error != nil { return nil, errors.Wrap(errors.ErrCodeDBQuery, "failed to update user role", result.Error) } if result.RowsAffected == 0 { return nil, errors.ErrUserRoleNotFound } // 重新查詢更新後的資料 if err := r.db.WithContext(ctx).Where("uid = ?", uid).First(&userRole).Error; err != nil { return nil, errors.Wrap(errors.ErrCodeDBQuery, "failed to get updated user role", err) } return &userRole, nil } func (r *userRoleRepository) Delete(ctx context.Context, uid string) error { result := r.db.WithContext(ctx). Model(&entity.UserRole{}). Where("uid = ?", uid). Update("status", entity.StatusDeleted) if result.Error != nil { return errors.Wrap(errors.ErrCodeDBQuery, "failed to delete user role", result.Error) } if result.RowsAffected == 0 { return errors.ErrUserRoleNotFound } return nil } func (r *userRoleRepository) Get(ctx context.Context, uid string) (*entity.UserRole, error) { var userRole entity.UserRole err := r.db.WithContext(ctx). Where("uid = ? AND status != ?", uid, entity.StatusDeleted). First(&userRole).Error if err != nil { if err == gorm.ErrRecordNotFound { return nil, errors.ErrUserRoleNotFound } return nil, errors.Wrap(errors.ErrCodeDBQuery, "failed to get user role", err) } return &userRole, nil } func (r *userRoleRepository) GetByRoleID(ctx context.Context, roleID string) ([]*entity.UserRole, error) { var userRoles []*entity.UserRole err := r.db.WithContext(ctx). Where("role_id = ? AND status != ?", roleID, entity.StatusDeleted). Find(&userRoles).Error if err != nil { return nil, errors.Wrap(errors.ErrCodeDBQuery, "failed to get user roles by role id", err) } return userRoles, nil } func (r *userRoleRepository) List(ctx context.Context, filter repository.UserRoleFilter) ([]*entity.UserRole, error) { query := r.buildQuery(ctx, filter) var userRoles []*entity.UserRole if err := query.Find(&userRoles).Error; err != nil { return nil, errors.Wrap(errors.ErrCodeDBQuery, "failed to list user roles", err) } return userRoles, nil } // CountByRoleID 統計每個角色的使用者數量 (批量查詢,避免 N+1) func (r *userRoleRepository) CountByRoleID(ctx context.Context, roleIDs []string) (map[string]int, error) { if len(roleIDs) == 0 { return make(map[string]int), nil } var counts []entity.RoleUserCount err := r.db.WithContext(ctx). Model(&entity.UserRole{}). Select("role_id, COUNT(*) as count"). Where("role_id IN ? AND status != ?", roleIDs, entity.StatusDeleted). Group("role_id"). Find(&counts).Error if err != nil { return nil, errors.Wrap(errors.ErrCodeDBQuery, "failed to count users by role id", err) } result := make(map[string]int) for _, c := range counts { result[c.RoleID] = c.Count } return result, nil } func (r *userRoleRepository) Exists(ctx context.Context, uid string) (bool, error) { var count int64 err := r.db.WithContext(ctx). Model(&entity.UserRole{}). Where("uid = ? AND status != ?", uid, entity.StatusDeleted). Count(&count).Error if err != nil { return false, errors.Wrap(errors.ErrCodeDBQuery, "failed to check user role exists", err) } return count > 0, nil } func (r *userRoleRepository) buildQuery(ctx context.Context, filter repository.UserRoleFilter) *gorm.DB { query := r.db.WithContext(ctx). Model(&entity.UserRole{}). Where("status != ?", entity.StatusDeleted) if filter.Brand != "" { query = query.Where("brand = ?", filter.Brand) } if filter.RoleID != "" { query = query.Where("role_id = ?", filter.RoleID) } if filter.Status != nil { query = query.Where("status = ?", *filter.Status) } return query }