Files
fm_be/internal/repository/mysql/federal_state_repo.go
2026-07-16 22:16:45 +07:00

242 lines
7.7 KiB
Go

package mysql
import (
"context"
"errors"
"strings"
"time"
"gorm.io/gorm"
"wucher/internal/domain/federal_state"
"wucher/internal/shared/pkg/apperrors"
"wucher/internal/shared/pkg/sortkey"
)
type FederalStateRepository struct {
db *gorm.DB
schema federalStateSchema
}
func NewFederalStateRepository(db *gorm.DB) *FederalStateRepository {
probe := newSchemaCache(db)
schema := federalStateSchema{}
schema.hasFederalStatesTable = probe.HasTable("federal_states")
schema.federalStatesHasName = schema.hasFederalStatesTable && probe.HasColumn("federal_states", "name")
schema.hasInsurancePatientDataTable = probe.HasTable("insurance_patient_data")
if schema.hasInsurancePatientDataTable {
schema.insurancePatientDataHasFederalStateID = probe.HasColumn("insurance_patient_data", "federal_state_id")
schema.insurancePatientDataHasState = probe.HasColumn("insurance_patient_data", "state")
schema.insurancePatientDataHasDeletedAt = probe.HasColumn("insurance_patient_data", "deleted_at")
}
schema.hasHealthInsuranceCompaniesTable = probe.HasTable("health_insurance_companies")
if schema.hasHealthInsuranceCompaniesTable {
schema.healthInsuranceCompaniesHasFederalStateID = probe.HasColumn("health_insurance_companies", "federal_state_id")
schema.healthInsuranceCompaniesHasState = probe.HasColumn("health_insurance_companies", "state")
schema.healthInsuranceCompaniesHasDeletedAt = probe.HasColumn("health_insurance_companies", "deleted_at")
}
schema.hasIcaosTable = probe.HasTable("icaos")
if schema.hasIcaosTable {
schema.icaosHasFederalStateID = probe.HasColumn("icaos", "federal_state_id")
schema.icaosHasDeletedAt = probe.HasColumn("icaos", "deleted_at")
}
return &FederalStateRepository{db: db, schema: schema}
}
func (r *FederalStateRepository) Create(ctx context.Context, row *federal_state.FederalState) error {
requestedIsActive := row.IsActive
db := r.db.WithContext(ctx)
if err := db.Create(row).Error; err != nil {
return err
}
return db.Model(&federal_state.FederalState{}).Where("id = ?", row.ID).UpdateColumn("is_active", requestedIsActive).Error
}
func (r *FederalStateRepository) Update(ctx context.Context, row *federal_state.FederalState) error {
return r.db.WithContext(ctx).Save(row).Error
}
func (r *FederalStateRepository) Delete(ctx context.Context, id []byte, deletedBy []byte) error {
if err := ensureNoReferenceBeforeDelete(ctx, r.db, "federal_states", id); err != nil {
return err
}
if err := r.ensureNoFederalStateUsage(ctx, id); err != nil {
return err
}
now := time.Now().UTC()
updates := map[string]any{
"deleted_at": now,
"deleted_by": deletedBy,
"updated_by": deletedBy,
}
return mapDeleteConstraintError(r.db.WithContext(ctx).
Model(&federal_state.FederalState{}).
Where("id = ? AND deleted_at IS NULL", id).
Updates(updates).Error)
}
func (r *FederalStateRepository) ensureNoFederalStateUsage(ctx context.Context, id []byte) error {
if len(id) != 16 {
return nil
}
related := make([]string, 0, 3)
db := r.db.WithContext(ctx)
stateName := ""
if r.schema.hasFederalStatesTable && r.schema.federalStatesHasName {
_ = db.Table("federal_states").Select("name").Where("id = ?", id).Limit(1).Scan(&stateName).Error
}
stateName = strings.TrimSpace(stateName)
if r.schema.hasInsurancePatientDataTable {
conditions := make([]string, 0, 2)
args := make([]any, 0, 2)
if r.schema.insurancePatientDataHasFederalStateID {
conditions = append(conditions, "federal_state_id = ?")
args = append(args, id)
}
if stateName != "" && r.schema.insurancePatientDataHasState {
conditions = append(conditions, "LOWER(TRIM(state)) = LOWER(TRIM(?))")
args = append(args, stateName)
}
if len(conditions) == 0 {
goto checkHealthInsuranceCompanies
}
query := db.Table("insurance_patient_data").Where("("+strings.Join(conditions, " OR ")+")", args...)
if r.schema.insurancePatientDataHasDeletedAt {
query = query.Where("deleted_at IS NULL")
}
var count int64
if err := query.Count(&count).Error; err != nil {
return err
}
if count > 0 {
related = append(related, "insurance patient data")
}
}
checkHealthInsuranceCompanies:
if r.schema.hasHealthInsuranceCompaniesTable {
conditions := make([]string, 0, 2)
args := make([]any, 0, 2)
if r.schema.healthInsuranceCompaniesHasFederalStateID {
conditions = append(conditions, "federal_state_id = ?")
args = append(args, id)
}
if stateName != "" && r.schema.healthInsuranceCompaniesHasState {
conditions = append(conditions, "LOWER(TRIM(state)) = LOWER(TRIM(?))")
args = append(args, stateName)
}
if len(conditions) == 0 {
goto checkICAOs
}
query := db.Table("health_insurance_companies").Where("("+strings.Join(conditions, " OR ")+")", args...)
if r.schema.healthInsuranceCompaniesHasDeletedAt {
query = query.Where("deleted_at IS NULL")
}
var count int64
if err := query.Count(&count).Error; err != nil {
return err
}
if count > 0 {
related = append(related, "health insurance companies")
}
}
checkICAOs:
if r.schema.hasIcaosTable {
if !r.schema.icaosHasFederalStateID {
goto finalize
}
var count int64
query := db.Table("icaos").Where("federal_state_id = ?", id)
if r.schema.icaosHasDeletedAt {
query = query.Where("deleted_at IS NULL")
}
if err := query.Count(&count).Error; err != nil {
return err
}
if count > 0 {
related = append(related, "icaos")
}
}
finalize:
if len(related) > 0 {
return apperrors.NewDeleteConflictError(related...)
}
return nil
}
type federalStateSchema struct {
hasFederalStatesTable bool
federalStatesHasName bool
hasInsurancePatientDataTable bool
insurancePatientDataHasFederalStateID bool
insurancePatientDataHasState bool
insurancePatientDataHasDeletedAt bool
hasHealthInsuranceCompaniesTable bool
healthInsuranceCompaniesHasFederalStateID bool
healthInsuranceCompaniesHasState bool
healthInsuranceCompaniesHasDeletedAt bool
hasIcaosTable bool
icaosHasFederalStateID bool
icaosHasDeletedAt bool
}
func (r *FederalStateRepository) GetByID(ctx context.Context, id []byte) (*federal_state.FederalState, error) {
var row federal_state.FederalState
err := r.db.WithContext(ctx).
Preload("Land", "deleted_at IS NULL").
Where("id = ? AND deleted_at IS NULL", id).
First(&row).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return &row, err
}
func (r *FederalStateRepository) List(ctx context.Context, filter, sort string, limit, offset int, landID []byte, landName string) ([]federal_state.FederalState, int64, error) {
var rows []federal_state.FederalState
var total int64
base := r.db.WithContext(ctx).Model(&federal_state.FederalState{}).Where("federal_states.deleted_at IS NULL")
if filter != "" {
like := "%" + filter + "%"
base = base.Where("federal_states.name LIKE ?", like)
}
if len(landID) > 0 {
base = base.Where("federal_states.land_id = ?", landID)
}
if trimmedLandName := strings.TrimSpace(landName); trimmedLandName != "" {
likeLandName := "%" + trimmedLandName + "%"
base = base.Joins("JOIN lands ON lands.id = federal_states.land_id AND lands.deleted_at IS NULL").
Where("lands.name LIKE ?", likeLandName)
}
query := base
if sort != "" {
query = query.Order(sort)
} else {
for _, clause := range sortkey.ActivePositiveSortClauses("federal_states", "is_active", "sortkey", "name", false) {
query = query.Order(clause)
}
}
if err := base.Count(&total).Error; err != nil {
return nil, 0, err
}
if limit > 0 {
query = query.Limit(limit).Offset(offset)
}
query = query.Preload("Land", "deleted_at IS NULL")
if err := query.Find(&rows).Error; err != nil {
return nil, 0, err
}
return rows, total, nil
}