Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial specification of JDQL #520

Merged
merged 22 commits into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
abf00cd
Draft specification of JDQL
gavinking Mar 3, 2024
c8ff958
add note about requirements surrounding JDQL functions
gavinking Mar 5, 2024
b831e30
Update spec/src/main/asciidoc/query-language.asciidoc
gavinking Mar 6, 2024
b95049c
clarify semantics of path expression involving null elements
gavinking Mar 6, 2024
d807f9c
Update spec/src/main/asciidoc/query-language.asciidoc
gavinking Mar 6, 2024
451b0c3
Update spec/src/main/asciidoc/query-language.asciidoc
gavinking Mar 6, 2024
7f80fd4
further clarify requirements for path expressions
gavinking Mar 6, 2024
925b8e1
clarify what happens if the database doesn't support:
gavinking Mar 6, 2024
14a867e
simplify select clause to a single path expression
gavinking Mar 6, 2024
613a267
add LOCAL TIME
gavinking Mar 6, 2024
659ef96
define enum order
gavinking Mar 6, 2024
352b511
undefine enum order
gavinking Mar 7, 2024
ebef494
split out new section dealing with ordering/comparison
gavinking Mar 9, 2024
c3a7adb
example of from-clause inference
gavinking Mar 9, 2024
a4157bf
failure to sort should be a DataException
gavinking Mar 12, 2024
edd3725
clarify that unsupported functions can be rejected at compile time
gavinking Mar 12, 2024
d13676c
add discussion of operator precedence to text
gavinking Mar 12, 2024
ebbda9d
Apply suggestions from code review
gavinking Mar 12, 2024
b761d12
'count(*)' -> 'count(this)'
gavinking Mar 15, 2024
43c8875
remove Contains and Empty operators from QbMN
gavinking Mar 15, 2024
7805071
for @njr-11
gavinking Mar 16, 2024
be1e8d6
Merge branch 'main' into jdql
gavinking Mar 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ By embracing type-safe access to entity attributes with Jakarta Data's static me

[source,java]
----
List<Product> found = products.findByNameContains(searchPattern, Order.by(
_Product.price.desc(),
_Product.name.asc(),
_Product.id.asc()));
List<Product> found = products.findByNameLike(searchPattern, Order.by(
_Product.price.desc(),
_Product.name.asc(),
_Product.id.asc()));
----

