fix(billing): cast outbox payloads for JSONB operators (#6928)

This commit is contained in:
Vikhyath Mondreti
2026-08-20 23:22:27 -07:00
committed by GitHub
parent ab66ce9149
commit fd5ea3e399
4 changed files with 22 additions and 4 deletions
@@ -650,6 +650,16 @@ describe('Enterprise workspace-move progress', () => {
failedCount: 1,
failed: [],
})
const renderedJoin = JSON.stringify(dbChainMockFns.innerJoin.mock.calls[0]?.[0])
expect(renderedJoin).toContain("::jsonb -> 'sourceOperationIds'")
expect(renderedJoin).toContain('jsonb_typeof')
const renderedFilters = dbChainMockFns.where.mock.calls
.map(([condition]) => JSON.stringify(condition))
.join('\n')
expect(renderedFilters).toContain("::jsonb -> 'sourceOperationIds'")
expect(renderedFilters).toContain('?|')
})
it('rejects provisioning lookups larger than one admin page', async () => {
@@ -1365,8 +1365,8 @@ async function getEnterpriseFollowUpProgress(
const arrayOperationIdExpression = sql<string>`source_operations.operation_id`
const sourceOperationRows = sql`lateral jsonb_array_elements_text(
case
when jsonb_typeof(${outboxEvent.payload} -> 'sourceOperationIds') = 'array'
then ${outboxEvent.payload} -> 'sourceOperationIds'
when jsonb_typeof(${outboxEvent.payload}::jsonb -> 'sourceOperationIds') = 'array'
then ${outboxEvent.payload}::jsonb -> 'sourceOperationIds'
else '[]'::jsonb
end
) as source_operations(operation_id)`
@@ -1391,7 +1391,7 @@ async function getEnterpriseFollowUpProgress(
.where(
and(
eq(outboxEvent.eventType, MIGRATED_INVITATION_EMAIL_EVENT_TYPE),
sql`coalesce(${outboxEvent.payload} -> 'sourceOperationIds', '[]'::jsonb) ?| array[${sql.join(
sql`coalesce(${outboxEvent.payload}::jsonb -> 'sourceOperationIds', '[]'::jsonb) ?| array[${sql.join(
uniqueOperationIds.map((operationId) => sql`${operationId}`),
sql`, `
)}]::text[]`
+8
View File
@@ -29,6 +29,7 @@ import {
enqueueOrReschedulePendingOutboxEvent,
enqueueOutboxEvent,
enqueueOutboxEvents,
outboxEventHasSourceOperationId,
outboxPayloadHasSourceOperationId,
processOutboxEvents,
} from './service'
@@ -123,6 +124,13 @@ describe('enqueueOutboxEvent', () => {
})
describe('outbox parent-operation correlation', () => {
it('casts JSON payloads before applying JSONB containment operators', () => {
const query = JSON.stringify(outboxEventHasSourceOperationId('operation-1'))
expect(query).toContain("::jsonb -> 'sourceOperationIds'")
expect(query).toContain('@> jsonb_build_array')
})
it('retains both scalar and coalesced parent operation identities', () => {
expect(
outboxPayloadHasSourceOperationId({ sourceOperationId: 'operation-1' }, 'operation-1')
+1 -1
View File
@@ -329,7 +329,7 @@ export async function addOutboxEventSourceOperationId(
export function outboxEventHasSourceOperationId(operationId: string) {
return sql<boolean>`(
${outboxEvent.payload} ->> 'sourceOperationId' = ${operationId}
or coalesce(${outboxEvent.payload} -> 'sourceOperationIds', '[]'::jsonb)
or coalesce(${outboxEvent.payload}::jsonb -> 'sourceOperationIds', '[]'::jsonb)
@> jsonb_build_array(${operationId}::text)
)`
}