@@ -142,6 +142,7 @@ public Select select(Selection selection) {
142142 Selection postProcess (Selection selection ) {
143143 return distinct ? new DistinctSelection (selection ) : selection ;
144144 }
145+
145146 };
146147 }
147148
@@ -299,6 +300,7 @@ public static WhereStep where(Origin source, PropertyPath path) {
299300 public static WhereStep where (Expression rhs ) {
300301
301302 return new WhereStep () {
303+
302304 @ Override
303305 public Predicate between (Expression lower , Expression upper ) {
304306 return new BetweenPredicate (rhs , lower , upper );
@@ -393,6 +395,7 @@ public Predicate eq(Expression value) {
393395 public Predicate neq (Expression value ) {
394396 return new OperatorPredicate (rhs , "!=" , value );
395397 }
398+
396399 };
397400 }
398401
@@ -506,7 +509,9 @@ default Select select(JpqlQueryBuilder.PathExpression path) {
506509 }
507510
508511 public interface Selection {
512+
509513 String render (RenderContext context );
514+
510515 }
511516
512517 /**
@@ -525,6 +530,7 @@ public String render(RenderContext context) {
525530 public String toString () {
526531 return render (RenderContext .EMPTY );
527532 }
533+
528534 }
529535
530536 static PathAndOrigin path (Origin origin , String path ) {
@@ -538,29 +544,28 @@ static PathAndOrigin path(Origin origin, String path) {
538544 throw new RuntimeException (e );
539545 }
540546 }
547+
541548 if (origin instanceof Join join ) {
542549
543550 Origin parent = join .source ;
544551 List <String > segments = new ArrayList <>();
545552 segments .add (join .path );
546553 while (!(parent instanceof Entity )) {
547- if (parent instanceof Join pj ) {
548- parent = pj .source ;
549- segments .add (pj .path );
554+ if (parent instanceof Join parentJoin ) {
555+ parent = parentJoin .source ;
556+ segments .add (parentJoin .path );
550557 } else {
551558 parent = null ;
552559 }
553560 }
554561
555- if (parent instanceof Entity ) {
556- Collections .reverse (segments );
557- segments .add (path );
558- PathAndOrigin path1 = path (parent , StringUtils .collectionToDelimitedString (segments , "." ));
559- return new PathAndOrigin (path1 .path ().getLeafProperty (), origin , false );
560- }
562+ Collections .reverse (segments );
563+ segments .add (path );
564+ PathAndOrigin joinedPath = path (parent , StringUtils .collectionToDelimitedString (segments , "." ));
565+ return new PathAndOrigin (joinedPath .path ().getLeafProperty (), origin , false );
561566 }
562- throw new IllegalStateException (" oh no " );
563567
568+ throw new IllegalStateException ("🙈 Unsupported origin type: " + origin );
564569 }
565570
566571 /**
@@ -579,6 +584,7 @@ public String render(RenderContext context) {
579584 public String toString () {
580585 return render (RenderContext .EMPTY );
581586 }
587+
582588 }
583589
584590 /**
@@ -598,6 +604,7 @@ public String render(RenderContext context) {
598604 public String toString () {
599605 return render (RenderContext .EMPTY );
600606 }
607+
601608 }
602609
603610 /**
@@ -618,6 +625,7 @@ public String render(RenderContext context) {
618625 public String toString () {
619626 return render (RenderContext .EMPTY );
620627 }
628+
621629 }
622630
623631 /**
@@ -652,21 +660,29 @@ public String render(RenderContext context) {
652660 public String toString () {
653661 return render (RenderContext .EMPTY );
654662 }
663+
655664 }
656665
657666 /**
658- * {@code WHERE} predicate .
667+ * Interface specifying a predicate or expression that can be rendered to {@code String} .
659668 */
660- public interface Predicate {
669+ public interface Renderable {
661670
662671 /**
663- * Render the predicate given {@link RenderContext}.
672+ * Render the predicate or expression given {@link RenderContext}.
664673 *
665674 * @param context
666675 * @return
667676 */
668677 String render (RenderContext context );
669678
679+ }
680+
681+ /**
682+ * {@code WHERE} predicate.
683+ */
684+ public interface Predicate extends Renderable {
685+
670686 /**
671687 * {@code OR}-concatenate this predicate with {@code other}.
672688 *
@@ -701,21 +717,21 @@ default Predicate and(Predicate other) { // don't like the structuring of this a
701717 default Predicate nest () {
702718 return new NestedPredicate (this );
703719 }
720+
704721 }
705722
706723 /**
707724 * Interface specifying an expression that can be rendered to {@code String}.
708725 */
709- public interface Expression {
726+ public interface Expression extends Renderable {
710727
711728 /**
712- * Render the expression given {@link RenderContext}.
729+ * Create an {@link AliasedExpression} with the given {@code alias}. If the expression is already aliased, the
730+ * previous alias is discarded and replaced with the new one.
713731 *
714- * @param context
732+ * @param alias
715733 * @return
716734 */
717- String render (RenderContext context );
718-
719735 default AliasedExpression as (String alias ) {
720736
721737 if (this instanceof DefaultAliasedExpression de ) {
@@ -724,6 +740,7 @@ default AliasedExpression as(String alias) {
724740
725741 return new DefaultAliasedExpression (this , alias );
726742 }
743+
727744 }
728745
729746 /**
@@ -756,6 +773,7 @@ public String getAlias() {
756773 public String toString () {
757774 return render (RenderContext .EMPTY );
758775 }
776+
759777 }
760778
761779 /**
@@ -768,6 +786,7 @@ public interface PathExpression extends Expression {
768786 * @return the associated {@link PropertyPath}.
769787 */
770788 PropertyPath getPropertyPath ();
789+
771790 }
772791
773792 /**
@@ -865,6 +884,7 @@ String render() {
865884
866885 return result .toString ();
867886 }
887+
868888 }
869889
870890 /**
@@ -889,6 +909,7 @@ public AbstractJpqlQuery where(Predicate predicate) {
889909 public String toString () {
890910 return render ();
891911 }
912+
892913 }
893914
894915 record OrderExpression (Expression sortExpression , @ org .springframework .lang .Nullable Sort .Direction direction ,
@@ -915,6 +936,7 @@ public String render(RenderContext context) {
915936
916937 return builder .toString ();
917938 }
939+
918940 }
919941
920942 /**
@@ -966,6 +988,7 @@ public String prefixWithAlias(Origin source, String fragment) {
966988 public boolean isConstructorContext () {
967989 return false ;
968990 }
991+
969992 }
970993
971994 static class ConstructorContext extends RenderContext {
@@ -978,6 +1001,7 @@ static class ConstructorContext extends RenderContext {
9781001 public boolean isConstructorContext () {
9791002 return true ;
9801003 }
1004+
9811005 }
9821006
9831007 /**
@@ -992,6 +1016,7 @@ public interface Origin {
9921016 * @return the simple name of the origin (e.g. {@link Class#getSimpleName()})
9931017 */
9941018 String getName ();
1019+
9951020 }
9961021
9971022 /**
@@ -1001,6 +1026,7 @@ public interface Origin {
10011026 public interface Bindable {
10021027
10031028 boolean isRoot ();
1029+
10041030 }
10051031
10061032 /**
@@ -1283,6 +1309,7 @@ default Predicate like(String value, String escape) {
12831309 * @return
12841310 */
12851311 Predicate neq (Expression value );
1312+
12861313 }
12871314
12881315 record LiteralExpression (String expression ) implements Expression {
@@ -1296,6 +1323,7 @@ public String render(RenderContext context) {
12961323 public String toString () {
12971324 return render (RenderContext .EMPTY );
12981325 }
1326+
12991327 }
13001328
13011329 record StringLiteralExpression (String literal ) implements Expression {
@@ -1313,6 +1341,7 @@ public String raw() {
13131341 public String toString () {
13141342 return render (RenderContext .EMPTY );
13151343 }
1344+
13161345 }
13171346
13181347 record ParameterExpression (ParameterPlaceholder parameter ) implements Expression {
@@ -1326,6 +1355,7 @@ public String render(RenderContext context) {
13261355 public String toString () {
13271356 return render (RenderContext .EMPTY );
13281357 }
1358+
13291359 }
13301360
13311361 record FunctionExpression (String function , List <Expression > arguments ) implements Expression {
@@ -1351,6 +1381,7 @@ public String render(RenderContext context) {
13511381 public String toString () {
13521382 return render (RenderContext .EMPTY );
13531383 }
1384+
13541385 }
13551386
13561387 record OperatorPredicate (Expression path , String operator , Expression predicate ) implements Predicate {
@@ -1364,6 +1395,7 @@ public String render(RenderContext context) {
13641395 public String toString () {
13651396 return render (RenderContext .EMPTY );
13661397 }
1398+
13671399 }
13681400
13691401 record MemberOfPredicate (Expression path , String operator , Expression predicate ) implements Predicate {
@@ -1377,6 +1409,7 @@ public String render(RenderContext context) {
13771409 public String toString () {
13781410 return render (RenderContext .EMPTY );
13791411 }
1412+
13801413 }
13811414
13821415 record LhsPredicate (Expression path , String predicate ) implements Predicate {
@@ -1390,6 +1423,7 @@ public String render(RenderContext context) {
13901423 public String toString () {
13911424 return render (RenderContext .EMPTY );
13921425 }
1426+
13931427 }
13941428
13951429 record BetweenPredicate (Expression path , Expression lower , Expression upper ) implements Predicate {
@@ -1403,6 +1437,7 @@ public String render(RenderContext context) {
14031437 public String toString () {
14041438 return render (RenderContext .EMPTY );
14051439 }
1440+
14061441 }
14071442
14081443 record LikePredicate (Expression left , String operator , Expression right , String escape ) implements Predicate {
@@ -1416,27 +1451,29 @@ public String render(RenderContext context) {
14161451 public String toString () {
14171452 return render (RenderContext .EMPTY );
14181453 }
1454+
14191455 }
14201456
14211457 record InPredicate (Expression path , String operator , Expression predicate ) implements Predicate {
14221458
14231459 @ Override
14241460 public String render (RenderContext context ) {
14251461
1426- String predicateStr = predicate .render (context );
1427-
1428- // Avoid double parentheses if predicate string already starts and ends with parentheses
1429- if (predicateStr .startsWith ("(" ) && predicateStr .endsWith (")" )) {
1430- return "%s %s %s" .formatted (path .render (context ), operator , predicateStr );
1431- }
1432-
1433- return "%s %s (%s)" .formatted (path .render (context ), operator , predicateStr );
1462+ Expression predicate = this .predicate ;
1463+ String rendered = predicate .render (context );
1464+
1465+ return (hasParenthesis (rendered ) ? "%s %s %s" : "%s %s (%s)" ).formatted (path .render (context ), operator , rendered );
14341466 }
14351467
14361468 @ Override
14371469 public String toString () {
14381470 return render (RenderContext .EMPTY );
14391471 }
1472+
1473+ private static boolean hasParenthesis (String str ) {
1474+ return str .startsWith ("(" ) && str .endsWith (")" );
1475+ }
1476+
14401477 }
14411478
14421479 record AndPredicate (Predicate left , Predicate right ) implements Predicate {
@@ -1450,6 +1487,7 @@ public String render(RenderContext context) {
14501487 public String toString () {
14511488 return render (RenderContext .EMPTY );
14521489 }
1490+
14531491 }
14541492
14551493 record OrPredicate (Predicate left , Predicate right ) implements Predicate {
@@ -1463,6 +1501,7 @@ public String render(RenderContext context) {
14631501 public String toString () {
14641502 return render (RenderContext .EMPTY );
14651503 }
1504+
14661505 }
14671506
14681507 record NestedPredicate (Predicate delegate ) implements Predicate {
@@ -1476,6 +1515,7 @@ public String render(RenderContext context) {
14761515 public String toString () {
14771516 return render (RenderContext .EMPTY );
14781517 }
1518+
14791519 }
14801520
14811521 /**
@@ -1507,6 +1547,7 @@ public String render(RenderContext context) {
15071547 public String getAlias () {
15081548 return path ().getSegment ();
15091549 }
1550+
15101551 }
15111552
15121553 /**
@@ -1541,5 +1582,7 @@ public static ParameterPlaceholder named(String name) {
15411582 Assert .hasText (name , "Placeholder name must not be empty" );
15421583 return new ParameterPlaceholder (":%s" .formatted (name ));
15431584 }
1585+
15441586 }
1587+
15451588}
0 commit comments