=== Maven
Expand Down
49 changes: 20 additions & 29 deletions api/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -309,48 +309,38 @@
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column</td></tr>
*
* <tr style="vertical-align: top; background-color:#eee"><td>{@code Contains}</td>
* <td>collections, strings</td>
* <td>For Collection attributes, requires that the entity's attribute value,
* which is a collection, includes the parameter value.
* For String attributes, requires that any substring of the entity's attribute value
* match the entity's attribute value, which can be a pattern with wildcard characters.</td>
* <td>{@code findByRecipientsContains(email)}
* <br>{@code findByDescriptionNotContains("refurbished")}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column<br>Document</td></tr>
*
* <tr style="vertical-align: top"><td>{@code Empty}</td>
* <td>collections</td>
* <td>Requires that the entity's attribute is an empty collection or has a null value.</td>
* <td>{@code countByPhoneNumbersEmpty()}
* <br>{@code findByInviteesNotEmpty()}</td>
* <td>strings</td>
* <td>Requires that a substring of the entity's attribute value
* matches the parameter value, which can be a pattern.</td>
* <td>{@code findByNameContains(middleName)}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column<br>Document<br>Graph</td></tr>
*
* <tr style="vertical-align: top; background-color:#eee"><td>{@code EndsWith}</td>
* <tr style="vertical-align: top"><td>{@code EndsWith}</td>
* <td>strings</td>
* <td>Requires that the characters at the end of the entity's attribute value
* match the parameter value, which can be a pattern.</td>
* <td>{@code findByNameEndsWith(surname)}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column<br>Document<br>Graph</td></tr>
*
* <tr style="vertical-align: top"><td>{@code False}</td>
* <tr style="vertical-align: top; background-color:#eee"><td>{@code False}</td>
* <td>boolean</td>
* <td>Requires that the entity's attribute value has a boolean value of false.</td>
* <td>{@code findByCanceledFalse()}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column</td></tr>
*
* <tr style="vertical-align: top; background-color:#eee"><td>{@code GreaterThan}</td>
* <tr style="vertical-align: top"><td>{@code GreaterThan}</td>
* <td>numeric, strings, time</td>
* <td>Requires that the entity's attribute value be larger than the parameter value.</td>
* <td>{@code findByStartTimeGreaterThan(startedAfter)}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column</td></tr>
*
* <tr style="vertical-align: top"><td>{@code GreaterThanEqual}</td>
* <tr style="vertical-align: top; background-color:#eee"><td>{@code GreaterThanEqual}</td>
* <td>numeric, strings, time</td>
* <td>Requires that the entity's attribute value be at least as big as the parameter value.</td>
* <td>{@code findByAgeGreaterThanEqual(minimumAge)}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column</td></tr>
*
* <tr style="vertical-align: top; background-color:#eee"><td>{@code IgnoreCase}</td>
* <tr style="vertical-align: "><td>{@code IgnoreCase}</td>
* <td>strings</td>
* <td>Requires case insensitive comparison. For query conditions
* as well as ordering, the {@code IgnoreCase} keyword can be
Expand All @@ -359,58 +349,58 @@
* <br>{@code findByZipcodeOrderByStreetIgnoreCaseAscHouseNumAsc(55904)}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column<br>Document<br>Graph</td></tr>
*
* <tr style="vertical-align: top"><td>{@code In}</td>
* <tr style="vertical-align: top; background-color:#eee"><td>{@code In}</td>
* <td>all attribute types</td>
* <td>Requires that the entity's attribute value be within the list that is the parameter value.</td>
* <td>{@code findByNameIn(names)}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column<br>Document<br>Graph</td></tr>
*
* <tr style="vertical-align: top; background-color:#eee"><td>{@code LessThan}</td>
* <tr style="vertical-align: top"><td>{@code LessThan}</td>
* <td>numeric, strings, time</td>
* <td>Requires that the entity's attribute value be less than the parameter value.</td>
* <td>{@code findByStartTimeLessThan(startedBefore)}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column</td></tr>
*
* <tr style="vertical-align: top"><td>{@code LessThanEqual}</td>
* <tr style="vertical-align: top; background-color:#eee"><td>{@code LessThanEqual}</td>
* <td>numeric, strings, time</td>
* <td>Requires that the entity's attribute value be at least as small as the parameter value.</td>
* <td>{@code findByAgeLessThanEqual(maximumAge)}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column</td></tr>
*
* <tr style="vertical-align: top; background-color:#eee"><td>{@code Like}</td>
* <tr style="vertical-align: top"><td>{@code Like}</td>
* <td>strings</td>
* <td>Requires that the entity's attribute value match the parameter value, which can be a pattern.</td>
* <td>{@code findByNameLike(namePattern)}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column<br>Document<br>Graph</td></tr>
*
* <tr style="vertical-align: top"><td>{@code Not}</td>
* <tr style="vertical-align: top; background-color:#eee"><td>{@code Not}</td>
* <td>condition</td>
* <td>Negates a condition.</td>
* <td>{@code deleteByNameNotLike(namePattern)}
* <br>{@code findByStatusNot("RUNNING")}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column</td></tr>
*
* <tr style="vertical-align: top; background-color:#eee"><td>{@code Null}</td>
* <tr style="vertical-align: top"><td>{@code Null}</td>
* <td>nullable types</td>
* <td>Requires that the entity's attribute has a null value.</td>
* <td>{@code findByEndTimeNull()}
* <br>{@code findByAgeNotNull()}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column<br>Document<br>Graph</td></tr>
*
* <tr style="vertical-align: top"><td>{@code Or}</td>
* <tr style="vertical-align: top; background-color:#eee"><td>{@code Or}</td>
* <td>conditions</td>
* <td>Requires at least one of the two conditions to be satisfied in order to match an entity.</td>
* <td>{@code findByPriceLessThanEqualOrDiscountGreaterThanEqual(maxPrice, minDiscount)}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column</td></tr>
*
* <tr style="vertical-align: top; background-color:#eee"><td>{@code StartsWith}</td>
* <tr style="vertical-align: top"><td>{@code StartsWith}</td>
* <td>strings</td>
* <td>Requires that the characters at the beginning of the entity's attribute value
* match the parameter value, which can be a pattern.</td>
* <td>{@code findByNameStartsWith(firstTwoLetters)}</td>
* <td style="font-family:sans-serif; font-size:0.8em">Key-value<br>Wide-Column<br>Document<br>Graph</td></tr>
*
* <tr style="vertical-align: top"><td>{@code True}</td>
* <tr style="vertical-align: top; background-color:#eee"><td>{@code True}</td>
* <td>boolean</td>
* <td>Requires that the entity's attribute value has a boolean value of true.</td>
* <td>{@code findByAvailableTrue()}</td>
Expand Down Expand Up @@ -478,7 +468,8 @@
* future releases without introducing breaking changes to applications.
* </p>
* <p>
* Reserved for query conditions: {@code AbsoluteValue}, {@code CharCount}, {@code ElementCount},
* Reserved for query conditions: {@code AbsoluteValue}, {@code CharCount},
* {@code ElementCount}, {@code Empty}
* {@code Rounded}, {@code RoundedDown}, {@code RoundedUp}, {@code Trimmed},
* {@code WithDay}, {@code WithHour}, {@code WithMinute}, {@code WithMonth},
* {@code WithQuarter}, {@code WithSecond}, {@code WithWeek}, {@code WithYear}.
Expand Down
93 changes: 93 additions & 0 deletions spec/src/antlr/JDQL.g4
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
grammar JDQL;

