Skip to content

Commit 1c88779

Browse files
committed
test(tables): cover built-in column filter and sort SQL
Range/equality/membership on id, createdAt, updatedAt now reference the physical column; a user column with a colliding key still falls back to the JSONB path.
1 parent 12792e9 commit 1c88779

1 file changed

Lines changed: 49 additions & 3 deletions

File tree

apps/sim/lib/table/__tests__/sql.test.ts

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,51 @@ describe('SQL Builder', () => {
376376
})
377377
})
378378

379+
describe('buildFilterClause > built-in columns', () => {
380+
it('filters createdAt range against the physical created_at column', () => {
381+
const out = render(
382+
buildFilterClause(
383+
{
384+
createdAt: { $gte: '2026-07-24T03:00:00.000Z', $lte: '2026-07-25T02:59:59.999Z' },
385+
} as Filter,
386+
TABLE,
387+
NO_COLUMNS
388+
)
389+
)
390+
expect(out).toBe(
391+
`${TABLE}.created_at >= '2026-07-24T03:00:00.000Z'::timestamptz AND ${TABLE}.created_at <= '2026-07-25T02:59:59.999Z'::timestamptz`
392+
)
393+
})
394+
395+
it('accepts a date string for a createdAt range (no numeric-cast rejection)', () => {
396+
expect(() =>
397+
buildFilterClause(
398+
{ createdAt: { $gte: '2026-07-24T03:00:00.000Z' } } as Filter,
399+
TABLE,
400+
NO_COLUMNS
401+
)
402+
).not.toThrow()
403+
})
404+
405+
it('filters id equality with = against the physical column, not JSONB containment', () => {
406+
const out = render(buildFilterClause({ id: 'row_123' }, TABLE, NO_COLUMNS))
407+
expect(out).toBe(`${TABLE}.id = 'row_123'`)
408+
})
409+
410+
it('filters id membership with IN', () => {
411+
const out = render(
412+
buildFilterClause({ id: { $in: ['a', 'b'] } } as Filter, TABLE, NO_COLUMNS)
413+
)
414+
expect(out).toBe(`${TABLE}.id IN ('a', 'b')`)
415+
})
416+
417+
it('lets a user column with the same key shadow the built-in', () => {
418+
const cols: ColumnDefinition[] = [{ id: 'id', name: 'id', type: 'string' }]
419+
const out = render(buildFilterClause({ id: 'row_123' }, TABLE, cols))
420+
expect(out).toBe(`${TABLE}.data @> '{"id":"row_123"}'::jsonb`)
421+
})
422+
})
423+
379424
describe('buildSortClause', () => {
380425
it('returns undefined for empty sort', () => {
381426
expect(buildSortClause({}, TABLE, NO_COLUMNS)).toBeUndefined()
@@ -400,13 +445,14 @@ describe('SQL Builder', () => {
400445
expect(out).toBe(`(${TABLE}.data->>'birthDate')::timestamptz ASC NULLS LAST`)
401446
})
402447

403-
it('sorts createdAt / updatedAt as direct column refs', () => {
448+
it('sorts built-in columns by their physical top-level column', () => {
404449
expect(render(buildSortClause({ createdAt: 'desc' }, TABLE, NO_COLUMNS))).toBe(
405-
`${TABLE}.createdAt DESC`
450+
`${TABLE}.created_at DESC`
406451
)
407452
expect(render(buildSortClause({ updatedAt: 'asc' }, TABLE, NO_COLUMNS))).toBe(
408-
`${TABLE}.updatedAt ASC`
453+
`${TABLE}.updated_at ASC`
409454
)
455+
expect(render(buildSortClause({ id: 'asc' }, TABLE, NO_COLUMNS))).toBe(`${TABLE}.id ASC`)
410456
})
411457

412458
it('combines multiple sort fields with commas', () => {

0 commit comments

Comments
 (0)