77
88import static org .junit .jupiter .api .Assertions .assertEquals ;
99import static org .junit .jupiter .api .Assertions .assertFalse ;
10- import static org .junit .jupiter .api .Assertions .assertNotNull ;
1110import static org .junit .jupiter .api .Assertions .assertThrows ;
1211import static org .junit .jupiter .api .Assertions .assertTrue ;
1312
@@ -56,12 +55,6 @@ void setUp() {
5655 fieldRef = rexBuilder .makeInputRef (rowType .getFieldList ().get (0 ).getType (), 0 ); // age field
5756 }
5857
59- @ Test
60- void testCreateCaseRangeAnalyzer () {
61- CaseRangeAnalyzer analyzer = CaseRangeAnalyzer .create ("test_agg" , rowType );
62- assertNotNull (analyzer );
63- }
64-
6558 @ Test
6659 void testAnalyzeSimpleCaseExpression () {
6760 // CASE
@@ -279,19 +272,7 @@ void testAnalyzeWithNullElse() {
279272 }
280273
281274 @ Test
282- void testAnalyzeNonCaseExpression () {
283- // Test with non-CASE expression - create a simple call that's not CASE
284- RexLiteral literal = rexBuilder .makeLiteral ("test" );
285- RexCall nonCaseCall = (RexCall ) rexBuilder .makeCall (SqlStdOperatorTable .UPPER , literal );
286-
287- CaseRangeAnalyzer analyzer = CaseRangeAnalyzer .create ("test" , rowType );
288- Optional <RangeAggregationBuilder > result = analyzer .analyze (nonCaseCall );
289-
290- assertFalse (result .isPresent ());
291- }
292-
293- @ Test
294- void testAnalyzeWithNonLiteralResult () {
275+ void testAnalyzeWithNonLiteralResultShouldNotSucceed () {
295276 // CASE WHEN age >= 18 THEN age ELSE 0 END (non-literal result)
296277
297278 RexLiteral literal18 = rexBuilder .makeExactLiteral (BigDecimal .valueOf (18 ));
@@ -314,7 +295,7 @@ void testAnalyzeWithNonLiteralResult() {
314295 }
315296
316297 @ Test
317- void testAnalyzeWithDifferentFields () {
298+ void testAnalyzeDifferentFieldsShouldThrow () {
318299 // Test comparing different fields in conditions
319300 RexInputRef nameFieldRef = rexBuilder .makeInputRef (rowType .getFieldList ().get (1 ).getType (), 1 );
320301
@@ -345,7 +326,7 @@ void testAnalyzeWithDifferentFields() {
345326 }
346327
347328 @ Test
348- void testAnalyzeWithAndCondition () {
329+ void testAnalyzeWithAndConditionShouldThrow () {
349330 // Test AND condition which should be unsupported
350331 RexLiteral literal18 = rexBuilder .makeExactLiteral (BigDecimal .valueOf (18 ));
351332 RexLiteral literal65 = rexBuilder .makeExactLiteral (BigDecimal .valueOf (65 ));
@@ -371,7 +352,7 @@ void testAnalyzeWithAndCondition() {
371352 }
372353
373354 @ Test
374- void testAnalyzeWithOrCondition () {
355+ void testAnalyzeWithOrConditionShouldThrow () {
375356 // Test OR condition which should be unsupported
376357 RexLiteral literal18 = rexBuilder .makeExactLiteral (BigDecimal .valueOf (18 ));
377358 RexLiteral literal65 = rexBuilder .makeExactLiteral (BigDecimal .valueOf (65 ));
@@ -465,30 +446,6 @@ void testAnalyzeWithReversedComparison() {
465446 assertEquals (normalizeJson (expectedJson ), normalizeJson (builder .toString ()));
466447 }
467448
468- @ Test
469- void testAnalyzeWithInvalidOperands () {
470- // Test condition with neither field reference nor literal
471- RexCall invalidCondition =
472- (RexCall )
473- rexBuilder .makeCall (
474- SqlStdOperatorTable .GREATER_THAN_OR_EQUAL ,
475- fieldRef ,
476- fieldRef ); // both sides are field refs
477-
478- RexLiteral resultLiteral = rexBuilder .makeLiteral ("result" );
479- RexLiteral elseLiteral = rexBuilder .makeLiteral ("else" );
480-
481- RexCall caseCall =
482- (RexCall )
483- rexBuilder .makeCall (
484- SqlStdOperatorTable .CASE ,
485- Arrays .asList (invalidCondition , resultLiteral , elseLiteral ));
486-
487- CaseRangeAnalyzer analyzer = CaseRangeAnalyzer .create ("test" , rowType );
488-
489- assertThrows (UnsupportedOperationException .class , () -> analyzer .analyze (caseCall ));
490- }
491-
492449 @ Test
493450 void testAnalyzeWithNullLiteralValue () {
494451 // Test with null literal value that can't be converted to Double
@@ -511,11 +468,6 @@ void testAnalyzeWithNullLiteralValue() {
511468 assertThrows (UnsupportedOperationException .class , () -> analyzer .analyze (caseCall ));
512469 }
513470
514- @ Test
515- void testDefaultElseKey () {
516- assertEquals ("null" , CaseRangeAnalyzer .DEFAULT_ELSE_KEY );
517- }
518-
519471 @ Test
520472 void testSimpleCaseGeneratesExpectedDSL () {
521473 // CASE WHEN age >= 18 THEN 'adult' ELSE 'minor' END
@@ -776,6 +728,77 @@ void testSearchConditionGeneratesExpectedDSL() {
776728 assertEquals (normalizeJson (expectedJson ), normalizeJson (builder .toString ()));
777729 }
778730
731+ @ Test
732+ void testSearchWithDiscontinuousRanges () {
733+ // age >= 20 && age < 30 -> '20-30'
734+ // age >= 40 && age <50 -> '40-50'
735+ // Create discontinuous ranges: [20, 30) and [40, 50)
736+ TreeRangeSet <BigDecimal > rangeSet = TreeRangeSet .create ();
737+ rangeSet .add (Range .closedOpen (BigDecimal .valueOf (20 ), BigDecimal .valueOf (30 )));
738+ rangeSet .add (Range .closedOpen (BigDecimal .valueOf (40 ), BigDecimal .valueOf (50 )));
739+
740+ Sarg <BigDecimal > sarg = Sarg .of (RexUnknownAs .UNKNOWN , rangeSet );
741+ RexNode sargLiteral =
742+ rexBuilder .makeSearchArgumentLiteral (sarg , typeFactory .createSqlType (SqlTypeName .DECIMAL ));
743+
744+ RexCall searchCall =
745+ (RexCall )
746+ rexBuilder .makeCall (SqlStdOperatorTable .SEARCH , Arrays .asList (fieldRef , sargLiteral ));
747+
748+ RexLiteral targetLiteral = rexBuilder .makeLiteral ("target_age" );
749+ RexLiteral otherLiteral =
750+ rexBuilder .makeNullLiteral (typeFactory .createSqlType (SqlTypeName .VARCHAR ));
751+
752+ RexCall caseCall =
753+ (RexCall )
754+ rexBuilder .makeCall (
755+ SqlStdOperatorTable .CASE , Arrays .asList (searchCall , targetLiteral , otherLiteral ));
756+
757+ CaseRangeAnalyzer analyzer = CaseRangeAnalyzer .create ("discontinuous_ranges" , rowType );
758+ Optional <RangeAggregationBuilder > result = analyzer .analyze (caseCall );
759+
760+ assertTrue (result .isPresent ());
761+ RangeAggregationBuilder builder = result .get ();
762+
763+ String expectedJson =
764+ """
765+ {
766+ "discontinuous_ranges" : {
767+ "range" : {
768+ "field" : "age",
769+ "ranges" : [
770+ {
771+ "key" : "target_age",
772+ "from" : 20.0,
773+ "to" : 30.0
774+ },
775+ {
776+ "key" : "target_age",
777+ "from" : 40.0,
778+ "to" : 50.0
779+ },
780+ {
781+ "key" : "null",
782+ "to" : 20.0
783+ },
784+ {
785+ "key" : "null",
786+ "from" : 30.0,
787+ "to" : 40.0
788+ },
789+ {
790+ "key" : "null",
791+ "from" : 50.0
792+ }
793+ ],
794+ "keyed" : true
795+ }
796+ }
797+ }""" ;
798+
799+ assertEquals (normalizeJson (expectedJson ), normalizeJson (builder .toString ()));
800+ }
801+
779802 /**
780803 * Helper method to normalize JSON strings for comparison by removing extra whitespace and
781804 * ensuring consistent formatting.
0 commit comments