15
15
*/
16
16
package org .springframework .data .jpa .repository .query ;
17
17
18
- import static org .assertj .core .api .Assertions .assertThat ;
19
- import static org .assertj . core . api . Assertions . assertThatExceptionOfType ;
18
+ import static org .assertj .core .api .Assertions .* ;
19
+ import static org .springframework . data . jpa . repository . query . JpqlQueryBuilder .* ;
20
20
21
21
import jakarta .persistence .Id ;
22
22
import jakarta .persistence .ManyToOne ;
28
28
import java .util .Map ;
29
29
30
30
import org .junit .jupiter .api .Test ;
31
- import org .springframework .data .domain .Sort ;
32
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .AbstractJpqlQuery ;
33
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .Entity ;
34
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .Expression ;
35
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .Join ;
36
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .OrderExpression ;
37
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .Origin ;
38
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .ParameterPlaceholder ;
39
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .PathAndOrigin ;
40
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .Predicate ;
41
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .RenderContext ;
42
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .SelectStep ;
43
- import org .springframework .data .jpa .repository .query .JpqlQueryBuilder .WhereStep ;
44
31
45
32
/**
33
+ * Unit tests for {@link JpqlQueryBuilder}.
34
+ *
46
35
* @author Christoph Strobl
47
36
*/
48
37
class JpqlQueryBuilderUnitTests {
49
38
50
- @ Test
39
+ @ Test // GH-3588
51
40
void placeholdersRenderCorrectly () {
52
41
53
42
assertThat (JpqlQueryBuilder .parameter (ParameterPlaceholder .indexed (1 )).render (RenderContext .EMPTY )).isEqualTo ("?1" );
@@ -56,89 +45,88 @@ void placeholdersRenderCorrectly() {
56
45
assertThat (JpqlQueryBuilder .parameter ("?1" ).render (RenderContext .EMPTY )).isEqualTo ("?1" );
57
46
}
58
47
59
- @ Test
60
- void placeholdersErrorOnInvaludInput () {
48
+ @ Test // GH-3588
49
+ void placeholdersErrorOnInvalidInput () {
61
50
assertThatExceptionOfType (IllegalArgumentException .class )
62
51
.isThrownBy (() -> JpqlQueryBuilder .parameter ((String ) null ));
63
52
assertThatExceptionOfType (IllegalArgumentException .class ).isThrownBy (() -> JpqlQueryBuilder .parameter ("" ));
64
53
}
65
54
66
- @ Test
55
+ @ Test // GH-3588
67
56
void stringLiteralRendersAsQuotedString () {
68
57
69
- assertThat (JpqlQueryBuilder . stringLiteral ("literal" ).render (RenderContext .EMPTY )).isEqualTo ("'literal'" );
58
+ assertThat (literal ("literal" ).render (RenderContext .EMPTY )).isEqualTo ("'literal'" );
70
59
71
60
/* JPA Spec - 4.6.1 Literals:
72
61
> A string literal that includes a single quote is represented by two single quotes--for example: 'literal''s'. */
73
- assertThat (JpqlQueryBuilder . stringLiteral ("literal's" ).render (RenderContext .EMPTY )).isEqualTo ("'literal''s'" );
62
+ assertThat (literal ("literal's" ).render (RenderContext .EMPTY )).isEqualTo ("'literal''s'" );
74
63
}
75
64
76
- @ Test
65
+ @ Test // GH-3588
77
66
void entity () {
78
67
79
68
Entity entity = JpqlQueryBuilder .entity (Order .class );
80
- assertThat (entity .alias ()).isEqualTo ("o" );
81
- assertThat (entity .entity ()).isEqualTo (Order .class .getName ());
82
- assertThat (entity .getName ()).isEqualTo (Order .class .getSimpleName ()); // TODO: this really confusing
83
- assertThat (entity .simpleName ()).isEqualTo (Order .class .getSimpleName ());
69
+ assertThat (entity .getAlias ()).isEqualTo ("o" );
70
+ assertThat (entity .getEntity ()).isEqualTo (Order .class .getName ());
71
+ assertThat (entity .getName ()).isEqualTo (Order .class .getSimpleName ());
84
72
}
85
73
86
- @ Test
74
+ @ Test // GH-3588
87
75
void literalExpressionRendersAsIs () {
88
- Expression expression = JpqlQueryBuilder . expression ("CONCAT(person.lastName, ‘, ’, person.firstName))" );
76
+ Expression expression = expression ("CONCAT(person.lastName, ‘, ’, person.firstName))" );
89
77
assertThat (expression .render (RenderContext .EMPTY )).isEqualTo ("CONCAT(person.lastName, ‘, ’, person.firstName))" );
90
78
}
91
79
92
- @ Test
80
+ @ Test // GH-3588
93
81
void xxx () {
94
82
95
83
Entity entity = JpqlQueryBuilder .entity (Order .class );
96
84
PathAndOrigin orderDate = JpqlQueryBuilder .path (entity , "date" );
97
85
98
- String fragment = JpqlQueryBuilder .where (orderDate ).eq ("{d '2024-11-05'}" ).render (ctx (entity ));
86
+ String fragment = JpqlQueryBuilder .where (orderDate ).eq (expression ( "{d '2024-11-05'}" ) ).render (ctx (entity ));
99
87
100
88
assertThat (fragment ).isEqualTo ("o.date = {d '2024-11-05'}" );
101
-
102
- // JpqlQueryBuilder.where(PathAndOrigin)
103
89
}
104
90
105
- @ Test
91
+ @ Test // GH-3588
106
92
void predicateRendering () {
107
93
108
-
109
94
Entity entity = JpqlQueryBuilder .entity (Order .class );
110
95
WhereStep where = JpqlQueryBuilder .where (JpqlQueryBuilder .path (entity , "country" ));
96
+ RenderContext context = ctx (entity );
97
+
98
+ assertThat (where .between (expression ("'AT'" ), expression ("'DE'" )).render (context ))
99
+ .isEqualTo ("o.country BETWEEN 'AT' AND 'DE'" );
100
+ assertThat (where .eq (expression ("'AT'" )).render (context )).isEqualTo ("o.country = 'AT'" );
101
+ assertThat (where .eq (literal ("AT" )).render (context )).isEqualTo ("o.country = 'AT'" );
102
+ assertThat (where .gt (expression ("'AT'" )).render (context )).isEqualTo ("o.country > 'AT'" );
103
+ assertThat (where .gte (expression ("'AT'" )).render (context )).isEqualTo ("o.country >= 'AT'" );
111
104
112
- assertThat (where .between ("'AT'" , "'DE'" ).render (ctx (entity ))).isEqualTo ("o.country BETWEEN 'AT' AND 'DE'" );
113
- assertThat (where .eq ("'AT'" ).render (ctx (entity ))).isEqualTo ("o.country = 'AT'" );
114
- assertThat (where .eq (JpqlQueryBuilder .stringLiteral ("AT" )).render (ctx (entity ))).isEqualTo ("o.country = 'AT'" );
115
- assertThat (where .gt ("'AT'" ).render (ctx (entity ))).isEqualTo ("o.country > 'AT'" );
116
- assertThat (where .gte ("'AT'" ).render (ctx (entity ))).isEqualTo ("o.country >= 'AT'" );
117
105
// TODO: that is really really bad
118
106
// lange namen
119
- assertThat (where .in ("'AT', 'DE'" ).render (ctx ( entity ) )).isEqualTo ("o.country IN ('AT', 'DE')" );
107
+ assertThat (where .in (expression ( "'AT', 'DE'" )) .render (context )).isEqualTo ("o.country IN ('AT', 'DE')" );
120
108
121
109
// 1 in age - cleanup what is not used - remove everything eles
122
110
// assertThat(where.inMultivalued("'AT', 'DE'").render(ctx(entity))).isEqualTo("o.country IN ('AT', 'DE')"); //
123
- assertThat (where .isEmpty ().render (ctx ( entity ) )).isEqualTo ("o.country IS EMPTY" );
124
- assertThat (where .isNotEmpty ().render (ctx ( entity ) )).isEqualTo ("o.country IS NOT EMPTY" );
125
- assertThat (where .isTrue ().render (ctx ( entity ) )).isEqualTo ("o.country = TRUE" );
126
- assertThat (where .isFalse ().render (ctx ( entity ) )).isEqualTo ("o.country = FALSE" );
127
- assertThat (where .isNull ().render (ctx ( entity ) )).isEqualTo ("o.country IS NULL" );
128
- assertThat (where .isNotNull ().render (ctx ( entity ) )).isEqualTo ("o.country IS NOT NULL" );
129
- assertThat (where .like ("'\\ _%'" , "" + EscapeCharacter .DEFAULT .getEscapeCharacter ()).render (ctx ( entity ) ))
111
+ assertThat (where .isEmpty ().render (context )).isEqualTo ("o.country IS EMPTY" );
112
+ assertThat (where .isNotEmpty ().render (context )).isEqualTo ("o.country IS NOT EMPTY" );
113
+ assertThat (where .isTrue ().render (context )).isEqualTo ("o.country = TRUE" );
114
+ assertThat (where .isFalse ().render (context )).isEqualTo ("o.country = FALSE" );
115
+ assertThat (where .isNull ().render (context )).isEqualTo ("o.country IS NULL" );
116
+ assertThat (where .isNotNull ().render (context )).isEqualTo ("o.country IS NOT NULL" );
117
+ assertThat (where .like ("'\\ _%'" , "" + EscapeCharacter .DEFAULT .getEscapeCharacter ()).render (context ))
130
118
.isEqualTo ("o.country LIKE '\\ _%' ESCAPE '\\ '" );
131
- assertThat (where .notLike ("'\\ _%'" , "" + EscapeCharacter .DEFAULT .getEscapeCharacter ()).render (ctx ( entity ) ))
119
+ assertThat (where .notLike (expression ( "'\\ _%'" ) , "" + EscapeCharacter .DEFAULT .getEscapeCharacter ()).render (context ))
132
120
.isEqualTo ("o.country NOT LIKE '\\ _%' ESCAPE '\\ '" );
133
- assertThat (where .lt ("'AT'" ).render (ctx ( entity ) )).isEqualTo ("o.country < 'AT'" );
134
- assertThat (where .lte ("'AT'" ).render (ctx ( entity ) )).isEqualTo ("o.country <= 'AT'" );
135
- assertThat (where .memberOf ("'AT'" ).render (ctx ( entity ) )).isEqualTo ("'AT' MEMBER OF o.country" );
121
+ assertThat (where .lt (expression ( "'AT'" )) .render (context )).isEqualTo ("o.country < 'AT'" );
122
+ assertThat (where .lte (expression ( "'AT'" )) .render (context )).isEqualTo ("o.country <= 'AT'" );
123
+ assertThat (where .memberOf (expression ( "'AT'" )) .render (context )).isEqualTo ("'AT' MEMBER OF o.country" );
136
124
// TODO: can we have this where.value(foo).memberOf(pathAndOrigin);
137
- assertThat (where .notMemberOf ("'AT'" ).render (ctx ( entity ) )).isEqualTo ("'AT' NOT MEMBER OF o.country" );
138
- assertThat (where .neq ("'AT'" ).render (ctx ( entity ) )).isEqualTo ("o.country != 'AT'" );
125
+ assertThat (where .notMemberOf (expression ( "'AT'" )) .render (context )).isEqualTo ("'AT' NOT MEMBER OF o.country" );
126
+ assertThat (where .neq (expression ( "'AT'" )) .render (context )).isEqualTo ("o.country != 'AT'" );
139
127
}
140
128
141
- @ Test
129
+ @ Test // GH-3588
142
130
void selectRendering () {
143
131
144
132
// make sure things are immutable
@@ -147,25 +135,12 @@ void selectRendering() {
147
135
assertThat (select .count ().render ()).startsWith ("SELECT COUNT(o)" );
148
136
assertThat (select .distinct ().entity ().render ()).startsWith ("SELECT DISTINCT o " );
149
137
assertThat (select .distinct ().count ().render ()).startsWith ("SELECT COUNT(DISTINCT o) " );
150
- assertThat (JpqlQueryBuilder .selectFrom (Order .class ).select (JpqlQueryBuilder .path (JpqlQueryBuilder .entity (Order .class ), "country" )).render ())
151
- .startsWith ("SELECT o.country " );
138
+ assertThat (JpqlQueryBuilder .selectFrom (Order .class )
139
+ .select (JpqlQueryBuilder .path (JpqlQueryBuilder .entity (Order .class ), "country" )).render ())
140
+ .startsWith ("SELECT o.country " );
152
141
}
153
142
154
- // @Test
155
- // void sorting() {
156
- //
157
- // JpqlQueryBuilder.orderBy(new OrderExpression() , Sort.Order.asc("country"));
158
- //
159
- // Entity entity = JpqlQueryBuilder.entity(Order.class);
160
- //
161
- // AbstractJpqlQuery query = JpqlQueryBuilder.selectFrom(Order.class)
162
- // .entity()
163
- // .orderBy()
164
- // .where(context -> "1 = 1");
165
- //
166
- // }
167
-
168
- @ Test
143
+ @ Test // GH-3588
169
144
void joins () {
170
145
171
146
Entity entity = JpqlQueryBuilder .entity (LineItem .class );
@@ -175,14 +150,14 @@ void joins() {
175
150
PathAndOrigin productName = JpqlQueryBuilder .path (li_pr , "name" );
176
151
PathAndOrigin personName = JpqlQueryBuilder .path (li_pr2 , "name" );
177
152
178
- String fragment = JpqlQueryBuilder .where (productName ).eq (JpqlQueryBuilder . stringLiteral ("ex30" ))
179
- .and (JpqlQueryBuilder .where (personName ).eq (JpqlQueryBuilder . stringLiteral ("ex40" ))).render (ctx (entity ));
153
+ String fragment = JpqlQueryBuilder .where (productName ).eq (literal ("ex30" ))
154
+ .and (JpqlQueryBuilder .where (personName ).eq (literal ("ex40" ))).render (ctx (entity ));
180
155
181
156
assertThat (fragment ).isEqualTo ("p.name = 'ex30' AND join_0.name = 'ex40'" );
182
157
}
183
158
184
- @ Test
185
- void x2 () {
159
+ @ Test // GH-3588
160
+ void joinOnPaths () {
186
161
187
162
Entity entity = JpqlQueryBuilder .entity (LineItem .class );
188
163
Join li_pr = JpqlQueryBuilder .innerJoin (entity , "product" );
@@ -191,36 +166,17 @@ void x2() {
191
166
PathAndOrigin productName = JpqlQueryBuilder .path (li_pr , "name" );
192
167
PathAndOrigin personName = JpqlQueryBuilder .path (li_pe , "name" );
193
168
194
- String fragment = JpqlQueryBuilder .where (productName ).eq (JpqlQueryBuilder .stringLiteral ("ex30" ))
195
- .and (JpqlQueryBuilder .where (personName ).eq (JpqlQueryBuilder .stringLiteral ("cstrobl" ))).render (ctx (entity ));
196
-
197
- assertThat (fragment ).isEqualTo ("p.name = 'ex30' AND join_0.name = 'cstrobl'" );
198
- }
199
-
200
- @ Test
201
- void x3 () {
202
-
203
- Entity entity = JpqlQueryBuilder .entity (LineItem .class );
204
- Join li_pr = JpqlQueryBuilder .innerJoin (entity , "product" );
205
- Join li_pe = JpqlQueryBuilder .innerJoin (entity , "person" );
206
-
207
- PathAndOrigin productName = JpqlQueryBuilder .path (li_pr , "name" );
208
- PathAndOrigin personName = JpqlQueryBuilder .path (li_pe , "name" );
209
-
210
- // JpqlQueryBuilder.and("x = y", "a = b"); -> x = y AND a = b
211
-
212
- // JpqlQueryBuilder.nested(JpqlQueryBuilder.and("x = y", "a = b")) (x = y AND a = b)
213
-
214
- String fragment = JpqlQueryBuilder .where (productName ).eq (JpqlQueryBuilder .stringLiteral ("ex30" ))
215
- .and (JpqlQueryBuilder .where (personName ).eq (JpqlQueryBuilder .stringLiteral ("cstrobl" ))).render (ctx (entity ));
169
+ String fragment = JpqlQueryBuilder .where (productName ).eq (literal ("ex30" ))
170
+ .and (JpqlQueryBuilder .where (personName ).eq (literal ("cstrobl" ))).render (ctx (entity ));
216
171
217
172
assertThat (fragment ).isEqualTo ("p.name = 'ex30' AND join_0.name = 'cstrobl'" );
218
173
}
219
174
220
175
static RenderContext ctx (Entity ... entities ) {
176
+
221
177
Map <Origin , String > aliases = new LinkedHashMap <>(entities .length );
222
178
for (Entity entity : entities ) {
223
- aliases .put (entity , entity .alias ());
179
+ aliases .put (entity , entity .getAlias ());
224
180
}
225
181
226
182
return new RenderContext (aliases );
0 commit comments