From efe4f1ecd920ab4dc11317209b12df0f0f4e261b Mon Sep 17 00:00:00 2001 From: Nathan Rauh Date: Tue, 5 Nov 2024 08:21:38 -0600 Subject: [PATCH 1/4] Issue #857 more types of comparisons for parameter based automatic query Signed-off-by: Nathan Rauh --- api/src/main/java/jakarta/data/Limit.java | 9 +- .../java/jakarta/data/page/CursoredPage.java | 17 +-- .../java/jakarta/data/page/PageRequest.java | 11 +- .../main/java/jakarta/data/repository/By.java | 5 +- .../main/java/jakarta/data/repository/Is.java | 118 ++++++++++++++++++ .../java/jakarta/data/repository/OrderBy.java | 8 +- .../jakarta/data/repository/Repository.java | 5 +- api/src/main/java/module-info.java | 90 ++++++++----- 8 files changed, 216 insertions(+), 47 deletions(-) create mode 100644 api/src/main/java/jakarta/data/repository/Is.java diff --git a/api/src/main/java/jakarta/data/Limit.java b/api/src/main/java/jakarta/data/Limit.java index ca2948bcd..d06981a2e 100644 --- a/api/src/main/java/jakarta/data/Limit.java +++ b/api/src/main/java/jakarta/data/Limit.java @@ -33,12 +33,15 @@ * For example,

* *
- * Product[] findByNameLike(String namePattern, Limit limit, Sort<?>... sorts);
+ * @Find
+ * Product[] named(@By(_Product.NAME) @Is(LikeIgnoreCase) String namePattern,
+ *                 Limit limit,
+ *                 Sort<Product>... sorts);
  * 
  * ...
- * mostExpensive50 = products.findByNameLike(pattern, Limit.of(50), Sort.desc("price"));
+ * mostExpensive50 = products.named(pattern, Limit.of(50), Sort.desc("price"));
  * ...
- * secondMostExpensive50 = products.findByNameLike(pattern, Limit.range(51, 100), Sort.desc("price"));
+ * secondMostExpensive50 = products.named(pattern, Limit.range(51, 100), Sort.desc("price"));
  * 
* *

A repository method may not be declared with: diff --git a/api/src/main/java/jakarta/data/page/CursoredPage.java b/api/src/main/java/jakarta/data/page/CursoredPage.java index 2ad70d295..71770f8ce 100644 --- a/api/src/main/java/jakarta/data/page/CursoredPage.java +++ b/api/src/main/java/jakarta/data/page/CursoredPage.java @@ -55,23 +55,26 @@ * query parameters) of type {@link PageRequest}, for example:

* *
- * @OrderBy("lastName")
- * @OrderBy("firstName")
- * @OrderBy("id")
- * CursoredPage<Employee> findByHoursWorkedGreaterThan(int hours, PageRequest pageRequest);
+ * @Find
+ * @OrderBy(_Employee.LASTNAME)
+ * @OrderBy(_Employee.FIRSTNAME)
+ * @OrderBy(_Employee.ID)
+ * CursoredPage<Employee> withOvertime(
+ *         @By(_Employee.HOURSWORKED) @Is(GreaterThan) int fullTimeHours,
+ *         PageRequest pageRequest);
  * 
* *

In initial page may be requested using an offset-based page request:

* *
- * page = employees.findByHoursWorkedGreaterThan(1500, PageRequest.ofSize(50));
+ * page = employees.withOvertime(40, PageRequest.ofSize(50));
  * 
* *

The next page may be requested relative to the end of the current page, * as follows:

* *
- * page = employees.findByHoursWorkedGreaterThan(1500, page.nextPageRequest());
+ * page = employees.withOvertime(40, page.nextPageRequest());
  * 
* *

Here, the instance of {@link PageRequest} returned by @@ -92,7 +95,7 @@ * PageRequest.ofPage(5) * .size(50) * .afterCursor(Cursor.forKey(emp.lastName, emp.firstName, emp.id)); - * page = employees.findByHoursWorkedGreaterThan(1500, pageRequest); + * page = employees.withOvertime(40, pageRequest); * * *

By making the query for the next page relative to observed values, diff --git a/api/src/main/java/jakarta/data/page/PageRequest.java b/api/src/main/java/jakarta/data/page/PageRequest.java index a73421d1d..f7d90a4b6 100644 --- a/api/src/main/java/jakarta/data/page/PageRequest.java +++ b/api/src/main/java/jakarta/data/page/PageRequest.java @@ -37,20 +37,25 @@ * example:

* *
+ * @Find
  * @OrderBy("age")
  * @OrderBy("ssn")
- * Person[] findByAgeBetween(int minAge, int maxAge, PageRequest pageRequest);
+ * Person[] agedBetween(@By("age") @Is(GreaterThanEqual) int minAge,
+ *                      @By("age") @Is(LessThanEqual) int maxAge,
+ *                      PageRequest pageRequest);
  * 
* *

This method might be called as follows:

