package repository import ( "context" "github.com/Caknoooo/go-gin-clean-starter/database/entities" "github.com/google/uuid" "gorm.io/gorm" ) type ( UserRepository interface { Register(ctx context.Context, tx *gorm.DB, user entities.M_User) (entities.M_User, error) GetUserById(ctx context.Context, tx *gorm.DB, userId string) (entities.M_User, error) GetUserByEmail(ctx context.Context, tx *gorm.DB, email string) (entities.M_User, error) GetUserByUsername(ctx context.Context, tx *gorm.DB, username string) (entities.M_User, error) CheckEmail(ctx context.Context, tx *gorm.DB, email string) (entities.M_User, bool, error) CheckUsername(ctx context.Context, tx *gorm.DB, username string) (entities.M_User, bool, error) Update(ctx context.Context, tx *gorm.DB, user entities.M_User) (entities.M_User, error) Delete(ctx context.Context, tx *gorm.DB, userId string) error SwitchRole(ctx context.Context, tx *gorm.DB, userId string, roleId string) (entities.M_User, error) GetAll(ctx context.Context, tx *gorm.DB) ([]entities.M_User, error) GetUserWarehouses(ctx context.Context, tx *gorm.DB, userId string) ([]entities.MWarehouseEntity, error) SwitchWarehouse(ctx context.Context, tx *gorm.DB, userId string, warehouseId string) (entities.M_User, error) AssignWarehousesToUser(ctx context.Context, tx *gorm.DB, userId string, warehouseIds []string) (entities.M_User, error) RemoveWarehousesFromUser(ctx context.Context, tx *gorm.DB, userId string, warehouseIds []string) (entities.M_User, error) ClearUserWarehouses(ctx context.Context, tx *gorm.DB, userId string) error AddUserWarehouses(ctx context.Context, tx *gorm.DB, userId string, warehouseIds []string) error AddUserWarehouse(ctx context.Context, tx *gorm.DB, userId string, warehouseId string) error RemoveUserWarehouse(ctx context.Context, tx *gorm.DB, userId string, warehouseId string) error BulkCreate(ctx context.Context, tx *gorm.DB, users []entities.M_User) error } userRepository struct { db *gorm.DB } ) // BulkCreate implements UserRepository. func (r *userRepository) BulkCreate(ctx context.Context, tx *gorm.DB, users []entities.M_User) error { if tx == nil { tx = r.db } if err := tx.WithContext(ctx).Create(&users).Error; err != nil { return err } return nil } // GetUserWarehouses implements UserRepository. func (r *userRepository) GetUserWarehouses(ctx context.Context, tx *gorm.DB, userId string) ([]entities.MWarehouseEntity, error) { if tx == nil { tx = r.db } var user entities.M_User // Preload relasi UserWarehouses dan Warehouse if err := tx.WithContext(ctx). Preload("UserWarehouses.Warehouse"). Where("id = ?", userId). Take(&user).Error; err != nil { return nil, err } var warehouses []entities.MWarehouseEntity for _, uw := range user.UserWarehouses { warehouses = append(warehouses, uw.Warehouse) } return warehouses, nil } // AddUserWarehouse implements UserRepository. func (r *userRepository) AddUserWarehouse(ctx context.Context, tx *gorm.DB, userId string, warehouseId string) error { if tx == nil { tx = r.db } uid := uuid.MustParse(userId) wid := uuid.MustParse(warehouseId) // Hapus dulu relasi yang sama jika ada if err := tx.WithContext(ctx). Where("user_id = ? AND warehouse_id = ?", uid, wid). Delete(&entities.MUserWarehouseEntity{}).Error; err != nil { return err } // Insert relasi baru entity := entities.MUserWarehouseEntity{ ID: uuid.New(), UserID: uid, WarehouseID: wid, } if err := tx.WithContext(ctx).Create(&entity).Error; err != nil { return err } return nil } // RemoveUserWarehouse implements UserRepository. func (r *userRepository) RemoveUserWarehouse(ctx context.Context, tx *gorm.DB, userId string, warehouseId string) error { if tx == nil { tx = r.db } // Delete specific warehouse relation if err := tx.WithContext(ctx). Where("user_id = ? AND warehouse_id = ?", userId, warehouseId). Delete(&entities.MUserWarehouseEntity{}).Error; err != nil { return err } return nil } func (r *userRepository) ClearUserWarehouses(ctx context.Context, tx *gorm.DB, userId string) error { return tx.WithContext(ctx). Where("user_id = ?", userId). Delete(&entities.MUserWarehouseEntity{}).Error } func (r *userRepository) AddUserWarehouses(ctx context.Context, tx *gorm.DB, userId string, warehouseIds []string) error { assignments := make([]entities.MUserWarehouseEntity, 0, len(warehouseIds)) uid := uuid.MustParse(userId) for _, wid := range warehouseIds { assignments = append(assignments, entities.MUserWarehouseEntity{ ID: uuid.New(), UserID: uid, WarehouseID: uuid.MustParse(wid), }) } return tx.WithContext(ctx).Create(&assignments).Error } // AssignWarehousesToUser implements UserRepository. func (r *userRepository) AssignWarehousesToUser(ctx context.Context, tx *gorm.DB, userId string, warehouseIds []string) (entities.M_User, error) { if tx == nil { tx = r.db } // Remove duplicates warehouseMap := make(map[string]struct{}) for _, wid := range warehouseIds { warehouseMap[wid] = struct{}{} } var uniqueWarehouseIds []string for wid := range warehouseMap { uniqueWarehouseIds = append(uniqueWarehouseIds, wid) } // Prepare assignments var assignments []entities.MUserWarehouseEntity for _, wid := range uniqueWarehouseIds { assignments = append(assignments, entities.MUserWarehouseEntity{ ID: uuid.New(), UserID: uuid.MustParse(userId), WarehouseID: uuid.MustParse(wid), }) } // Insert assignments, ignore duplicates due to unique index if err := tx.WithContext(ctx).Create(&assignments).Error; err != nil { return entities.M_User{}, err } // Reload user with updated warehouses var user entities.M_User if err := tx.WithContext(ctx). Preload("Client"). Preload("Roles"). Preload("Warehouses"). Where("id = ?", userId). Take(&user).Error; err != nil { return entities.M_User{}, err } return user, nil } // RemoveWarehousesFromUser implements UserRepository. func (r *userRepository) RemoveWarehousesFromUser(ctx context.Context, tx *gorm.DB, userId string, warehouseIds []string) (entities.M_User, error) { if tx == nil { tx = r.db } // Remove assignments if err := tx.WithContext(ctx). Where("user_id = ? AND warehouse_id IN ?", userId, warehouseIds). Delete(&entities.MUserWarehouseEntity{}).Error; err != nil { return entities.M_User{}, err } // Reload user with updated warehouses var user entities.M_User if err := tx.WithContext(ctx). Preload("Client"). Preload("Roles"). Preload("Warehouses"). Where("id = ?", userId). Take(&user).Error; err != nil { return entities.M_User{}, err } return user, nil } // SwitchWarehouse implements UserRepository. func (r *userRepository) SwitchWarehouse(ctx context.Context, tx *gorm.DB, userId string, warehouseId string) (entities.M_User, error) { if tx == nil { tx = r.db } var user entities.M_User // Get user with warehouses if err := tx.WithContext(ctx). Preload("Warehouses"). Where("id = ?", userId). Take(&user).Error; err != nil { return entities.M_User{}, err } var warehouse entities.MWarehouseEntity if err := tx.WithContext(ctx). Where("id = ?", warehouseId). Take(&warehouse).Error; err != nil { return entities.M_User{}, err } // Remove all existing warehouse relations for this user if err := tx.WithContext(ctx). Where("user_id = ?", userId). Delete(&entities.MUserWarehouseEntity{}).Error; err != nil { return entities.M_User{}, err } // Add new warehouse relation newUserWarehouse := entities.MUserWarehouseEntity{ UserID: user.ID, WarehouseID: warehouse.ID, } if err := tx.WithContext(ctx).Create(&newUserWarehouse).Error; err != nil { return entities.M_User{}, err } // Reload user with updated warehouses if err := tx.WithContext(ctx). Preload("Warehouses"). Where("id = ?", userId). Take(&user).Error; err != nil { return entities.M_User{}, err } return user, nil } // GetAll implements UserRepository. func (r *userRepository) GetAll(ctx context.Context, tx *gorm.DB) ([]entities.M_User, error) { if tx == nil { tx = r.db } var users []entities.M_User if err := tx.WithContext(ctx). Preload("Client"). Preload("Roles"). Find(&users).Error; err != nil { return nil, err } return users, nil } // CheckUsername implements UserRepository. func (r *userRepository) CheckUsername(ctx context.Context, tx *gorm.DB, username string) (entities.M_User, bool, error) { if tx == nil { tx = r.db } var user entities.M_User if err := tx.WithContext(ctx).Where("username = ?", username).Take(&user).Error; err != nil { return entities.M_User{}, false, err } return user, true, nil } // GetUserByUsername implements UserRepository. func (r *userRepository) GetUserByUsername(ctx context.Context, tx *gorm.DB, username string) (entities.M_User, error) { if tx == nil { tx = r.db } var user entities.M_User if err := tx.WithContext(ctx). Preload("Roles"). Preload("Client"). Preload("Warehouses"). Where("username = ?", username). Take(&user).Error; err != nil { return entities.M_User{}, err } return user, nil } // SwitchRole implements UserRepository. func (r *userRepository) SwitchRole(ctx context.Context, tx *gorm.DB, userId string, roleId string) (entities.M_User, error) { if tx == nil { tx = r.db } var user entities.M_User // Preload UserRoles dan Role di dalamnya if err := tx.WithContext(ctx). Where("id = ?", userId). Preload("UserRoles.Role"). Take(&user).Error; err != nil { return entities.M_User{}, err } var role entities.M_Role if err := tx.WithContext(ctx).Where("id = ?", roleId).Take(&role).Error; err != nil { return entities.M_User{}, err } // Ganti semua role user dengan role baru (hapus yang lama, insert yang baru) if err := tx.WithContext(ctx). Where("user_id = ?", userId). Delete(&entities.M_User_Role{}).Error; err != nil { return entities.M_User{}, err } newUserRole := entities.M_User_Role{ UserID: user.ID, RoleID: role.ID, } if err := tx.WithContext(ctx).Create(&newUserRole).Error; err != nil { return entities.M_User{}, err } // Ambil ulang user beserta roles-nya if err := tx.WithContext(ctx). Where("id = ?", userId). Preload("UserRoles.Role"). Take(&user).Error; err != nil { return entities.M_User{}, err } return user, nil } func (r *userRepository) Register(ctx context.Context, tx *gorm.DB, user entities.M_User) (entities.M_User, error) { if tx == nil { tx = r.db } if err := tx.WithContext(ctx).Create(&user).Error; err != nil { return entities.M_User{}, err } return user, nil } func (r *userRepository) GetUserById(ctx context.Context, tx *gorm.DB, userId string) (entities.M_User, error) { if tx == nil { tx = r.db } var user entities.M_User if err := tx.WithContext(ctx). Preload("Client"). Preload("Roles"). Preload("Warehouses"). Where("id = ?", userId). Take(&user).Error; err != nil { return entities.M_User{}, err } return user, nil } func (r *userRepository) GetUserByEmail(ctx context.Context, tx *gorm.DB, email string) (entities.M_User, error) { if tx == nil { tx = r.db } var user entities.M_User if err := tx.WithContext(ctx). Preload("Client"). Preload("Roles"). Preload("Warehouses"). Where("email = ?", email). Take(&user).Error; err != nil { return entities.M_User{}, err } return user, nil } func (r *userRepository) CheckEmail(ctx context.Context, tx *gorm.DB, email string) (entities.M_User, bool, error) { if tx == nil { tx = r.db } var user entities.M_User if err := tx.WithContext(ctx).Where("email = ?", email).Take(&user).Error; err != nil { return entities.M_User{}, false, err } return user, true, nil } func (r *userRepository) Update(ctx context.Context, tx *gorm.DB, user entities.M_User) (entities.M_User, error) { if tx == nil { tx = r.db } if err := tx.WithContext(ctx).Updates(&user).Error; err != nil { return entities.M_User{}, err } return user, nil } func (r *userRepository) Delete(ctx context.Context, tx *gorm.DB, userId string) error { if tx == nil { tx = r.db } if err := tx.WithContext(ctx).Delete(&entities.M_User{}, "id = ?", userId).Error; err != nil { return err } return nil } func NewUserRepository(db *gorm.DB) UserRepository { return &userRepository{ db: db, } }