mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
fix(cleanup): compare live-paused statuses with IN, not ANY over a row constructor (#6004)
This commit is contained in:
@@ -256,7 +256,7 @@ async function cleanupLegacyLargeExecutionValues(
|
||||
SELECT 1
|
||||
FROM ${pausedExecutions} AS ref_pe
|
||||
WHERE ref_pe.execution_id = ref.execution_id
|
||||
AND ref_pe.status = ANY(${LIVE_PAUSED_REFERENCE_STATUSES}::text[])
|
||||
AND ref_pe.status IN ${LIVE_PAUSED_REFERENCE_STATUSES}
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -279,7 +279,7 @@ async function cleanupLegacyLargeExecutionValues(
|
||||
SELECT 1
|
||||
FROM ${pausedExecutions} AS parent_owner_pe
|
||||
WHERE parent_owner_pe.execution_id = parent_value.owner_execution_id
|
||||
AND parent_owner_pe.status = ANY(${LIVE_PAUSED_REFERENCE_STATUSES}::text[])
|
||||
AND parent_owner_pe.status IN ${LIVE_PAUSED_REFERENCE_STATUSES}
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
@@ -300,7 +300,7 @@ async function cleanupLegacyLargeExecutionValues(
|
||||
SELECT 1
|
||||
FROM ${pausedExecutions} AS parent_ref_pe
|
||||
WHERE parent_ref_pe.execution_id = parent_ref.execution_id
|
||||
AND parent_ref_pe.status = ANY(${LIVE_PAUSED_REFERENCE_STATUSES}::text[])
|
||||
AND parent_ref_pe.status IN ${LIVE_PAUSED_REFERENCE_STATUSES}
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -316,7 +316,7 @@ async function cleanupLegacyLargeExecutionValues(
|
||||
SELECT 1
|
||||
FROM ${pausedExecutions} AS pe
|
||||
WHERE pe.execution_id = split_part(${workspaceFiles.key}, '/', 4)
|
||||
AND pe.status = ANY(${LIVE_PAUSED_REFERENCE_STATUSES}::text[])
|
||||
AND pe.status IN ${LIVE_PAUSED_REFERENCE_STATUSES}
|
||||
)`
|
||||
)
|
||||
)
|
||||
|
||||
@@ -412,7 +412,7 @@ async function pruneStaleReferences(
|
||||
SELECT 1
|
||||
FROM ${pausedExecutions} AS pe
|
||||
WHERE pe.execution_id = ref.execution_id
|
||||
AND pe.status = ANY(${LIVE_PAUSED_REFERENCE_STATUSES}::text[])
|
||||
AND pe.status IN ${LIVE_PAUSED_REFERENCE_STATUSES}
|
||||
)
|
||||
)
|
||||
OR ref.source NOT IN ('execution_log', 'paused_snapshot')
|
||||
@@ -568,7 +568,7 @@ export function unreferencedLargeValuePredicate() {
|
||||
SELECT 1
|
||||
FROM ${pausedExecutions} AS pe
|
||||
WHERE pe.execution_id = elvr.execution_id
|
||||
AND pe.status = ANY(${LIVE_PAUSED_REFERENCE_STATUSES}::text[])
|
||||
AND pe.status IN ${LIVE_PAUSED_REFERENCE_STATUSES}
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -582,7 +582,7 @@ export function unreferencedLargeValuePredicate() {
|
||||
SELECT 1
|
||||
FROM ${pausedExecutions} AS owner_pe
|
||||
WHERE owner_pe.execution_id = ${executionLargeValues.ownerExecutionId}
|
||||
AND owner_pe.status = ANY(${LIVE_PAUSED_REFERENCE_STATUSES}::text[])
|
||||
AND owner_pe.status IN ${LIVE_PAUSED_REFERENCE_STATUSES}
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
@@ -602,7 +602,7 @@ export function unreferencedLargeValuePredicate() {
|
||||
SELECT 1
|
||||
FROM ${pausedExecutions} AS parent_owner_pe
|
||||
WHERE parent_owner_pe.execution_id = parent_value.owner_execution_id
|
||||
AND parent_owner_pe.status = ANY(${LIVE_PAUSED_REFERENCE_STATUSES}::text[])
|
||||
AND parent_owner_pe.status IN ${LIVE_PAUSED_REFERENCE_STATUSES}
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
@@ -623,7 +623,7 @@ export function unreferencedLargeValuePredicate() {
|
||||
SELECT 1
|
||||
FROM ${pausedExecutions} AS parent_ref_pe
|
||||
WHERE parent_ref_pe.execution_id = parent_ref.execution_id
|
||||
AND parent_ref_pe.status = ANY(${LIVE_PAUSED_REFERENCE_STATUSES}::text[])
|
||||
AND parent_ref_pe.status IN ${LIVE_PAUSED_REFERENCE_STATUSES}
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @vitest-environment node
|
||||
*/
|
||||
|
||||
// Renders the real predicate against the real drizzle dialect and schema: the
|
||||
// bug this guards against is a SQL *rendering* bug, so the global drizzle-orm
|
||||
// and schema mocks would hide it entirely.
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
vi.unmock('drizzle-orm')
|
||||
vi.unmock('@sim/db')
|
||||
vi.unmock('@sim/db/schema')
|
||||
|
||||
process.env.DATABASE_URL ??= 'postgresql://user:pass@localhost:5432/test'
|
||||
|
||||
const { PgDialect } = await import('drizzle-orm/pg-core')
|
||||
const { LIVE_PAUSED_REFERENCE_STATUSES, unreferencedLargeValuePredicate } = await import(
|
||||
'@/lib/execution/payloads/large-value-metadata'
|
||||
)
|
||||
|
||||
describe('unreferencedLargeValuePredicate SQL', () => {
|
||||
const { sql: text, params } = new PgDialect().sqlToQuery(unreferencedLargeValuePredicate())
|
||||
|
||||
it('compares paused status against an IN list', () => {
|
||||
expect(text).toMatch(/\.status IN \(\$\d+, \$\d+, \$\d+\)/)
|
||||
expect(params).toEqual(expect.arrayContaining([...LIVE_PAUSED_REFERENCE_STATUSES]))
|
||||
})
|
||||
|
||||
it('never emits ANY() over drizzle-expanded statuses', () => {
|
||||
// Drizzle renders a JS array as `($1, $2, $3)` — correct for IN, but
|
||||
// `ANY((...)::text[])` makes Postgres reject the whole statement with
|
||||
// "cannot cast type record to text[]", which killed cleanup-logs for two months.
|
||||
expect(text).not.toMatch(/ANY\(\(\$\d+/)
|
||||
})
|
||||
|
||||
it('never emits a dangling comparison operator before IN', () => {
|
||||
// `status = IN (...)` is a syntax error Postgres only reports at execution time.
|
||||
expect(text).not.toMatch(/=\s*IN\s*\(/)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user