refactor(go): split portfolio, workshop, training/models, roadmap stores
portfolio/store.go (818 LOC) → store_portfolio.go, store_items.go, store_metrics.go workshop/store.go (793 LOC) → store_sessions.go, store_participants.go, store_responses.go training/models.go (757 LOC) → models_enums.go, models_core.go, models_api.go, models_blocks.go roadmap/store.go (757 LOC) → store_roadmap.go, store_items.go, store_import.go All files under 350 LOC. Zero behavior changes, same package declarations. go vet passes on all five packages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
227
ai-compliance-sdk/internal/roadmap/store_roadmap.go
Normal file
227
ai-compliance-sdk/internal/roadmap/store_roadmap.go
Normal file
@@ -0,0 +1,227 @@
|
||||
package roadmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
// Store handles roadmap data persistence
|
||||
type Store struct {
|
||||
pool *pgxpool.Pool
|
||||
}
|
||||
|
||||
// NewStore creates a new roadmap store
|
||||
func NewStore(pool *pgxpool.Pool) *Store {
|
||||
return &Store{pool: pool}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Roadmap CRUD Operations
|
||||
// ============================================================================
|
||||
|
||||
// CreateRoadmap creates a new roadmap
|
||||
func (s *Store) CreateRoadmap(ctx context.Context, r *Roadmap) error {
|
||||
r.ID = uuid.New()
|
||||
r.CreatedAt = time.Now().UTC()
|
||||
r.UpdatedAt = r.CreatedAt
|
||||
if r.Status == "" {
|
||||
r.Status = "draft"
|
||||
}
|
||||
if r.Version == "" {
|
||||
r.Version = "1.0"
|
||||
}
|
||||
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
INSERT INTO roadmaps (
|
||||
id, tenant_id, namespace_id, title, description, version,
|
||||
assessment_id, portfolio_id, status,
|
||||
total_items, completed_items, progress,
|
||||
start_date, target_date,
|
||||
created_at, updated_at, created_by
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6,
|
||||
$7, $8, $9,
|
||||
$10, $11, $12,
|
||||
$13, $14,
|
||||
$15, $16, $17
|
||||
)
|
||||
`,
|
||||
r.ID, r.TenantID, r.NamespaceID, r.Title, r.Description, r.Version,
|
||||
r.AssessmentID, r.PortfolioID, r.Status,
|
||||
r.TotalItems, r.CompletedItems, r.Progress,
|
||||
r.StartDate, r.TargetDate,
|
||||
r.CreatedAt, r.UpdatedAt, r.CreatedBy,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// GetRoadmap retrieves a roadmap by ID
|
||||
func (s *Store) GetRoadmap(ctx context.Context, id uuid.UUID) (*Roadmap, error) {
|
||||
var r Roadmap
|
||||
|
||||
err := s.pool.QueryRow(ctx, `
|
||||
SELECT
|
||||
id, tenant_id, namespace_id, title, description, version,
|
||||
assessment_id, portfolio_id, status,
|
||||
total_items, completed_items, progress,
|
||||
start_date, target_date,
|
||||
created_at, updated_at, created_by
|
||||
FROM roadmaps WHERE id = $1
|
||||
`, id).Scan(
|
||||
&r.ID, &r.TenantID, &r.NamespaceID, &r.Title, &r.Description, &r.Version,
|
||||
&r.AssessmentID, &r.PortfolioID, &r.Status,
|
||||
&r.TotalItems, &r.CompletedItems, &r.Progress,
|
||||
&r.StartDate, &r.TargetDate,
|
||||
&r.CreatedAt, &r.UpdatedAt, &r.CreatedBy,
|
||||
)
|
||||
|
||||
if err == pgx.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
// ListRoadmaps lists roadmaps for a tenant with optional filters
|
||||
func (s *Store) ListRoadmaps(ctx context.Context, tenantID uuid.UUID, filters *RoadmapFilters) ([]Roadmap, error) {
|
||||
query := `
|
||||
SELECT
|
||||
id, tenant_id, namespace_id, title, description, version,
|
||||
assessment_id, portfolio_id, status,
|
||||
total_items, completed_items, progress,
|
||||
start_date, target_date,
|
||||
created_at, updated_at, created_by
|
||||
FROM roadmaps WHERE tenant_id = $1`
|
||||
|
||||
args := []interface{}{tenantID}
|
||||
argIdx := 2
|
||||
|
||||
if filters != nil {
|
||||
if filters.Status != "" {
|
||||
query += fmt.Sprintf(" AND status = $%d", argIdx)
|
||||
args = append(args, filters.Status)
|
||||
argIdx++
|
||||
}
|
||||
if filters.AssessmentID != nil {
|
||||
query += fmt.Sprintf(" AND assessment_id = $%d", argIdx)
|
||||
args = append(args, *filters.AssessmentID)
|
||||
argIdx++
|
||||
}
|
||||
if filters.PortfolioID != nil {
|
||||
query += fmt.Sprintf(" AND portfolio_id = $%d", argIdx)
|
||||
args = append(args, *filters.PortfolioID)
|
||||
argIdx++
|
||||
}
|
||||
}
|
||||
|
||||
query += " ORDER BY created_at DESC"
|
||||
|
||||
if filters != nil && filters.Limit > 0 {
|
||||
query += fmt.Sprintf(" LIMIT $%d", argIdx)
|
||||
args = append(args, filters.Limit)
|
||||
argIdx++
|
||||
|
||||
if filters.Offset > 0 {
|
||||
query += fmt.Sprintf(" OFFSET $%d", argIdx)
|
||||
args = append(args, filters.Offset)
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := s.pool.Query(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var roadmaps []Roadmap
|
||||
for rows.Next() {
|
||||
var r Roadmap
|
||||
err := rows.Scan(
|
||||
&r.ID, &r.TenantID, &r.NamespaceID, &r.Title, &r.Description, &r.Version,
|
||||
&r.AssessmentID, &r.PortfolioID, &r.Status,
|
||||
&r.TotalItems, &r.CompletedItems, &r.Progress,
|
||||
&r.StartDate, &r.TargetDate,
|
||||
&r.CreatedAt, &r.UpdatedAt, &r.CreatedBy,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roadmaps = append(roadmaps, r)
|
||||
}
|
||||
|
||||
return roadmaps, nil
|
||||
}
|
||||
|
||||
// UpdateRoadmap updates a roadmap
|
||||
func (s *Store) UpdateRoadmap(ctx context.Context, r *Roadmap) error {
|
||||
r.UpdatedAt = time.Now().UTC()
|
||||
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
UPDATE roadmaps SET
|
||||
title = $2, description = $3, version = $4,
|
||||
assessment_id = $5, portfolio_id = $6, status = $7,
|
||||
total_items = $8, completed_items = $9, progress = $10,
|
||||
start_date = $11, target_date = $12,
|
||||
updated_at = $13
|
||||
WHERE id = $1
|
||||
`,
|
||||
r.ID, r.Title, r.Description, r.Version,
|
||||
r.AssessmentID, r.PortfolioID, r.Status,
|
||||
r.TotalItems, r.CompletedItems, r.Progress,
|
||||
r.StartDate, r.TargetDate,
|
||||
r.UpdatedAt,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteRoadmap deletes a roadmap and its items
|
||||
func (s *Store) DeleteRoadmap(ctx context.Context, id uuid.UUID) error {
|
||||
// Delete items first
|
||||
_, err := s.pool.Exec(ctx, "DELETE FROM roadmap_items WHERE roadmap_id = $1", id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete roadmap
|
||||
_, err = s.pool.Exec(ctx, "DELETE FROM roadmaps WHERE id = $1", id)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateRoadmapProgress recalculates and updates roadmap progress
|
||||
func (s *Store) UpdateRoadmapProgress(ctx context.Context, roadmapID uuid.UUID) error {
|
||||
var total, completed int
|
||||
|
||||
s.pool.QueryRow(ctx,
|
||||
"SELECT COUNT(*) FROM roadmap_items WHERE roadmap_id = $1",
|
||||
roadmapID).Scan(&total)
|
||||
|
||||
s.pool.QueryRow(ctx,
|
||||
"SELECT COUNT(*) FROM roadmap_items WHERE roadmap_id = $1 AND status = 'COMPLETED'",
|
||||
roadmapID).Scan(&completed)
|
||||
|
||||
progress := 0
|
||||
if total > 0 {
|
||||
progress = (completed * 100) / total
|
||||
}
|
||||
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
UPDATE roadmaps SET
|
||||
total_items = $2,
|
||||
completed_items = $3,
|
||||
progress = $4,
|
||||
updated_at = $5
|
||||
WHERE id = $1
|
||||
`, roadmapID, total, completed, progress, time.Now().UTC())
|
||||
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user