kontenhumas-be/app/module/clients/repository/clients.repository.go

281 lines
8.4 KiB
Go

package repository
import (
"fmt"
"netidhub-saas-be/app/database"
"netidhub-saas-be/app/database/entity"
"netidhub-saas-be/app/module/clients/request"
"netidhub-saas-be/utils/client"
"netidhub-saas-be/utils/paginator"
"strings"
"github.com/google/uuid"
"github.com/rs/zerolog"
"gorm.io/gorm"
)
type clientsRepository struct {
DB *database.Database
Log zerolog.Logger
}
// ClientsRepository define interface of IClientsRepository
type ClientsRepository interface {
GetAll(req request.ClientsQueryRequest) (clientss []*entity.Clients, paging paginator.Pagination, err error)
FindOne(id uuid.UUID) (clients *entity.Clients, err error)
FindOneByClientId(clientId *uuid.UUID) (clients *entity.Clients, err error)
FindByName(name string) (clients *entity.Clients, err error)
FindByImagePathName(name string) (clients *entity.Clients, err error)
Create(clients *entity.Clients) (clientsReturn *entity.Clients, err error)
Update(id uuid.UUID, clients *entity.Clients) (err error)
Delete(id uuid.UUID) (err error)
// New hierarchy methods
GetWithHierarchy(clientId uuid.UUID) (*entity.Clients, error)
GetSubClients(parentId uuid.UUID, includeInactive bool) ([]entity.Clients, error)
GetAllSubClients(parentId uuid.UUID) ([]entity.Clients, error)
GetRootClients() ([]entity.Clients, error)
GetClientStats(clientId uuid.UUID) (map[string]interface{}, error)
MoveClient(clientId, newParentId uuid.UUID) error
IsParentClient(clientId uuid.UUID) (bool, error)
}
func NewClientsRepository(db *database.Database, logger zerolog.Logger) ClientsRepository {
return &clientsRepository{
DB: db,
Log: logger,
}
}
// implement interface of IClientsRepository
func (_i *clientsRepository) GetAll(req request.ClientsQueryRequest) (clientss []*entity.Clients, paging paginator.Pagination, err error) {
var count int64
query := _i.DB.DB.Model(&entity.Clients{})
// Name filter
if req.Name != nil && *req.Name != "" {
name := strings.ToLower(*req.Name)
query = query.Where("LOWER(name) LIKE ?", "%"+strings.ToLower(name)+"%")
}
// Type filter
if req.ClientType != nil && *req.ClientType != "" && *req.ClientType != "all" {
query = query.Where("client_type = ?", *req.ClientType)
}
// Parent filter
if req.ParentClientId != nil {
query = query.Where("parent_client_id = ?", *req.ParentClientId)
}
// Only parent clients
if req.OnlyParentClients != nil && *req.OnlyParentClients {
query = query.Where("id IN (SELECT DISTINCT parent_client_id FROM clients WHERE parent_client_id IS NOT NULL)")
}
// Only standalone
if req.OnlyStandalone != nil && *req.OnlyStandalone {
query = query.Where("client_type = ?", "standalone")
}
// Active filter
if req.IsActive != nil {
query = query.Where("is_active = ?", *req.IsActive)
} else {
query = query.Where("is_active = ?", true) // Default: only active
}
// Preload relationships
query = query.Preload("ParentClient").Preload("SubClients", "is_active = ?", true)
// Count total records
query.Count(&count)
// Apply sorting
if req.Pagination.SortBy != "" {
direction := "ASC"
if req.Pagination.Sort == "desc" {
direction = "DESC"
}
query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
} else {
direction := "DESC"
sortBy := "created_at"
query.Order(fmt.Sprintf("%s %s", sortBy, direction))
}
// Apply pagination (manual calculation for better performance)
page := req.Pagination.Page
limit := req.Pagination.Limit
if page <= 0 {
page = 1
}
if limit <= 0 {
limit = 10
}
offset := (page - 1) * limit
err = query.Offset(offset).Limit(limit).Find(&clientss).Error
if err != nil {
return
}
// Create pagination response
paging = paginator.Pagination{
Page: page,
Limit: limit,
Count: count,
TotalPage: int((count + int64(limit) - 1) / int64(limit)),
}
return
}
func (_i *clientsRepository) FindOne(id uuid.UUID) (clients *entity.Clients, err error) {
if err := _i.DB.DB.First(&clients, id).Error; err != nil {
return nil, err
}
return clients, nil
}
func (_i *clientsRepository) FindOneByClientId(clientId *uuid.UUID) (clients *entity.Clients, err error) {
if clientId == nil {
return nil, nil
}
if err := _i.DB.DB.Where("id = ?", *clientId).First(&clients).Error; err != nil {
return nil, err
}
return clients, nil
}
func (_i *clientsRepository) FindByName(name string) (clients *entity.Clients, err error) {
if err := _i.DB.DB.Where("name = ?", name).First(&clients).Error; err != nil {
return nil, err
}
return clients, nil
}
func (_i *clientsRepository) FindByImagePathName(name string) (clients *entity.Clients, err error) {
if err := _i.DB.DB.Where("logo_image_path like ?", "%"+name+"%").First(&clients).Error; err != nil {
return nil, err
}
return clients, nil
}
func (_i *clientsRepository) Create(clients *entity.Clients) (clientsReturn *entity.Clients, err error) {
result := _i.DB.DB.Create(clients)
return clients, result.Error
}
func (_i *clientsRepository) Update(id uuid.UUID, clients *entity.Clients) (err error) {
return _i.DB.DB.Model(&entity.Clients{}).
Where(&entity.Clients{ID: id}).
Updates(clients).Error
}
func (_i *clientsRepository) Delete(id uuid.UUID) error {
return _i.DB.DB.Delete(&entity.Clients{}, id).Error
}
// =====================================================================
// NEW HIERARCHY METHODS
// =====================================================================
// GetWithHierarchy gets client with parent and sub-clients loaded
func (_i *clientsRepository) GetWithHierarchy(clientId uuid.UUID) (*entity.Clients, error) {
var client entity.Clients
err := _i.DB.DB.Preload("ParentClient").
Preload("SubClients", "is_active = ?", true).
Where("id = ?", clientId).
First(&client).Error
return &client, err
}
// GetSubClients gets direct children of a client
func (_i *clientsRepository) GetSubClients(parentId uuid.UUID, includeInactive bool) ([]entity.Clients, error) {
var clients []entity.Clients
query := _i.DB.DB.Where("parent_client_id = ?", parentId)
if !includeInactive {
query = query.Where("is_active = ?", true)
}
err := query.Find(&clients).Error
return clients, err
}
// GetAllSubClients gets all descendants recursively
func (_i *clientsRepository) GetAllSubClients(parentId uuid.UUID) ([]entity.Clients, error) {
subClientIDs, err := client.GetSubClientIDs(_i.DB.DB, parentId)
if err != nil || len(subClientIDs) == 0 {
return []entity.Clients{}, err
}
var clients []entity.Clients
err = _i.DB.DB.Where("id IN ?", subClientIDs).Find(&clients).Error
return clients, err
}
// GetRootClients gets all clients without parent
func (_i *clientsRepository) GetRootClients() ([]entity.Clients, error) {
var clients []entity.Clients
err := _i.DB.DB.Where("parent_client_id IS NULL AND is_active = ?", true).
Find(&clients).Error
return clients, err
}
// GetClientStats gets statistics for a client
func (_i *clientsRepository) GetClientStats(clientId uuid.UUID) (map[string]interface{}, error) {
stats := make(map[string]interface{})
// Count users
var userCount int64
_i.DB.DB.Model(&entity.Users{}).Where("client_id = ? AND is_active = ?", clientId, true).Count(&userCount)
stats["total_users"] = userCount
// Count articles
var articleCount int64
_i.DB.DB.Model(&entity.Articles{}).Where("client_id = ? AND is_active = ?", clientId, true).Count(&articleCount)
stats["total_articles"] = articleCount
// Count sub-clients
var subClientCount int64
_i.DB.DB.Model(&entity.Clients{}).Where("parent_client_id = ? AND is_active = ?", clientId, true).Count(&subClientCount)
stats["sub_client_count"] = subClientCount
return stats, nil
}
// MoveClient moves a client to a different parent
func (_i *clientsRepository) MoveClient(clientId, newParentId uuid.UUID) error {
// Validate no circular reference
if newParentId != uuid.Nil {
// Check if newParent is a descendant of client (would create circle)
descendants, _ := client.GetSubClientIDs(_i.DB.DB, clientId)
for _, descId := range descendants {
if descId == newParentId {
return gorm.ErrInvalidData // Circular reference
}
}
}
return _i.DB.DB.Model(&entity.Clients{}).
Where("id = ?", clientId).
Update("parent_client_id", newParentId).Error
}
// IsParentClient checks if client has children
func (_i *clientsRepository) IsParentClient(clientId uuid.UUID) (bool, error) {
var count int64
err := _i.DB.DB.Model(&entity.Clients{}).
Where("parent_client_id = ? AND is_active = ?", clientId, true).
Count(&count).Error
return count > 0, err
}