← back to Norma
fix(api): cast org_id param as ::uuid not ::text in pipeline/stats + settings
eb21d0d7a3011b62a3e36e249586f671f8004bc8 · 2026-05-20 07:51:18 -0700 · Steve Abrams
petition_pipeline.org_id, drafts.org_id, news_items.org_id, collaborations.org_id,
partners.org_id, old_leads.org_id are all uuid columns. The previous $1::text NULL
guard caused pg to infer the bound param as text, then the org_id = $1 comparison
threw 'operator does not exist: uuid = text' for any non-null orgId.
/api/pipeline/stats was 500-ing for SDCC staff. /api/settings would have done the
same had the .catch() not been swallowing it silently into a 0-row default.
Cast both occurrences as ::uuid so the null-guard and the comparison agree.
Files touched
M app/api/pipeline/stats/route.tsM app/api/settings/route.ts
Diff
commit eb21d0d7a3011b62a3e36e249586f671f8004bc8
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed May 20 07:51:18 2026 -0700
fix(api): cast org_id param as ::uuid not ::text in pipeline/stats + settings
petition_pipeline.org_id, drafts.org_id, news_items.org_id, collaborations.org_id,
partners.org_id, old_leads.org_id are all uuid columns. The previous $1::text NULL
guard caused pg to infer the bound param as text, then the org_id = $1 comparison
threw 'operator does not exist: uuid = text' for any non-null orgId.
/api/pipeline/stats was 500-ing for SDCC staff. /api/settings would have done the
same had the .catch() not been swallowing it silently into a 0-row default.
Cast both occurrences as ::uuid so the null-guard and the comparison agree.
---
app/api/pipeline/stats/route.ts | 10 +++++-----
app/api/settings/route.ts | 10 +++++-----
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/app/api/pipeline/stats/route.ts b/app/api/pipeline/stats/route.ts
index 71ef93f..5bd6aba 100644
--- a/app/api/pipeline/stats/route.ts
+++ b/app/api/pipeline/stats/route.ts
@@ -25,7 +25,7 @@ export async function GET(request: NextRequest) {
query(
`SELECT status, COUNT(*)::int AS count
FROM petition_pipeline
- WHERE ($1::text IS NULL OR org_id = $1)
+ WHERE ($1::uuid IS NULL OR org_id = $1::uuid)
GROUP BY status
ORDER BY count DESC`,
[orgId]
@@ -33,21 +33,21 @@ export async function GET(request: NextRequest) {
query(
`SELECT platform, COUNT(*)::int AS count
FROM petition_pipeline
- WHERE ($1::text IS NULL OR org_id = $1)
+ WHERE ($1::uuid IS NULL OR org_id = $1::uuid)
GROUP BY platform
ORDER BY count DESC`,
[orgId]
),
query(
`SELECT COUNT(*)::int AS total FROM petition_pipeline
- WHERE ($1::text IS NULL OR org_id = $1)`,
+ WHERE ($1::uuid IS NULL OR org_id = $1::uuid)`,
[orgId]
),
query(
`SELECT COUNT(*)::int AS count
FROM petition_pipeline
WHERE created_at >= NOW() - INTERVAL '24 hours'
- AND ($1::text IS NULL OR org_id = $1)`,
+ AND ($1::uuid IS NULL OR org_id = $1::uuid)`,
[orgId]
),
query(
@@ -56,7 +56,7 @@ export async function GET(request: NextRequest) {
COUNT(*)::int AS ai_generated
FROM petition_pipeline
WHERE ai_confidence IS NOT NULL
- AND ($1::text IS NULL OR org_id = $1)`,
+ AND ($1::uuid IS NULL OR org_id = $1::uuid)`,
[orgId]
),
]);
diff --git a/app/api/settings/route.ts b/app/api/settings/route.ts
index 929ba6e..574047e 100644
--- a/app/api/settings/route.ts
+++ b/app/api/settings/route.ts
@@ -22,11 +22,11 @@ export async function GET(request: NextRequest) {
// Also get data stats (scoped by org where possible)
const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;
const statsQueries = await Promise.all([
- query(`SELECT COUNT(*)::int AS count FROM drafts WHERE ($1::text IS NULL OR org_id = $1)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
- query(`SELECT COUNT(*)::int AS count FROM news_items WHERE ($1::text IS NULL OR org_id = $1)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
- query(`SELECT COUNT(*)::int AS count FROM collaborations WHERE ($1::text IS NULL OR org_id = $1)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
- query(`SELECT COUNT(*)::int AS count FROM partners WHERE ($1::text IS NULL OR org_id = $1)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
- query(`SELECT COUNT(*)::int AS count FROM old_leads WHERE ($1::text IS NULL OR org_id = $1)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
+ query(`SELECT COUNT(*)::int AS count FROM drafts WHERE ($1::uuid IS NULL OR org_id = $1::uuid)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
+ query(`SELECT COUNT(*)::int AS count FROM news_items WHERE ($1::uuid IS NULL OR org_id = $1::uuid)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
+ query(`SELECT COUNT(*)::int AS count FROM collaborations WHERE ($1::uuid IS NULL OR org_id = $1::uuid)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
+ query(`SELECT COUNT(*)::int AS count FROM partners WHERE ($1::uuid IS NULL OR org_id = $1::uuid)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
+ query(`SELECT COUNT(*)::int AS count FROM old_leads WHERE ($1::uuid IS NULL OR org_id = $1::uuid)`, [orgId]).catch(() => ({ rows: [{ count: 0 }] })),
]);
settings.data_stats = {
← c0eed7c docs: morning wakeup brief — DB password fix + verification
·
back to Norma
·
petition create: debounce double-submit via useRef guard + 3 9619a2a →