Skip to content

Commit 4595945

Browse files
committed
Add findByIds API to Panache
1 parent c118051 commit 4595945

File tree

22 files changed

+363
-38
lines changed

22 files changed

+363
-38
lines changed

docs/src/main/asciidoc/hibernate-orm-panache.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ List<Person> allPersons = Person.listAll();
223223
// finding a specific person by ID
224224
person = Person.findById(personId);
225225
226+
// finding specific persons by their IDs
227+
List<Person> personsById = Person.findByIds(personId);
228+
226229
// finding a specific person by ID via an Optional
227230
Optional<Person> optional = Person.findByIdOptional(personId);
228231
person = optional.orElseThrow(() -> new NotFoundException());
@@ -441,6 +444,9 @@ List<Person> allPersons = personRepository.listAll();
441444
// finding a specific person by ID
442445
person = personRepository.findById(personId);
443446
447+
// finding specific persons by their IDs
448+
List<Person> personsById = personRepository.findByIds(personId);
449+
444450
// finding a specific person by ID via an Optional
445451
Optional<Person> optional = personRepository.findByIdOptional(personId);
446452
person = optional.orElseThrow(() -> new NotFoundException());

docs/src/main/asciidoc/mongodb-panache.adoc

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@ List<Person> allPersons = Person.listAll();
205205
ObjectId personId = new ObjectId(idAsString);
206206
person = Person.findById(personId);
207207
208+
// finding a specific persons by their ID
209+
ObjectId personId1 = new ObjectId(id1AsString);
210+
ObjectId personId2 = new ObjectId(id2AsString);
211+
List<Person> person = Person.findByIds(List.of(personId1, personId2);
212+
208213
// finding a specific person by ID via an Optional
209214
Optional<Person> optional = Person.findByIdOptional(personId);
210215
person = optional.orElseThrow(() -> new NotFoundException());
@@ -373,6 +378,11 @@ List<Person> allPersons = personRepository.listAll();
373378
ObjectId personId = new ObjectId(idAsString);
374379
person = personRepository.findById(personId);
375380
381+
// finding a specific persons by their ID
382+
ObjectId personId1 = new ObjectId(id1AsString);
383+
ObjectId personId2 = new ObjectId(id2AsString);
384+
List<Person> person = personRepository.findByIds(List.of(personId1, personId2);
385+
376386
// finding a specific person by ID via an Optional
377387
Optional<Person> optional = personRepository.findByIdOptional(personId);
378388
person = optional.orElseThrow(() -> new NotFoundException());
@@ -863,7 +873,7 @@ data class Person (
863873

864874
[IMPORTANT]
865875
====
866-
Unlike the @BsonCreator approach, `val` cannot be used here. Properties must be defined as `var`, otherwise, the system creates an object with
876+
Unlike the @BsonCreator approach, `val` cannot be used here. Properties must be defined as `var`, otherwise, the system creates an object with
867877
`null` values for every property.
868878
====
869879

@@ -935,6 +945,11 @@ Uni<List<ReactivePerson>> allPersons = ReactivePerson.listAll();
935945
ObjectId personId = new ObjectId(idAsString);
936946
Uni<ReactivePerson> personById = ReactivePerson.findById(personId);
937947
948+
// finding a specific persons by their ID
949+
ObjectId personId1 = new ObjectId(id1AsString);
950+
ObjectId personId2 = new ObjectId(id2AsString);
951+
Uni<List<Person>> person = ReactivePerson.findByIds(List.of(personId1, personId2);
952+
938953
// finding a specific person by ID via an Optional
939954
Uni<Optional<ReactivePerson>> optional = ReactivePerson.findByIdOptional(personId);
940955
personById = optional.map(o -> o.orElseThrow(() -> new NotFoundException()));

extensions/panache/hibernate-orm-panache-common/runtime/src/main/java/io/quarkus/hibernate/orm/panache/common/runtime/AbstractJpaOperations.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@
22

33
import static io.quarkus.hibernate.orm.runtime.PersistenceUnitUtil.DEFAULT_PERSISTENCE_UNIT_NAME;
44

5-
import java.util.Collections;
6-
import java.util.List;
7-
import java.util.Map;
5+
import java.util.*;
86
import java.util.Map.Entry;
9-
import java.util.Optional;
107
import java.util.stream.Stream;
118

129
import jakarta.persistence.EntityManager;
@@ -195,6 +192,14 @@ public Optional<?> findByIdOptional(Class<?> entityClass, Object id, LockModeTyp
195192
return Optional.ofNullable(findById(entityClass, id, lockModeType));
196193
}
197194

195+
public List<?> findByIds(Class<?> entityClass, Object... ids) {
196+
return findByIds(entityClass, Arrays.asList(ids));
197+
}
198+
199+
public List<?> findByIds(Class<?> entityClass, List<Object> ids) {
200+
return getSession(entityClass).findMultiple(entityClass, ids);
201+
}
202+
198203
public PanacheQueryType find(Class<?> entityClass, String query, Object... params) {
199204
return find(entityClass, query, null, params);
200205
}

extensions/panache/hibernate-orm-panache-kotlin/runtime/src/test/kotlin/io/quarkus/hibernate/orm/panache/kotlin/runtime/TestAnalogs.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class TestAnalogs {
3636
compare(
3737
map(JavaPanacheRepository::class),
3838
map(PanacheRepository::class),
39-
listOf("findByIdOptional"),
39+
listOf("findByIdOptional", "findByIds"),
4040
)
4141
}
4242

@@ -61,7 +61,9 @@ class TestAnalogs {
6161
}
6262
}
6363
}
64-
javaMethods.removeIf { it.name.endsWith("Optional") || it in implemented }
64+
javaMethods.removeIf {
65+
it.name.endsWith("Optional") || it.name == "findByIds" || it in implemented
66+
}
6567

6668
// methods("javaMethods", javaMethods)
6769
// methods("kotlinMethods", kotlinMethods)
@@ -101,7 +103,10 @@ class TestAnalogs {
101103
}
102104

103105
javaMethods.removeIf {
104-
it.name.endsWith("Optional") || it.name in allowList || it in implemented
106+
it.name.endsWith("Optional") ||
107+
it.name == "findByIds" ||
108+
it.name in allowList ||
109+
it in implemented
105110
}
106111

107112
// methods("javaMethods", javaMethods)

extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/PanacheEntityBase.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,30 @@ public static <T extends PanacheEntityBase> Optional<T> findByIdOptional(Object
162162
throw implementationInjectionMissing();
163163
}
164164

165+
/**
166+
* Find entities of this type by their IDs.
167+
*
168+
* @param ids the IDs of the entities to find.
169+
* @return a list containing the entities found, with null elements representing missing entities, whose positions in the
170+
* list match the positions of their ids in the given list of identifiers.
171+
*/
172+
@GenerateBridge
173+
public static <T extends PanacheEntityBase> List<T> findByIds(Object... ids) {
174+
throw implementationInjectionMissing();
175+
}
176+
177+
/**
178+
* Find entities of this type by their IDs.
179+
*
180+
* @param ids the IDs of the entities to find.
181+
* @return a list containing the entities found, with null elements representing missing entities, whose positions in the
182+
* list match the positions of their ids in the given list of identifiers.
183+
*/
184+
@GenerateBridge
185+
public static <T extends PanacheEntityBase> List<T> findByIds(List<Object> ids) {
186+
throw implementationInjectionMissing();
187+
}
188+
165189
/**
166190
* Find entities using a query, with optional indexed parameters.
167191
*

extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/PanacheRepositoryBase.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,30 @@ default Optional<Entity> findByIdOptional(Id id, LockModeType lockModeType) {
161161
throw INSTANCE.implementationInjectionMissing();
162162
}
163163

164+
/**
165+
* Find entities of this type by their IDs.
166+
*
167+
* @param ids the IDs of the entities to find.
168+
* @return a list containing the entities found, with null elements representing missing entities, whose positions in the
169+
* list match the positions of their ids in the given list of identifiers.
170+
*/
171+
@GenerateBridge
172+
default <T extends PanacheEntityBase> List<T> findByIds(Object... ids) {
173+
throw INSTANCE.implementationInjectionMissing();
174+
}
175+
176+
/**
177+
* Find entities of this type by their IDs.
178+
*
179+
* @param ids the IDs of the entities to find.
180+
* @return a list containing the entities found, with null elements representing missing entities, whose positions in the
181+
* list match the positions of their ids in the given list of identifiers.
182+
*/
183+
@GenerateBridge
184+
default <T extends PanacheEntityBase> List<T> findByIds(List<Object> ids) {
185+
throw INSTANCE.implementationInjectionMissing();
186+
}
187+
164188
/**
165189
* Find entities using a query, with optional indexed parameters.
166190
*

extensions/panache/hibernate-reactive-panache-kotlin/runtime/src/test/kotlin/io/quarkus/hibernate/reactive/panache/kotlin/TestAnalogs.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ class TestAnalogs {
6666
}
6767
}
6868
}
69-
javaMethods.removeIf { it.name == "findByIdOptional" || it in implemented }
69+
javaMethods.removeIf {
70+
it.name == "findByIdOptional" || it.name == "findByIds" || it in implemented
71+
}
7072

7173
methods("javaMethods", javaMethods)
7274
methods("kotlinMethods", kotlinMethods)

extensions/panache/mongodb-panache-common/deployment/src/test/java/io/quarkus/mongodb/panache/common/MongoDatabaseResolverTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ public void resolveUsingTwoTenantsReactive() {
6464
resolveUsingTwoTenantsTest(true);
6565
}
6666

67+
@Test
68+
public void resolveUsingFindByIdsImperative() {
69+
resolveUsingFindByIds(false);
70+
}
71+
72+
@Test
73+
public void resolveUsingFindByIdsReactive() {
74+
resolveUsingFindByIds(true);
75+
}
76+
6777
private void resolveUsingTwoTenantsTest(final boolean isReactive) {
6878
// arrange
6979
Person personTenant1 = new Person();
@@ -94,6 +104,33 @@ private void resolveUsingTwoTenantsTest(final boolean isReactive) {
94104
assertPerson(personTenant2, (Person) result2);
95105
}
96106

107+
private void resolveUsingFindByIds(final boolean isReactive) {
108+
// arrange
109+
Person person = new Person();
110+
person.id = 3L;
111+
person.firstname = "Pedro";
112+
person.lastname = "Pereira";
113+
114+
Person person2 = new Person();
115+
person2.id = 4L;
116+
person2.firstname = "Tibé";
117+
person2.lastname = "Venâncio";
118+
119+
String TENANT = isReactive ? "reactive-sanjoka" : "sanjoka";
120+
121+
persistPerson(isReactive, person, TENANT);
122+
persistPerson(isReactive, person2, TENANT);
123+
124+
// act
125+
CustomMongoDatabaseResolver.DATABASE = TENANT;
126+
final List<Person> result = (List<Person>) findPersonByIdsUsingMongoOperations(isReactive,
127+
List.of(person.id, person2.id));
128+
129+
// assert
130+
assertPerson(person, result.get(0));
131+
assertPerson(person2, result.get(1));
132+
}
133+
97134
private void persistPerson(final boolean isReactive, final Person person, final String databaseName) {
98135
final Document document = new Document()
99136
.append("_id", person.id)
@@ -120,6 +157,12 @@ private Person findPersonByIdUsingMongoOperations(final boolean isReactive, fina
120157
: (Person) OPERATIONS.findById(Person.class, id);
121158
}
122159

160+
private List<?> findPersonByIdsUsingMongoOperations(final boolean isReactive, final List<Long> ids) {
161+
return isReactive
162+
? REACTIVE_OPERATIONS.findByIds(Person.class, ids).await().indefinitely()
163+
: OPERATIONS.findByIds(Person.class, ids);
164+
}
165+
123166
private void assertPerson(final Person expected, final Person value) {
124167
assertNotNull(value);
125168
assertEquals(expected.id, value.id);

extensions/panache/mongodb-panache-common/runtime/src/main/java/io/quarkus/mongodb/panache/common/reactive/runtime/ReactiveMongoOperations.java

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
package io.quarkus.mongodb.panache.common.reactive.runtime;
22

3+
import static com.mongodb.client.model.Filters.in;
34
import static io.quarkus.mongodb.panache.common.runtime.BeanUtils.beanName;
45
import static io.quarkus.mongodb.panache.common.runtime.BeanUtils.clientFromArc;
56
import static io.quarkus.mongodb.panache.common.runtime.BeanUtils.getDatabaseName;
67
import static io.quarkus.mongodb.panache.common.runtime.BeanUtils.getDatabaseNameFromResolver;
78

8-
import java.util.ArrayList;
9-
import java.util.Arrays;
10-
import java.util.List;
11-
import java.util.Map;
12-
import java.util.Optional;
9+
import java.util.*;
1310
import java.util.concurrent.ConcurrentHashMap;
1411
import java.util.function.Function;
1512
import java.util.stream.Collectors;
@@ -25,10 +22,7 @@
2522
import org.jboss.logging.Logger;
2623

2724
import com.mongodb.ReadPreference;
28-
import com.mongodb.client.model.InsertOneModel;
29-
import com.mongodb.client.model.ReplaceOneModel;
30-
import com.mongodb.client.model.ReplaceOptions;
31-
import com.mongodb.client.model.WriteModel;
25+
import com.mongodb.client.model.*;
3226
import com.mongodb.client.result.DeleteResult;
3327

3428
import io.quarkus.mongodb.panache.common.MongoEntity;
@@ -386,6 +380,24 @@ public Uni<Optional> findByIdOptional(Class<?> entityClass, Object id) {
386380
.onItem().transform(Optional::ofNullable);
387381
}
388382

383+
public <Entity, ID> Uni<List<Entity>> findByIds(Class<?> entityClass, ID... ids) {
384+
return findByIds(entityClass, Arrays.asList(ids));
385+
}
386+
387+
public <Entity, ID> Uni<List<Entity>> findByIds(Class<?> entityClass, List<ID> ids) {
388+
ReactiveMongoCollection collection = mongoCollection(entityClass);
389+
390+
var nonNullIds = ids.stream()
391+
.filter(Objects::nonNull)
392+
.toList();
393+
394+
if (Panache.getCurrentSession() != null) {
395+
return collection.find(Panache.getCurrentSession(), in(ID, nonNullIds)).collect().asList();
396+
}
397+
398+
return collection.find(in(ID, nonNullIds)).collect().asList();
399+
}
400+
389401
public QueryType find(Class<?> entityClass, String query, Object... params) {
390402
return find(entityClass, query, null, params);
391403
}

extensions/panache/mongodb-panache-common/runtime/src/main/java/io/quarkus/mongodb/panache/common/runtime/MongoOperations.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package io.quarkus.mongodb.panache.common.runtime;
22

3-
import java.util.ArrayList;
4-
import java.util.Arrays;
5-
import java.util.List;
6-
import java.util.Map;
7-
import java.util.Optional;
3+
import static com.mongodb.client.model.Filters.in;
4+
5+
import java.util.*;
86
import java.util.concurrent.ConcurrentHashMap;
97
import java.util.function.Function;
108
import java.util.stream.Collectors;
@@ -425,6 +423,23 @@ public Optional findByIdOptional(Class<?> entityClass, Object id) {
425423
return Optional.ofNullable(findById(entityClass, id));
426424
}
427425

426+
public <Entity, ID> List<Entity> findByIds(Class<?> entityClass, ID... ids) {
427+
return findByIds(entityClass, Arrays.asList(ids));
428+
}
429+
430+
public <Entity, ID> List<Entity> findByIds(Class<?> entityClass, List<ID> ids) {
431+
MongoCollection collection = mongoCollection(entityClass);
432+
433+
var nonNullIds = ids.stream()
434+
.filter(Objects::nonNull)
435+
.toList();
436+
437+
ClientSession session = getSession(entityClass);
438+
439+
return session == null ? (List<Entity>) collection.find(in(ID, nonNullIds)).into(new ArrayList<>())
440+
: (List<Entity>) collection.find(session, in(ID, nonNullIds)).into(new ArrayList<>());
441+
}
442+
428443
public QueryType find(Class<?> entityClass, String query, Object... params) {
429444
return find(entityClass, query, null, params);
430445
}

0 commit comments

Comments
 (0)