From 74f860488ffb41b4e4acbe158a58895520b8968b Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sun, 17 Mar 2024 23:55:56 +0100 Subject: [PATCH] allow multi-valued parameters to @Find & @Delete methods - interpreted as defining an "in" condition - allows a methods of BasicRepository to be redefined in terms of @Find & @Delete --- .../jakarta/data/repository/BasicRepository.java | 14 ++++++++++---- .../main/java/jakarta/data/repository/Delete.java | 11 ++++++----- .../main/java/jakarta/data/repository/Find.java | 11 ++++++++--- spec/src/main/asciidoc/repository.asciidoc | 5 ++++- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/jakarta/data/repository/BasicRepository.java b/api/src/main/java/jakarta/data/repository/BasicRepository.java index 5a0ca7fe8..37a337f80 100644 --- a/api/src/main/java/jakarta/data/repository/BasicRepository.java +++ b/api/src/main/java/jakarta/data/repository/BasicRepository.java @@ -24,6 +24,8 @@ import java.util.Optional; import java.util.stream.Stream; +import static jakarta.data.repository.By.ID; + /** *

A built-in repository supertype for performing basic operations on entities.

* @@ -140,7 +142,8 @@ public interface BasicRepository extends DataRepository { * @return the entity with the given Id or {@link Optional#empty()} if none is found. * @throws NullPointerException when the Id is {@code null}. */ - Optional findById(K id); + @Find + Optional findById(@By(ID) K id); /** * Returns whether an entity with the given Id exists. @@ -186,7 +189,8 @@ public interface BasicRepository extends DataRepository { * ids. * @throws NullPointerException in case the given {@link Iterable ids} or one of its items is {@code null}. */ - Stream findByIdIn(Iterable ids); + @Find + Stream findByIdIn(@By(ID) Iterable ids); /** * Deletes the entity with the given Id. @@ -196,7 +200,8 @@ public interface BasicRepository extends DataRepository { * @param id must not be {@code null}. * @throws NullPointerException when the Id is {@code null}. */ - void deleteById(K id); + @Delete + void deleteById(@By(ID) K id); /** * Deletes a given entity. Deletion is performed by matching the Id, and if the entity is @@ -219,7 +224,8 @@ public interface BasicRepository extends DataRepository { * @param ids must not be {@code null}. Must not contain {@code null} elements. * @throws NullPointerException when the iterable is {@code null} or contains {@code null} elements. */ - void deleteByIdIn(Iterable ids); + @Delete + void deleteByIdIn(@By(ID) Iterable ids); /** * Deletes the given entities. Deletion of each entity is performed by matching the unique identifier, diff --git a/api/src/main/java/jakarta/data/repository/Delete.java b/api/src/main/java/jakarta/data/repository/Delete.java index 199d59024..6590479a1 100644 --- a/api/src/main/java/jakarta/data/repository/Delete.java +++ b/api/src/main/java/jakarta/data/repository/Delete.java @@ -63,9 +63,10 @@ *

Alternatively, the {@code Delete} annotation may be used to annotate a repository method with no parameter of * entity type. Then the repository method is interpreted as a parameter-based automatic query method. The entity type * to be deleted is the primary entity type of the repository. The method return type must be {@code void}, {@code int}, - * or {@code long}. Every parameter of the annotated method must have exactly the same type and name (the parameter name - * in the Java source, or a name assigned by {@link By @By}) as a persistent field or property of the entity class. - * Parameters of type {@code Sort}, {@code Order}, {@code Limit}, and {@code PageRequest} are prohibited. + * or {@code long}. Every parameter of the annotated method must have exactly the same name (the parameter name in the + * Java source, or a name assigned by {@link By @By}) as a persistent field or property of the entity class and be of + * type {@code T}, {@code T[]}, or {@code Iterable} where {@code T} is the type of the field or property. Parameters + * of type {@code Sort}, {@code Order}, {@code Limit}, and {@code PageRequest} are prohibited. *

*

For example, consider an interface representing a garage:

*
@@ -76,10 +77,10 @@
  *     void unparkAll();
  *
  *     {@code @Delete}
- *     void unpark(String registration);
+ *     void unpark(String[] registration);
  * }
  * 
- *

Here,{@code unparkAll()} deletes every {@code Car}, while {@code unpark(String)} deletes any {@code Car} with a + *

Here,{@code unparkAll()} deletes every {@code Car}, while {@code unpark(String)} deletes every {@code Car} with a * matching value of its {@code registration} field. *

*

An automatic query method annotated {@code Delete} removes every record which satisfies the parameter-based diff --git a/api/src/main/java/jakarta/data/repository/Find.java b/api/src/main/java/jakarta/data/repository/Find.java index dbc12de80..56f6ec26b 100644 --- a/api/src/main/java/jakarta/data/repository/Find.java +++ b/api/src/main/java/jakarta/data/repository/Find.java @@ -33,8 +33,9 @@ * type returned by the query. Each parameter of the annotated method must either: *

*
    - *
  • have exactly the same type and name (the parameter name in the Java source, or a name assigned by {@link By @By}) - * as a persistent field or property of the entity class, or
  • + *
  • have exactly the name (the parameter name in the Java source, or a name assigned by {@link By @By}) as a + * persistent field or property of the entity class and be of type {@code T}, {@code T[]}, or {@code Iterable} + * where {@code T} is the type of the field or property, or
  • *
  • be of type {@link jakarta.data.Limit}, {@link jakarta.data.Sort}, {@link jakarta.data.Order}, or * {@link jakarta.data.page.PageRequest}.
  • *
@@ -49,10 +50,14 @@ * interface Garage { * {@code @Find} * {@code List} getCarsWithModel(@By("model") String model); + * + * {@code @Find} + * {@code List} getCarsWithYearIn(@By("modelYear") int[] years); * } * *

The {@code @Find} annotation indicates that the {@code getCarsWithModel(model)} method retrieves {@code Car} - * instances with the given value of the {@code model} field. + * instances with the given value of the {@code model} field, and that the {@code getCarsWithYearIn(years)} method + * retrieves cars with any one of the given values of the {@code modelYear} field. *

* *

A method annotated with {@code @Find} must return one of the following types:

diff --git a/spec/src/main/asciidoc/repository.asciidoc b/spec/src/main/asciidoc/repository.asciidoc index cf0e67a81..bd7e06d41 100644 --- a/spec/src/main/asciidoc/repository.asciidoc +++ b/spec/src/main/asciidoc/repository.asciidoc @@ -831,7 +831,7 @@ Each automatic query method must be assigned an entity type. The rules for infer Jakarta Data infers a query based on the parameters of the method. Each parameter must either: -- have exactly the same type and name as a persistent field or property of the entity class, or +- have exactly the same name as a persistent field or property of the entity class and be of type `T`, `T[]`, or `Iterable` where `T` is the type of the field or property, or - be of type `Limit`, `Order`, `PageRequest`, or `Sort`. Parameter names map parameters to persistent fields. A repository with parameter-based automatic query methods must either: @@ -851,6 +851,9 @@ For example: @Find Book bookByIsbn(String isbn); +@Find +List booksByIsbn(@By("isbn") String[] isbns); + @Find List booksByYear(Year year, Sort order, Limit limit);