Each of the four oversized files (training/store.go 1569 LOC, ucca/rules.go 1231 LOC, ucca_handlers.go 1135 LOC, document_export.go 1101 LOC) is split by logical group into same-package files, all under the 500-line hard cap. Zero behavior changes, no renamed exported symbols. Also fixed pre-existing hazard_library split (missing functions and duplicate UUID keys from a prior session). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
113 lines
3.0 KiB
Go
113 lines
3.0 KiB
Go
package training
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// GetMatrixForRole returns all matrix entries for a given role
|
|
func (s *Store) GetMatrixForRole(ctx context.Context, tenantID uuid.UUID, roleCode string) ([]TrainingMatrixEntry, error) {
|
|
rows, err := s.pool.Query(ctx, `
|
|
SELECT
|
|
tm.id, tm.tenant_id, tm.role_code, tm.module_id,
|
|
tm.is_mandatory, tm.priority, tm.created_at,
|
|
m.module_code, m.title
|
|
FROM training_matrix tm
|
|
JOIN training_modules m ON m.id = tm.module_id
|
|
WHERE tm.tenant_id = $1 AND tm.role_code = $2
|
|
ORDER BY tm.priority ASC
|
|
`, tenantID, roleCode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var entries []TrainingMatrixEntry
|
|
for rows.Next() {
|
|
var entry TrainingMatrixEntry
|
|
err := rows.Scan(
|
|
&entry.ID, &entry.TenantID, &entry.RoleCode, &entry.ModuleID,
|
|
&entry.IsMandatory, &entry.Priority, &entry.CreatedAt,
|
|
&entry.ModuleCode, &entry.ModuleTitle,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
entries = append(entries, entry)
|
|
}
|
|
|
|
if entries == nil {
|
|
entries = []TrainingMatrixEntry{}
|
|
}
|
|
|
|
return entries, nil
|
|
}
|
|
|
|
// GetMatrixForTenant returns the full CTM for a tenant
|
|
func (s *Store) GetMatrixForTenant(ctx context.Context, tenantID uuid.UUID) ([]TrainingMatrixEntry, error) {
|
|
rows, err := s.pool.Query(ctx, `
|
|
SELECT
|
|
tm.id, tm.tenant_id, tm.role_code, tm.module_id,
|
|
tm.is_mandatory, tm.priority, tm.created_at,
|
|
m.module_code, m.title
|
|
FROM training_matrix tm
|
|
JOIN training_modules m ON m.id = tm.module_id
|
|
WHERE tm.tenant_id = $1
|
|
ORDER BY tm.role_code ASC, tm.priority ASC
|
|
`, tenantID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var entries []TrainingMatrixEntry
|
|
for rows.Next() {
|
|
var entry TrainingMatrixEntry
|
|
err := rows.Scan(
|
|
&entry.ID, &entry.TenantID, &entry.RoleCode, &entry.ModuleID,
|
|
&entry.IsMandatory, &entry.Priority, &entry.CreatedAt,
|
|
&entry.ModuleCode, &entry.ModuleTitle,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
entries = append(entries, entry)
|
|
}
|
|
|
|
if entries == nil {
|
|
entries = []TrainingMatrixEntry{}
|
|
}
|
|
|
|
return entries, nil
|
|
}
|
|
|
|
// SetMatrixEntry creates or updates a CTM entry
|
|
func (s *Store) SetMatrixEntry(ctx context.Context, entry *TrainingMatrixEntry) error {
|
|
entry.ID = uuid.New()
|
|
entry.CreatedAt = time.Now().UTC()
|
|
|
|
_, err := s.pool.Exec(ctx, `
|
|
INSERT INTO training_matrix (
|
|
id, tenant_id, role_code, module_id, is_mandatory, priority, created_at
|
|
) VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
ON CONFLICT (tenant_id, role_code, module_id)
|
|
DO UPDATE SET is_mandatory = EXCLUDED.is_mandatory, priority = EXCLUDED.priority
|
|
`,
|
|
entry.ID, entry.TenantID, entry.RoleCode, entry.ModuleID,
|
|
entry.IsMandatory, entry.Priority, entry.CreatedAt,
|
|
)
|
|
|
|
return err
|
|
}
|
|
|
|
// DeleteMatrixEntry removes a CTM entry
|
|
func (s *Store) DeleteMatrixEntry(ctx context.Context, tenantID uuid.UUID, roleCode string, moduleID uuid.UUID) error {
|
|
_, err := s.pool.Exec(ctx,
|
|
"DELETE FROM training_matrix WHERE tenant_id = $1 AND role_code = $2 AND module_id = $3",
|
|
tenantID, roleCode, moduleID,
|
|
)
|
|
return err
|
|
}
|