* *
- * var page = people.findByAgeBetween(35, 59,
+ * var page = people.agedBetween(
+ *                35, 59,
  *                PageRequest.ofSize(100));
  * var results = page.content();
  * ...
  * while (page.hasNext()) {
- *     page = people.findByAgeBetween(35, 59,
+ *     page = people.agedBetween(
+ *                35, 59,
  *                page.nextPageRequest().withoutTotal());
  *     results = page.content();
  *   ...
diff --git a/api/src/main/java/jakarta/data/repository/By.java b/api/src/main/java/jakarta/data/repository/By.java
index 233dec891..cb01804a1 100644
--- a/api/src/main/java/jakarta/data/repository/By.java
+++ b/api/src/main/java/jakarta/data/repository/By.java
@@ -33,7 +33,10 @@
  *     to the unique identifier attribute.
  * 
  * 

Arguments to the annotated parameter are compared to values of the - * mapped attribute.

+ * mapped attribute. The equality comparison is used by default.

+ * + *

For other types of basic comparisons, include the {@link Is} annotation.

+ * *

The attribute name may be a compound name like {@code address.city}.

* *

For example, for a {@code Person} entity with attributes {@code ssn}, diff --git a/api/src/main/java/jakarta/data/repository/Is.java b/api/src/main/java/jakarta/data/repository/Is.java new file mode 100644 index 000000000..20adb800c --- /dev/null +++ b/api/src/main/java/jakarta/data/repository/Is.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * 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 + * + * http://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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package jakarta.data.repository; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *

Annotates a parameter of a repository {@link Find} or {@link Delete} method, + * indicating how a persistent field is compared against the parameter's value. + * The {@link By} annotation is used on the same parameter to identify the + * persistent field.

+ * + *

For example,

+ * + *
+ * @Repository
+ * public interface Products extends CrudRepository<Product, Long> {
+ *
+ *     // Find all Product entities where the price field is less than a maximum value.
+ *     @Find
+ *     List<Product> pricedBelow(@By(_Product.PRICE) @Is(LessThan) float max);
+ *
+ *     // Find a page of Product entities where the name field matches a pattern, ignoring case.
+ *     @Find
+ *     Page<Product> search(@By(_Product.NAME) @Is(LikeIgnoreCase) String pattern,
+ *                          PageRequest pagination,
+ *                          Order<Product> order);
+ *
+ *     // Remove Product entities with any of the unique identifiers listed.
+ *     @Delete
+ *     void remove(@By(ID) @Is(In) List<Long> productIds);
+ * }
+ * 
+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface Is { + /** + *

The type of comparison operation to use when comparing a persistent + * field against a value that is supplied to a repository method.

+ * + *

The following example compares the year a person was born against + * a minimum and maximum year that are supplied as parameters to a repository + * method:

+ * + *
+     * @Find
+     * @OrderBy(_Person.YEAR_BORN)
+     * List<Person> bornWithin(@By(_Person.YEAR_BORN) @Is(GreaterThanEqual) float minYear,
+     *                         @By(_Person.YEAR_BORN) @Is(LessThanEqual) float maxYear);
+     * 
+ * + *

The default comparison operation is the {@linkplain Op#Equal equality} + * comparison.

+ * + * @return the type of comparison operation. + */ + Op value() default Op.Equal; + + /** + *

Comparison operations for the {@link Is} annotation.

+ * + *

For more concise code, it can be convenient to statically import one + * or more comparison operations. For example:

+ * + *
+     * import static jakarta.data.repository.Is.Op.*;
+     * 
+ */ + public static enum Op { + // TODO add JavaDoc with examples to these + Equal, + GreaterThan, + GreaterThanEqual, + IgnoreCase, + In, + LessThan, + LessThanEqual, + Like, + LikeIgnoreCase, + // TODO might want to give more thought to the exact names, + Prefixed, + PrefixedIgnoreCase, + Substringed, + SubstringedIgnoreCase, + Suffixed, + SuffixedIgnoreCase, + Not, + NotIgnoreCase, + NotIn, + NotLike, + NotLikeIgnoreCase, + NotPrefixed, + NotPrefixedIgnoreCase, + NotSubstringed, + NotSubstringedIgnoreCase, + NotSuffixed, + NotSuffixedIgnoreCase; + } +} diff --git a/api/src/main/java/jakarta/data/repository/OrderBy.java b/api/src/main/java/jakarta/data/repository/OrderBy.java index 207afd121..8c1822508 100644 --- a/api/src/main/java/jakarta/data/repository/OrderBy.java +++ b/api/src/main/java/jakarta/data/repository/OrderBy.java @@ -62,8 +62,9 @@ *

The default sort order is ascending. The {@code descending} member can be * used to specify the sort direction.

*
- * @OrderBy(value = "price", descending = true)
- * {@code Stream} findByPriceLessThanEqual(double maxPrice);
+ * @Find
+ * @OrderBy(value = _Product.PRICE, descending = true)
+ * {@code Stream} pricedBelow(@By(_Product.PRICE) @Is(LessThan) double maxPrice);
  * 
* *

A repository method with an {@code @OrderBy} annotation must not @@ -115,8 +116,9 @@ *

For example,

* *
+     * @Find
      * @OrderBy("age")
-     * Stream<Person> findByLastName(String lastName);
+     * Stream<Person> withLastName(@By("lastName") @Is(IgnoreCase) String surname);
      * 
* * @return entity attribute name. diff --git a/api/src/main/java/jakarta/data/repository/Repository.java b/api/src/main/java/jakarta/data/repository/Repository.java index 6812adcb2..bfc59513c 100644 --- a/api/src/main/java/jakarta/data/repository/Repository.java +++ b/api/src/main/java/jakarta/data/repository/Repository.java @@ -37,8 +37,9 @@ * @Repository * public interface Products extends DataRepository<Product, Long> { * + * @Find * @OrderBy("price") - * List<Product> findByNameLike(String namePattern); + * List<Product> named(@By("name") @Is(LikeIgnoreCase) String namePattern); * * @Query("UPDATE Product SET price = price - (price * ?1) WHERE price * ?1 <= ?2") * int putOnSale(float rateOfDiscount, float maxDiscount); @@ -52,7 +53,7 @@ * Products products; * * ... - * found = products.findByNameLike("%Printer%"); + * found = products.named("%Printer%"); * numUpdated = products.putOnSale(0.15f, 20.0f); *
* diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java index cfb4d2f88..1638d5dde 100644 --- a/api/src/main/java/module-info.java +++ b/api/src/main/java/module-info.java @@ -28,6 +28,7 @@ import jakarta.data.repository.Delete; import jakarta.data.repository.Find; import jakarta.data.repository.Insert; +import jakarta.data.repository.Is; import jakarta.data.repository.OrderBy; import jakarta.data.repository.Param; import jakarta.data.repository.Query; @@ -70,8 +71,11 @@ * @Insert * void create(Product prod); * + * @Find * @OrderBy("price") - * List<Product> findByNameIgnoreCaseLikeAndPriceLessThan(String namePattern, float max); + * List<Product> search( + * @By("name") @Is(LikeIgnoreCase) String namePattern, + * @By("price") @Is(LessThanEqual) float max); * * @Query("UPDATE Product SET price = price * (1.0 - ?1) WHERE yearProduced <= ?2") * int discountOldInventory(float rateOfDiscount, int maxYear); @@ -91,7 +95,7 @@ * ... * products.create(newProduct); * - * found = products.findByNameIgnoreCaseLikeAndPriceLessThan("%cell%phone%", 900.0f); + * found = products.search("%cell%phone%", 900.0f); * * numDiscounted = products.discountOldInventory(0.15f, Year.now().getValue() - 1); * @@ -150,8 +154,10 @@ * * @Repository * public interface Purchases { + * @Find * @OrderBy("address.zipCode") - * List<Purchase> findByAddressZipCodeIn(List<Integer> zipCodes); + * List<Purchase> forZipCodes( + * @By("address.zipCode") @Is(In) List<Integer> zipCodes); * * @Query("WHERE address.zipCode = ?1") * List<Purchase> forZipCode(int zipCode); @@ -711,15 +717,19 @@ * with the {@code -parameters} compiler option so that parameter names are * available at runtime.

* - *

Each parameter determines a query condition, and each such condition - * is an equality condition. All conditions must match for a record to + *

Each parameter determines a query condition. By default, each such condition + * is an equality condition. The {@link Is} annotation can be combined with the + * {@link By} annotation to request other types of basic comparisons for a + * repository method parameter. All conditions must match for a record to * satisfy the query.

* *
  * @Find
  * @OrderBy("lastName")
  * @OrderBy("firstName")
- * List<Person> peopleByAgeAndNationality(int age, Country nationality);
+ * List<Person> ofNationalityAndOlderThan(
+ *         Country nationality,
+ *         @By("age") @Is(GreaterThan) int minAge);
  * 
* *
@@ -727,6 +737,11 @@
  * Optional<Person> person(String ssn);
  * 
* + *
+ * @Delete
+ * void remove(@By("status") @Is(In) List<Status> list);
+ * 
+ * *

The {@code _} character may be used in a method parameter name to * reference an embedded attribute.

* @@ -742,11 +757,19 @@ * *
  * // Query by Method Name
- * Vehicle[] findByMakeAndModelAndYear(String makerName, String model, int year, Sort<?>... sorts);
+ * Vehicle[] findByMakeAndModelAndYearBetween(String makerName,
+ *                                            String model,
+ *                                            int minYear,
+ *                                            int maxYear,
+ *                                            Sort<?>... sorts);
  *
  * // parameter-based conditions
  * @Find
- * Vehicle[] searchFor(String make, String model, int year, Sort<?>... sorts);
+ * Vehicle[] search(String make,
+ *                  String model,
+ *                  @By(_Vehicle.YEAR) @Is(GreaterThanEqual) int minYear,
+ *                  @By(_Vehicle.YEAR) @Is(LessThanEqual) int maxYear,
+ *                  Sort<?>... sorts);
  * 
* *

For further information, refer to the {@linkplain Find API documentation} @@ -784,11 +807,13 @@ * allows its results to be split and retrieved in pages. For example,

* *
- * Product[] findByNameLikeOrderByAmountSoldDescIdAsc(
- *                 String pattern, PageRequest pageRequest);
+ * @Find
+ * @OrderBy(value = _Product.AMOUNT_SOLD, descending = true)
+ * @OrderBy(ID)
+ * Product[] named(@By(_Product.NAME) @Is(LikeIgnoreCase) String pattern,
+ *                 PageRequest pageRequest);
  * ...
- * page1 = products.findByNameLikeOrderByAmountSoldDescIdAsc(
- *                 "%phone%", PageRequest.ofSize(20));
+ * page1 = products.named("%phone%", PageRequest.ofSize(20));
  * 
* *

When using pagination, always ensure that the ordering is consistent @@ -802,16 +827,17 @@ * For example,

* *
- * Product[] findByNameLikeAndPriceBetween(String pattern,
- *                                         float minPrice,
- *                                         float maxPrice,
- *                                         PageRequest pageRequest,
- *                                         Order<Product> order);
+ * @Find
+ * Product[] search(@By("name") @Is(LikeIgnoreCase) String pattern,
+ *                  @By("price") @Is(GreaterThanEqual) float minPrice,
+ *                  @By("price") @Is(LessThanEqual) float maxPrice,
+ *                  PageRequest pageRequest,
+ *                  Order<Product> order);
  *
  * ...
  * PageRequest page1Request = PageRequest.ofSize(25);
  *
- * page1 = products.findByNameLikeAndPriceBetween(
+ * page1 = products.search(
  *                 namePattern, minPrice, maxPrice, page1Request,
  *                 Order.by(Sort.desc("price"), Sort.asc("id"));
  * 
@@ -821,13 +847,17 @@ * of {@link Sort} and passed to the repository find method. For example,

* *
- * Product[] findByNameLike(String pattern, Limit max, Order<Product> sortBy);
+ * @Find
+ * Product[] named(@By("name") @Is(LikeIgnoreCase) String pattern,
+ *                 Limit max,
+ *                 Order<Product> sortBy);
  *
  * ...
- * found = products.findByNameLike(namePattern, Limit.of(25),
- *                                 Order.by(Sort.desc("price"),
- *                                          Sort.desc("amountSold"),
- *                                          Sort.asc("id")));
+ * found = products.named(namePattern,
+ *                        Limit.of(25),
+ *                        Order.by(Sort.desc("price"),
+ *                                 Sort.desc("amountSold"),
+ *                                 Sort.asc("id")));
  * 
* *

Generic, untyped {@link Sort} criteria can be supplied directly to a @@ -835,13 +865,17 @@ * For example,

* *
- * Product[] findByNameLike(String pattern, Limit max, {@code Sort...} sortBy);
+ * @Find
+ * Product[] named(@By("name") @Is(LikeIgnoreCase) String pattern,
+ *                 Limit max,
+ *                 {@code Sort...} sortBy);
  *
  * ...
- * found = products.findByNameLike(namePattern, Limit.of(25),
- *                                 Sort.desc("price"),
- *                                 Sort.desc("amountSold"),
- *                                 Sort.asc("name"));
+ * found = products.named(namePattern,
+ *                        Limit.of(25),
+ *                        Sort.desc("price"),
+ *                        Sort.desc("amountSold"),
+ *                        Sort.asc("name"));
  * 
* *

Returning subsets of entity attributes

From e9e7e1c4be395f3910bf02d8b4dcc7c027b7a608 Mon Sep 17 00:00:00 2001 From: Nathan Rauh Date: Thu, 7 Nov 2024 09:56:19 -0600 Subject: [PATCH 2/4] Switch to String constants with capitalized names --- api/src/main/java/jakarta/data/Limit.java | 2 +- .../java/jakarta/data/page/CursoredPage.java | 2 +- .../java/jakarta/data/page/PageRequest.java | 4 +- .../main/java/jakarta/data/repository/Is.java | 81 ++++++++----------- .../java/jakarta/data/repository/OrderBy.java | 4 +- .../jakarta/data/repository/Repository.java | 2 +- api/src/main/java/module-info.java | 26 +++--- 7 files changed, 53 insertions(+), 68 deletions(-) diff --git a/api/src/main/java/jakarta/data/Limit.java b/api/src/main/java/jakarta/data/Limit.java index d06981a2e..33270b342 100644 --- a/api/src/main/java/jakarta/data/Limit.java +++ b/api/src/main/java/jakarta/data/Limit.java @@ -34,7 +34,7 @@ * *
  * @Find
- * Product[] named(@By(_Product.NAME) @Is(LikeIgnoreCase) String namePattern,
+ * Product[] named(@By(_Product.NAME) @Is(LIKE_IGNORE_CASE) String namePattern,
  *                 Limit limit,
  *                 Sort<Product>... sorts);
  * 
diff --git a/api/src/main/java/jakarta/data/page/CursoredPage.java b/api/src/main/java/jakarta/data/page/CursoredPage.java
index 71770f8ce..4716e0c3b 100644
--- a/api/src/main/java/jakarta/data/page/CursoredPage.java
+++ b/api/src/main/java/jakarta/data/page/CursoredPage.java
@@ -60,7 +60,7 @@
  * @OrderBy(_Employee.FIRSTNAME)
  * @OrderBy(_Employee.ID)
  * CursoredPage<Employee> withOvertime(
- *         @By(_Employee.HOURSWORKED) @Is(GreaterThan) int fullTimeHours,
+ *         @By(_Employee.HOURSWORKED) @Is(GREATER_THAN) int fullTimeHours,
  *         PageRequest pageRequest);
  * 
* diff --git a/api/src/main/java/jakarta/data/page/PageRequest.java b/api/src/main/java/jakarta/data/page/PageRequest.java index f7d90a4b6..b779a9369 100644 --- a/api/src/main/java/jakarta/data/page/PageRequest.java +++ b/api/src/main/java/jakarta/data/page/PageRequest.java @@ -40,8 +40,8 @@ * @Find * @OrderBy("age") * @OrderBy("ssn") - * Person[] agedBetween(@By("age") @Is(GreaterThanEqual) int minAge, - * @By("age") @Is(LessThanEqual) int maxAge, + * Person[] agedBetween(@By("age") @Is(GREATER_THAN_EQ) int minAge, + * @By("age") @Is(LESS_THAN_EQ) int maxAge, * PageRequest pageRequest); * * diff --git a/api/src/main/java/jakarta/data/repository/Is.java b/api/src/main/java/jakarta/data/repository/Is.java index 20adb800c..ac1cfea1b 100644 --- a/api/src/main/java/jakarta/data/repository/Is.java +++ b/api/src/main/java/jakarta/data/repository/Is.java @@ -36,26 +36,45 @@ * * // Find all Product entities where the price field is less than a maximum value. * @Find - * List<Product> pricedBelow(@By(_Product.PRICE) @Is(LessThan) float max); + * List<Product> pricedBelow(@By(_Product.PRICE) @Is(LESS_THAN) float max); * * // Find a page of Product entities where the name field matches a pattern, ignoring case. * @Find - * Page<Product> search(@By(_Product.NAME) @Is(LikeIgnoreCase) String pattern, + * Page<Product> search(@By(_Product.NAME) @Is(LIKE_IGNORE_CASE) String pattern, * PageRequest pagination, * Order<Product> order); * * // Remove Product entities with any of the unique identifiers listed. * @Delete - * void remove(@By(ID) @Is(In) List<Long> productIds); + * void remove(@By(ID) @Is(IN) List<Long> productIds); * } * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface Is { + // TODO add JavaDoc with examples to these + String EQUAL = "EQUAL"; + String GREATER_THAN = "GREATER_THAN"; + String GREATER_THAN_EQ = "GREATER_THAN_EQ"; + String IGNORE_CASE = "IGNORE_CASE"; + String IN = "IN"; + String LESS_THAN = "LESS_THAN"; + String LESS_THAN_EQ = "LESS_THAN_EQ"; + String LIKE = "LIKE"; + String LIKE_IGNORE_CASE = "LIKE_IGNORE_CASE"; + String NOT = "NOT"; + String NOT_IGNORE_CASE = "NOT_IGNORE_CASE"; + String NOT_IN = "NOT_IN"; + String NOT_LIKE = "NOT_LIKE"; + String NOT_LIKE_IGNORE_CASE = "NOT_LIKE_IGNORE_CASE"; + /** *

The type of comparison operation to use when comparing a persistent - * field against a value that is supplied to a repository method.

+ * field against a value that is supplied to a repository method. + * For portable applications, the comparison operation must be one of the + * constants defined within this class. Jakarta Data providers might choose + * to provide their own constants as non-portable extensions.

* *

The following example compares the year a person was born against * a minimum and maximum year that are supplied as parameters to a repository @@ -64,55 +83,21 @@ *

      * @Find
      * @OrderBy(_Person.YEAR_BORN)
-     * List<Person> bornWithin(@By(_Person.YEAR_BORN) @Is(GreaterThanEqual) float minYear,
-     *                         @By(_Person.YEAR_BORN) @Is(LessThanEqual) float maxYear);
+     * List<Person> bornWithin(@By(_Person.YEAR_BORN) @Is(TREATER_THAN_EQ) float minYear,
+     *                         @By(_Person.YEAR_BORN) @Is(LESS_THAN_EQ) float maxYear);
      * 
* - *

The default comparison operation is the {@linkplain Op#Equal equality} - * comparison.

- * - * @return the type of comparison operation. - */ - Op value() default Op.Equal; - - /** - *

Comparison operations for the {@link Is} annotation.

+ *

The default comparison operation is the {@linkplain #EQUAL equality} + * comparison.

* - *

For more concise code, it can be convenient to statically import one - * or more comparison operations. For example:

+ *

For concise code, it can be convenient for a repository interface to + * statically import one or more constants from this class. For example:

* *
-     * import static jakarta.data.repository.Is.Op.*;
+     * import static jakarta.data.repository.Is.*;
      * 
+ * + * @return the type of comparison operation. */ - public static enum Op { - // TODO add JavaDoc with examples to these - Equal, - GreaterThan, - GreaterThanEqual, - IgnoreCase, - In, - LessThan, - LessThanEqual, - Like, - LikeIgnoreCase, - // TODO might want to give more thought to the exact names, - Prefixed, - PrefixedIgnoreCase, - Substringed, - SubstringedIgnoreCase, - Suffixed, - SuffixedIgnoreCase, - Not, - NotIgnoreCase, - NotIn, - NotLike, - NotLikeIgnoreCase, - NotPrefixed, - NotPrefixedIgnoreCase, - NotSubstringed, - NotSubstringedIgnoreCase, - NotSuffixed, - NotSuffixedIgnoreCase; - } + String value() default EQUAL; } diff --git a/api/src/main/java/jakarta/data/repository/OrderBy.java b/api/src/main/java/jakarta/data/repository/OrderBy.java index 8c1822508..c6ce93653 100644 --- a/api/src/main/java/jakarta/data/repository/OrderBy.java +++ b/api/src/main/java/jakarta/data/repository/OrderBy.java @@ -64,7 +64,7 @@ *
  * @Find
  * @OrderBy(value = _Product.PRICE, descending = true)
- * {@code Stream} pricedBelow(@By(_Product.PRICE) @Is(LessThan) double maxPrice);
+ * {@code Stream} pricedBelow(@By(_Product.PRICE) @Is(LESS_THAN) double maxPrice);
  * 
* *

A repository method with an {@code @OrderBy} annotation must not @@ -118,7 +118,7 @@ *

      * @Find
      * @OrderBy("age")
-     * Stream<Person> withLastName(@By("lastName") @Is(IgnoreCase) String surname);
+     * Stream<Person> withLastName(@By("lastName") @Is(IGNORE_CASE) String surname);
      * 
* * @return entity attribute name. diff --git a/api/src/main/java/jakarta/data/repository/Repository.java b/api/src/main/java/jakarta/data/repository/Repository.java index bfc59513c..93d7bb82d 100644 --- a/api/src/main/java/jakarta/data/repository/Repository.java +++ b/api/src/main/java/jakarta/data/repository/Repository.java @@ -39,7 +39,7 @@ * * @Find * @OrderBy("price") - * List<Product> named(@By("name") @Is(LikeIgnoreCase) String namePattern); + * List<Product> named(@By("name") @Is(LIKE_IGNORE_CASE) String namePattern); * * @Query("UPDATE Product SET price = price - (price * ?1) WHERE price * ?1 <= ?2") * int putOnSale(float rateOfDiscount, float maxDiscount); diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java index 1638d5dde..789c762ef 100644 --- a/api/src/main/java/module-info.java +++ b/api/src/main/java/module-info.java @@ -74,8 +74,8 @@ * @Find * @OrderBy("price") * List<Product> search( - * @By("name") @Is(LikeIgnoreCase) String namePattern, - * @By("price") @Is(LessThanEqual) float max); + * @By("name") @Is(LIKE_IGNORE_CASE) String namePattern, + * @By("price") @Is(lESS_THAN_EQ) float max); * * @Query("UPDATE Product SET price = price * (1.0 - ?1) WHERE yearProduced <= ?2") * int discountOldInventory(float rateOfDiscount, int maxYear); @@ -157,7 +157,7 @@ * @Find * @OrderBy("address.zipCode") * List<Purchase> forZipCodes( - * @By("address.zipCode") @Is(In) List<Integer> zipCodes); + * @By("address.zipCode") @Is(IN) List<Integer> zipCodes); * * @Query("WHERE address.zipCode = ?1") * List<Purchase> forZipCode(int zipCode); @@ -729,7 +729,7 @@ * @OrderBy("firstName") * List<Person> ofNationalityAndOlderThan( * Country nationality, - * @By("age") @Is(GreaterThan) int minAge); + * @By("age") @Is(GREATER_THAN) int minAge); * * *
@@ -739,7 +739,7 @@
  *
  * 
  * @Delete
- * void remove(@By("status") @Is(In) List<Status> list);
+ * void remove(@By("status") @Is(IN) List<Status> list);
  * 
* *

The {@code _} character may be used in a method parameter name to @@ -767,8 +767,8 @@ * @Find * Vehicle[] search(String make, * String model, - * @By(_Vehicle.YEAR) @Is(GreaterThanEqual) int minYear, - * @By(_Vehicle.YEAR) @Is(LessThanEqual) int maxYear, + * @By(_Vehicle.YEAR) @Is(GREATER_THAN_EQ) int minYear, + * @By(_Vehicle.YEAR) @Is(LESS_THAN_EQ) int maxYear, * Sort<?>... sorts); *

* @@ -810,7 +810,7 @@ * @Find * @OrderBy(value = _Product.AMOUNT_SOLD, descending = true) * @OrderBy(ID) - * Product[] named(@By(_Product.NAME) @Is(LikeIgnoreCase) String pattern, + * Product[] named(@By(_Product.NAME) @Is(LIKE_IGNORE_CASE) String pattern, * PageRequest pageRequest); * ... * page1 = products.named("%phone%", PageRequest.ofSize(20)); @@ -828,9 +828,9 @@ * *
  * @Find
- * Product[] search(@By("name") @Is(LikeIgnoreCase) String pattern,
- *                  @By("price") @Is(GreaterThanEqual) float minPrice,
- *                  @By("price") @Is(LessThanEqual) float maxPrice,
+ * Product[] search(@By("name") @Is(LIKE_IGNORE_CASE) String pattern,
+ *                  @By("price") @Is(GREATER_THAN_EQ) float minPrice,
+ *                  @By("price") @Is(LESS_THAN_EQ) float maxPrice,
  *                  PageRequest pageRequest,
  *                  Order<Product> order);
  *
@@ -848,7 +848,7 @@
  *
  * 
  * @Find
- * Product[] named(@By("name") @Is(LikeIgnoreCase) String pattern,
+ * Product[] named(@By("name") @Is(LIKE_IGNORE_CASE) String pattern,
  *                 Limit max,
  *                 Order<Product> sortBy);
  *
@@ -866,7 +866,7 @@
  *
  * 
  * @Find
- * Product[] named(@By("name") @Is(LikeIgnoreCase) String pattern,
+ * Product[] named(@By("name") @Is(LIKE_IGNORE_CASE) String pattern,
  *                 Limit max,
  *                 {@code Sort...} sortBy);
  *

From cd19343c5a3d25be57f40e2ca186e5abb21ff88f Mon Sep 17 00:00:00 2001
From: Nathan Rauh 
Date: Fri, 8 Nov 2024 13:44:03 -0600
Subject: [PATCH 3/4] Put the enumeration back, but keep the upper case, and
 shorten IGNORE_CASE to ANY_CASE

---
 api/src/main/java/jakarta/data/Limit.java     |  2 +-
 .../main/java/jakarta/data/repository/Is.java | 78 +++++++++++++------
 .../java/jakarta/data/repository/OrderBy.java |  2 +-
 .../jakarta/data/repository/Repository.java   |  2 +-
 api/src/main/java/module-info.java            | 10 +--
 5 files changed, 61 insertions(+), 33 deletions(-)

diff --git a/api/src/main/java/jakarta/data/Limit.java b/api/src/main/java/jakarta/data/Limit.java
index 33270b342..ddd1a150d 100644
--- a/api/src/main/java/jakarta/data/Limit.java
+++ b/api/src/main/java/jakarta/data/Limit.java
@@ -34,7 +34,7 @@
  *
  * 
  * @Find
- * Product[] named(@By(_Product.NAME) @Is(LIKE_IGNORE_CASE) String namePattern,
+ * Product[] named(@By(_Product.NAME) @Is(LIKE_ANY_CASE) String namePattern,
  *                 Limit limit,
  *                 Sort<Product>... sorts);
  * 
diff --git a/api/src/main/java/jakarta/data/repository/Is.java b/api/src/main/java/jakarta/data/repository/Is.java
index ac1cfea1b..c12eade51 100644
--- a/api/src/main/java/jakarta/data/repository/Is.java
+++ b/api/src/main/java/jakarta/data/repository/Is.java
@@ -25,8 +25,10 @@
 /**
  * 

Annotates a parameter of a repository {@link Find} or {@link Delete} method, * indicating how a persistent field is compared against the parameter's value. - * The {@link By} annotation is used on the same parameter to identify the - * persistent field.

+ * The {@link By} annotation can be used on the same parameter to identify the + * persistent field. Otherwise, if the {@code -parameters} compile option is + * enabled, the the persistent field is inferred by matching the name of the + * method parameter.

* *

For example,

* @@ -40,7 +42,7 @@ * * // Find a page of Product entities where the name field matches a pattern, ignoring case. * @Find - * Page<Product> search(@By(_Product.NAME) @Is(LIKE_IGNORE_CASE) String pattern, + * Page<Product> search(@By(_Product.NAME) @Is(LIKE_ANY_CASE) String pattern, * PageRequest pagination, * Order<Product> order); * @@ -53,28 +55,10 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface Is { - // TODO add JavaDoc with examples to these - String EQUAL = "EQUAL"; - String GREATER_THAN = "GREATER_THAN"; - String GREATER_THAN_EQ = "GREATER_THAN_EQ"; - String IGNORE_CASE = "IGNORE_CASE"; - String IN = "IN"; - String LESS_THAN = "LESS_THAN"; - String LESS_THAN_EQ = "LESS_THAN_EQ"; - String LIKE = "LIKE"; - String LIKE_IGNORE_CASE = "LIKE_IGNORE_CASE"; - String NOT = "NOT"; - String NOT_IGNORE_CASE = "NOT_IGNORE_CASE"; - String NOT_IN = "NOT_IN"; - String NOT_LIKE = "NOT_LIKE"; - String NOT_LIKE_IGNORE_CASE = "NOT_LIKE_IGNORE_CASE"; /** *

The type of comparison operation to use when comparing a persistent - * field against a value that is supplied to a repository method. - * For portable applications, the comparison operation must be one of the - * constants defined within this class. Jakarta Data providers might choose - * to provide their own constants as non-portable extensions.

+ * field against a value that is supplied to a repository method..

* *

The following example compares the year a person was born against * a minimum and maximum year that are supplied as parameters to a repository @@ -83,7 +67,7 @@ *

      * @Find
      * @OrderBy(_Person.YEAR_BORN)
-     * List<Person> bornWithin(@By(_Person.YEAR_BORN) @Is(TREATER_THAN_EQ) float minYear,
+     * List<Person> bornWithin(@By(_Person.YEAR_BORN) @Is(GREATER_THAN_EQ) float minYear,
      *                         @By(_Person.YEAR_BORN) @Is(LESS_THAN_EQ) float maxYear);
      * 
* @@ -94,10 +78,54 @@ * statically import one or more constants from this class. For example:

* *
-     * import static jakarta.data.repository.Is.*;
+     * import static jakarta.data.repository.Is.Op.*;
      * 
* * @return the type of comparison operation. */ - String value() default EQUAL; + Op value() default Op.EQUAL; + + /** + *

Comparison operations for the {@link Is} annotation.

+ * + *

For more concise code, it can be convenient to statically import one + * or more comparison operations. For example:

+ * + *
+     * import static jakarta.data.repository.Is.Op.*;
+     * 
+ */ + public static enum Op { + // TODO add JavaDoc with examples to these + ANY_CASE, + EQUAL, + GREATER_THAN, + GREATER_THAN_ANY_CASE, + GREATER_THAN_EQ, + GREATER_THAN_EQ_ANY_CASE, + IN, + LESS_THAN, + LESS_THAN_ANY_CASE, + LESS_THAN_EQ, + LESS_THAN_EQ_ANY_CASE, + LIKE, + LIKE_ANY_CASE, + PREFIXED, + PREFIXED_ANY_CASE, + SUBSTRINGED, + SUBSTRINGED_ANY_CASE, + SUFFIXED, + SUFFIXED_ANY_CASE, + NOT, + NOT_ANY_CASE, + NOT_IN, + NOT_LIKE, + NOT_LIKE_ANY_CASE, + NOT_PREFIXED, + NOT_PREFIXED_ANY_CASE, + NOT_SUBSTRINGED, + NOT_SUBSTRINGED_ANY_CASE, + NOT_SUFFIXED, + NOT_SUFFIXED_ANY_CASE; + } } diff --git a/api/src/main/java/jakarta/data/repository/OrderBy.java b/api/src/main/java/jakarta/data/repository/OrderBy.java index c6ce93653..8d84373ec 100644 --- a/api/src/main/java/jakarta/data/repository/OrderBy.java +++ b/api/src/main/java/jakarta/data/repository/OrderBy.java @@ -118,7 +118,7 @@ *
      * @Find
      * @OrderBy("age")
-     * Stream<Person> withLastName(@By("lastName") @Is(IGNORE_CASE) String surname);
+     * Stream<Person> withLastName(@By("lastName") @Is(ANY_CASE) String surname);
      * 
* * @return entity attribute name. diff --git a/api/src/main/java/jakarta/data/repository/Repository.java b/api/src/main/java/jakarta/data/repository/Repository.java index 93d7bb82d..d020f4d4e 100644 --- a/api/src/main/java/jakarta/data/repository/Repository.java +++ b/api/src/main/java/jakarta/data/repository/Repository.java @@ -39,7 +39,7 @@ * * @Find * @OrderBy("price") - * List<Product> named(@By("name") @Is(LIKE_IGNORE_CASE) String namePattern); + * List<Product> named(@By("name") @Is(LIKE_ANY_CASE) String namePattern); * * @Query("UPDATE Product SET price = price - (price * ?1) WHERE price * ?1 <= ?2") * int putOnSale(float rateOfDiscount, float maxDiscount); diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java index 789c762ef..87281f858 100644 --- a/api/src/main/java/module-info.java +++ b/api/src/main/java/module-info.java @@ -74,7 +74,7 @@ * @Find * @OrderBy("price") * List<Product> search( - * @By("name") @Is(LIKE_IGNORE_CASE) String namePattern, + * @By("name") @Is(LIKE_ANY_CASE) String namePattern, * @By("price") @Is(lESS_THAN_EQ) float max); * * @Query("UPDATE Product SET price = price * (1.0 - ?1) WHERE yearProduced <= ?2") @@ -810,7 +810,7 @@ * @Find * @OrderBy(value = _Product.AMOUNT_SOLD, descending = true) * @OrderBy(ID) - * Product[] named(@By(_Product.NAME) @Is(LIKE_IGNORE_CASE) String pattern, + * Product[] named(@By(_Product.NAME) @Is(LIKE_ANY_CASE) String pattern, * PageRequest pageRequest); * ... * page1 = products.named("%phone%", PageRequest.ofSize(20)); @@ -828,7 +828,7 @@ * *
  * @Find
- * Product[] search(@By("name") @Is(LIKE_IGNORE_CASE) String pattern,
+ * Product[] search(@By("name") @Is(LIKE_ANY_CASE) String pattern,
  *                  @By("price") @Is(GREATER_THAN_EQ) float minPrice,
  *                  @By("price") @Is(LESS_THAN_EQ) float maxPrice,
  *                  PageRequest pageRequest,
@@ -848,7 +848,7 @@
  *
  * 
  * @Find
- * Product[] named(@By("name") @Is(LIKE_IGNORE_CASE) String pattern,
+ * Product[] named(@By("name") @Is(LIKE_ANY_CASE) String pattern,
  *                 Limit max,
  *                 Order<Product> sortBy);
  *
@@ -866,7 +866,7 @@
  *
  * 
  * @Find
- * Product[] named(@By("name") @Is(LIKE_IGNORE_CASE) String pattern,
+ * Product[] named(@By("name") @Is(LIKE_ANY_CASE) String pattern,
  *                 Limit max,
  *                 {@code Sort...} sortBy);
  *

From a55eebad5c5bc65cec7e25bc6c68442a29d98e68 Mon Sep 17 00:00:00 2001
From: Nathan Rauh 
Date: Mon, 17 Feb 2025 11:33:02 -0600
Subject: [PATCH 4/4] Reuse existing Operator enum

---
 api/src/main/java/jakarta/data/Limit.java     |  2 +-
 .../data/metamodel/restrict/Operator.java     | 23 ++++++-
 .../java/jakarta/data/page/PageRequest.java   |  4 +-
 .../jakarta/data/repository/IgnoreCase.java   | 60 +++++++++++++++++++
 .../main/java/jakarta/data/repository/Is.java | 60 +++----------------
 .../java/jakarta/data/repository/OrderBy.java |  2 +-
 .../jakarta/data/repository/Repository.java   |  2 +-
 api/src/main/java/module-info.java            | 20 +++----
 8 files changed, 106 insertions(+), 67 deletions(-)
 create mode 100644 api/src/main/java/jakarta/data/repository/IgnoreCase.java

diff --git a/api/src/main/java/jakarta/data/Limit.java b/api/src/main/java/jakarta/data/Limit.java
index ddd1a150d..7f144f252 100644
--- a/api/src/main/java/jakarta/data/Limit.java
+++ b/api/src/main/java/jakarta/data/Limit.java
@@ -34,7 +34,7 @@
  *
  * 
  * @Find
- * Product[] named(@By(_Product.NAME) @Is(LIKE_ANY_CASE) String namePattern,
+ * Product[] named(@By(_Product.NAME) @Is(LIKE) @IgnoreCase String namePattern,
  *                 Limit limit,
  *                 Sort<Product>... sorts);
  * 
diff --git a/api/src/main/java/jakarta/data/metamodel/restrict/Operator.java b/api/src/main/java/jakarta/data/metamodel/restrict/Operator.java
index 8cb178c10..84015544d 100644
--- a/api/src/main/java/jakarta/data/metamodel/restrict/Operator.java
+++ b/api/src/main/java/jakarta/data/metamodel/restrict/Operator.java
@@ -27,7 +27,13 @@ public enum Operator {
     LIKE,
     NOT_EQUAL,
     NOT_IN,
-    NOT_LIKE;
+    NOT_LIKE,
+    NOT_PREFIXED,
+    NOT_SUBSTRINGED,
+    NOT_SUFFIXED,
+    PREFIXED,
+    SUBSTRINGED,
+    SUFFIXED;
 
     /**
      * Representation of the operator as it appears in query language.
@@ -35,6 +41,9 @@ public enum Operator {
      * in query langugae.
      *
      * @return the representation of the operator in query language.
+     *         For operators that have a more complex representation in
+     *         query language, this method returns the {@link #name()}
+     *         of the operator.
      */
     String asQueryLanguage() {
         return switch (this) {
@@ -48,6 +57,12 @@ String asQueryLanguage() {
             case NOT_EQUAL -> "<>";
             case NOT_IN -> "NOT IN";
             case NOT_LIKE -> "NOT LIKE";
+            case NOT_PREFIXED -> NOT_PREFIXED.name();
+            case NOT_SUBSTRINGED -> NOT_SUBSTRINGED.name();
+            case NOT_SUFFIXED -> NOT_SUFFIXED.name();
+            case PREFIXED -> PREFIXED.name();
+            case SUBSTRINGED -> SUBSTRINGED.name();
+            case SUFFIXED -> SUFFIXED.name();
         };
     }
 
@@ -68,6 +83,12 @@ Operator negate() {
             case NOT_EQUAL -> EQUAL;
             case NOT_IN -> IN;
             case NOT_LIKE -> LIKE;
+            case NOT_PREFIXED -> PREFIXED;
+            case NOT_SUBSTRINGED -> SUBSTRINGED;
+            case NOT_SUFFIXED -> SUFFIXED;
+            case PREFIXED -> NOT_PREFIXED;
+            case SUBSTRINGED -> NOT_SUBSTRINGED;
+            case SUFFIXED -> NOT_SUFFIXED;
         };
     }
 }
diff --git a/api/src/main/java/jakarta/data/page/PageRequest.java b/api/src/main/java/jakarta/data/page/PageRequest.java
index b779a9369..d88dc6a9c 100644
--- a/api/src/main/java/jakarta/data/page/PageRequest.java
+++ b/api/src/main/java/jakarta/data/page/PageRequest.java
@@ -40,8 +40,8 @@
  * @Find
  * @OrderBy("age")
  * @OrderBy("ssn")
- * Person[] agedBetween(@By("age") @Is(GREATER_THAN_EQ) int minAge,
- *                      @By("age") @Is(LESS_THAN_EQ) int maxAge,
+ * Person[] agedBetween(@By("age") @Is(GREATER_THAN_EQUAL) int minAge,
+ *                      @By("age") @Is(LESS_THAN_EQUAL) int maxAge,
  *                      PageRequest pageRequest);
  * 
* diff --git a/api/src/main/java/jakarta/data/repository/IgnoreCase.java b/api/src/main/java/jakarta/data/repository/IgnoreCase.java new file mode 100644 index 000000000..da69c020c --- /dev/null +++ b/api/src/main/java/jakarta/data/repository/IgnoreCase.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024,2025 Contributors to the Eclipse Foundation + * + * 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 + * + * http://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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package jakarta.data.repository; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import jakarta.data.metamodel.restrict.Operator; + +/** + *

Annotates a parameter of a repository {@link Find} or {@link Delete} method, + * indicating that a persistent field should be compared ignoring case. + * The {@link By} annotation can be used on the same parameter to identify the + * persistent field. Otherwise, if the {@code -parameters} compile option is + * enabled, the the persistent field is inferred by matching the name of the + * method parameter. The {@link Operator#EQUAL EQUAL} comparison is assumed + * unless the {@link Is} annotation is used on the same parameter to choose a + * different type of comparison.

+ * + *

For example,

+ * + *
+ * @Repository
+ * public interface People extends BasicRepository<Person, Long> {
+ *
+ *     // Find all Person entities where the lastName matches the respective value
+ *     // ignoring case.
+ *     @Find
+ *     List<Person> withSurname(@By(_Person.LASTNAME) @IgnoreCase String surname);
+ *
+ *     // Find a page of Person entities where the lastName field begins with the
+ *     // supplied prefix, ignoring case.
+ *     @Find
+ *     Page<Person> withSurnamePrefix(@By(_Product.LASTNAME) @Is(PREFIXED) @IgnoreCase String prefix,
+ *                                    PageRequest pagination,
+ *                                    Order<Person> order);
+ * }
+ * 
+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +public @interface IgnoreCase { +} diff --git a/api/src/main/java/jakarta/data/repository/Is.java b/api/src/main/java/jakarta/data/repository/Is.java index c12eade51..3d3d6ba43 100644 --- a/api/src/main/java/jakarta/data/repository/Is.java +++ b/api/src/main/java/jakarta/data/repository/Is.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Contributors to the Eclipse Foundation + * Copyright (c) 2024,2025 Contributors to the Eclipse Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import jakarta.data.metamodel.restrict.Operator; + /** *

Annotates a parameter of a repository {@link Find} or {@link Delete} method, * indicating how a persistent field is compared against the parameter's value. @@ -42,7 +44,7 @@ * * // Find a page of Product entities where the name field matches a pattern, ignoring case. * @Find - * Page<Product> search(@By(_Product.NAME) @Is(LIKE_ANY_CASE) String pattern, + * Page<Product> search(@By(_Product.NAME) @Is(LIKE) @IgnoreCase String pattern, * PageRequest pagination, * Order<Product> order); * @@ -67,65 +69,21 @@ *

      * @Find
      * @OrderBy(_Person.YEAR_BORN)
-     * List<Person> bornWithin(@By(_Person.YEAR_BORN) @Is(GREATER_THAN_EQ) float minYear,
-     *                         @By(_Person.YEAR_BORN) @Is(LESS_THAN_EQ) float maxYear);
+     * List<Person> bornWithin(@By(_Person.YEAR_BORN) @Is(GREATER_THAN_EQUAL) float minYear,
+     *                         @By(_Person.YEAR_BORN) @Is(LESS_THAN_EQUAL) float maxYear);
      * 
* - *

The default comparison operation is the {@linkplain #EQUAL equality} + *

The default comparison operation is the {@linkplain Operator#EQUAL equality} * comparison.

* *

For concise code, it can be convenient for a repository interface to * statically import one or more constants from this class. For example:

* *
-     * import static jakarta.data.repository.Is.Op.*;
+     * import static jakarta.data.metamodel.restrict.Operator.*;
      * 
* * @return the type of comparison operation. */ - Op value() default Op.EQUAL; - - /** - *

Comparison operations for the {@link Is} annotation.

- * - *

For more concise code, it can be convenient to statically import one - * or more comparison operations. For example:

- * - *
-     * import static jakarta.data.repository.Is.Op.*;
-     * 
- */ - public static enum Op { - // TODO add JavaDoc with examples to these - ANY_CASE, - EQUAL, - GREATER_THAN, - GREATER_THAN_ANY_CASE, - GREATER_THAN_EQ, - GREATER_THAN_EQ_ANY_CASE, - IN, - LESS_THAN, - LESS_THAN_ANY_CASE, - LESS_THAN_EQ, - LESS_THAN_EQ_ANY_CASE, - LIKE, - LIKE_ANY_CASE, - PREFIXED, - PREFIXED_ANY_CASE, - SUBSTRINGED, - SUBSTRINGED_ANY_CASE, - SUFFIXED, - SUFFIXED_ANY_CASE, - NOT, - NOT_ANY_CASE, - NOT_IN, - NOT_LIKE, - NOT_LIKE_ANY_CASE, - NOT_PREFIXED, - NOT_PREFIXED_ANY_CASE, - NOT_SUBSTRINGED, - NOT_SUBSTRINGED_ANY_CASE, - NOT_SUFFIXED, - NOT_SUFFIXED_ANY_CASE; - } + Operator value() default Operator.EQUAL; } diff --git a/api/src/main/java/jakarta/data/repository/OrderBy.java b/api/src/main/java/jakarta/data/repository/OrderBy.java index 8d84373ec..ff1e1c6cc 100644 --- a/api/src/main/java/jakarta/data/repository/OrderBy.java +++ b/api/src/main/java/jakarta/data/repository/OrderBy.java @@ -118,7 +118,7 @@ *
      * @Find
      * @OrderBy("age")
-     * Stream<Person> withLastName(@By("lastName") @Is(ANY_CASE) String surname);
+     * Stream<Person> withLastName(@By("lastName") @IgnoreCase String surname);
      * 
* * @return entity attribute name. diff --git a/api/src/main/java/jakarta/data/repository/Repository.java b/api/src/main/java/jakarta/data/repository/Repository.java index d020f4d4e..f3e820680 100644 --- a/api/src/main/java/jakarta/data/repository/Repository.java +++ b/api/src/main/java/jakarta/data/repository/Repository.java @@ -39,7 +39,7 @@ * * @Find * @OrderBy("price") - * List<Product> named(@By("name") @Is(LIKE_ANY_CASE) String namePattern); + * List<Product> named(@By("name") @Is(LIKE) @IgnoreCase String namePattern); * * @Query("UPDATE Product SET price = price - (price * ?1) WHERE price * ?1 <= ?2") * int putOnSale(float rateOfDiscount, float maxDiscount); diff --git a/api/src/main/java/module-info.java b/api/src/main/java/module-info.java index 87281f858..4be5dae70 100644 --- a/api/src/main/java/module-info.java +++ b/api/src/main/java/module-info.java @@ -74,8 +74,8 @@ * @Find * @OrderBy("price") * List<Product> search( - * @By("name") @Is(LIKE_ANY_CASE) String namePattern, - * @By("price") @Is(lESS_THAN_EQ) float max); + * @By("name") @Is(LIKE) @IgnoreCase String namePattern, + * @By("price") @Is(lESS_THAN_EQUAL) float max); * * @Query("UPDATE Product SET price = price * (1.0 - ?1) WHERE yearProduced <= ?2") * int discountOldInventory(float rateOfDiscount, int maxYear); @@ -767,8 +767,8 @@ * @Find * Vehicle[] search(String make, * String model, - * @By(_Vehicle.YEAR) @Is(GREATER_THAN_EQ) int minYear, - * @By(_Vehicle.YEAR) @Is(LESS_THAN_EQ) int maxYear, + * @By(_Vehicle.YEAR) @Is(GREATER_THAN_EQUAL) int minYear, + * @By(_Vehicle.YEAR) @Is(LESS_THAN_EQUAL) int maxYear, * Sort<?>... sorts); *
* @@ -810,7 +810,7 @@ * @Find * @OrderBy(value = _Product.AMOUNT_SOLD, descending = true) * @OrderBy(ID) - * Product[] named(@By(_Product.NAME) @Is(LIKE_ANY_CASE) String pattern, + * Product[] named(@By(_Product.NAME) @Is(LIKE) @IgnoreCase String pattern, * PageRequest pageRequest); * ... * page1 = products.named("%phone%", PageRequest.ofSize(20)); @@ -828,9 +828,9 @@ * *
  * @Find
- * Product[] search(@By("name") @Is(LIKE_ANY_CASE) String pattern,
- *                  @By("price") @Is(GREATER_THAN_EQ) float minPrice,
- *                  @By("price") @Is(LESS_THAN_EQ) float maxPrice,
+ * Product[] search(@By("name") @Is(LIKE) @IgnoreCase String pattern,
+ *                  @By("price") @Is(GREATER_THAN_EQUAL) float minPrice,
+ *                  @By("price") @Is(LESS_THAN_EQUAL) float maxPrice,
  *                  PageRequest pageRequest,
  *                  Order<Product> order);
  *
@@ -848,7 +848,7 @@
  *
  * 
  * @Find
- * Product[] named(@By("name") @Is(LIKE_ANY_CASE) String pattern,
+ * Product[] named(@By("name") @Is(LIKE) @IgnoreCase String pattern,
  *                 Limit max,
  *                 Order<Product> sortBy);
  *
@@ -866,7 +866,7 @@
  *
  * 
  * @Find
- * Product[] named(@By("name") @Is(LIKE_ANY_CASE) String pattern,
+ * Product[] named(@By("name") @Is(LIKE) @IgnoreCase String pattern,
  *                 Limit max,
  *                 {@code Sort...} sortBy);
  *