Files
Agent-System/internal/projectinstance/store_pg_meta.go
T
WeiCHEN 943becfb2a refactor(projectinstance): split store.go into use-case files
Move mem/pg activate/live/meta/plan/token/seed paths into ≤800-line
siblings without behavior change; short tests green.
2026-09-23 09:54:17 +08:00

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
}