1515 */
1616package org .springframework .data .jpa .repository .query ;
1717
18+ import static org .assertj .core .api .Assertions .*;
19+ import static org .assertj .core .api .Assumptions .*;
20+
21+ import java .util .stream .Stream ;
22+
23+ import org .junit .jupiter .api .Test ;
24+ import org .junit .jupiter .params .ParameterizedTest ;
25+ import org .junit .jupiter .params .provider .Arguments ;
26+ import org .junit .jupiter .params .provider .MethodSource ;
27+ import org .springframework .data .domain .Sort ;
28+
1829/**
1930 * TCK Tests for {@link JSqlParserQueryEnhancer}.
2031 *
2132 * @author Mark Paluch
33+ * @author Diego Krupitza
34+ * @author Geoffrey Deremetz
2235 */
2336public class JSqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests {
2437
@@ -27,4 +40,181 @@ QueryEnhancer createQueryEnhancer(DeclaredQuery declaredQuery) {
2740 return new JSqlParserQueryEnhancer (declaredQuery );
2841 }
2942
43+ @ Override
44+ @ ParameterizedTest // GH-2773
45+ @ MethodSource ("jpqlCountQueries" )
46+ void shouldDeriveJpqlCountQuery (String query , String expected ) {
47+
48+ assumeThat (query ).as ("JSQLParser does not support simple JPQL syntax" ).doesNotStartWithIgnoringCase ("FROM" );
49+
50+ assumeThat (query ).as ("JSQLParser does not support constructor JPQL syntax" ).doesNotContain (" new " );
51+
52+ super .shouldDeriveJpqlCountQuery (query , expected );
53+ }
54+
55+ @ Test
56+ // GH-2578
57+ void setOperationListWorks () {
58+
59+ String setQuery = "select SOME_COLUMN from SOME_TABLE where REPORTING_DATE = :REPORTING_DATE \n " //
60+ + "except \n " //
61+ + "select SOME_COLUMN from SOME_OTHER_TABLE where REPORTING_DATE = :REPORTING_DATE" ;
62+
63+ StringQuery stringQuery = new StringQuery (setQuery , true );
64+ QueryEnhancer queryEnhancer = QueryEnhancerFactory .forQuery (stringQuery );
65+
66+ assertThat (stringQuery .getAlias ()).isNullOrEmpty ();
67+ assertThat (stringQuery .getProjection ()).isEqualToIgnoringCase ("SOME_COLUMN" );
68+ assertThat (stringQuery .hasConstructorExpression ()).isFalse ();
69+
70+ assertThat (queryEnhancer .createCountQueryFor ()).isEqualToIgnoringCase (setQuery );
71+ assertThat (queryEnhancer .applySorting (Sort .by ("SOME_COLUMN" ))).endsWith ("ORDER BY SOME_COLUMN ASC" );
72+ assertThat (queryEnhancer .getJoinAliases ()).isEmpty ();
73+ assertThat (queryEnhancer .detectAlias ()).isNullOrEmpty ();
74+ assertThat (queryEnhancer .getProjection ()).isEqualToIgnoringCase ("SOME_COLUMN" );
75+ assertThat (queryEnhancer .hasConstructorExpression ()).isFalse ();
76+ }
77+
78+ @ Test // GH-2578
79+ void complexSetOperationListWorks () {
80+
81+ String setQuery = "select SOME_COLUMN from SOME_TABLE where REPORTING_DATE = :REPORTING_DATE \n " //
82+ + "except \n " //
83+ + "select SOME_COLUMN from SOME_OTHER_TABLE where REPORTING_DATE = :REPORTING_DATE \n " //
84+ + "union select SOME_COLUMN from SOME_OTHER_OTHER_TABLE" ;
85+
86+ StringQuery stringQuery = new StringQuery (setQuery , true );
87+ QueryEnhancer queryEnhancer = QueryEnhancerFactory .forQuery (stringQuery );
88+
89+ assertThat (stringQuery .getAlias ()).isNullOrEmpty ();
90+ assertThat (stringQuery .getProjection ()).isEqualToIgnoringCase ("SOME_COLUMN" );
91+ assertThat (stringQuery .hasConstructorExpression ()).isFalse ();
92+
93+ assertThat (queryEnhancer .createCountQueryFor ()).isEqualToIgnoringCase (setQuery );
94+ assertThat (queryEnhancer .applySorting (Sort .by ("SOME_COLUMN" ).ascending ())).endsWith ("ORDER BY SOME_COLUMN ASC" );
95+ assertThat (queryEnhancer .getJoinAliases ()).isEmpty ();
96+ assertThat (queryEnhancer .detectAlias ()).isNullOrEmpty ();
97+ assertThat (queryEnhancer .getProjection ()).isEqualToIgnoringCase ("SOME_COLUMN" );
98+ assertThat (queryEnhancer .hasConstructorExpression ()).isFalse ();
99+ }
100+
101+ @ Test // GH-2578
102+ void deeplyNestedcomplexSetOperationListWorks () {
103+
104+ String setQuery = "SELECT CustomerID FROM (\n " //
105+ + "\t \t \t select * from Customers\n " //
106+ + "\t \t \t except\n " //
107+ + "\t \t \t select * from Customers where country = 'Austria'\n " //
108+ + "\t )\n " //
109+ + "\t except\n " //
110+ + "\t select CustomerID from customers where country = 'Germany'\n " //
111+ + "\t ;" ;
112+
113+ StringQuery stringQuery = new StringQuery (setQuery , true );
114+ QueryEnhancer queryEnhancer = QueryEnhancerFactory .forQuery (stringQuery );
115+
116+ assertThat (stringQuery .getAlias ()).isNullOrEmpty ();
117+ assertThat (stringQuery .getProjection ()).isEqualToIgnoringCase ("CustomerID" );
118+ assertThat (stringQuery .hasConstructorExpression ()).isFalse ();
119+
120+ assertThat (queryEnhancer .createCountQueryFor ()).isEqualToIgnoringCase (setQuery );
121+ assertThat (queryEnhancer .applySorting (Sort .by ("CustomerID" ).descending ())).endsWith ("ORDER BY CustomerID DESC" );
122+ assertThat (queryEnhancer .getJoinAliases ()).isEmpty ();
123+ assertThat (queryEnhancer .detectAlias ()).isNullOrEmpty ();
124+ assertThat (queryEnhancer .getProjection ()).isEqualToIgnoringCase ("CustomerID" );
125+ assertThat (queryEnhancer .hasConstructorExpression ()).isFalse ();
126+ }
127+
128+ @ Test // GH-2578
129+ void valuesStatementsWorks () {
130+
131+ String setQuery = "VALUES (1, 2, 'test')" ;
132+
133+ StringQuery stringQuery = new StringQuery (setQuery , true );
134+ QueryEnhancer queryEnhancer = QueryEnhancerFactory .forQuery (stringQuery );
135+
136+ assertThat (stringQuery .getAlias ()).isNullOrEmpty ();
137+ assertThat (stringQuery .getProjection ()).isNullOrEmpty ();
138+ assertThat (stringQuery .hasConstructorExpression ()).isFalse ();
139+
140+ assertThat (queryEnhancer .createCountQueryFor ()).isEqualToIgnoringCase (setQuery );
141+ assertThat (queryEnhancer .applySorting (Sort .by ("CustomerID" ).descending ())).isEqualTo (setQuery );
142+ assertThat (queryEnhancer .getJoinAliases ()).isEmpty ();
143+ assertThat (queryEnhancer .detectAlias ()).isNullOrEmpty ();
144+ assertThat (queryEnhancer .getProjection ()).isNullOrEmpty ();
145+ assertThat (queryEnhancer .hasConstructorExpression ()).isFalse ();
146+ }
147+
148+ @ Test // GH-2578
149+ void withStatementsWorks () {
150+
151+ String setQuery = "with sample_data(day, value) as (values ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16))) \n "
152+ + "select day, value from sample_data as a" ;
153+
154+ StringQuery stringQuery = new StringQuery (setQuery , true );
155+ QueryEnhancer queryEnhancer = QueryEnhancerFactory .forQuery (stringQuery );
156+
157+ assertThat (stringQuery .getAlias ()).isEqualToIgnoringCase ("a" );
158+ assertThat (stringQuery .getProjection ()).isEqualToIgnoringCase ("day, value" );
159+ assertThat (stringQuery .hasConstructorExpression ()).isFalse ();
160+
161+ assertThat (queryEnhancer .createCountQueryFor ()).isEqualToIgnoringCase (
162+ "with sample_data (day, value) AS (VALUES ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16)))\n "
163+ + "SELECT count(1) FROM sample_data AS a" );
164+ assertThat (queryEnhancer .applySorting (Sort .by ("day" ).descending ())).endsWith ("ORDER BY a.day DESC" );
165+ assertThat (queryEnhancer .getJoinAliases ()).isEmpty ();
166+ assertThat (queryEnhancer .detectAlias ()).isEqualToIgnoringCase ("a" );
167+ assertThat (queryEnhancer .getProjection ()).isEqualToIgnoringCase ("day, value" );
168+ assertThat (queryEnhancer .hasConstructorExpression ()).isFalse ();
169+ }
170+
171+ @ Test // GH-2578
172+ void multipleWithStatementsWorks () {
173+
174+ String setQuery = "with sample_data(day, value) as (values ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16))), test2 as (values (1,2,3)) \n "
175+ + "select day, value from sample_data as a" ;
176+
177+ StringQuery stringQuery = new StringQuery (setQuery , true );
178+ QueryEnhancer queryEnhancer = QueryEnhancerFactory .forQuery (stringQuery );
179+
180+ assertThat (stringQuery .getAlias ()).isEqualToIgnoringCase ("a" );
181+ assertThat (stringQuery .getProjection ()).isEqualToIgnoringCase ("day, value" );
182+ assertThat (stringQuery .hasConstructorExpression ()).isFalse ();
183+
184+ assertThat (queryEnhancer .createCountQueryFor ()).isEqualToIgnoringCase (
185+ "with sample_data (day, value) AS (VALUES ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16))),test2 AS (VALUES (1, 2, 3))\n "
186+ + "SELECT count(1) FROM sample_data AS a" );
187+ assertThat (queryEnhancer .applySorting (Sort .by ("day" ).descending ())).endsWith ("ORDER BY a.day DESC" );
188+ assertThat (queryEnhancer .getJoinAliases ()).isEmpty ();
189+ assertThat (queryEnhancer .detectAlias ()).isEqualToIgnoringCase ("a" );
190+ assertThat (queryEnhancer .getProjection ()).isEqualToIgnoringCase ("day, value" );
191+ assertThat (queryEnhancer .hasConstructorExpression ()).isFalse ();
192+ }
193+
194+ @ ParameterizedTest // GH-2641
195+ @ MethodSource ("mergeStatementWorksSource" )
196+ void mergeStatementWorksWithJSqlParser (String query , String alias ) {
197+
198+ StringQuery stringQuery = new StringQuery (query , true );
199+ QueryEnhancer queryEnhancer = QueryEnhancerFactory .forQuery (stringQuery );
200+
201+ assertThat (queryEnhancer .detectAlias ()).isEqualTo (alias );
202+ assertThat (QueryUtils .detectAlias (query )).isNull ();
203+
204+ assertThat (queryEnhancer .getJoinAliases ()).isEmpty ();
205+ assertThat (queryEnhancer .detectAlias ()).isEqualTo (alias );
206+ assertThat (queryEnhancer .getProjection ()).isEmpty ();
207+ assertThat (queryEnhancer .hasConstructorExpression ()).isFalse ();
208+ }
209+
210+ static Stream <Arguments > mergeStatementWorksSource () {
211+
212+ return Stream .of ( //
213+ Arguments .of (
214+ "merge into a using (select id, value from b) query on (a.id = query.id) when matched then update set a.value = value" ,
215+ "query" ),
216+ Arguments .of (
217+ "merge into a using (select id2, value from b) on (id = id2) when matched then update set a.value = value" ,
218+ null ));
219+ }
30220}
0 commit comments