statement : select_statement | update_statement | delete_statement;

select_statement : select_clause? from_clause? where_clause? orderby_clause?;
otaviojava marked this conversation as resolved.
Show resolved Hide resolved
gavinking marked this conversation as resolved.
Show resolved Hide resolved
gavinking marked this conversation as resolved.
Show resolved Hide resolved
update_statement : 'UPDATE' entity_name set_clause where_clause?;
delete_statement : 'DELETE' from_clause where_clause?;

from_clause : 'FROM' entity_name;

where_clause : 'WHERE' conditional_expression;

set_clause : 'SET' update_item (',' update_item)*;
update_item : state_field_path_expression '=' (scalar_expression | 'NULL');

select_clause : 'SELECT' select_list;
select_list
: state_field_path_expression
| aggregate_expression
;
aggregate_expression : 'COUNT' '(' 'THIS' ')';

orderby_clause : 'ORDER' 'BY' orderby_item (',' orderby_item)*;
orderby_item : state_field_path_expression ('ASC' | 'DESC');

conditional_expression
gavinking marked this conversation as resolved.
Show resolved Hide resolved
// highest to lowest precedence
: '(' conditional_expression ')'
| null_comparison_expression
| in_expression
| between_expression
| like_expression
gavinking marked this conversation as resolved.
Show resolved Hide resolved
| comparison_expression
| 'NOT' conditional_expression
| conditional_expression 'AND' conditional_expression
| conditional_expression 'OR' conditional_expression
;

comparison_expression : scalar_expression ('=' | '>' | '>=' | '<' | '<=' | '<>') scalar_expression;
between_expression : scalar_expression 'NOT'? 'BETWEEN' scalar_expression 'AND' scalar_expression;
like_expression : scalar_expression 'NOT'? 'LIKE' STRING;

in_expression : state_field_path_expression 'NOT'? 'IN' '(' in_item (',' in_item)* ')';
in_item : literal | enum_literal | input_parameter; // could simplify to just literal

null_comparison_expression : state_field_path_expression 'IS' 'NOT'? 'NULL';

scalar_expression
// highest to lowest precedence
: '(' scalar_expression ')'
| primary_expression
| ('+' | '-') scalar_expression
| scalar_expression ('*' | '/') scalar_expression
| scalar_expression ('+' | '-') scalar_expression
| scalar_expression '||' scalar_expression
;

primary_expression
: function_expression
| special_expression
| state_field_path_expression
| enum_literal
| input_parameter
| literal
;

function_expression
: 'ABS' '(' scalar_expression ')'
| 'LENGTH' '(' scalar_expression ')'
| 'LOWER' '(' scalar_expression ')'
| 'UPPER' '(' scalar_expression ')'
| 'LEFT' '(' scalar_expression ',' scalar_expression ')'
| 'RIGHT' '(' scalar_expression ',' scalar_expression ')'
gavinking marked this conversation as resolved.
Show resolved Hide resolved
;

special_expression
: 'LOCAL' 'DATE'
| 'LOCAL' 'DATETIME'
| 'LOCAL' 'TIME'
| 'TRUE'
| 'FALSE'
;

state_field_path_expression : IDENTIFIER ('.' IDENTIFIER)*;
gavinking marked this conversation as resolved.
Show resolved Hide resolved

entity_name : IDENTIFIER; // no ambiguity

enum_literal : IDENTIFIER; // ambiguity with state_field_path_expression resolvable semantically

input_parameter : ':' IDENTIFIER | '?' INTEGER;

literal : STRING | INTEGER | DOUBLE;

1 change: 1 addition & 0 deletions spec/src/main/asciidoc/jakarta-data.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ include::chapters/license/license-efsl.adoc[]

include::chapters/introduction/introduction.asciidoc[]
include::repository.asciidoc[]
include::query-language.asciidoc[]
include::jakarta-ee.adoc[]
include::portability.asciidoc[]
Loading