Move mem/pg activate/live/meta/plan/token/seed paths into ≤800-line siblings without behavior change; short tests green.
115 lines
3.9 KiB
Go
115 lines
3.9 KiB
Go
package projectinstance
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
func (s *pgStore) GetProjectMeta(ctx context.Context, projectID int64) (string, string, int, int, error) {
|
|
var lifecycle, activeKey string
|
|
var selVer, planRev int
|
|
err := s.pool.QueryRow(ctx, `
|
|
SELECT COALESCE(lifecycle_status, 'planning'), COALESCE(active_workflow_key, ''),
|
|
COALESCE(workflow_selection_version, 1), COALESCE(workflow_plan_revision, 0)
|
|
FROM projects WHERE id = $1
|
|
`, projectID).Scan(&lifecycle, &activeKey, &selVer, &planRev)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return "", "", 0, 0, ErrProjectNotFound
|
|
}
|
|
return lifecycle, activeKey, selVer, planRev, err
|
|
}
|
|
|
|
func (s *pgStore) UpdateProjectAfterActivate(ctx context.Context, projectID int64, workflowKey string, expectedVersion int, activatedBy int64) error {
|
|
tag, err := s.pool.Exec(ctx, `
|
|
UPDATE projects SET lifecycle_status = 'active', active_workflow_key = $2,
|
|
workflow_selection_version = workflow_selection_version + 1,
|
|
active_workflow_changed_at = now(), active_workflow_changed_by = $4,
|
|
updated_at = now()
|
|
WHERE id = $1 AND workflow_selection_version = $3
|
|
`, projectID, workflowKey, expectedVersion, activatedBy)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if tag.RowsAffected() == 0 {
|
|
return ErrConcurrentConflict
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *pgStore) BumpPlanRevision(ctx context.Context, projectID int64, expectedPlanRevision int) (int, error) {
|
|
var newRev int
|
|
err := s.pool.QueryRow(ctx, `
|
|
UPDATE projects SET workflow_plan_revision = workflow_plan_revision + 1, updated_at = now()
|
|
WHERE id = $1 AND workflow_plan_revision = $2
|
|
RETURNING workflow_plan_revision
|
|
`, projectID, expectedPlanRevision).Scan(&newRev)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return 0, ErrPlanRevisionConflict
|
|
}
|
|
return newRev, err
|
|
}
|
|
|
|
func (s *pgStore) GetPlanningInstance(ctx context.Context, projectID int64) (*WorkflowInstance, error) {
|
|
row := s.pool.QueryRow(ctx, `
|
|
SELECT id, project_id, workflow_version_id, instance_no, status, config_revision, plan_hash,
|
|
config_snapshot, activated_by, activated_at, created_by, created_at, updated_at
|
|
FROM project_workflow_instances WHERE project_id = $1 AND status = 'planning'
|
|
ORDER BY id DESC LIMIT 1
|
|
`, projectID)
|
|
inst, err := scanInstance(row)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, nil
|
|
}
|
|
return inst, err
|
|
}
|
|
|
|
func (s *pgStore) GetLiveInstance(ctx context.Context, projectID int64) (*WorkflowInstance, error) {
|
|
row := s.pool.QueryRow(ctx, `
|
|
SELECT id, project_id, workflow_version_id, instance_no, status, config_revision, plan_hash,
|
|
config_snapshot, activated_by, activated_at, created_by, created_at, updated_at
|
|
FROM project_workflow_instances
|
|
WHERE project_id = $1 AND status IN ('active', 'awaiting_stage_confirmation', 'termination_requested')
|
|
ORDER BY id DESC LIMIT 1
|
|
`, projectID)
|
|
inst, err := scanInstance(row)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, nil
|
|
}
|
|
return inst, err
|
|
}
|
|
|
|
func (s *pgStore) GetGoverningInstanceForAccess(ctx context.Context, projectID int64) (*WorkflowInstance, error) {
|
|
live, err := s.GetLiveInstance(ctx, projectID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if live != nil {
|
|
return live, nil
|
|
}
|
|
row := s.pool.QueryRow(ctx, `
|
|
SELECT id, project_id, workflow_version_id, instance_no, status, config_revision, plan_hash,
|
|
config_snapshot, activated_by, activated_at, created_by, created_at, updated_at
|
|
FROM project_workflow_instances
|
|
WHERE project_id = $1 AND status IN ('completed', 'terminated')
|
|
ORDER BY id DESC LIMIT 1
|
|
`, projectID)
|
|
inst, err := scanInstance(row)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, nil
|
|
}
|
|
return inst, err
|
|
}
|
|
|
|
func (s *pgStore) HasLiveInstance(ctx context.Context, projectID int64) (bool, error) {
|
|
var ok bool
|
|
err := s.pool.QueryRow(ctx, `
|
|
SELECT EXISTS (
|
|
SELECT 1 FROM project_workflow_instances
|
|
WHERE project_id = $1 AND status IN ('active', 'awaiting_stage_confirmation', 'termination_requested')
|
|
)
|
|
`, projectID).Scan(&ok)
|
|
return ok, err
|
|
}
|