@@ -282,6 +282,91 @@ describe('SQLiteUtils tests', () => {
282282
283283 expect ( whereClauseFromPredicate ( predicateGroup as any ) ) . toEqual ( expected ) ;
284284 } ) ;
285+
286+ it ( 'should generate valid WHERE clause with `in` operator and AND condition' , ( ) => {
287+ const predicateGroup = {
288+ type : 'and' ,
289+ predicates : [
290+ {
291+ field : 'status' ,
292+ operator : 'in' ,
293+ operand : [ 'active' , 'pending' ] ,
294+ } ,
295+ {
296+ field : 'priority' ,
297+ operator : 'ge' ,
298+ operand : 5 ,
299+ } ,
300+ ] ,
301+ } ;
302+
303+ const expected = [
304+ `WHERE ("status" IN (?, ?) AND "priority" >= ?)` ,
305+ [ 'active' , 'pending' , 5 ] ,
306+ ] ;
307+
308+ expect ( whereClauseFromPredicate ( predicateGroup as any ) ) . toEqual ( expected ) ;
309+ } ) ;
310+
311+ it ( 'should generate valid WHERE clause with `notIn` operator and OR condition' , ( ) => {
312+ const predicateGroup = {
313+ type : 'or' ,
314+ predicates : [
315+ {
316+ field : 'status' ,
317+ operator : 'notIn' ,
318+ operand : [ 'archived' , 'deleted' ] ,
319+ } ,
320+ {
321+ field : 'isActive' ,
322+ operator : 'eq' ,
323+ operand : true ,
324+ } ,
325+ ] ,
326+ } ;
327+
328+ const expected = [
329+ `WHERE ("status" NOT IN (?, ?) OR "isActive" = ?)` ,
330+ [ 'archived' , 'deleted' , true ] ,
331+ ] ;
332+
333+ expect ( whereClauseFromPredicate ( predicateGroup as any ) ) . toEqual ( expected ) ;
334+ } ) ;
335+
336+ it ( 'should generate valid WHERE clause with nested AND/OR containing `in` operators' , ( ) => {
337+ const predicateGroup = {
338+ type : 'and' ,
339+ predicates : [
340+ {
341+ type : 'or' ,
342+ predicates : [
343+ {
344+ field : 'category' ,
345+ operator : 'in' ,
346+ operand : [ 'tech' , 'science' ] ,
347+ } ,
348+ {
349+ field : 'featured' ,
350+ operator : 'eq' ,
351+ operand : true ,
352+ } ,
353+ ] ,
354+ } ,
355+ {
356+ field : 'status' ,
357+ operator : 'notIn' ,
358+ operand : [ 'draft' , 'archived' ] ,
359+ } ,
360+ ] ,
361+ } ;
362+
363+ const expected = [
364+ `WHERE (("category" IN (?, ?) OR "featured" = ?) AND "status" NOT IN (?, ?))` ,
365+ [ 'tech' , 'science' , true , 'draft' , 'archived' ] ,
366+ ] ;
367+
368+ expect ( whereClauseFromPredicate ( predicateGroup as any ) ) . toEqual ( expected ) ;
369+ } ) ;
285370 } ) ;
286371
287372 describe ( 'whereConditionFromPredicateObject' , ( ) => {
@@ -337,6 +422,126 @@ describe('SQLiteUtils tests', () => {
337422 expected ,
338423 ) ;
339424 } ) ;
425+
426+ it ( 'should generate valid `in` condition with string array' , ( ) => {
427+ const predicate = {
428+ field : 'status' ,
429+ operator : 'in' ,
430+ operand : [ 'active' , 'pending' , 'draft' ] ,
431+ } ;
432+
433+ const expected = [ `"status" IN (?, ?, ?)` , [ 'active' , 'pending' , 'draft' ] ] ;
434+
435+ expect ( whereConditionFromPredicateObject ( predicate as any ) ) . toEqual ( expected ) ;
436+ } ) ;
437+
438+ it ( 'should generate valid `notIn` condition with string array' , ( ) => {
439+ const predicate = {
440+ field : 'status' ,
441+ operator : 'notIn' ,
442+ operand : [ 'archived' , 'deleted' ] ,
443+ } ;
444+
445+ const expected = [ `"status" NOT IN (?, ?)` , [ 'archived' , 'deleted' ] ] ;
446+
447+ expect ( whereConditionFromPredicateObject ( predicate as any ) ) . toEqual ( expected ) ;
448+ } ) ;
449+
450+ it ( 'should generate valid `in` condition with number array' , ( ) => {
451+ const predicate = {
452+ field : 'priority' ,
453+ operator : 'in' ,
454+ operand : [ 1 , 3 , 5 ] ,
455+ } ;
456+
457+ const expected = [ `"priority" IN (?, ?, ?)` , [ 1 , 3 , 5 ] ] ;
458+
459+ expect ( whereConditionFromPredicateObject ( predicate as any ) ) . toEqual ( expected ) ;
460+ } ) ;
461+
462+ it ( 'should generate valid `notIn` condition with mixed types' , ( ) => {
463+ const predicate = {
464+ field : 'value' ,
465+ operator : 'notIn' ,
466+ operand : [ 1 , 'two' , true , null ] ,
467+ } ;
468+
469+ const expected = [ `"value" NOT IN (?, ?, ?, ?)` , [ 1 , 'two' , true , null ] ] ;
470+
471+ expect ( whereConditionFromPredicateObject ( predicate as any ) ) . toEqual ( expected ) ;
472+ } ) ;
473+
474+ it ( 'should handle empty array for `in` (always false)' , ( ) => {
475+ const predicate = {
476+ field : 'status' ,
477+ operator : 'in' ,
478+ operand : [ ] ,
479+ } ;
480+
481+ const expected = [ `1 = 0` , [ ] ] ;
482+
483+ expect ( whereConditionFromPredicateObject ( predicate as any ) ) . toEqual ( expected ) ;
484+ } ) ;
485+
486+ it ( 'should handle empty array for `notIn` (always true)' , ( ) => {
487+ const predicate = {
488+ field : 'status' ,
489+ operator : 'notIn' ,
490+ operand : [ ] ,
491+ } ;
492+
493+ const expected = [ `1 = 1` , [ ] ] ;
494+
495+ expect ( whereConditionFromPredicateObject ( predicate as any ) ) . toEqual ( expected ) ;
496+ } ) ;
497+
498+ it ( 'should throw error for `in` with non-array operand' , ( ) => {
499+ const predicate = {
500+ field : 'status' ,
501+ operator : 'in' ,
502+ operand : 'not-an-array' ,
503+ } ;
504+
505+ expect ( ( ) => whereConditionFromPredicateObject ( predicate as any ) ) . toThrow (
506+ 'Operand for in must be an array' ,
507+ ) ;
508+ } ) ;
509+
510+ it ( 'should throw error for `notIn` with non-array operand' , ( ) => {
511+ const predicate = {
512+ field : 'status' ,
513+ operator : 'notIn' ,
514+ operand : 'not-an-array' ,
515+ } ;
516+
517+ expect ( ( ) => whereConditionFromPredicateObject ( predicate as any ) ) . toThrow (
518+ 'Operand for notIn must be an array' ,
519+ ) ;
520+ } ) ;
521+
522+ it ( 'should handle `in` with complex objects (JSON.stringify)' , ( ) => {
523+ const predicate = {
524+ field : 'metadata' ,
525+ operator : 'in' ,
526+ operand : [ { id : 1 } , { id : 2 } ] ,
527+ } ;
528+
529+ const expected = [ `"metadata" IN (?, ?)` , [ '{"id":1}' , '{"id":2}' ] ] ;
530+
531+ expect ( whereConditionFromPredicateObject ( predicate as any ) ) . toEqual ( expected ) ;
532+ } ) ;
533+
534+ it ( 'should handle `notIn` with null values' , ( ) => {
535+ const predicate = {
536+ field : 'tags' ,
537+ operator : 'notIn' ,
538+ operand : [ 'urgent' , null , 'archived' ] ,
539+ } ;
540+
541+ const expected = [ `"tags" NOT IN (?, ?, ?)` , [ 'urgent' , null , 'archived' ] ] ;
542+
543+ expect ( whereConditionFromPredicateObject ( predicate as any ) ) . toEqual ( expected ) ;
544+ } ) ;
340545 } ) ;
341546
342547 describe ( 'limitClauseFromPagination' , ( ) => {
0 commit comments