Merge (Hql|Jpql|Eql)SpecificationTests with their corresponding QueryRendererTests.
Closes #3692
This commit is contained in:
@@ -347,6 +347,38 @@ class EqlQueryRendererTests {
|
||||
assertQuery("SELECT e FROM Employee e WHERE CAST(e.salary NUMERIC(10, 2)) > 0.0");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void substring() {
|
||||
|
||||
assertQuery("select substring(c.number, 1, 2) " + //
|
||||
"from Call c");
|
||||
|
||||
assertQuery("select substring(c.number, 1) " + //
|
||||
"from Call c");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void currentDateFunctions() {
|
||||
|
||||
assertQuery("select CURRENT_DATE " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select CURRENT_TIME " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select CURRENT_TIMESTAMP " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_DATE " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_TIME " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_DATETIME " + //
|
||||
"from Call c ");
|
||||
}
|
||||
|
||||
@Test
|
||||
void pathExpressionsNamedParametersExample() {
|
||||
|
||||
@@ -458,18 +490,13 @@ class EqlQueryRendererTests {
|
||||
* @see #functionInvocationExampleWithCorrection()
|
||||
*/
|
||||
@Test
|
||||
@Disabled(SPEC_FAULT + "FUNCTION calls needs a comparator")
|
||||
void functionInvocationExample_SPEC_BUG() {
|
||||
void functionInvocationExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c
|
||||
FROM Customer c
|
||||
WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionInvocationExampleWithCorrection() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c
|
||||
|
||||
@@ -1,937 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.data.jpa.repository.query.QueryRenderer.TokenRenderer;
|
||||
|
||||
/**
|
||||
* Tests built around examples of EQL found in the JPA spec
|
||||
* https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc<br/>
|
||||
* <br/>
|
||||
* IMPORTANT: Purely verifies the parser without any transformations.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
class EqlSpecificationTests {
|
||||
|
||||
private static final String SPEC_FAULT = "Disabled due to spec fault> ";
|
||||
|
||||
private static String parseWithoutChanges(String query) {
|
||||
|
||||
JpaQueryEnhancer.EqlQueryParser parser = JpaQueryEnhancer.EqlQueryParser.parseQuery(query);
|
||||
|
||||
return TokenRenderer.render(new EqlQueryRenderer().visit(parser.getContext()));
|
||||
}
|
||||
|
||||
private void assertQuery(String query) {
|
||||
|
||||
String slimmedDownQuery = reduceWhitespace(query);
|
||||
assertThat(parseWithoutChanges(slimmedDownQuery)).isEqualTo(slimmedDownQuery);
|
||||
}
|
||||
|
||||
private String reduceWhitespace(String original) {
|
||||
|
||||
return original //
|
||||
.replaceAll("[ \\t\\n]{1,}", " ") //
|
||||
.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#example
|
||||
*/
|
||||
@Test
|
||||
void joinExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order AS o JOIN o.lineItems AS l
|
||||
WHERE l.shipped = FALSE
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#example
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#identification-variables
|
||||
*/
|
||||
@Test
|
||||
void joinExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o JOIN o.lineItems l JOIN l.product p
|
||||
WHERE p.productType = 'office_supplies'
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#range-variable-declarations
|
||||
*/
|
||||
@Test
|
||||
void rangeVariableDeclarations() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o1
|
||||
FROM Order o1, Order o2
|
||||
WHERE o1.quantity > o2.quantity AND
|
||||
o2.customer.lastname = 'Smith' AND
|
||||
o2.customer.firstname = 'John'
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#path-expressions
|
||||
*/
|
||||
@Test
|
||||
void pathExpressionsExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT i.name, VALUE(p)
|
||||
FROM Item i JOIN i.photos p
|
||||
WHERE KEY(p) LIKE '%egret'
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#path-expressions
|
||||
*/
|
||||
@Test
|
||||
void pathExpressionsExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT i.name, p
|
||||
FROM Item i JOIN i.photos p
|
||||
WHERE KEY(p) LIKE '%egret'
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#path-expressions
|
||||
*/
|
||||
@Test
|
||||
void pathExpressionsExample3() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT p.vendor
|
||||
FROM Employee e JOIN e.contactInfo.phones p
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#path-expressions
|
||||
*/
|
||||
@Test
|
||||
void pathExpressionsExample4() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT p.vendor
|
||||
FROM Employee e JOIN e.contactInfo c JOIN c.phones p
|
||||
WHERE e.contactInfo.address.zipcode = '95054'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void pathExpressionSyntaxExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT l.product
|
||||
FROM Order AS o JOIN o.lineItems l
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinsExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c FROM Customer c, Employee e WHERE c.hatsize = e.shoesize
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinsExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c FROM Customer c JOIN c.orders o WHERE c.status = 1
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinsInnerExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c FROM Customer c INNER JOIN c.orders o WHERE c.status = 1
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinsInExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT OBJECT(c) FROM Customer c, IN(c.orders) o WHERE c.status = 1
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void doubleJoinExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT p.vendor
|
||||
FROM Employee e JOIN e.contactInfo c JOIN c.phones p
|
||||
WHERE c.address.zipcode = '95054'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void leftJoinExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT s.name, COUNT(p)
|
||||
FROM Suppliers s LEFT JOIN s.products p
|
||||
GROUP BY s.name
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void leftJoinOnExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT s.name, COUNT(p)
|
||||
FROM Suppliers s LEFT JOIN s.products p
|
||||
ON p.status = 'inStock'
|
||||
GROUP BY s.name
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void leftJoinWhereExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT s.name, COUNT(p)
|
||||
FROM Suppliers s LEFT JOIN s.products p
|
||||
WHERE p.status = 'inStock'
|
||||
GROUP BY s.name
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void leftJoinFetchExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT d
|
||||
FROM Department d LEFT JOIN FETCH d.employees
|
||||
WHERE d.deptno = 1
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionMemberExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o JOIN o.lineItems l
|
||||
WHERE l.product.productType = 'office_supplies'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionMemberInExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o, IN(o.lineItems) l
|
||||
WHERE l.product.productType = 'office_supplies'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClauseExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order AS o JOIN o.lineItems l JOIN l.product p
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClauseDowncastingExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT b.name, b.ISBN
|
||||
FROM Order o JOIN TREAT(o.product AS Book) b
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClauseDowncastingExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) lp
|
||||
WHERE lp.budget > 1000
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #fromClauseDowncastingExample3fixed()
|
||||
*/
|
||||
@Test
|
||||
@Disabled(SPEC_FAULT + "Use double-quotes when it should be using single-quotes for a string literal")
|
||||
void fromClauseDowncastingExample3_SPEC_BUG() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN e.projects p
|
||||
WHERE TREAT(p AS LargeProject).budget > 1000
|
||||
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
|
||||
OR p.description LIKE "cost overrun"
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClauseDowncastingExample3fixed() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN e.projects p
|
||||
WHERE TREAT(p AS LargeProject).budget > 1000
|
||||
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
|
||||
OR p.description LIKE 'cost overrun'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClauseDowncastingExample4() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE TREAT(e AS Exempt).vacationDays > 10
|
||||
OR TREAT(e AS Contractor).hours > 100
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void substring() {
|
||||
|
||||
assertQuery("select substring(c.number, 1, 2) " + //
|
||||
"from Call c");
|
||||
|
||||
assertQuery("select substring(c.number, 1) " + //
|
||||
"from Call c");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void currentDateFunctions() {
|
||||
|
||||
assertQuery("select CURRENT_DATE " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select CURRENT_TIME " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select CURRENT_TIMESTAMP " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_DATE " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_TIME " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_DATETIME " + //
|
||||
"from Call c ");
|
||||
}
|
||||
|
||||
@Test
|
||||
void pathExpressionsNamedParametersExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c
|
||||
FROM Customer c
|
||||
WHERE c.status = :stat
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void betweenExpressionsExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT t
|
||||
FROM CreditCard c JOIN c.transactionHistory t
|
||||
WHERE c.holder.name = 'John Doe' AND INDEX(t) BETWEEN 0 AND 9
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void isEmptyExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE o.lineItems IS EMPTY
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void memberOfExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT p
|
||||
FROM Person p
|
||||
WHERE 'Joe' MEMBER OF p.nicknames
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void existsSubSelectExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE EXISTS (SELECT spouseEmp
|
||||
FROM Employee spouseEmp
|
||||
WHERE spouseEmp = emp.spouse)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void allExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT emp
|
||||
FROM Employee emp
|
||||
WHERE emp.salary > ALL (SELECT m.salary
|
||||
FROM Manager m
|
||||
WHERE m.department = emp.department)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void existsSubSelectExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE EXISTS (SELECT spouseEmp
|
||||
FROM Employee spouseEmp
|
||||
WHERE spouseEmp = emp.spouse)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void subselectNumericComparisonExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c
|
||||
FROM Customer c
|
||||
WHERE (SELECT AVG(o.price) FROM c.orders o) > 100
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void subselectNumericComparisonExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT goodCustomer
|
||||
FROM Customer goodCustomer
|
||||
WHERE goodCustomer.balanceOwed < (SELECT AVG(c.balanceOwed) / 2.0 FROM Customer c)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT w.name
|
||||
FROM Course c JOIN c.studentWaitlist w
|
||||
WHERE c.name = 'Calculus'
|
||||
AND INDEX(w) = 0
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #functionInvocationExampleWithCorrection()
|
||||
*/
|
||||
@Test
|
||||
@Disabled(SPEC_FAULT + "FUNCTION calls needs a comparator")
|
||||
void functionInvocationExample_SPEC_BUG() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c
|
||||
FROM Customer c
|
||||
WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionInvocationExampleWithCorrection() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c
|
||||
FROM Customer c
|
||||
WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) = TRUE
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateCaseExample1() {
|
||||
|
||||
assertQuery("""
|
||||
UPDATE Employee e
|
||||
SET e.salary =
|
||||
CASE WHEN e.rating = 1 THEN e.salary * 1.1
|
||||
WHEN e.rating = 2 THEN e.salary * 1.05
|
||||
ELSE e.salary * 1.01
|
||||
END
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateCaseExample2() {
|
||||
|
||||
assertQuery("""
|
||||
UPDATE Employee e
|
||||
SET e.salary =
|
||||
CASE e.rating WHEN 1 THEN e.salary * 1.1
|
||||
WHEN 2 THEN e.salary * 1.05
|
||||
ELSE e.salary * 1.01
|
||||
END
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectCaseExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e.name,
|
||||
CASE TYPE(e) WHEN Exempt THEN 'Exempt'
|
||||
WHEN Contractor THEN 'Contractor'
|
||||
WHEN Intern THEN 'Intern'
|
||||
ELSE 'NonExempt'
|
||||
END
|
||||
FROM Employee e
|
||||
WHERE e.dept.name = 'Engineering'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectCaseExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e.name,
|
||||
f.name,
|
||||
CONCAT(CASE WHEN f.annualMiles > 50000 THEN 'Platinum '
|
||||
WHEN f.annualMiles > 25000 THEN 'Gold '
|
||||
ELSE ''
|
||||
END,
|
||||
'Frequent Flyer')
|
||||
FROM Employee e JOIN e.frequentFlierPlan f
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e
|
||||
FROM Employee e
|
||||
WHERE TYPE(e) IN (Exempt, Contractor)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e
|
||||
FROM Employee e
|
||||
WHERE TYPE(e) IN (:empType1, :empType2)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest3() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e
|
||||
FROM Employee e
|
||||
WHERE TYPE(e) IN :empTypes
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest4() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT TYPE(e)
|
||||
FROM Employee e
|
||||
WHERE TYPE(e) <> Exempt
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest5() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c.status, AVG(c.filledOrderCount), COUNT(c)
|
||||
FROM Customer c
|
||||
GROUP BY c.status
|
||||
HAVING c.status IN (1, 2)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest6() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c.country, COUNT(c)
|
||||
FROM Customer c
|
||||
GROUP BY c.country
|
||||
HAVING COUNT(c) > 30
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest7() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c, COUNT(o)
|
||||
FROM Customer c JOIN c.orders o
|
||||
GROUP BY c
|
||||
HAVING COUNT(o) >= 5
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest8() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c.id, c.status
|
||||
FROM Customer c JOIN c.orders o
|
||||
WHERE o.count > 100
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest9() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT v.location.street, KEY(i).title, VALUE(i)
|
||||
FROM VideoStore v JOIN v.videoInventory i
|
||||
WHERE v.location.zipcode = '94301' AND VALUE(i) > 0
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest10() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o.lineItems FROM Order AS o
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest11() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c, COUNT(l) AS itemCount
|
||||
FROM Customer c JOIN c.Orders o JOIN o.lineItems l
|
||||
WHERE c.address.state = 'CA'
|
||||
GROUP BY c
|
||||
ORDER BY itemCount
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest12() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT NEW com.acme.example.CustomerDetails(c.id, c.status, o.count)
|
||||
FROM Customer c JOIN c.orders o
|
||||
WHERE o.count > 100
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest13() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e.address AS addr
|
||||
FROM Employee e
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest14() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT AVG(o.quantity) FROM Order o
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest15() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT SUM(l.price)
|
||||
FROM Order o JOIN o.lineItems l JOIN o.customer c
|
||||
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest16() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT COUNT(o) FROM Order o
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest17() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT COUNT(l.price)
|
||||
FROM Order o JOIN o.lineItems l JOIN o.customer c
|
||||
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest18() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT COUNT(l)
|
||||
FROM Order o JOIN o.lineItems l JOIN o.customer c
|
||||
WHERE c.lastname = 'Smith' AND c.firstname = 'John' AND l.price IS NOT NULL
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest19() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Customer c JOIN c.orders o JOIN c.address a
|
||||
WHERE a.state = 'CA'
|
||||
ORDER BY o.quantity DESC, o.totalcost
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest20() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o.quantity, a.zipcode
|
||||
FROM Customer c JOIN c.orders o JOIN c.address a
|
||||
WHERE a.state = 'CA'
|
||||
ORDER BY o.quantity, a.zipcode
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest21() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o.quantity, o.cost * 1.08 AS taxedCost, a.zipcode
|
||||
FROM Customer c JOIN c.orders o JOIN c.address a
|
||||
WHERE a.state = 'CA' AND a.county = 'Santa Clara'
|
||||
ORDER BY o.quantity, taxedCost, a.zipcode
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest22() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT AVG(o.quantity) as q, a.zipcode
|
||||
FROM Customer c JOIN c.orders o JOIN c.address a
|
||||
WHERE a.state = 'CA'
|
||||
GROUP BY a.zipcode
|
||||
ORDER BY q DESC
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest23() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT p.product_name
|
||||
FROM Order o JOIN o.lineItems l JOIN l.product p JOIN o.customer c
|
||||
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
|
||||
ORDER BY p.price
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* This query is specifically dubbed illegal in the spec. It may actually be failing for a different reason.
|
||||
*/
|
||||
@Test
|
||||
void theRest24() {
|
||||
|
||||
assertThatExceptionOfType(BadJpqlGrammarException.class).isThrownBy(() -> {
|
||||
assertQuery("""
|
||||
SELECT p.product_name
|
||||
FROM Order o, IN(o.lineItems) l JOIN o.customer c
|
||||
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
|
||||
ORDER BY o.quantity
|
||||
""");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest25() {
|
||||
|
||||
assertQuery("""
|
||||
DELETE
|
||||
FROM Customer c
|
||||
WHERE c.status = 'inactive'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest26() {
|
||||
|
||||
assertQuery("""
|
||||
DELETE
|
||||
FROM Customer c
|
||||
WHERE c.status = 'inactive'
|
||||
AND c.orders IS EMPTY
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest27() {
|
||||
|
||||
assertQuery("""
|
||||
UPDATE Customer c
|
||||
SET c.status = 'outstanding'
|
||||
WHERE c.balance < 10000
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest28() {
|
||||
|
||||
assertQuery("""
|
||||
UPDATE Employee e
|
||||
SET e.address.building = 22
|
||||
WHERE e.address.building = 14
|
||||
AND e.address.city = 'Santa Clara'
|
||||
AND e.project = 'Jakarta EE'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest29() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest30() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE o.shippingAddress.state = 'CA'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest31() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o.shippingAddress.state
|
||||
FROM Order o
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest32() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o JOIN o.lineItems l
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest33() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE o.lineItems IS NOT EMPTY
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest34() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE o.lineItems IS EMPTY
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest35() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o JOIN o.lineItems l
|
||||
WHERE l.shipped = FALSE
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest36() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE
|
||||
NOT (o.shippingAddress.state = o.billingAddress.state AND
|
||||
o.shippingAddress.city = o.billingAddress.city AND
|
||||
o.shippingAddress.street = o.billingAddress.street)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest37() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE o.shippingAddress <> o.billingAddress
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest38() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o JOIN o.lineItems l
|
||||
WHERE l.product.name = ?1
|
||||
""");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,321 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
/**
|
||||
* Test to verify compliance of {@link JpqlParser} with standard SQL. Other than {@link JpqlSpecificationTests} tests in
|
||||
* this class check that the parser follows a lenient approach and does not error on well known concepts like numeric
|
||||
* suffix.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class JpqlComplianceTests {
|
||||
|
||||
private static String parseWithoutChanges(String query) {
|
||||
|
||||
JpaQueryEnhancer.JpqlQueryParser parser = JpaQueryEnhancer.JpqlQueryParser.parseQuery(query);
|
||||
|
||||
return QueryRenderer.render(new JpqlQueryRenderer().visit(parser.getContext()));
|
||||
}
|
||||
|
||||
private void assertQuery(String query) {
|
||||
|
||||
String slimmedDownQuery = reduceWhitespace(query);
|
||||
assertThat(parseWithoutChanges(slimmedDownQuery)).isEqualTo(slimmedDownQuery);
|
||||
}
|
||||
|
||||
private String reduceWhitespace(String original) {
|
||||
|
||||
return original //
|
||||
.replaceAll("[ \\t\\n]{1,}", " ") //
|
||||
.trim();
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectQueries() {
|
||||
|
||||
assertQuery("Select e FROM Employee e WHERE e.salary > 100000");
|
||||
assertQuery("Select e FROM Employee e WHERE e.id = :id");
|
||||
assertQuery("Select MAX(e.salary) FROM Employee e");
|
||||
assertQuery("Select e.firstName FROM Employee e");
|
||||
assertQuery("Select e.firstName, e.lastName FROM Employee e");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectClause() {
|
||||
|
||||
assertQuery("SELECT COUNT(e) FROM Employee e");
|
||||
assertQuery("SELECT MAX(e.salary) FROM Employee e");
|
||||
assertQuery("SELECT NEW com.acme.reports.EmpReport(e.firstName, e.lastName, e.salary) FROM Employee e");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClause() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e");
|
||||
assertQuery("SELECT e, a FROM Employee e, MailingAddress a WHERE e.address = a.address");
|
||||
assertQuery("SELECT e FROM com.acme.Employee e");
|
||||
}
|
||||
|
||||
@Test
|
||||
void join() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e JOIN e.address a WHERE a.city = :city");
|
||||
assertQuery("SELECT e FROM Employee e JOIN e.projects p JOIN e.projects p2 WHERE p.name = :p1 AND p2.name = :p2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinFetch() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e JOIN FETCH e.address");
|
||||
assertQuery("SELECT e FROM Employee e JOIN FETCH e.address a ORDER BY a.city");
|
||||
assertQuery("SELECT e FROM Employee e JOIN FETCH e.address AS a ORDER BY a.city");
|
||||
}
|
||||
|
||||
@Test
|
||||
void leftJoin() {
|
||||
assertQuery("SELECT e FROM Employee e LEFT JOIN e.address a ORDER BY a.city");
|
||||
}
|
||||
|
||||
@Test // GH-3277
|
||||
void numericLiterals() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.id = 1234");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.id = 1234L");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14F");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14e32D");
|
||||
}
|
||||
|
||||
@Test // GH-3308
|
||||
void newWithStrings() {
|
||||
assertQuery("select new com.example.demo.SampleObject(se.id, se.sampleValue, \"java\") from SampleEntity se");
|
||||
}
|
||||
|
||||
@Test
|
||||
void orderByClause() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e ORDER BY e.lastName ASC, e.firstName ASC"); // Typo in EQL document
|
||||
assertQuery("SELECT e FROM Employee e LEFT JOIN e.manager m ORDER BY m.lastName NULLS FIRST");
|
||||
assertQuery("SELECT e FROM Employee e ORDER BY e.address");
|
||||
}
|
||||
|
||||
@Test
|
||||
void groupByClause() {
|
||||
|
||||
assertQuery("SELECT AVG(e.salary), e.address.city FROM Employee e GROUP BY e.address.city");
|
||||
assertQuery("SELECT e, COUNT(p) FROM Employee e LEFT JOIN e.projects p GROUP BY e");
|
||||
}
|
||||
|
||||
@Test
|
||||
void havingClause() {
|
||||
assertQuery(
|
||||
"SELECT AVG(e.salary), e.address.city FROM Employee e GROUP BY e.address.city HAVING AVG(e.salary) > 100000");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void union() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT MAX(e.salary) FROM Employee e WHERE e.address.city = :city1
|
||||
UNION SELECT MAX(e.salary) FROM Employee e WHERE e.address.city = :city2
|
||||
""");
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode1
|
||||
INTERSECT SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode2
|
||||
""");
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
EXCEPT SELECT e FROM Employee e WHERE e.salary > e.manager.salary
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whereClause() {
|
||||
// TBD
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateQueries() {
|
||||
assertQuery("UPDATE Employee e SET e.salary = 60000 WHERE e.salary = 50000");
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteQueries() {
|
||||
assertQuery("DELETE FROM Employee e WHERE e.department IS NULL");
|
||||
}
|
||||
|
||||
@Test
|
||||
void literals() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.name = 'Bob'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.id = 1234");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.id = 1234L");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14F");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14e32D");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.active = TRUE");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.startDate = {d'2012-01-03'}");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.startTime = {t'09:00:00'}");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.version = {ts'2012-01-03 09:00:00.000000001'}");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.gender = org.acme.Gender.MALE");
|
||||
assertQuery("UPDATE Employee e SET e.manager = NULL WHERE e.manager = :manager");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionsInSelect() {
|
||||
|
||||
assertQuery("SELECT e.salary - 1000 FROM Employee e");
|
||||
assertQuery("SELECT e.salary + 1000 FROM Employee e");
|
||||
assertQuery("SELECT e.salary * 2 FROM Employee e");
|
||||
assertQuery("SELECT e.salary * 2.0 FROM Employee e");
|
||||
assertQuery("SELECT e.salary / 2 FROM Employee e");
|
||||
assertQuery("SELECT e.salary / 2.0 FROM Employee e");
|
||||
assertQuery("SELECT ABS(e.salary - e.manager.salary) FROM Employee e");
|
||||
assertQuery(
|
||||
"select e from Employee e where case e.firstName when 'Bob' then 'Robert' when 'Jill' then 'Gillian' else '' end = 'Robert'");
|
||||
assertQuery(
|
||||
"select case when e.firstName = 'Bob' then 'Robert' when e.firstName = 'Jill' then 'Gillian' else '' end from Employee e where e.firstName = 'Bob' or e.firstName = 'Jill'");
|
||||
assertQuery(
|
||||
"select e from Employee e where case when e.firstName = 'Bob' then 'Robert' when e.firstName = 'Jill' then 'Gillian' else '' end = 'Robert'");
|
||||
assertQuery("SELECT COALESCE(e.salary, 0) FROM Employee e");
|
||||
assertQuery("SELECT CONCAT(e.firstName, ' ', e.lastName) FROM Employee e");
|
||||
assertQuery("SELECT e.name, CURRENT_DATE FROM Employee e");
|
||||
assertQuery("SELECT e.name, CURRENT_TIME FROM Employee e");
|
||||
assertQuery("SELECT e.name, CURRENT_TIMESTAMP FROM Employee e");
|
||||
assertQuery("SELECT LENGTH(e.lastName) FROM Employee e");
|
||||
assertQuery("SELECT LOWER(e.lastName) FROM Employee e");
|
||||
assertQuery("SELECT MOD(e.hoursWorked, 8) FROM Employee e");
|
||||
assertQuery("SELECT NULLIF(e.salary, 0) FROM Employee e");
|
||||
assertQuery("SELECT SQRT(o.RESULT) FROM Output o");
|
||||
assertQuery("SELECT SUBSTRING(e.lastName, 0, 2) FROM Employee e");
|
||||
assertQuery(
|
||||
"SELECT TRIM(TRAILING FROM e.lastName), TRIM(e.lastName), TRIM(LEADING '-' FROM e.lastName) FROM Employee e");
|
||||
assertQuery("SELECT UPPER(e.lastName) FROM Employee e");
|
||||
assertQuery("SELECT CAST(e.salary NUMERIC(10, 2)) FROM Employee e");
|
||||
assertQuery("SELECT EXTRACT(YEAR FROM e.startDate) FROM Employee e");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionsInWhere() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary - 1000 > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary + 1000 > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary * 2 > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary * 2.0 > 0.0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary / 2 > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary / 2.0 > 0.0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE ABS(e.salary - e.manager.salary) > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE COALESCE(e.salary, 0) > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE CONCAT(e.firstName, ' ', e.lastName) = 'Bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE CURRENT_DATE > CURRENT_TIME");
|
||||
assertQuery("SELECT e FROM Employee e WHERE CURRENT_TIME > CURRENT_TIMESTAMP");
|
||||
assertQuery("SELECT e FROM Employee e WHERE LENGTH(e.lastName) > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE LOWER(e.lastName) = 'bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE MOD(e.hoursWorked, 8) > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE SQRT(o.RESULT) > 0.0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE SUBSTRING(e.lastName, 0, 2) = 'Bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE TRIM(TRAILING FROM e.lastName) = 'Bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE TRIM(e.lastName) = 'Bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE TRIM(LEADING '-' FROM e.lastName) = 'Bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE UPPER(e.lastName) = 'BILBO'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE CAST(e.salary NUMERIC(10, 2)) > 0.0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE EXTRACT(YEAR FROM e.startDate) = '2023'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void specialOperators() {
|
||||
|
||||
assertQuery("SELECT toDo FROM Employee e JOIN e.toDoList toDo WHERE INDEX(toDo) = 1");
|
||||
assertQuery("SELECT p FROM Employee e JOIN e.priorities p WHERE KEY(p) = 'high'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE SIZE(e.managedEmployees) < 2");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.managedEmployees IS EMPTY");
|
||||
assertQuery("SELECT e FROM Employee e WHERE 'write code' MEMBER OF e.responsibilities");
|
||||
assertQuery("SELECT p FROM Project p WHERE TYPE(p) = LargeProject");
|
||||
|
||||
/**
|
||||
* NOTE: The following query has been altered to properly align with EclipseLink test code despite NOT matching
|
||||
* their ref docs. See https://github.com/eclipse-ee4j/eclipselink/issues/1949 for more details.
|
||||
*/
|
||||
assertQuery("SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) p WHERE p.budget > 1000000");
|
||||
|
||||
assertQuery("SELECT p FROM Phone p WHERE FUNCTION('TO_NUMBER', p.areaCode) > 613");
|
||||
}
|
||||
|
||||
@Test // GH-3314
|
||||
void isNullAndIsNotNull() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e WHERE (e.active IS null OR e.active = true)");
|
||||
assertQuery("SELECT e FROM Employee e WHERE (e.active IS NULL OR e.active = true)");
|
||||
assertQuery("SELECT e FROM Employee e WHERE (e.active IS NOT null OR e.active = true)");
|
||||
assertQuery("SELECT e FROM Employee e WHERE (e.active IS NOT NULL OR e.active = true)");
|
||||
}
|
||||
|
||||
@Test // GH-3496
|
||||
void lateralShouldBeAValidParameter() {
|
||||
|
||||
assertQuery("select e from Employee e where e.lateral = :_lateral");
|
||||
assertQuery("select te from TestEntity te where te.lateral = :lateral");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void intersect() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode1
|
||||
INTERSECT SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode2
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void except() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
EXCEPT SELECT e FROM Employee e WHERE e.salary > e.manager.salary
|
||||
""");
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3136
|
||||
@ValueSource(strings = { "STRING", "INTEGER", "FLOAT", "DOUBLE" })
|
||||
void cast(String targetType) {
|
||||
assertQuery("SELECT CAST(e.salary AS %s) FROM Employee e".formatted(targetType));
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3136
|
||||
@ValueSource(strings = { "LEFT", "RIGHT" })
|
||||
void leftRightStringFunctions(String keyword) {
|
||||
assertQuery("SELECT %s(e.name, 3) FROM Employee e".formatted(keyword));
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void replaceStringFunctions() {
|
||||
assertQuery("SELECT REPLACE(e.name, 'o', 'a') FROM Employee e");
|
||||
assertQuery("SELECT REPLACE(e.name, ' ', '_') FROM Employee e");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void stringConcatWithPipes() {
|
||||
assertQuery("SELECT e.firstname || e.lastname AS name FROM Employee e");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -70,6 +70,266 @@ class JpqlQueryRendererTests {
|
||||
.trim();
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectQueries() {
|
||||
|
||||
assertQuery("Select e FROM Employee e WHERE e.salary > 100000");
|
||||
assertQuery("Select e FROM Employee e WHERE e.id = :id");
|
||||
assertQuery("Select MAX(e.salary) FROM Employee e");
|
||||
assertQuery("Select e.firstName FROM Employee e");
|
||||
assertQuery("Select e.firstName, e.lastName FROM Employee e");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectClause() {
|
||||
|
||||
assertQuery("SELECT COUNT(e) FROM Employee e");
|
||||
assertQuery("SELECT MAX(e.salary) FROM Employee e");
|
||||
assertQuery("SELECT NEW com.acme.reports.EmpReport(e.firstName, e.lastName, e.salary) FROM Employee e");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClause() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e");
|
||||
assertQuery("SELECT e, a FROM Employee e, MailingAddress a WHERE e.address = a.address");
|
||||
assertQuery("SELECT e FROM com.acme.Employee e");
|
||||
}
|
||||
|
||||
@Test
|
||||
void join() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e JOIN e.address a WHERE a.city = :city");
|
||||
assertQuery("SELECT e FROM Employee e JOIN e.projects p JOIN e.projects p2 WHERE p.name = :p1 AND p2.name = :p2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinFetch() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e JOIN FETCH e.address");
|
||||
assertQuery("SELECT e FROM Employee e JOIN FETCH e.address a ORDER BY a.city");
|
||||
assertQuery("SELECT e FROM Employee e JOIN FETCH e.address AS a ORDER BY a.city");
|
||||
}
|
||||
|
||||
@Test
|
||||
void leftJoin() {
|
||||
assertQuery("SELECT e FROM Employee e LEFT JOIN e.address a ORDER BY a.city");
|
||||
}
|
||||
|
||||
@Test // GH-3277
|
||||
void numericLiterals() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.id = 1234");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.id = 1234L");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14F");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14e32D");
|
||||
}
|
||||
|
||||
@Test // GH-3308
|
||||
void newWithStrings() {
|
||||
assertQuery("select new com.example.demo.SampleObject(se.id, se.sampleValue, \"java\") from SampleEntity se");
|
||||
}
|
||||
|
||||
@Test
|
||||
void orderByClause() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e ORDER BY e.lastName ASC, e.firstName ASC"); // Typo in EQL document
|
||||
assertQuery("SELECT e FROM Employee e LEFT JOIN e.manager m ORDER BY m.lastName NULLS FIRST");
|
||||
assertQuery("SELECT e FROM Employee e ORDER BY e.address");
|
||||
}
|
||||
|
||||
@Test
|
||||
void groupByClause() {
|
||||
|
||||
assertQuery("SELECT AVG(e.salary), e.address.city FROM Employee e GROUP BY e.address.city");
|
||||
assertQuery("SELECT e, COUNT(p) FROM Employee e LEFT JOIN e.projects p GROUP BY e");
|
||||
}
|
||||
|
||||
@Test
|
||||
void havingClause() {
|
||||
assertQuery(
|
||||
"SELECT AVG(e.salary), e.address.city FROM Employee e GROUP BY e.address.city HAVING AVG(e.salary) > 100000");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void union() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT MAX(e.salary) FROM Employee e WHERE e.address.city = :city1
|
||||
UNION SELECT MAX(e.salary) FROM Employee e WHERE e.address.city = :city2
|
||||
""");
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode1
|
||||
INTERSECT SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode2
|
||||
""");
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
EXCEPT SELECT e FROM Employee e WHERE e.salary > e.manager.salary
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whereClause() {
|
||||
// TBD
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateQueries() {
|
||||
assertQuery("UPDATE Employee e SET e.salary = 60000 WHERE e.salary = 50000");
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteQueries() {
|
||||
assertQuery("DELETE FROM Employee e WHERE e.department IS NULL");
|
||||
}
|
||||
|
||||
@Test
|
||||
void literals() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.name = 'Bob'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.id = 1234");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.id = 1234L");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14F");
|
||||
assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14e32D");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.active = TRUE");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.startDate = {d'2012-01-03'}");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.startTime = {t'09:00:00'}");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.version = {ts'2012-01-03 09:00:00.000000001'}");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.gender = org.acme.Gender.MALE");
|
||||
assertQuery("UPDATE Employee e SET e.manager = NULL WHERE e.manager = :manager");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionsInSelect() {
|
||||
|
||||
assertQuery("SELECT e.salary - 1000 FROM Employee e");
|
||||
assertQuery("SELECT e.salary + 1000 FROM Employee e");
|
||||
assertQuery("SELECT e.salary * 2 FROM Employee e");
|
||||
assertQuery("SELECT e.salary * 2.0 FROM Employee e");
|
||||
assertQuery("SELECT e.salary / 2 FROM Employee e");
|
||||
assertQuery("SELECT e.salary / 2.0 FROM Employee e");
|
||||
assertQuery("SELECT ABS(e.salary - e.manager.salary) FROM Employee e");
|
||||
assertQuery(
|
||||
"select e from Employee e where case e.firstName when 'Bob' then 'Robert' when 'Jill' then 'Gillian' else '' end = 'Robert'");
|
||||
assertQuery(
|
||||
"select case when e.firstName = 'Bob' then 'Robert' when e.firstName = 'Jill' then 'Gillian' else '' end from Employee e where e.firstName = 'Bob' or e.firstName = 'Jill'");
|
||||
assertQuery(
|
||||
"select e from Employee e where case when e.firstName = 'Bob' then 'Robert' when e.firstName = 'Jill' then 'Gillian' else '' end = 'Robert'");
|
||||
assertQuery("SELECT COALESCE(e.salary, 0) FROM Employee e");
|
||||
assertQuery("SELECT CONCAT(e.firstName, ' ', e.lastName) FROM Employee e");
|
||||
assertQuery("SELECT e.name, CURRENT_DATE FROM Employee e");
|
||||
assertQuery("SELECT e.name, CURRENT_TIME FROM Employee e");
|
||||
assertQuery("SELECT e.name, CURRENT_TIMESTAMP FROM Employee e");
|
||||
assertQuery("SELECT LENGTH(e.lastName) FROM Employee e");
|
||||
assertQuery("SELECT LOWER(e.lastName) FROM Employee e");
|
||||
assertQuery("SELECT MOD(e.hoursWorked, 8) FROM Employee e");
|
||||
assertQuery("SELECT NULLIF(e.salary, 0) FROM Employee e");
|
||||
assertQuery("SELECT SQRT(o.RESULT) FROM Output o");
|
||||
assertQuery("SELECT SUBSTRING(e.lastName, 0, 2) FROM Employee e");
|
||||
assertQuery(
|
||||
"SELECT TRIM(TRAILING FROM e.lastName), TRIM(e.lastName), TRIM(LEADING '-' FROM e.lastName) FROM Employee e");
|
||||
assertQuery("SELECT UPPER(e.lastName) FROM Employee e");
|
||||
assertQuery("SELECT CAST(e.salary NUMERIC(10, 2)) FROM Employee e");
|
||||
assertQuery("SELECT EXTRACT(YEAR FROM e.startDate) FROM Employee e");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionsInWhere() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary - 1000 > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary + 1000 > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary * 2 > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary * 2.0 > 0.0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary / 2 > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.salary / 2.0 > 0.0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE ABS(e.salary - e.manager.salary) > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE COALESCE(e.salary, 0) > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE CONCAT(e.firstName, ' ', e.lastName) = 'Bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE CURRENT_DATE > CURRENT_TIME");
|
||||
assertQuery("SELECT e FROM Employee e WHERE CURRENT_TIME > CURRENT_TIMESTAMP");
|
||||
assertQuery("SELECT e FROM Employee e WHERE LENGTH(e.lastName) > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE LOWER(e.lastName) = 'bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE MOD(e.hoursWorked, 8) > 0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE SQRT(o.RESULT) > 0.0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE SUBSTRING(e.lastName, 0, 2) = 'Bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE TRIM(TRAILING FROM e.lastName) = 'Bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE TRIM(e.lastName) = 'Bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE TRIM(LEADING '-' FROM e.lastName) = 'Bilbo'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE UPPER(e.lastName) = 'BILBO'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE CAST(e.salary NUMERIC(10, 2)) > 0.0");
|
||||
assertQuery("SELECT e FROM Employee e WHERE EXTRACT(YEAR FROM e.startDate) = '2023'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void specialOperators() {
|
||||
|
||||
assertQuery("SELECT toDo FROM Employee e JOIN e.toDoList toDo WHERE INDEX(toDo) = 1");
|
||||
assertQuery("SELECT p FROM Employee e JOIN e.priorities p WHERE KEY(p) = 'high'");
|
||||
assertQuery("SELECT e FROM Employee e WHERE SIZE(e.managedEmployees) < 2");
|
||||
assertQuery("SELECT e FROM Employee e WHERE e.managedEmployees IS EMPTY");
|
||||
assertQuery("SELECT e FROM Employee e WHERE 'write code' MEMBER OF e.responsibilities");
|
||||
assertQuery("SELECT p FROM Project p WHERE TYPE(p) = LargeProject");
|
||||
|
||||
/**
|
||||
* NOTE: The following query has been altered to properly align with EclipseLink test code despite NOT matching
|
||||
* their ref docs. See https://github.com/eclipse-ee4j/eclipselink/issues/1949 for more details.
|
||||
*/
|
||||
assertQuery("SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) p WHERE p.budget > 1000000");
|
||||
|
||||
assertQuery("SELECT p FROM Phone p WHERE FUNCTION('TO_NUMBER', p.areaCode) > 613");
|
||||
}
|
||||
|
||||
@Test // GH-3314
|
||||
void isNullAndIsNotNull() {
|
||||
|
||||
assertQuery("SELECT e FROM Employee e WHERE (e.active IS null OR e.active = true)");
|
||||
assertQuery("SELECT e FROM Employee e WHERE (e.active IS NULL OR e.active = true)");
|
||||
assertQuery("SELECT e FROM Employee e WHERE (e.active IS NOT null OR e.active = true)");
|
||||
assertQuery("SELECT e FROM Employee e WHERE (e.active IS NOT NULL OR e.active = true)");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void intersect() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode1
|
||||
INTERSECT SELECT e FROM Employee e JOIN e.phones p WHERE p.areaCode = :areaCode2
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void except() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
EXCEPT SELECT e FROM Employee e WHERE e.salary > e.manager.salary
|
||||
""");
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3136
|
||||
@ValueSource(strings = { "STRING", "INTEGER", "FLOAT", "DOUBLE" })
|
||||
void cast(String targetType) {
|
||||
assertQuery("SELECT CAST(e.salary AS %s) FROM Employee e".formatted(targetType));
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3136
|
||||
@ValueSource(strings = { "LEFT", "RIGHT" })
|
||||
void leftRightStringFunctions(String keyword) {
|
||||
assertQuery("SELECT %s(e.name, 3) FROM Employee e".formatted(keyword));
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void replaceStringFunctions() {
|
||||
assertQuery("SELECT REPLACE(e.name, 'o', 'a') FROM Employee e");
|
||||
assertQuery("SELECT REPLACE(e.name, ' ', '_') FROM Employee e");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void stringConcatWithPipes() {
|
||||
assertQuery("SELECT e.firstname || e.lastname AS name FROM Employee e");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#example
|
||||
*/
|
||||
@@ -348,6 +608,38 @@ class JpqlQueryRendererTests {
|
||||
assertQuery("SELECT e FROM Employee e WHERE CAST(e.salary NUMERIC(10, 2)) > 0.0");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void substring() {
|
||||
|
||||
assertQuery("select substring(c.number, 1, 2) " + //
|
||||
"from Call c");
|
||||
|
||||
assertQuery("select substring(c.number, 1) " + //
|
||||
"from Call c");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void currentDateFunctions() {
|
||||
|
||||
assertQuery("select CURRENT_DATE " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select CURRENT_TIME " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select CURRENT_TIMESTAMP " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_DATE " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_TIME " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_DATETIME " + //
|
||||
"from Call c ");
|
||||
}
|
||||
|
||||
@Test
|
||||
void pathExpressionsNamedParametersExample() {
|
||||
|
||||
|
||||
@@ -1,941 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.data.jpa.repository.query.QueryRenderer.TokenRenderer;
|
||||
|
||||
/**
|
||||
* Tests built around examples of JPQL found in the JPA spec
|
||||
* https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc<br/>
|
||||
* <br/>
|
||||
* IMPORTANT: Purely verifies the parser without any transformations.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @since 3.1
|
||||
*/
|
||||
class JpqlSpecificationTests {
|
||||
|
||||
private static final String SPEC_FAULT = "Disabled due to spec fault> ";
|
||||
|
||||
/**
|
||||
* Parse the query using {@link HqlParser} then run it through the query-preserving {@link HqlQueryRenderer}.
|
||||
*/
|
||||
private static String parseWithoutChanges(String query) {
|
||||
|
||||
JpaQueryEnhancer.JpqlQueryParser parser = JpaQueryEnhancer.JpqlQueryParser.parseQuery(query);
|
||||
|
||||
return TokenRenderer.render(new JpqlQueryRenderer().visit(parser.getContext()));
|
||||
}
|
||||
|
||||
private void assertQuery(String query) {
|
||||
|
||||
String slimmedDownQuery = reduceWhitespace(query);
|
||||
assertThat(parseWithoutChanges(slimmedDownQuery)).isEqualTo(slimmedDownQuery);
|
||||
}
|
||||
|
||||
private String reduceWhitespace(String original) {
|
||||
|
||||
return original //
|
||||
.replaceAll("[ \\t\\n]{1,}", " ") //
|
||||
.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#example
|
||||
*/
|
||||
@Test
|
||||
void joinExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order AS o JOIN o.lineItems AS l
|
||||
WHERE l.shipped = FALSE
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#example
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#identification-variables
|
||||
*/
|
||||
@Test
|
||||
void joinExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o JOIN o.lineItems l JOIN l.product p
|
||||
WHERE p.productType = 'office_supplies'
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#range-variable-declarations
|
||||
*/
|
||||
@Test
|
||||
void rangeVariableDeclarations() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o1
|
||||
FROM Order o1, Order o2
|
||||
WHERE o1.quantity > o2.quantity AND
|
||||
o2.customer.lastname = 'Smith' AND
|
||||
o2.customer.firstname = 'John'
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#path-expressions
|
||||
*/
|
||||
@Test
|
||||
void pathExpressionsExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT i.name, VALUE(p)
|
||||
FROM Item i JOIN i.photos p
|
||||
WHERE KEY(p) LIKE '%egret'
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#path-expressions
|
||||
*/
|
||||
@Test
|
||||
void pathExpressionsExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT i.name, p
|
||||
FROM Item i JOIN i.photos p
|
||||
WHERE KEY(p) LIKE '%egret'
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#path-expressions
|
||||
*/
|
||||
@Test
|
||||
void pathExpressionsExample3() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT p.vendor
|
||||
FROM Employee e JOIN e.contactInfo.phones p
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/jakartaee/persistence/blob/master/spec/src/main/asciidoc/ch04-query-language.adoc#path-expressions
|
||||
*/
|
||||
@Test
|
||||
void pathExpressionsExample4() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT p.vendor
|
||||
FROM Employee e JOIN e.contactInfo c JOIN c.phones p
|
||||
WHERE e.contactInfo.address.zipcode = '95054'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void pathExpressionSyntaxExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT l.product
|
||||
FROM Order AS o JOIN o.lineItems l
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinsExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c FROM Customer c, Employee e WHERE c.hatsize = e.shoesize
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinsExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c FROM Customer c JOIN c.orders o WHERE c.status = 1
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinsInnerExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c FROM Customer c INNER JOIN c.orders o WHERE c.status = 1
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void joinsInExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT OBJECT(c) FROM Customer c, IN(c.orders) o WHERE c.status = 1
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void doubleJoinExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT p.vendor
|
||||
FROM Employee e JOIN e.contactInfo c JOIN c.phones p
|
||||
WHERE c.address.zipcode = '95054'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void leftJoinExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT s.name, COUNT(p)
|
||||
FROM Suppliers s LEFT JOIN s.products p
|
||||
GROUP BY s.name
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void leftJoinOnExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT s.name, COUNT(p)
|
||||
FROM Suppliers s LEFT JOIN s.products p
|
||||
ON p.status = 'inStock'
|
||||
GROUP BY s.name
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void leftJoinWhereExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT s.name, COUNT(p)
|
||||
FROM Suppliers s LEFT JOIN s.products p
|
||||
WHERE p.status = 'inStock'
|
||||
GROUP BY s.name
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void leftJoinFetchExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT d
|
||||
FROM Department d LEFT JOIN FETCH d.employees
|
||||
WHERE d.deptno = 1
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionMemberExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o JOIN o.lineItems l
|
||||
WHERE l.product.productType = 'office_supplies'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void collectionMemberInExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o, IN(o.lineItems) l
|
||||
WHERE l.product.productType = 'office_supplies'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClauseExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order AS o JOIN o.lineItems l JOIN l.product p
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClauseDowncastingExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT b.name, b.ISBN
|
||||
FROM Order o JOIN TREAT(o.product AS Book) b
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClauseDowncastingExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) lp
|
||||
WHERE lp.budget > 1000
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #fromClauseDowncastingExample3fixed()
|
||||
*/
|
||||
@Test
|
||||
@Disabled(SPEC_FAULT + "Use double-quotes when it should be using single-quotes for a string literal")
|
||||
void fromClauseDowncastingExample3_SPEC_BUG() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN e.projects p
|
||||
WHERE TREAT(p AS LargeProject).budget > 1000
|
||||
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
|
||||
OR p.description LIKE "cost overrun"
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClauseDowncastingExample3fixed() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e JOIN e.projects p
|
||||
WHERE TREAT(p AS LargeProject).budget > 1000
|
||||
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
|
||||
OR p.description LIKE 'cost overrun'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromClauseDowncastingExample4() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e FROM Employee e
|
||||
WHERE TREAT(e AS Exempt).vacationDays > 10
|
||||
OR TREAT(e AS Contractor).hours > 100
|
||||
""");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void substring() {
|
||||
|
||||
assertQuery("select substring(c.number, 1, 2) " + //
|
||||
"from Call c");
|
||||
|
||||
assertQuery("select substring(c.number, 1) " + //
|
||||
"from Call c");
|
||||
}
|
||||
|
||||
@Test // GH-3136
|
||||
void currentDateFunctions() {
|
||||
|
||||
assertQuery("select CURRENT_DATE " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select CURRENT_TIME " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select CURRENT_TIMESTAMP " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_DATE " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_TIME " + //
|
||||
"from Call c ");
|
||||
|
||||
assertQuery("select LOCAL_DATETIME " + //
|
||||
"from Call c ");
|
||||
}
|
||||
|
||||
@Test
|
||||
void pathExpressionsNamedParametersExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c
|
||||
FROM Customer c
|
||||
WHERE c.status = :stat
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void betweenExpressionsExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT t
|
||||
FROM CreditCard c JOIN c.transactionHistory t
|
||||
WHERE c.holder.name = 'John Doe' AND INDEX(t) BETWEEN 0 AND 9
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void isEmptyExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE o.lineItems IS EMPTY
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void memberOfExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT p
|
||||
FROM Person p
|
||||
WHERE 'Joe' MEMBER OF p.nicknames
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void existsSubSelectExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE EXISTS (SELECT spouseEmp
|
||||
FROM Employee spouseEmp
|
||||
WHERE spouseEmp = emp.spouse)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void allExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT emp
|
||||
FROM Employee emp
|
||||
WHERE emp.salary > ALL (SELECT m.salary
|
||||
FROM Manager m
|
||||
WHERE m.department = emp.department)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void existsSubSelectExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT emp
|
||||
FROM Employee emp
|
||||
WHERE EXISTS (SELECT spouseEmp
|
||||
FROM Employee spouseEmp
|
||||
WHERE spouseEmp = emp.spouse)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void subselectNumericComparisonExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c
|
||||
FROM Customer c
|
||||
WHERE (SELECT AVG(o.price) FROM c.orders o) > 100
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void subselectNumericComparisonExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT goodCustomer
|
||||
FROM Customer goodCustomer
|
||||
WHERE goodCustomer.balanceOwed < (SELECT AVG(c.balanceOwed) / 2.0 FROM Customer c)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexExample() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT w.name
|
||||
FROM Course c JOIN c.studentWaitlist w
|
||||
WHERE c.name = 'Calculus'
|
||||
AND INDEX(w) = 0
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #functionInvocationExampleWithCorrection()
|
||||
*/
|
||||
@Test
|
||||
@Disabled(SPEC_FAULT + "FUNCTION calls needs a comparator")
|
||||
void functionInvocationExample_SPEC_BUG() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c
|
||||
FROM Customer c
|
||||
WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionInvocationExampleWithCorrection() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c
|
||||
FROM Customer c
|
||||
WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) = TRUE
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateCaseExample1() {
|
||||
|
||||
assertQuery("""
|
||||
UPDATE Employee e
|
||||
SET e.salary =
|
||||
CASE WHEN e.rating = 1 THEN e.salary * 1.1
|
||||
WHEN e.rating = 2 THEN e.salary * 1.05
|
||||
ELSE e.salary * 1.01
|
||||
END
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateCaseExample2() {
|
||||
|
||||
assertQuery("""
|
||||
UPDATE Employee e
|
||||
SET e.salary =
|
||||
CASE e.rating WHEN 1 THEN e.salary * 1.1
|
||||
WHEN 2 THEN e.salary * 1.05
|
||||
ELSE e.salary * 1.01
|
||||
END
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectCaseExample1() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e.name,
|
||||
CASE TYPE(e) WHEN Exempt THEN 'Exempt'
|
||||
WHEN Contractor THEN 'Contractor'
|
||||
WHEN Intern THEN 'Intern'
|
||||
ELSE 'NonExempt'
|
||||
END
|
||||
FROM Employee e
|
||||
WHERE e.dept.name = 'Engineering'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void selectCaseExample2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e.name,
|
||||
f.name,
|
||||
CONCAT(CASE WHEN f.annualMiles > 50000 THEN 'Platinum '
|
||||
WHEN f.annualMiles > 25000 THEN 'Gold '
|
||||
ELSE ''
|
||||
END,
|
||||
'Frequent Flyer')
|
||||
FROM Employee e JOIN e.frequentFlierPlan f
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e
|
||||
FROM Employee e
|
||||
WHERE TYPE(e) IN (Exempt, Contractor)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest2() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e
|
||||
FROM Employee e
|
||||
WHERE TYPE(e) IN (:empType1, :empType2)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest3() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e
|
||||
FROM Employee e
|
||||
WHERE TYPE(e) IN :empTypes
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest4() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT TYPE(e)
|
||||
FROM Employee e
|
||||
WHERE TYPE(e) <> Exempt
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest5() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c.status, AVG(c.filledOrderCount), COUNT(c)
|
||||
FROM Customer c
|
||||
GROUP BY c.status
|
||||
HAVING c.status IN (1, 2)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest6() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c.country, COUNT(c)
|
||||
FROM Customer c
|
||||
GROUP BY c.country
|
||||
HAVING COUNT(c) > 30
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest7() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c, COUNT(o)
|
||||
FROM Customer c JOIN c.orders o
|
||||
GROUP BY c
|
||||
HAVING COUNT(o) >= 5
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest8() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c.id, c.status
|
||||
FROM Customer c JOIN c.orders o
|
||||
WHERE o.count > 100
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest9() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT v.location.street, KEY(i).title, VALUE(i)
|
||||
FROM VideoStore v JOIN v.videoInventory i
|
||||
WHERE v.location.zipcode = '94301' AND VALUE(i) > 0
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest10() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o.lineItems FROM Order AS o
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest11() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT c, COUNT(l) AS itemCount
|
||||
FROM Customer c JOIN c.Orders o JOIN o.lineItems l
|
||||
WHERE c.address.state = 'CA'
|
||||
GROUP BY c
|
||||
ORDER BY itemCount
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest12() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT NEW com.acme.example.CustomerDetails(c.id, c.status, o.count)
|
||||
FROM Customer c JOIN c.orders o
|
||||
WHERE o.count > 100
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest13() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT e.address AS addr
|
||||
FROM Employee e
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest14() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT AVG(o.quantity) FROM Order o
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest15() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT SUM(l.price)
|
||||
FROM Order o JOIN o.lineItems l JOIN o.customer c
|
||||
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest16() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT COUNT(o) FROM Order o
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest17() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT COUNT(l.price)
|
||||
FROM Order o JOIN o.lineItems l JOIN o.customer c
|
||||
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest18() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT COUNT(l)
|
||||
FROM Order o JOIN o.lineItems l JOIN o.customer c
|
||||
WHERE c.lastname = 'Smith' AND c.firstname = 'John' AND l.price IS NOT NULL
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest19() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Customer c JOIN c.orders o JOIN c.address a
|
||||
WHERE a.state = 'CA'
|
||||
ORDER BY o.quantity DESC, o.totalcost
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest20() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o.quantity, a.zipcode
|
||||
FROM Customer c JOIN c.orders o JOIN c.address a
|
||||
WHERE a.state = 'CA'
|
||||
ORDER BY o.quantity, a.zipcode
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest21() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o.quantity, o.cost * 1.08 AS taxedCost, a.zipcode
|
||||
FROM Customer c JOIN c.orders o JOIN c.address a
|
||||
WHERE a.state = 'CA' AND a.county = 'Santa Clara'
|
||||
ORDER BY o.quantity, taxedCost, a.zipcode
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest22() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT AVG(o.quantity) as q, a.zipcode
|
||||
FROM Customer c JOIN c.orders o JOIN c.address a
|
||||
WHERE a.state = 'CA'
|
||||
GROUP BY a.zipcode
|
||||
ORDER BY q DESC
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest23() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT p.product_name
|
||||
FROM Order o JOIN o.lineItems l JOIN l.product p JOIN o.customer c
|
||||
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
|
||||
ORDER BY p.price
|
||||
""");
|
||||
}
|
||||
|
||||
/**
|
||||
* This query is specifically dubbed illegal in the spec. It may actually be failing for a different reason.
|
||||
*/
|
||||
@Test
|
||||
void theRest24() {
|
||||
|
||||
assertThatExceptionOfType(BadJpqlGrammarException.class).isThrownBy(() -> {
|
||||
assertQuery("""
|
||||
SELECT p.product_name
|
||||
FROM Order o, IN(o.lineItems) l JOIN o.customer c
|
||||
WHERE c.lastname = 'Smith' AND c.firstname = 'John'
|
||||
ORDER BY o.quantity
|
||||
""");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest25() {
|
||||
|
||||
assertQuery("""
|
||||
DELETE
|
||||
FROM Customer c
|
||||
WHERE c.status = 'inactive'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest26() {
|
||||
|
||||
assertQuery("""
|
||||
DELETE
|
||||
FROM Customer c
|
||||
WHERE c.status = 'inactive'
|
||||
AND c.orders IS EMPTY
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest27() {
|
||||
|
||||
assertQuery("""
|
||||
UPDATE Customer c
|
||||
SET c.status = 'outstanding'
|
||||
WHERE c.balance < 10000
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest28() {
|
||||
|
||||
assertQuery("""
|
||||
UPDATE Employee e
|
||||
SET e.address.building = 22
|
||||
WHERE e.address.building = 14
|
||||
AND e.address.city = 'Santa Clara'
|
||||
AND e.project = 'Jakarta EE'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest29() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest30() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE o.shippingAddress.state = 'CA'
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest31() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o.shippingAddress.state
|
||||
FROM Order o
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest32() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o JOIN o.lineItems l
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest33() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE o.lineItems IS NOT EMPTY
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest34() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE o.lineItems IS EMPTY
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest35() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o JOIN o.lineItems l
|
||||
WHERE l.shipped = FALSE
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest36() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE
|
||||
NOT (o.shippingAddress.state = o.billingAddress.state AND
|
||||
o.shippingAddress.city = o.billingAddress.city AND
|
||||
o.shippingAddress.street = o.billingAddress.street)
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest37() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT o
|
||||
FROM Order o
|
||||
WHERE o.shippingAddress <> o.billingAddress
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void theRest38() {
|
||||
|
||||
assertQuery("""
|
||||
SELECT DISTINCT o
|
||||
FROM Order o JOIN o.lineItems l
|
||||
WHERE l.product.name = ?1
|
||||
""");
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ class QueryEnhancerUnitTests {
|
||||
@MethodSource("detectsAliasWithUCorrectlySource")
|
||||
void detectsAliasWithUCorrectly(DeclaredQuery query, String alias) {
|
||||
|
||||
assumeThat(query.getQueryString()).as("JsqlParser does not support simple JPA syntax.")
|
||||
assumeThat(query.getQueryString()).as("JsqlParser does not support simple JPA syntax")
|
||||
.doesNotStartWithIgnoringCase("from");
|
||||
|
||||
assertThat(getEnhancer(query).detectAlias()).isEqualTo(alias);
|
||||
|
||||
Reference in New Issue
Block a user