@@ -4,7 +4,7 @@ import { inTransform } from './in';
44describe ( 'In transforms Tests' , ( ) => {
55 it ( 'Should throw error if values are undefined' , ( ) => {
66 expect ( ( ) =>
7- inTransform ( {
7+ inTransform ( {
88 member : 'country' ,
99 operator : 'contains' ,
1010 memberInfo : {
@@ -16,130 +16,231 @@ describe('In transforms Tests', () => {
1616 ) . toThrow ( ) ;
1717 } ) ;
1818
19- it ( 'Should return the correct value for string member' , ( ) => {
20- const expectedOutput = {
21- "alias" : "" ,
22- "children" : [
23- {
24- "alias" : "" ,
25- "class" : "COLUMN_REF" ,
26- "column_names" : [
27- "country" ,
28- ] ,
29- "type" : "COLUMN_REF" ,
30- } ,
31- {
32- "alias" : "" ,
33- "class" : "CONSTANT" ,
34- "type" : "VALUE_CONSTANT" ,
35- "value" : {
36- "is_null" : false ,
37- "type" : {
38- "id" : "VARCHAR" ,
39- "type_info" : null ,
40- } ,
41- "value" : "US" ,
42- } ,
43- } ,
44- ] ,
45- "class" : "OPERATOR" ,
46- "type" : "COMPARE_IN" ,
47- } ;
48- expect (
49- inTransform ( {
50- member : 'country' ,
51- operator : 'contains' ,
52- values : [ 'US' ] ,
53- memberInfo : {
54- name : 'country' ,
55- sql : 'table.country' ,
56- type : 'string' ,
57- } ,
58- } )
59- ) . toEqual ( expectedOutput ) ;
19+ it ( 'Should return optimized string_split approach for string type' , ( ) => {
20+ const result = inTransform ( {
21+ member : 'country' ,
22+ operator : 'in' ,
23+ values : [ 'US' , 'Canada' , 'Mexico' ] ,
24+ memberInfo : {
25+ name : 'country' ,
26+ sql : 'table.country' ,
27+ type : 'string' ,
28+ } ,
29+ } ) ;
30+
31+ // Check it returns a subquery structure with string_split
32+ expect ( result ) . toHaveProperty ( 'class' , 'SUBQUERY' ) ;
33+ expect ( result ) . toHaveProperty ( 'type' , 'SUBQUERY' ) ;
34+ expect ( result ) . toHaveProperty ( 'subquery_type' , 'ANY' ) ;
35+
36+ // Verify it's using string_split
37+ const selectList = ( result as any ) . subquery . node . select_list [ 0 ] ;
38+ expect ( selectList . function_name ) . toBe ( 'unnest' ) ;
39+ expect ( selectList . children [ 0 ] . function_name ) . toBe ( 'string_split' ) ;
40+
41+ // Verify no CAST for strings
42+ expect ( selectList . type ) . toBe ( 'FUNCTION' ) ;
6043 } ) ;
6144
62- it ( 'Should return the correct value for string_array member' , ( ) => {
45+ it ( 'Should return optimized string_split approach with CAST for number type' , ( ) => {
46+ const result = inTransform ( {
47+ member : 'order_id' ,
48+ operator : 'in' ,
49+ values : [ 1 , 2 , 3 ] ,
50+ memberInfo : {
51+ name : 'order_id' ,
52+ sql : 'table.order_id' ,
53+ type : 'number' ,
54+ } ,
55+ } ) ;
56+
57+ // Check it returns a subquery structure
58+ expect ( result ) . toHaveProperty ( 'class' , 'SUBQUERY' ) ;
59+ expect ( result ) . toHaveProperty ( 'type' , 'SUBQUERY' ) ;
60+ expect ( result ) . toHaveProperty ( 'subquery_type' , 'ANY' ) ;
61+
62+ // Verify it's using string_split with CAST
63+ const selectList = ( result as any ) . subquery . node . select_list [ 0 ] ;
64+ expect ( selectList . type ) . toBe ( 'OPERATOR_CAST' ) ;
65+ expect ( selectList . cast_type . id ) . toBe ( 'DOUBLE' ) ;
66+ expect ( selectList . child . function_name ) . toBe ( 'unnest' ) ;
67+ expect ( selectList . child . children [ 0 ] . function_name ) . toBe ( 'string_split' ) ;
68+ } ) ;
69+
70+ it ( 'Should return standard ARRAY_CONSTRUCTOR for string_array type' , ( ) => {
6371 const output = inTransform ( {
6472 member : 'country' ,
65- operator : 'contains ' ,
73+ operator : 'in ' ,
6674 values : [ 'US' , 'Germany' , 'Israel' ] ,
6775 memberInfo : {
6876 name : 'country' ,
6977 sql : 'table.country' ,
7078 type : 'string_array' ,
7179 } ,
7280 } ) as ConjunctionExpression ;
73- expect ( output ) . toEqual ( {
74- "alias" : "" ,
75- "catalog" : "" ,
76- "children" : [
77- {
78- "alias" : "" ,
79- "class" : "COLUMN_REF" ,
80- "column_names" : [
81- "country" ,
82- ] ,
83- "type" : "COLUMN_REF" ,
81+
82+ // For array types, should use && operator with ARRAY_CONSTRUCTOR
83+ expect ( output . function_name ) . toBe ( '&&' ) ;
84+ expect ( output . children [ 1 ] . type ) . toBe ( 'ARRAY_CONSTRUCTOR' ) ;
85+ expect ( output . children [ 1 ] . children . length ) . toBe ( 3 ) ;
86+ } ) ;
87+
88+ it ( 'Should return standard COMPARE_IN for other types (default case)' , ( ) => {
89+ const output = inTransform ( {
90+ member : 'some_field' ,
91+ operator : 'in' ,
92+ values : [ 'val1' , 'val2' ] ,
93+ memberInfo : {
94+ name : 'some_field' ,
95+ sql : 'table.some_field' ,
96+ type : 'time' as any , // Unknown type to trigger default case
97+ } ,
98+ } ) ;
99+
100+ // Default case should use COMPARE_IN
101+ expect ( output ) . toHaveProperty ( 'type' , 'COMPARE_IN' ) ;
102+ expect ( output ) . toHaveProperty ( 'class' , 'OPERATOR' ) ;
103+ expect ( ( output as any ) . children . length ) . toBe ( 3 ) ; // column + 2 values
104+ } ) ;
105+
106+ it ( 'Should handle large value lists efficiently with string_split' , ( ) => {
107+ const largeValueList = Array . from ( { length : 1000 } , ( _ , i ) => `value${ i } ` ) ;
108+ const result = inTransform ( {
109+ member : 'country' ,
110+ operator : 'in' ,
111+ values : largeValueList ,
112+ memberInfo : {
113+ name : 'country' ,
114+ sql : 'table.country' ,
115+ type : 'string' ,
116+ } ,
117+ } ) ;
118+
119+ // Should still use subquery approach
120+ expect ( result ) . toHaveProperty ( 'class' , 'SUBQUERY' ) ;
121+
122+ // Verify only 2 VALUE_CONSTANT nodes (joined string + delimiter)
123+ const selectList = ( result as any ) . subquery . node . select_list [ 0 ] ;
124+ const stringSplitChildren = selectList . children [ 0 ] . children ;
125+ expect ( stringSplitChildren . length ) . toBe ( 2 ) ;
126+ expect ( stringSplitChildren [ 0 ] . value . value ) . toContain ( '§‡¶' ) ; // Contains delimiter
127+ } ) ;
128+
129+ it ( 'Should use delimiter to join values' , ( ) => {
130+ const result = inTransform ( {
131+ member : 'country' ,
132+ operator : 'in' ,
133+ values : [ 'US' , 'Canada' ] ,
134+ memberInfo : {
135+ name : 'country' ,
136+ sql : 'table.country' ,
137+ type : 'string' ,
138+ } ,
139+ } ) ;
140+
141+ const selectList = ( result as any ) . subquery . node . select_list [ 0 ] ;
142+ const joinedValue = selectList . children [ 0 ] . children [ 0 ] . value . value ;
143+ const delimiter = selectList . children [ 0 ] . children [ 1 ] . value . value ;
144+
145+ expect ( delimiter ) . toBe ( '§‡¶' ) ;
146+ expect ( joinedValue ) . toBe ( 'US§‡¶Canada' ) ;
147+ } ) ;
148+
149+ it ( 'Should handle the original test case structure for reference' , ( ) => {
150+ const output = inTransform ( {
151+ member : 'country' ,
152+ operator : 'in' ,
153+ values : [ 'US' , 'Germany' , 'Israel' ] ,
154+ memberInfo : {
155+ name : 'country' ,
156+ sql : 'table.country' ,
157+ type : 'string_array' ,
158+ } ,
159+ } ) as ConjunctionExpression ;
160+ expect ( output ) . toEqual ( {
161+ alias : '' ,
162+ catalog : '' ,
163+ children : [
164+ {
165+ alias : '' ,
166+ class : 'COLUMN_REF' ,
167+ column_names : [ 'country' ] ,
168+ type : 'COLUMN_REF' ,
84169 } ,
170+ {
171+ alias : '' ,
172+ children : [
85173 {
86- "alias" : "" ,
87- "children" : [
88- {
89- "alias" : "" ,
90- "class" : "CONSTANT" ,
91- "type" : "VALUE_CONSTANT" ,
92- "value" : {
93- "is_null" : false ,
94- "type" : {
95- "id" : "VARCHAR" ,
96- "type_info" : null ,
97- } ,
98- "value" : "US" ,
174+ alias : '' ,
175+ class : 'CONSTANT' ,
176+ type : 'VALUE_CONSTANT' ,
177+ value : {
178+ is_null : false ,
179+ type : {
180+ id : 'VARCHAR' ,
181+ type_info : null ,
99182 } ,
183+ value : 'US' ,
184+ } ,
100185 } ,
101186 {
102- "alias" : "" ,
103- "class" : "CONSTANT" ,
104- "type" : "VALUE_CONSTANT" ,
105- "value" : {
106- "is_null" : false ,
107- "type" : {
108- "id" : "VARCHAR" ,
109- "type_info" : null ,
110- } ,
111- "value" : "Germany" ,
187+ alias : '' ,
188+ class : 'CONSTANT' ,
189+ type : 'VALUE_CONSTANT' ,
190+ value : {
191+ is_null : false ,
192+ type : {
193+ id : 'VARCHAR' ,
194+ type_info : null ,
112195 } ,
196+ value : 'Germany' ,
197+ } ,
113198 } ,
114199 {
115- "alias" : "" ,
116- "class" : "CONSTANT" ,
117- "type" : "VALUE_CONSTANT" ,
118- "value" : {
119- "is_null" : false ,
120- "type" : {
121- "id" : "VARCHAR" ,
122- "type_info" : null ,
123- } ,
124- "value" : "Israel" ,
200+ alias : '' ,
201+ class : 'CONSTANT' ,
202+ type : 'VALUE_CONSTANT' ,
203+ value : {
204+ is_null : false ,
205+ type : {
206+ id : 'VARCHAR' ,
207+ type_info : null ,
125208 } ,
126- } ] ,
127- "class" : "OPERATOR" ,
128- "type" : "ARRAY_CONSTRUCTOR" ,
129- } ,
130- ] ,
131- "class" : "FUNCTION" ,
132- "distinct" : false ,
133- "export_state" : false ,
134- "filter" : null ,
135- "function_name" : "&&" ,
136- "is_operator" : true ,
137- "order_bys" : {
138- "orders" : [ ] ,
139- "type" : "ORDER_MODIFIER" ,
209+ value : 'Israel' ,
210+ } ,
211+ } ,
212+ ] ,
213+ class : 'OPERATOR' ,
214+ type : 'ARRAY_CONSTRUCTOR' ,
140215 } ,
141- "schema" : "" ,
142- "type" : "FUNCTION" ,
216+ ] ,
217+ class : 'FUNCTION' ,
218+ distinct : false ,
219+ export_state : false ,
220+ filter : null ,
221+ function_name : '&&' ,
222+ is_operator : true ,
223+ order_bys : {
224+ orders : [ ] ,
225+ type : 'ORDER_MODIFIER' ,
226+ } ,
227+ schema : '' ,
228+ type : 'FUNCTION' ,
143229 } ) ;
144230 } ) ;
231+
232+ it ( 'Should throw error if values array is empty' , ( ) => {
233+ expect ( ( ) =>
234+ inTransform ( {
235+ member : 'country' ,
236+ operator : 'in' ,
237+ values : [ ] ,
238+ memberInfo : {
239+ name : 'country' ,
240+ sql : 'table.country' ,
241+ type : 'string' ,
242+ } ,
243+ } )
244+ ) . toThrow ( 'In filter must have at least one value' ) ;
245+ } ) ;
145246} ) ;
0 commit comments