fix(landscape): cast run status parameter so SetRunStatus type-checks in Postgres

The status parameter was used both as the assigned value (varchar column)
and in CASE comparisons against text literals, so Postgres deduced two
types for $2 and every run failed at SetRunStatus(running) with SQLSTATE
42P08; the failure also prevented marking the run failed, leaving it
queued. Cast every use to text.

Add TEST_DB_URL-gated repository tests (skipped without a database) that
exercise the landscape run/node SQL and the new dataset period/group
queries against a real Postgres, and document them in the README.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-11 18:02:24 +05:00
parent d06d67436b
commit dae9294b4d
4 changed files with 283 additions and 3 deletions

View File

@@ -165,9 +165,12 @@ func (r *LandscapeRepository) CountRuns(ctx context.Context) (int, error) {
// Returns domain.ErrNotFound if the run does not exist.
func (r *LandscapeRepository) SetRunStatus(ctx context.Context, id uuid.UUID, status domain.LPRunStatus, errMsg *string) error {
tag, err := r.pool.Exec(ctx,
`UPDATE lp_runs SET status = $2, error = $3,
started_at = CASE WHEN $2 = 'running' THEN now() ELSE started_at END,
finished_at = CASE WHEN $2 IN ('succeeded','failed') THEN now() ELSE finished_at END
// $2 is used both as the assigned value (varchar column) and in the CASE
// comparisons (text literals); the explicit ::text casts keep Postgres
// from deducing two different types for one parameter (SQLSTATE 42P08).
`UPDATE lp_runs SET status = $2::text, error = $3,
started_at = CASE WHEN $2::text = 'running' THEN now() ELSE started_at END,
finished_at = CASE WHEN $2::text IN ('succeeded','failed') THEN now() ELSE finished_at END
WHERE id = $1`,
id, status, errMsg,
)