@@ -431,19 +431,7 @@ public Predicate neq(Expression value) {
431431 }
432432
433433 public static @ Nullable Predicate or (List <Predicate > intermediate ) {
434-
435- Predicate predicate = null ;
436-
437- for (Predicate other : intermediate ) {
438-
439- if (predicate == null ) {
440- predicate = other ;
441- } else {
442- predicate = predicate .or (other );
443- }
444- }
445-
446- return predicate ;
434+ return intermediate .isEmpty () ? null : OrPredicate .of (intermediate );
447435 }
448436
449437 /**
@@ -712,23 +700,7 @@ public interface Predicate extends Renderable {
712700 @ Contract ("_ -> new" )
713701 @ CheckReturnValue
714702 default Predicate or (Predicate other ) {
715-
716- // Flatten OR composition: Or([a,b]).or(c) -> Or([a,b,c])
717- List <Predicate > parts = new ArrayList <>();
718-
719- if (this instanceof OrPredicate op ) {
720- parts .addAll (op .parts ());
721- } else {
722- parts .add (this );
723- }
724-
725- if (other instanceof OrPredicate op ) {
726- parts .addAll (op .parts ());
727- } else {
728- parts .add (other );
729- }
730-
731- return new OrPredicate (parts );
703+ return OrPredicate .of (this , other );
732704 }
733705
734706 /**
@@ -740,26 +712,7 @@ default Predicate or(Predicate other) {
740712 @ Contract ("_ -> new" )
741713 @ CheckReturnValue
742714 default Predicate and (Predicate other ) {
743-
744- // don't like the structuring of this and the nest() thing
745- //
746- // Flatten AND composition to avoid deep nesting:
747- // And([a,b]).and(c) -> And([a,b,c])
748- List <Predicate > parts = new ArrayList <>();
749-
750- if (this instanceof AndPredicate ap ) {
751- parts .addAll (ap .parts ());
752- } else {
753- parts .add (this );
754- }
755-
756- if (other instanceof AndPredicate ap ) {
757- parts .addAll (ap .parts ());
758- } else {
759- parts .add (other );
760- }
761-
762- return new AndPredicate (parts );
715+ return AndPredicate .of (this , other );
763716 }
764717
765718 /**
@@ -1566,20 +1519,40 @@ private static boolean hasParenthesis(String str) {
15661519 record AndPredicate (List <Predicate > parts ) implements Predicate {
15671520
15681521 AndPredicate {
1569-
15701522 Assert .notEmpty (parts , "Predicate parts must not be empty" );
1523+ }
15711524
1572- // Flatten nested AND predicates to keep the internal representation normalized.
1573- List <Predicate > flattened = new ArrayList <>(parts .size ());
1574- for (Predicate p : parts ) {
1575- if (p instanceof AndPredicate ap ) {
1576- flattened .addAll (ap .parts ());
1525+ public static AndPredicate of (List <Predicate > predicates ) {
1526+
1527+ if (predicates .size () == 1 ) {
1528+
1529+ Predicate predicate = predicates .get (0 );
1530+ if (predicate instanceof AndPredicate ap ) {
1531+ return ap ;
1532+ }
1533+
1534+ return new AndPredicate (Collections .singletonList (predicate ));
1535+ }
1536+
1537+ List <Predicate > flattened = new ArrayList <>(predicates .size ());
1538+ for (Predicate p : predicates ) {
1539+ if (p instanceof AndPredicate op ) {
1540+ flattened .addAll (op .parts ());
15771541 } else {
15781542 flattened .add (p );
15791543 }
15801544 }
15811545
1582- parts = List .copyOf (flattened );
1546+ return new AndPredicate (flattened );
1547+ }
1548+
1549+ public static AndPredicate of (Predicate predicate , Predicate other ) {
1550+ return of (List .of (predicate , other ));
1551+ }
1552+
1553+ @ Override
1554+ public Predicate and (Predicate other ) {
1555+ return of (this , other );
15831556 }
15841557
15851558 @ Override
@@ -1598,20 +1571,29 @@ public String toString() {
15981571 record OrPredicate (List <Predicate > parts ) implements Predicate {
15991572
16001573 OrPredicate {
1601-
16021574 Assert .notEmpty (parts , "Predicate parts must not be empty" );
1575+ }
1576+
1577+ public static OrPredicate of (List <Predicate > predicates ) {
16031578
1604- // Flatten nested OR predicates to keep the internal representation normalized.
1605- List <Predicate > flattened = new ArrayList <>(parts .size ());
1606- for (Predicate p : parts ) {
1579+ if (predicates .size () == 1 ) {
1580+ return new OrPredicate (Collections .singletonList (predicates .get (0 )));
1581+ }
1582+
1583+ List <Predicate > flattened = new ArrayList <>(predicates .size ());
1584+ for (Predicate p : predicates ) {
16071585 if (p instanceof OrPredicate op ) {
16081586 flattened .addAll (op .parts ());
16091587 } else {
16101588 flattened .add (p );
16111589 }
16121590 }
16131591
1614- parts = List .copyOf (flattened );
1592+ return new OrPredicate (flattened );
1593+ }
1594+
1595+ public static OrPredicate of (Predicate predicate , Predicate other ) {
1596+ return of (List .of (predicate , other ));
16151597 }
16161598
16171599 @ Override
@@ -1621,6 +1603,11 @@ public String render(RenderContext context) {
16211603 .collect (Collectors .joining (" OR " ));
16221604 }
16231605
1606+ @ Override
1607+ public Predicate or (Predicate other ) {
1608+ return of (this , other );
1609+ }
1610+
16241611 @ Override
16251612 public String toString () {
16261613 return render (RenderContext .EMPTY );
0 commit comments