@@ -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