@@ -25,9 +25,9 @@ const supabase = createClient(
2525)
2626
2727const table = csTable ( 'protect-ci' , {
28- encrypted : csColumn ( 'encrypted' ) . freeTextSearch ( ) . equality ( ) . orderAndRange ( ) ,
29- age : csColumn ( 'age' ) . dataType ( 'number' ) . equality ( ) . orderAndRange ( ) ,
30- score : csColumn ( 'score' ) . dataType ( 'number' ) . equality ( ) . orderAndRange ( ) ,
28+ encrypted : csColumn ( 'encrypted' ) . freeTextSearch ( ) . equality ( ) ,
29+ age : csColumn ( 'age' ) . dataType ( 'number' ) . equality ( ) ,
30+ score : csColumn ( 'score' ) . dataType ( 'number' ) . equality ( ) ,
3131} )
3232
3333// Hard code this as the CI database doesn't support order by on encrypted columns
@@ -277,304 +277,4 @@ describe('supabase', () => {
277277 }
278278 }
279279 } , 30000 )
280-
281- it ( 'should insert and query encrypted number data with range queries' , async ( ) => {
282- let insertedData : { id : number } [ ] = [ ]
283-
284- try {
285- const protectClient = await protect ( { schemas : [ table ] } )
286-
287- const testScores = [ 15 , 25 , 35 , 45 , 55 ]
288- const models = testScores . map ( ( score ) => ( {
289- score : score ,
290- otherField : `score-${ score } ` ,
291- } ) )
292-
293- const encryptedModels = await protectClient . bulkEncryptModels (
294- models ,
295- table ,
296- )
297-
298- if ( encryptedModels . failure ) {
299- throw new Error ( `[protect]: ${ encryptedModels . failure . message } ` )
300- }
301-
302- const { data : insertResult , error : insertError } = await supabase
303- . from ( 'protect-ci' )
304- . insert ( bulkModelsToEncryptedPgComposites ( encryptedModels . data ) )
305- . select ( 'id' )
306-
307- if ( insertError ) {
308- throw new Error ( `[protect]: ${ insertError . message } ` )
309- }
310-
311- insertedData = insertResult
312-
313- // Test range query: scores >= 30
314- const minScoreTerm = await protectClient . createSearchTerms ( [
315- {
316- value : 30 ,
317- column : table . score ,
318- table : table ,
319- returnType : 'composite-literal' ,
320- } ,
321- ] )
322-
323- if ( minScoreTerm . failure ) {
324- throw new Error ( `[protect]: ${ minScoreTerm . failure . message } ` )
325- }
326-
327- const { data : rangeData , error : rangeError } = await supabase
328- . from ( 'protect-ci' )
329- . select ( 'id, score::jsonb, otherField' )
330- . gte ( 'score' , minScoreTerm . data [ 0 ] )
331-
332- if ( rangeError ) {
333- throw new Error ( `[protect]: ${ rangeError . message } ` )
334- }
335-
336- expect ( rangeData ) . toHaveLength ( 3 ) // Should find scores 35, 45, 55
337-
338- const decryptedRangeData =
339- await protectClient . bulkDecryptModels ( rangeData )
340-
341- if ( decryptedRangeData . failure ) {
342- throw new Error ( `[protect]: ${ decryptedRangeData . failure . message } ` )
343- }
344-
345- const foundScores = decryptedRangeData . data
346- . map ( ( d ) => d . score )
347- . filter (
348- ( score ) : score is number => score !== null && score !== undefined ,
349- )
350- . sort ( ( a , b ) => a - b )
351-
352- expect ( foundScores ) . toEqual ( [ 35 , 45 , 55 ] )
353- } finally {
354- // Cleanup - always runs regardless of success or failure
355- if ( insertedData . length > 0 ) {
356- const deleteResult = await supabase
357- . from ( 'protect-ci' )
358- . delete ( )
359- . in (
360- 'id' ,
361- insertedData . map ( ( d : { id : number } ) => d . id ) ,
362- )
363-
364- if ( deleteResult . error ) {
365- console . error (
366- 'Failed to delete test data:' ,
367- deleteResult . error . message ,
368- )
369- }
370- }
371- }
372- } , 30000 )
373-
374- it ( 'should insert and sort encrypted number data' , async ( ) => {
375- if ( SKIP_ORDER_BY_TEST ) {
376- console . log ( 'Skipping order by test - not supported by this database' )
377- return
378- }
379-
380- let insertedData : { id : number } [ ] = [ ]
381-
382- try {
383- const protectClient = await protect ( { schemas : [ table ] } )
384-
385- const testAges = [ 45 , 25 , 35 , 15 , 55 ]
386- const models = testAges . map ( ( age ) => ( {
387- age : age ,
388- otherField : `age-${ age } ` ,
389- } ) )
390-
391- const encryptedModels = await protectClient . bulkEncryptModels (
392- models ,
393- table ,
394- )
395-
396- if ( encryptedModels . failure ) {
397- throw new Error ( `[protect]: ${ encryptedModels . failure . message } ` )
398- }
399-
400- const { data : insertResult , error : insertError } = await supabase
401- . from ( 'protect-ci' )
402- . insert ( bulkModelsToEncryptedPgComposites ( encryptedModels . data ) )
403- . select ( 'id' )
404-
405- if ( insertError ) {
406- throw new Error ( `[protect]: ${ insertError . message } ` )
407- }
408-
409- insertedData = insertResult
410-
411- // Test sorting by age (ascending)
412- const { data : sortedData , error : sortError } = await supabase
413- . from ( 'protect-ci' )
414- . select ( 'id, age::jsonb, otherField' )
415- . in (
416- 'id' ,
417- insertedData . map ( ( d : { id : number } ) => d . id ) ,
418- )
419- . order ( 'age' , { ascending : true } )
420-
421- if ( sortError ) {
422- throw new Error ( `[protect]: ${ sortError . message } ` )
423- }
424-
425- const decryptedSortedData =
426- await protectClient . bulkDecryptModels ( sortedData )
427-
428- if ( decryptedSortedData . failure ) {
429- throw new Error ( `[protect]: ${ decryptedSortedData . failure . message } ` )
430- }
431-
432- const sortedAges = decryptedSortedData . data . map ( ( d ) => d . age )
433-
434- expect ( sortedAges ) . toEqual ( [ 15 , 25 , 35 , 45 , 55 ] )
435- } finally {
436- // Cleanup - always runs regardless of success or failure
437- if ( insertedData . length > 0 ) {
438- const deleteResult = await supabase
439- . from ( 'protect-ci' )
440- . delete ( )
441- . in (
442- 'id' ,
443- insertedData . map ( ( d : { id : number } ) => d . id ) ,
444- )
445-
446- if ( deleteResult . error ) {
447- console . error (
448- 'Failed to delete test data:' ,
449- deleteResult . error . message ,
450- )
451- }
452- }
453- }
454- } , 30000 )
455-
456- it ( 'should handle complex number queries with multiple conditions' , async ( ) => {
457- let insertedData : { id : number } [ ] = [ ]
458-
459- try {
460- const protectClient = await protect ( { schemas : [ table ] } )
461-
462- const testData = [
463- { age : 20 , score : 80 } ,
464- { age : 25 , score : 90 } ,
465- { age : 30 , score : 75 } ,
466- { age : 35 , score : 85 } ,
467- { age : 40 , score : 75 } ,
468- ]
469-
470- const models = testData . map ( ( data , index ) => ( {
471- age : data . age ,
472- score : data . score ,
473- otherField : `user-${ index } ` ,
474- } ) )
475-
476- const encryptedModels = await protectClient . bulkEncryptModels (
477- models ,
478- table ,
479- )
480-
481- if ( encryptedModels . failure ) {
482- throw new Error ( `[protect]: ${ encryptedModels . failure . message } ` )
483- }
484-
485- const { data : insertResult , error : insertError } = await supabase
486- . from ( 'protect-ci' )
487- . insert ( bulkModelsToEncryptedPgComposites ( encryptedModels . data ) )
488- . select ( 'id' )
489-
490- if ( insertError ) {
491- throw new Error ( `[protect]: ${ insertError . message } ` )
492- }
493-
494- insertedData = insertResult
495-
496- // Create search terms for range queries
497- const terms = await protectClient . createSearchTerms ( [
498- {
499- value : 25 ,
500- column : table . age ,
501- table : table ,
502- returnType : 'composite-literal' ,
503- } ,
504- {
505- value : 35 ,
506- column : table . age ,
507- table : table ,
508- returnType : 'composite-literal' ,
509- } ,
510- {
511- value : 75 ,
512- column : table . score ,
513- table : table ,
514- returnType : 'composite-literal' ,
515- } ,
516- ] )
517-
518- if ( terms . failure ) {
519- throw new Error ( '[protect]: Search term creation failed' )
520- }
521-
522- // Query: age >= 25 AND age <= 35 AND score >= 75
523- const { data : filteredData , error : filterError } = await supabase
524- . from ( 'protect-ci' )
525- . select ( 'id, age::jsonb, score::jsonb, otherField' )
526- . gte ( 'age' , terms . data [ 0 ] )
527- . lte ( 'age' , terms . data [ 1 ] )
528- . gte ( 'score' , terms . data [ 2 ] )
529- . in (
530- 'id' ,
531- insertedData . map ( ( d : { id : number } ) => d . id ) ,
532- )
533-
534- if ( filterError ) {
535- throw new Error ( `[protect]: ${ filterError . message } ` )
536- }
537-
538- const decryptedFilteredData =
539- await protectClient . bulkDecryptModels ( filteredData )
540-
541- if ( decryptedFilteredData . failure ) {
542- throw new Error ( `[protect]: ${ decryptedFilteredData . failure . message } ` )
543- }
544-
545- // Should find: { age: 25, score: 90 }, { age: 30, score: 75 }, { age: 35, score: 85 }
546- expect ( decryptedFilteredData . data ) . toHaveLength ( 3 )
547-
548- const foundData = decryptedFilteredData . data . map ( ( d ) => ( {
549- age : d . age ,
550- score : d . score ,
551- } ) )
552-
553- expect ( foundData ) . toEqual (
554- expect . arrayContaining ( [
555- { age : 25 , score : 90 } ,
556- { age : 30 , score : 75 } ,
557- { age : 35 , score : 85 } ,
558- ] ) ,
559- )
560- } finally {
561- // Cleanup - always runs regardless of success or failure
562- if ( insertedData . length > 0 ) {
563- const deleteResult = await supabase
564- . from ( 'protect-ci' )
565- . delete ( )
566- . in (
567- 'id' ,
568- insertedData . map ( ( d : { id : number } ) => d . id ) ,
569- )
570-
571- if ( deleteResult . error ) {
572- console . error (
573- 'Failed to delete test data:' ,
574- deleteResult . error . message ,
575- )
576- }
577- }
578- }
579- } , 30000 )
580280} )
0 commit comments