mirror of
https://github.com/jlengrand/quarkus.git
synced 2026-03-10 08:41:22 +00:00
Merge pull request #5567 from loicmathieu/feat/mongo-panache-rx
Reactive MongoDB with Panache
This commit is contained in:
@@ -321,6 +321,11 @@
|
||||
<artifactId>quarkus-panache-common-deployment</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-mongodb-panache-deployment</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-mongodb-client-deployment</artifactId>
|
||||
|
||||
@@ -582,6 +582,109 @@ data class Person (
|
||||
): PanacheMongoEntity()
|
||||
----
|
||||
|
||||
== Reactive Entities and Repositories
|
||||
|
||||
MongoDB with Panache allows using reactive style implementation for both entities and repositories.
|
||||
For this, you need to use the Reactive variants when defining your entities : `ReactivePanacheMongoEntity` or `ReactivePanacheMongoEntityBase`,
|
||||
and when defining your repositories: `ReactivePanacheMongoRepository` or `ReactivePanacheMongoRepositoryBase`.
|
||||
|
||||
The reactive variant of the `Person` class will be:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
public class ReactivePerson extends ReactivePanacheMongoEntity {
|
||||
public String name;
|
||||
public LocalDate birth;
|
||||
public Status status;
|
||||
|
||||
// return name as uppercase in the model
|
||||
public String getName(){
|
||||
return name.toUpperCase();
|
||||
}
|
||||
|
||||
// store all names in lowercase in the DB
|
||||
public void setName(String name){
|
||||
this.name = name.toLowerCase();
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
You will have access to the same functionalities of the _imperative_ variant inside the reactive one: bson annotations, custom ID, PanacheQL, ...
|
||||
But the methods on your entities or repositories will all return reactive types.
|
||||
|
||||
See the equivalent methods from the imperative example with the reactive variant:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
// creating a person
|
||||
ReactivePerson person = new ReactivePerson();
|
||||
person.name = "Loïc";
|
||||
person.birth = LocalDate.of(1910, Month.FEBRUARY, 1);
|
||||
person.status = Status.Alive;
|
||||
|
||||
// persist it
|
||||
CompletionStage<Void> cs1 = person.persist();
|
||||
|
||||
person.status = Status.Dead;
|
||||
|
||||
// Your must call update() in order to send your entity modifications to MongoDB
|
||||
CompletionStage<Void> cs2 = person.update();
|
||||
|
||||
// delete it
|
||||
CompletionStage<Void> cs3 = person.delete();
|
||||
|
||||
// getting a list of all persons
|
||||
CompletionStage<List<ReactivePerson>> allPersons = ReactivePerson.listAll();
|
||||
|
||||
// finding a specific person by ID
|
||||
CompletionStage<ReactivePerson> personById = ReactivePerson.findById(personId);
|
||||
|
||||
// finding a specific person by ID via an Optional
|
||||
CompletionStage<Optional<ReactivePerson>> optional = ReactivePerson.findByIdOptional(personId);
|
||||
personById = optional.thenApply(o -> o.orElseThrow(() -> new NotFoundException()));
|
||||
|
||||
// finding all living persons
|
||||
CompletionStage<List<ReactivePerson>> livingPersons = ReactivePerson.list("status", Status.Alive);
|
||||
|
||||
// counting all persons
|
||||
CompletionStage<Long> countAll = ReactivePerson.count();
|
||||
|
||||
// counting all living persons
|
||||
CompletionStage<Long> countAlive = ReactivePerson.count("status", Status.Alive);
|
||||
|
||||
// delete all living persons
|
||||
CompletionStage<Long> deleteCount = ReactivePerson.delete("status", Status.Alive);
|
||||
|
||||
// delete all persons
|
||||
deleteCount = ReactivePerson.deleteAll();
|
||||
----
|
||||
|
||||
TIP: If you use MongoDB with Panache in conjunction with RESTEasy, you can directly return a reactive type inside your JAX-RS resource endpoint as RESTEasy will handle it correctly.
|
||||
|
||||
The same query facility exists for the reactive types, but the `stream()` methods act differently: they return a reactive stream `Publisher` instead of a `Stream`.
|
||||
|
||||
It allows more advanced reactive use cases, for example you can use it to send server-sent events (SSE) via RESTEasy:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
import org.jboss.resteasy.annotations.SseElementType;
|
||||
import org.reactivestreams.Publisher;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
|
||||
@GET
|
||||
@Path("/stream")
|
||||
@Produces(MediaType.SERVER_SENT_EVENTS)
|
||||
@SseElementType(MediaType.APPLICATION_JSON)
|
||||
public Publisher<ReactivePerson> streamPersons() {
|
||||
return ReactivePerson.streamAll();
|
||||
}
|
||||
----
|
||||
|
||||
TIP: `@SseElementType(MediaType.APPLICATION_JSON)` tells RESTEasy to serialize the object in JSON.
|
||||
|
||||
|
||||
== How and why we simplify MongoDB API
|
||||
|
||||
When it comes to writing MongoDB entities, there are a number of annoying things that users have grown used to
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.bson.codecs.configuration.CodecRegistry;
|
||||
import org.bson.conversions.Bson;
|
||||
import org.eclipse.microprofile.reactive.streams.operators.PublisherBuilder;
|
||||
|
||||
@@ -30,6 +31,13 @@ public interface ReactiveMongoCollection<T> {
|
||||
*/
|
||||
MongoNamespace getNamespace();
|
||||
|
||||
/**
|
||||
* Gets the codec registry of this collection.
|
||||
*
|
||||
* @return the codec registry
|
||||
*/
|
||||
CodecRegistry getCodecRegistry();
|
||||
|
||||
/**
|
||||
* Get the class of documents stored in this collection.
|
||||
*
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.bson.codecs.configuration.CodecRegistry;
|
||||
import org.bson.conversions.Bson;
|
||||
import org.eclipse.microprofile.reactive.streams.operators.PublisherBuilder;
|
||||
import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreams;
|
||||
@@ -59,6 +60,11 @@ public class ReactiveMongoCollectionImpl<T> implements ReactiveMongoCollection<T
|
||||
return collection.getNamespace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodecRegistry getCodecRegistry() {
|
||||
return collection.getCodecRegistry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getDocumentClass() {
|
||||
return collection.getDocumentClass();
|
||||
|
||||
@@ -71,11 +71,6 @@ public class PanacheMongoEntityEnhancer extends PanacheEntityEnhancer<MetamodelI
|
||||
protected void generateAccessorGetField(MethodVisitor mv, EntityField field) {
|
||||
mv.visitFieldInsn(Opcodes.GETFIELD, thisClass.getInternalName(), field.name, field.descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public void collectFields(ClassInfo classInfo) {
|
||||
|
||||
@@ -45,11 +45,16 @@ import io.quarkus.mongodb.panache.PanacheMongoRecorder;
|
||||
import io.quarkus.mongodb.panache.PanacheMongoRepository;
|
||||
import io.quarkus.mongodb.panache.PanacheMongoRepositoryBase;
|
||||
import io.quarkus.mongodb.panache.ProjectionFor;
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheMongoEntity;
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheMongoEntityBase;
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheMongoRepository;
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheMongoRepositoryBase;
|
||||
import io.quarkus.panache.common.deployment.PanacheEntityClassesBuildItem;
|
||||
import io.quarkus.panache.common.deployment.PanacheFieldAccessEnhancer;
|
||||
import io.quarkus.panache.common.deployment.PanacheRepositoryEnhancer;
|
||||
|
||||
public class PanacheResourceProcessor {
|
||||
// blocking types
|
||||
static final DotName DOTNAME_PANACHE_REPOSITORY_BASE = DotName.createSimple(PanacheMongoRepositoryBase.class.getName());
|
||||
private static final DotName DOTNAME_PANACHE_REPOSITORY = DotName.createSimple(PanacheMongoRepository.class.getName());
|
||||
static final DotName DOTNAME_PANACHE_ENTITY_BASE = DotName.createSimple(PanacheMongoEntityBase.class.getName());
|
||||
@@ -58,6 +63,15 @@ public class PanacheResourceProcessor {
|
||||
private static final DotName DOTNAME_PROJECTION_FOR = DotName.createSimple(ProjectionFor.class.getName());
|
||||
private static final DotName DOTNAME_BSON_PROPERTY = DotName.createSimple(BsonProperty.class.getName());
|
||||
|
||||
// reactive types: Axle
|
||||
static final DotName DOTNAME_AXLE_PANACHE_REPOSITORY_BASE = DotName
|
||||
.createSimple(ReactivePanacheMongoRepositoryBase.class.getName());
|
||||
private static final DotName DOTNAME_AXLE_PANACHE_REPOSITORY = DotName
|
||||
.createSimple(ReactivePanacheMongoRepository.class.getName());
|
||||
static final DotName DOTNAME_AXLE_PANACHE_ENTITY_BASE = DotName
|
||||
.createSimple(ReactivePanacheMongoEntityBase.class.getName());
|
||||
private static final DotName DOTNAME_AXLE_PANACHE_ENTITY = DotName.createSimple(ReactivePanacheMongoEntity.class.getName());
|
||||
|
||||
private static final DotName DOTNAME_OBJECT_ID = DotName.createSimple(ObjectId.class.getName());
|
||||
|
||||
private static final DotName DOTNAME_OBJECT = DotName.createSimple(Object.class.getName());
|
||||
@@ -284,4 +298,58 @@ public class PanacheResourceProcessor {
|
||||
extractMappings(classPropertyMapping, superClass, index);
|
||||
}
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
void buildAxle(CombinedIndexBuildItem index,
|
||||
ApplicationIndexBuildItem applicationIndex,
|
||||
BuildProducer<BytecodeTransformerBuildItem> transformers) throws Exception {
|
||||
|
||||
ReactivePanacheMongoRepositoryEnhancer daoEnhancer = new ReactivePanacheMongoRepositoryEnhancer(index.getIndex());
|
||||
Set<String> daoClasses = new HashSet<>();
|
||||
for (ClassInfo classInfo : index.getIndex().getAllKnownImplementors(DOTNAME_AXLE_PANACHE_REPOSITORY_BASE)) {
|
||||
// Skip PanacheRepository
|
||||
if (classInfo.name().equals(DOTNAME_AXLE_PANACHE_REPOSITORY))
|
||||
continue;
|
||||
if (PanacheRepositoryEnhancer.skipRepository(classInfo))
|
||||
continue;
|
||||
daoClasses.add(classInfo.name().toString());
|
||||
}
|
||||
for (ClassInfo classInfo : index.getIndex().getAllKnownImplementors(DOTNAME_AXLE_PANACHE_REPOSITORY)) {
|
||||
if (PanacheRepositoryEnhancer.skipRepository(classInfo))
|
||||
continue;
|
||||
daoClasses.add(classInfo.name().toString());
|
||||
}
|
||||
for (String daoClass : daoClasses) {
|
||||
transformers.produce(new BytecodeTransformerBuildItem(daoClass, daoEnhancer));
|
||||
}
|
||||
|
||||
ReactivePanacheMongoEntityEnhancer modelEnhancer = new ReactivePanacheMongoEntityEnhancer(index.getIndex());
|
||||
Set<String> modelClasses = new HashSet<>();
|
||||
// Note that we do this in two passes because for some reason Jandex does not give us subtypes
|
||||
// of PanacheMongoEntity if we ask for subtypes of PanacheMongoEntityBase
|
||||
for (ClassInfo classInfo : index.getIndex().getAllKnownSubclasses(DOTNAME_AXLE_PANACHE_ENTITY_BASE)) {
|
||||
if (classInfo.name().equals(DOTNAME_AXLE_PANACHE_ENTITY))
|
||||
continue;
|
||||
if (modelClasses.add(classInfo.name().toString()))
|
||||
modelEnhancer.collectFields(classInfo);
|
||||
}
|
||||
for (ClassInfo classInfo : index.getIndex().getAllKnownSubclasses(DOTNAME_AXLE_PANACHE_ENTITY)) {
|
||||
if (modelClasses.add(classInfo.name().toString()))
|
||||
modelEnhancer.collectFields(classInfo);
|
||||
}
|
||||
for (String modelClass : modelClasses) {
|
||||
transformers.produce(new BytecodeTransformerBuildItem(modelClass, modelEnhancer));
|
||||
}
|
||||
|
||||
if (!modelEnhancer.entities.isEmpty()) {
|
||||
PanacheFieldAccessEnhancer panacheFieldAccessEnhancer = new PanacheFieldAccessEnhancer(
|
||||
modelEnhancer.getModelInfo());
|
||||
for (ClassInfo classInfo : applicationIndex.getIndex().getKnownClasses()) {
|
||||
String className = classInfo.name().toString();
|
||||
if (!modelClasses.contains(className)) {
|
||||
transformers.produce(new BytecodeTransformerBuildItem(className, panacheFieldAccessEnhancer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package io.quarkus.mongodb.panache.deployment;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bson.codecs.pojo.annotations.BsonIgnore;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
import org.jboss.jandex.FieldInfo;
|
||||
import org.jboss.jandex.IndexView;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import io.quarkus.gizmo.DescriptorUtils;
|
||||
import io.quarkus.mongodb.panache.axle.runtime.ReactiveMongoOperations;
|
||||
import io.quarkus.panache.common.deployment.EntityField;
|
||||
import io.quarkus.panache.common.deployment.EntityModel;
|
||||
import io.quarkus.panache.common.deployment.MetamodelInfo;
|
||||
import io.quarkus.panache.common.deployment.PanacheEntityEnhancer;
|
||||
|
||||
public class ReactivePanacheMongoEntityEnhancer extends PanacheEntityEnhancer<MetamodelInfo<EntityModel<EntityField>>> {
|
||||
public final static String MONGO_OPERATIONS_NAME = ReactiveMongoOperations.class.getName();
|
||||
public final static String MONGO_OPERATIONS_BINARY_NAME = MONGO_OPERATIONS_NAME.replace('.', '/');
|
||||
|
||||
private static final DotName DOTNAME_BSON_IGNORE = DotName.createSimple(BsonIgnore.class.getName());
|
||||
|
||||
final Map<String, EntityModel> entities = new HashMap<>();
|
||||
|
||||
public ReactivePanacheMongoEntityEnhancer(IndexView index) {
|
||||
super(index, PanacheResourceProcessor.DOTNAME_AXLE_PANACHE_ENTITY_BASE);
|
||||
modelInfo = new MetamodelInfo<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassVisitor apply(String className, ClassVisitor outputClassVisitor) {
|
||||
return new PanacheMongoEntityClassVisitor(className, outputClassVisitor, modelInfo, panacheEntityBaseClassInfo,
|
||||
indexView.getClassByName(DotName.createSimple(className)));
|
||||
}
|
||||
|
||||
static class PanacheMongoEntityClassVisitor extends PanacheEntityClassVisitor<EntityField> {
|
||||
|
||||
public PanacheMongoEntityClassVisitor(String className, ClassVisitor outputClassVisitor,
|
||||
MetamodelInfo<EntityModel<EntityField>> modelInfo, ClassInfo panacheEntityBaseClassInfo,
|
||||
ClassInfo entityInfo) {
|
||||
super(className, outputClassVisitor, modelInfo, panacheEntityBaseClassInfo, entityInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectModel(MethodVisitor mv) {
|
||||
mv.visitLdcInsn(thisClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getModelDescriptor() {
|
||||
return "Ljava/lang/Class;";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPanacheOperationsBinaryName() {
|
||||
return MONGO_OPERATIONS_BINARY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateAccessorSetField(MethodVisitor mv, EntityField field) {
|
||||
mv.visitFieldInsn(Opcodes.PUTFIELD, thisClass.getInternalName(), field.name, field.descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateAccessorGetField(MethodVisitor mv, EntityField field) {
|
||||
mv.visitFieldInsn(Opcodes.GETFIELD, thisClass.getInternalName(), field.name, field.descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
public void collectFields(ClassInfo classInfo) {
|
||||
EntityModel<EntityField> entityModel = new EntityModel<>(classInfo);
|
||||
for (FieldInfo fieldInfo : classInfo.fields()) {
|
||||
String name = fieldInfo.name();
|
||||
if (Modifier.isPublic(fieldInfo.flags()) && !fieldInfo.hasAnnotation(DOTNAME_BSON_IGNORE)) {
|
||||
entityModel.addField(new EntityField(name, DescriptorUtils.typeToString(fieldInfo.type())));
|
||||
}
|
||||
}
|
||||
modelInfo.addEntityModel(entityModel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package io.quarkus.mongodb.panache.deployment;
|
||||
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
import org.jboss.jandex.IndexView;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheMongoRepository;
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheMongoRepositoryBase;
|
||||
import io.quarkus.panache.common.deployment.PanacheRepositoryEnhancer;
|
||||
|
||||
public class ReactivePanacheMongoRepositoryEnhancer extends PanacheRepositoryEnhancer {
|
||||
public final static DotName PANACHE_REPOSITORY_BASE_NAME = DotName
|
||||
.createSimple(ReactivePanacheMongoRepositoryBase.class.getName());
|
||||
|
||||
public final static DotName PANACHE_REPOSITORY_NAME = DotName.createSimple(ReactivePanacheMongoRepository.class.getName());
|
||||
|
||||
public ReactivePanacheMongoRepositoryEnhancer(IndexView index) {
|
||||
super(index, PanacheResourceProcessor.DOTNAME_AXLE_PANACHE_REPOSITORY_BASE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassVisitor apply(String className, ClassVisitor outputClassVisitor) {
|
||||
return new PanacheMongoRepositoryClassVisitor(className, outputClassVisitor, panacheRepositoryBaseClassInfo,
|
||||
this.indexView);
|
||||
}
|
||||
|
||||
static class PanacheMongoRepositoryClassVisitor extends PanacheRepositoryClassVisitor {
|
||||
|
||||
public PanacheMongoRepositoryClassVisitor(String className, ClassVisitor outputClassVisitor,
|
||||
ClassInfo panacheRepositoryBaseClassInfo, IndexView indexView) {
|
||||
super(className, outputClassVisitor, panacheRepositoryBaseClassInfo, indexView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DotName getPanacheRepositoryDotName() {
|
||||
return PANACHE_REPOSITORY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DotName getPanacheRepositoryBaseDotName() {
|
||||
return PANACHE_REPOSITORY_BASE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPanacheOperationsBinaryName() {
|
||||
return ReactivePanacheMongoEntityEnhancer.MONGO_OPERATIONS_BINARY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectModel(MethodVisitor mv) {
|
||||
// inject Class
|
||||
mv.visitLdcInsn(entityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getModelDescriptor() {
|
||||
return "Ljava/lang/Class;";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,11 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-panacheql</artifactId>
|
||||
<artifactId>quarkus-mongodb-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-mongodb-client</artifactId>
|
||||
<artifactId>quarkus-panacheql</artifactId>
|
||||
</dependency>
|
||||
<!-- This is optional to avoid pulling libraries if jax-rs/jsonb is not on the path-->
|
||||
<!-- But needed to provides default serializer/deserializer for JsonB -->
|
||||
@@ -74,19 +74,6 @@
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/classes</directory>
|
||||
<excludes>
|
||||
<!-- We avoid indexing it as it needs to be included in the apps only if jaxrs and jsonb are. -->
|
||||
<exclude>**/PanacheMongoJsonbContextResolver.class</exclude>
|
||||
<!-- We avoid indexing it as it needs to be included in the apps only if jackson is. -->
|
||||
<exclude>**/ObjectMapperProducer.class</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
0
extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/MongoEntity.java
Executable file → Normal file
0
extensions/panache/mongodb-panache/runtime/src/main/java/io/quarkus/mongodb/panache/MongoEntity.java
Executable file → Normal file
@@ -0,0 +1,30 @@
|
||||
package io.quarkus.mongodb.panache.axle;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
/**
|
||||
* Represents an entity with a generated ID field {@link #id} of type {@link ObjectId}. If your
|
||||
* Mongo entities extend this class they gain the ID field and auto-generated accessors
|
||||
* to all their public fields, as well as all the useful methods from {@link ReactivePanacheMongoEntityBase}.
|
||||
*
|
||||
* If you want a custom ID type or strategy, you can directly extend {@link ReactivePanacheMongoEntityBase}
|
||||
* instead, and write your own ID field. You will still get auto-generated accessors and
|
||||
* all the useful methods.
|
||||
*
|
||||
* @see ReactivePanacheMongoEntityBase
|
||||
*/
|
||||
public abstract class ReactivePanacheMongoEntity extends ReactivePanacheMongoEntityBase {
|
||||
|
||||
/**
|
||||
* The auto-generated ID field.
|
||||
* This field is set by Mongo when this entity is persisted.
|
||||
*
|
||||
* @see #persist()
|
||||
*/
|
||||
public ObjectId id;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + "<" + id + ">";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,892 @@
|
||||
package io.quarkus.mongodb.panache.axle;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import io.quarkus.mongodb.ReactiveMongoCollection;
|
||||
import io.quarkus.mongodb.ReactiveMongoDatabase;
|
||||
import io.quarkus.mongodb.panache.axle.runtime.ReactiveMongoOperations;
|
||||
import io.quarkus.panache.common.Parameters;
|
||||
import io.quarkus.panache.common.Sort;
|
||||
import io.quarkus.panache.common.impl.GenerateBridge;
|
||||
|
||||
/**
|
||||
* Represents an entity. If your Mongo entities extend this class they gain auto-generated accessors
|
||||
* to all their public fields, as well as a lot of useful
|
||||
* methods. Unless you have a custom ID strategy, you should not extend this class directly but extend
|
||||
* {@link ReactivePanacheMongoEntity} instead.
|
||||
*
|
||||
* @see ReactivePanacheMongoEntity
|
||||
*/
|
||||
public abstract class ReactivePanacheMongoEntityBase {
|
||||
|
||||
// Operations
|
||||
|
||||
/**
|
||||
* Persist this entity in the database.
|
||||
* This will set it's ID field if not already set.
|
||||
*
|
||||
* @see #persist(Iterable)
|
||||
* @see #persist(Stream)
|
||||
* @see #persist(Object, Object...)
|
||||
*/
|
||||
public CompletionStage<Void> persist() {
|
||||
return ReactiveMongoOperations.persist(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this entity in the database.
|
||||
*
|
||||
* @see #update(Iterable)
|
||||
* @see #update(Stream)
|
||||
* @see #update(Object, Object...)
|
||||
*/
|
||||
public CompletionStage<Void> update() {
|
||||
return ReactiveMongoOperations.update(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist this entity in the database or update it if it already exist.
|
||||
*
|
||||
* @see #persistOrUpdate(Iterable)
|
||||
* @see #persistOrUpdate(Stream)
|
||||
* @see #persistOrUpdate(Object, Object...)
|
||||
*/
|
||||
public CompletionStage<Void> persistOrUpdate() {
|
||||
return ReactiveMongoOperations.persistOrUpdate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this entity from the database, if it is already persisted.
|
||||
*
|
||||
* @see #delete(String, Object...)
|
||||
* @see #delete(String, Map)
|
||||
* @see #delete(String, Parameters)
|
||||
* @see #deleteAll()
|
||||
*/
|
||||
public CompletionStage<Void> delete() {
|
||||
return ReactiveMongoOperations.delete(this);
|
||||
}
|
||||
|
||||
// Queries
|
||||
|
||||
/**
|
||||
* Find an entity of this type by ID.
|
||||
*
|
||||
* @param id the ID of the entity to find.
|
||||
* @return the entity found, or <code>null</code> if not found.
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<T> findById(Object id) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an entity of this type by ID.
|
||||
*
|
||||
* @param id the ID of the entity to find.
|
||||
* @return if found, an optional containing the entity, else <code>Optional.empty()</code>.
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<Optional<T>> findByIdOptional(Object id) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query, with optional indexed parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Sort, Object...)
|
||||
* @see #find(String, Map)
|
||||
* @see #find(String, Parameters)
|
||||
* @see #list(String, Object...)
|
||||
* @see #stream(String, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> ReactivePanacheQuery<T> find(String query, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query and the given sort options, with optional indexed parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Object...)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Object...)
|
||||
* @see #stream(String, Sort, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> ReactivePanacheQuery<T> find(String query, Sort sort,
|
||||
Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Map} of named parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Object...)
|
||||
* @see #find(String, Parameters)
|
||||
* @see #list(String, Map)
|
||||
* @see #stream(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> ReactivePanacheQuery<T> find(String query,
|
||||
Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query and the given sort options, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Map} of indexed parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Map)
|
||||
* @see #find(String, Sort, Object...)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Map)
|
||||
* @see #stream(String, Sort, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> ReactivePanacheQuery<T> find(String query, Sort sort,
|
||||
Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Parameters} of named parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #find(String, Map)
|
||||
* @see #find(String, Parameters)
|
||||
* @see #list(String, Parameters)
|
||||
* @see #stream(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> ReactivePanacheQuery<T> find(String query, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query and the given sort options, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Parameters} of indexed parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> ReactivePanacheQuery<T> find(String query, Sort sort,
|
||||
Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a BSON query.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> ReactivePanacheQuery<T> find(Document query) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a a BSON query and a BSON sort.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @param sort the {@link Document} sort
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> ReactivePanacheQuery<T> find(Document query, Document sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type.
|
||||
*
|
||||
* @return a new {@link ReactivePanacheQuery} instance to find all entities of this type.
|
||||
* @see #findAll(Sort)
|
||||
* @see #listAll()
|
||||
* @see #streamAll()
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> ReactivePanacheQuery<T> findAll() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type, in the given order.
|
||||
*
|
||||
* @param sort the sort order to use
|
||||
* @return a new {@link ReactivePanacheQuery} instance to find all entities of this type.
|
||||
* @see #findAll()
|
||||
* @see #listAll(Sort)
|
||||
* @see #streamAll(Sort)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> ReactivePanacheQuery<T> findAll(Sort sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with optional indexed parameters.
|
||||
* This method is a shortcut for <code>find(query, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Sort, Object...)
|
||||
* @see #list(String, Map)
|
||||
* @see #list(String, Parameters)
|
||||
* @see #find(String, Object...)
|
||||
* @see #stream(String, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<List<T>> list(String query, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with optional indexed parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Object...)
|
||||
* @see #list(String, Sort, Map)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #find(String, Sort, Object...)
|
||||
* @see #stream(String, Sort, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<List<T>> list(String query, Sort sort,
|
||||
Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Map} of named parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Sort, Map)
|
||||
* @see #list(String, Object...)
|
||||
* @see #list(String, Parameters)
|
||||
* @see #find(String, Map)
|
||||
* @see #stream(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<List<T>> list(String query,
|
||||
Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Map} of indexed parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Map)
|
||||
* @see #list(String, Sort, Object...)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #stream(String, Sort, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<List<T>> list(String query, Sort sort,
|
||||
Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Parameters} of named parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #list(String, Object...)
|
||||
* @see #list(String, Map)
|
||||
* @see #find(String, Parameters)
|
||||
* @see #stream(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<List<T>> list(String query, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Parameters} of indexed parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Parameters)
|
||||
* @see #list(String, Sort, Object...)
|
||||
* @see #list(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<List<T>> list(String query, Sort sort,
|
||||
Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a BSON query.
|
||||
* This method is a shortcut for <code>find(query).list()</code>.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<List<T>> list(Document query) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a a BSON query and a BSON sort.
|
||||
* This method is a shortcut for <code>find(query, sort).list()</code>.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @param sort the {@link Document} sort
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<List<T>> list(Document query, Document sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type.
|
||||
* This method is a shortcut for <code>findAll().list()</code>.
|
||||
*
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #listAll(Sort)
|
||||
* @see #findAll()
|
||||
* @see #streamAll()
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<List<T>> listAll() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type, in the given order.
|
||||
* This method is a shortcut for <code>findAll(sort).list()</code>.
|
||||
*
|
||||
* @param sort the sort order to use
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #listAll()
|
||||
* @see #findAll(Sort)
|
||||
* @see #streamAll(Sort)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> CompletionStage<List<T>> listAll(Sort sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with optional indexed parameters.
|
||||
* This method is a shortcut for <code>find(query, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Sort, Object...)
|
||||
* @see #stream(String, Map)
|
||||
* @see #stream(String, Parameters)
|
||||
* @see #find(String, Object...)
|
||||
* @see #list(String, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> Publisher<T> stream(String query, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with optional indexed parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Object...)
|
||||
* @see #stream(String, Sort, Map)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
* @see #find(String, Sort, Object...)
|
||||
* @see #list(String, Sort, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> Publisher<T> stream(String query, Sort sort, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Map} of named parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Sort, Map)
|
||||
* @see #stream(String, Object...)
|
||||
* @see #stream(String, Parameters)
|
||||
* @see #find(String, Map)
|
||||
* @see #list(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> Publisher<T> stream(String query, Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Map} of indexed parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Map)
|
||||
* @see #stream(String, Sort, Object...)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #list(String, Sort, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> Publisher<T> stream(String query, Sort sort,
|
||||
Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Parameters} of named parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
* @see #stream(String, Object...)
|
||||
* @see #stream(String, Map)
|
||||
* @see #find(String, Parameters)
|
||||
* @see #list(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> Publisher<T> stream(String query, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Parameters} of indexed parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Parameters)
|
||||
* @see #stream(String, Sort, Object...)
|
||||
* @see #stream(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> Publisher<T> stream(String query, Sort sort, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a BSON query.
|
||||
* This method is a shortcut for <code>find(query).stream()</code>.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> Publisher<T> stream(Document query) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a a BSON query and a BSON sort.
|
||||
* This method is a shortcut for <code>find(query, sort).stream()</code>.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @param sort the {@link Document} sort
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> Publisher<T> stream(Document query, Document sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type.
|
||||
* This method is a shortcut for <code>findAll().stream()</code>.
|
||||
*
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #streamAll(Sort)
|
||||
* @see #findAll()
|
||||
* @see #listAll()
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> Publisher<T> streamAll() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type, in the given order.
|
||||
* This method is a shortcut for <code>findAll(sort).stream()</code>.
|
||||
*
|
||||
* @param sort the sort order to use
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #streamAll()
|
||||
* @see #findAll(Sort)
|
||||
* @see #listAll(Sort)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> Publisher<T> streamAll(Sort sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of this type of entity in the database.
|
||||
*
|
||||
* @return the number of this type of entity in the database.
|
||||
* @see #count(String, Object...)
|
||||
* @see #count(String, Map)
|
||||
* @see #count(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static CompletionStage<Long> count() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of this type of entity matching the given query, with optional indexed parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return the number of entities counted.
|
||||
* @see #count()
|
||||
* @see #count(String, Map)
|
||||
* @see #count(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static CompletionStage<Long> count(String query, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of this type of entity matching the given query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Map} of named parameters
|
||||
* @return the number of entities counted.
|
||||
* @see #count()
|
||||
* @see #count(String, Object...)
|
||||
* @see #count(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static CompletionStage<Long> count(String query, Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of this type of entity matching the given query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Parameters} of named parameters
|
||||
* @return the number of entities counted.
|
||||
* @see #count()
|
||||
* @see #count(String, Object...)
|
||||
* @see #count(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static CompletionStage<Long> count(String query, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of this type of entity matching the given query
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @return he number of entities counted.
|
||||
* @see #count()
|
||||
* @see #count(String, Object...)
|
||||
* @see #count(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static CompletionStage<Long> count(Document query) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all entities of this type from the database.
|
||||
*
|
||||
* @return the number of entities deleted.
|
||||
* @see #delete(String, Object...)
|
||||
* @see #delete(String, Map)
|
||||
* @see #delete(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static CompletionStage<Long> deleteAll() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all entities of this type matching the given query, with optional indexed parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return the number of entities deleted.
|
||||
* @see #deleteAll()
|
||||
* @see #delete(String, Map)
|
||||
* @see #delete(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static CompletionStage<Long> delete(String query, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all entities of this type matching the given query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Map} of named parameters
|
||||
* @return the number of entities deleted.
|
||||
* @see #deleteAll()
|
||||
* @see #delete(String, Object...)
|
||||
* @see #delete(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static CompletionStage<Long> delete(String query, Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all entities of this type matching the given query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Parameters} of named parameters
|
||||
* @return the number of entities deleted.
|
||||
* @see #deleteAll()
|
||||
* @see #delete(String, Object...)
|
||||
* @see #delete(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static CompletionStage<Long> delete(String query, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all entities of this type matching the given query
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @return he number of entities counted.
|
||||
* @see #count()
|
||||
* @see #count(String, Object...)
|
||||
* @see #count(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static CompletionStage<Long> delete(Document query) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert all given entities.
|
||||
*
|
||||
* @param entities the entities to insert
|
||||
* @see #persist()
|
||||
* @see #persist(Stream)
|
||||
* @see #persist(Object,Object...)
|
||||
*/
|
||||
public static CompletionStage<Void> persist(Iterable<?> entities) {
|
||||
return ReactiveMongoOperations.persist(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert all given entities.
|
||||
*
|
||||
* @param entities the entities to insert
|
||||
* @see #persist()
|
||||
* @see #persist(Iterable)
|
||||
* @see #persist(Object,Object...)
|
||||
*/
|
||||
public static CompletionStage<Void> persist(Stream<?> entities) {
|
||||
return ReactiveMongoOperations.persist(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert all given entities.
|
||||
*
|
||||
* @param entities the entities to update
|
||||
* @see #persist()
|
||||
* @see #persist(Stream)
|
||||
* @see #persist(Iterable)
|
||||
*/
|
||||
public static CompletionStage<Void> persist(Object firstEntity, Object... entities) {
|
||||
return ReactiveMongoOperations.persist(firstEntity, entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all given entities.
|
||||
*
|
||||
* @param entities the entities to update
|
||||
* @see #update()
|
||||
* @see #update(Stream)
|
||||
* @see #update(Object,Object...)
|
||||
*/
|
||||
public static CompletionStage<Void> update(Iterable<?> entities) {
|
||||
return ReactiveMongoOperations.update(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all given entities.
|
||||
*
|
||||
* @param entities the entities to insert
|
||||
* @see #update()
|
||||
* @see #update(Iterable)
|
||||
* @see #update(Object,Object...)
|
||||
*/
|
||||
public static CompletionStage<Void> update(Stream<?> entities) {
|
||||
return ReactiveMongoOperations.update(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all given entities.
|
||||
*
|
||||
* @param entities the entities to update
|
||||
* @see #update()
|
||||
* @see #update(Stream)
|
||||
* @see #update(Iterable)
|
||||
*/
|
||||
public static CompletionStage<Void> update(Object firstEntity, Object... entities) {
|
||||
return ReactiveMongoOperations.update(firstEntity, entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist all given entities or update them if they already exist.
|
||||
*
|
||||
* @param entities the entities to update
|
||||
* @see #persistOrUpdate()
|
||||
* @see #persistOrUpdate(Stream)
|
||||
* @see #persistOrUpdate(Object,Object...)
|
||||
*/
|
||||
public static CompletionStage<Void> persistOrUpdate(Iterable<?> entities) {
|
||||
return ReactiveMongoOperations.persistOrUpdate(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist all given entities.
|
||||
*
|
||||
* @param entities the entities to insert
|
||||
* @see #persistOrUpdate()
|
||||
* @see #persistOrUpdate(Iterable)
|
||||
* @see #persistOrUpdate(Object,Object...)
|
||||
*/
|
||||
public static CompletionStage<Void> persistOrUpdate(Stream<?> entities) {
|
||||
return ReactiveMongoOperations.persistOrUpdate(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist all given entities.
|
||||
*
|
||||
* @param entities the entities to update
|
||||
* @see #persistOrUpdate()
|
||||
* @see #persistOrUpdate(Stream)
|
||||
* @see #persistOrUpdate(Iterable)
|
||||
*/
|
||||
public static CompletionStage<Void> persistOrUpdate(Object firstEntity, Object... entities) {
|
||||
return ReactiveMongoOperations.persistOrUpdate(firstEntity, entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to access the underlying Mongo Collection.
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static <T extends ReactivePanacheMongoEntityBase> ReactiveMongoCollection<T> mongoCollection() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to access the underlying Mongo Database.
|
||||
*/
|
||||
@GenerateBridge
|
||||
public static ReactiveMongoDatabase mongoDatabase() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.quarkus.mongodb.panache.axle;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
/**
|
||||
* Represents a Repository for a specific type of entity {@code Entity}, with an ID type
|
||||
* of {@code ObjectId}. Implementing this repository will gain you the exact same useful methods
|
||||
* that are on {@link ReactivePanacheMongoEntityBase}. If you have a custom ID strategy, you should
|
||||
* implement {@link ReactivePanacheMongoRepositoryBase} instead.
|
||||
*
|
||||
* @param <Entity> The type of entity to operate on
|
||||
*/
|
||||
public interface ReactivePanacheMongoRepository<Entity> extends ReactivePanacheMongoRepositoryBase<Entity, ObjectId> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,889 @@
|
||||
package io.quarkus.mongodb.panache.axle;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import io.quarkus.mongodb.ReactiveMongoCollection;
|
||||
import io.quarkus.mongodb.ReactiveMongoDatabase;
|
||||
import io.quarkus.mongodb.panache.axle.runtime.ReactiveMongoOperations;
|
||||
import io.quarkus.panache.common.Parameters;
|
||||
import io.quarkus.panache.common.Sort;
|
||||
import io.quarkus.panache.common.impl.GenerateBridge;
|
||||
|
||||
/**
|
||||
* Represents a Repository for a specific type of entity {@code Entity}, with an ID type
|
||||
* of {@code Id}. Implementing this repository will gain you the exact same useful methods
|
||||
* that are on {@link ReactivePanacheMongoEntityBase}. Unless you have a custom ID strategy, you should not
|
||||
* implement this interface directly but implement {@link ReactivePanacheMongoRepository} instead.
|
||||
*
|
||||
* @param <Entity> The type of entity to operate on
|
||||
* @param <Id> The ID type of the entity
|
||||
* @see ReactivePanacheMongoRepository
|
||||
*/
|
||||
public interface ReactivePanacheMongoRepositoryBase<Entity, Id> {
|
||||
|
||||
// Operations
|
||||
|
||||
/**
|
||||
* Persist the given entity in the database.
|
||||
* This will set it's ID field if not already set.
|
||||
*
|
||||
* @param entity the entity to insert.
|
||||
* @see #persist(Iterable)
|
||||
* @see #persist(Stream)
|
||||
* @see #persist(Object, Object...)
|
||||
*/
|
||||
public default CompletionStage<Void> persist(Entity entity) {
|
||||
return ReactiveMongoOperations.persist(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given entity in the database.
|
||||
*
|
||||
* @param entity the entity to update.
|
||||
* @see #update(Iterable)
|
||||
* @see #update(Stream)
|
||||
* @see #update(Object, Object...)
|
||||
*/
|
||||
public default CompletionStage<Void> update(Entity entity) {
|
||||
return ReactiveMongoOperations.update(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist the given entity in the database or update it if it already exist.
|
||||
*
|
||||
* @param entity the entity to update.
|
||||
* @see #persistOrUpdate(Iterable)
|
||||
* @see #persistOrUpdate(Stream)
|
||||
* @see #persistOrUpdate(Object, Object...)
|
||||
*/
|
||||
public default CompletionStage<Void> persistOrUpdate(Entity entity) {
|
||||
return ReactiveMongoOperations.persistOrUpdate(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given entity from the database, if it is already persisted.
|
||||
*
|
||||
* @param entity the entity to delete.
|
||||
* @see #delete(String, Object...)
|
||||
* @see #delete(String, Map)
|
||||
* @see #delete(String, Parameters)
|
||||
* @see #deleteAll()
|
||||
*/
|
||||
public default CompletionStage<Void> delete(Entity entity) {
|
||||
return ReactiveMongoOperations.delete(entity);
|
||||
}
|
||||
|
||||
// Queries
|
||||
|
||||
/**
|
||||
* Find an entity of this type by ID.
|
||||
*
|
||||
* @param id the ID of the entity to find.
|
||||
* @return the entity found, or <code>null</code> if not found.
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Entity> findById(Id id) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an entity of this type by ID.
|
||||
*
|
||||
* @param id the ID of the entity to find.
|
||||
* @return if found, an optional containing the entity, else <code>Optional.empty()</code>.
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Optional<Entity>> findByIdOptional(Object id) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query, with optional indexed parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Sort, Object...)
|
||||
* @see #find(String, Map)
|
||||
* @see #find(String, Parameters)
|
||||
* @see #list(String, Object...)
|
||||
* @see #stream(String, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> find(String query, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query and the given sort options, with optional indexed parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Object...)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Object...)
|
||||
* @see #stream(String, Sort, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> find(String query, Sort sort, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Map} of named parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Object...)
|
||||
* @see #find(String, Parameters)
|
||||
* @see #list(String, Map)
|
||||
* @see #stream(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> find(String query, Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query and the given sort options, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Map} of indexed parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Map)
|
||||
* @see #find(String, Sort, Object...)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Map)
|
||||
* @see #stream(String, Sort, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> find(String query, Sort sort, Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Parameters} of named parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #find(String, Map)
|
||||
* @see #find(String, Parameters)
|
||||
* @see #list(String, Parameters)
|
||||
* @see #stream(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> find(String query, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a query and the given sort options, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Parameters} of indexed parameters
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> find(String query, Sort sort, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a BSON query.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> find(Document query) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a a BSON query and a BSON sort.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @param sort the {@link Document} sort
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> find(Document query, Document sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type.
|
||||
*
|
||||
* @return a new {@link ReactivePanacheQuery} instance to find all entities of this type.
|
||||
* @see #findAll(Sort)
|
||||
* @see #listAll()
|
||||
* @see #streamAll()
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> findAll() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type, in the given order.
|
||||
*
|
||||
* @param sort the sort order to use
|
||||
* @return a new {@link ReactivePanacheQuery} instance to find all entities of this type.
|
||||
* @see #findAll()
|
||||
* @see #listAll(Sort)
|
||||
* @see #streamAll(Sort)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> findAll(Sort sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with optional indexed parameters.
|
||||
* This method is a shortcut for <code>find(query, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Sort, Object...)
|
||||
* @see #list(String, Map)
|
||||
* @see #list(String, Parameters)
|
||||
* @see #find(String, Object...)
|
||||
* @see #stream(String, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<List<Entity>> list(String query, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with optional indexed parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Object...)
|
||||
* @see #list(String, Sort, Map)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #find(String, Sort, Object...)
|
||||
* @see #stream(String, Sort, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<List<Entity>> list(String query, Sort sort, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Map} of named parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Sort, Map)
|
||||
* @see #list(String, Object...)
|
||||
* @see #list(String, Parameters)
|
||||
* @see #find(String, Map)
|
||||
* @see #stream(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<List<Entity>> list(String query, Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Map} of indexed parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Map)
|
||||
* @see #list(String, Sort, Object...)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #stream(String, Sort, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<List<Entity>> list(String query, Sort sort, Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Parameters} of named parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #list(String, Object...)
|
||||
* @see #list(String, Map)
|
||||
* @see #find(String, Parameters)
|
||||
* @see #stream(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<List<Entity>> list(String query, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).list()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Parameters} of indexed parameters
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #list(String, Parameters)
|
||||
* @see #list(String, Sort, Object...)
|
||||
* @see #list(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<List<Entity>> list(String query, Sort sort, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a BSON query.
|
||||
* This method is a shortcut for <code>find(query).list()</code>.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> list(Document query) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a a BSON query and a BSON sort.
|
||||
* This method is a shortcut for <code>find(query, sort).list()</code>.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @param sort the {@link Document} sort
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactivePanacheQuery<Entity> list(Document query, Document sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type.
|
||||
* This method is a shortcut for <code>findAll().list()</code>.
|
||||
*
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #listAll(Sort)
|
||||
* @see #findAll()
|
||||
* @see #streamAll()
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<List<Entity>> listAll() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type, in the given order.
|
||||
* This method is a shortcut for <code>findAll(sort).list()</code>.
|
||||
*
|
||||
* @param sort the sort order to use
|
||||
* @return a {@link List} containing all results, without paging
|
||||
* @see #listAll()
|
||||
* @see #findAll(Sort)
|
||||
* @see #streamAll(Sort)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<List<Entity>> listAll(Sort sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with optional indexed parameters.
|
||||
* This method is a shortcut for <code>find(query, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Sort, Object...)
|
||||
* @see #stream(String, Map)
|
||||
* @see #stream(String, Parameters)
|
||||
* @see #find(String, Object...)
|
||||
* @see #list(String, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default Publisher<Entity> stream(String query, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with optional indexed parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Object...)
|
||||
* @see #stream(String, Sort, Map)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
* @see #find(String, Sort, Object...)
|
||||
* @see #list(String, Sort, Object...)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default Publisher<Entity> stream(String query, Sort sort, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Map} of named parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Sort, Map)
|
||||
* @see #stream(String, Object...)
|
||||
* @see #stream(String, Parameters)
|
||||
* @see #find(String, Map)
|
||||
* @see #list(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default Publisher<Entity> stream(String query, Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Map} of indexed parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Map)
|
||||
* @see #stream(String, Sort, Object...)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #list(String, Sort, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default Publisher<Entity> stream(String query, Sort sort, Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Parameters} of named parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
* @see #stream(String, Object...)
|
||||
* @see #stream(String, Map)
|
||||
* @see #find(String, Parameters)
|
||||
* @see #list(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default Publisher<Entity> stream(String query, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities matching a query and the given sort options, with named parameters.
|
||||
* This method is a shortcut for <code>find(query, sort, params).stream()</code>.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param sort the sort strategy to use
|
||||
* @param params {@link Parameters} of indexed parameters
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #stream(String, Parameters)
|
||||
* @see #stream(String, Sort, Object...)
|
||||
* @see #stream(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default Publisher<Entity> stream(String query, Sort sort, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a BSON query.
|
||||
* This method is a shortcut for <code>find(query).stream()</code>.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default Publisher<Entity> stream(Document query) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find entities using a a BSON query and a BSON sort.
|
||||
* This method is a shortcut for <code>find(query, sort).stream()</code>.
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @param sort the {@link Document} sort
|
||||
* @return a new {@link ReactivePanacheQuery} instance for the given query
|
||||
* @see #find(String, Parameters)
|
||||
* @see #find(String, Sort, Map)
|
||||
* @see #find(String, Sort, Parameters)
|
||||
* @see #list(String, Sort, Parameters)
|
||||
* @see #stream(String, Sort, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default Publisher<Entity> stream(Document query, Document sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type.
|
||||
* This method is a shortcut for <code>findAll().stream()</code>.
|
||||
*
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #streamAll(Sort)
|
||||
* @see #findAll()
|
||||
* @see #listAll()
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default Publisher<Entity> streamAll(Sort sort) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entities of this type, in the given order.
|
||||
* This method is a shortcut for <code>findAll(sort).stream()</code>.
|
||||
*
|
||||
* @return a {@link Stream} containing all results, without paging
|
||||
* @see #streamAll()
|
||||
* @see #findAll(Sort)
|
||||
* @see #listAll(Sort)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default Publisher<Entity> streamAll() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of this type of entity in the database.
|
||||
*
|
||||
* @return the number of this type of entity in the database.
|
||||
* @see #count(String, Object...)
|
||||
* @see #count(String, Map)
|
||||
* @see #count(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Long> count() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of this type of entity matching the given query, with optional indexed parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return the number of entities counted.
|
||||
* @see #count()
|
||||
* @see #count(String, Map)
|
||||
* @see #count(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Long> count(String query, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of this type of entity matching the given query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Map} of named parameters
|
||||
* @return the number of entities counted.
|
||||
* @see #count()
|
||||
* @see #count(String, Object...)
|
||||
* @see #count(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Long> count(String query, Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of this type of entity matching the given query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Parameters} of named parameters
|
||||
* @return the number of entities counted.
|
||||
* @see #count()
|
||||
* @see #count(String, Object...)
|
||||
* @see #count(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Long> count(String query, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of this type of entity matching the given query
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @return he number of entities counted.
|
||||
* @see #count()
|
||||
* @see #count(String, Object...)
|
||||
* @see #count(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Long> count(Document query) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all entities of this type from the database.
|
||||
*
|
||||
* @return the number of entities deleted.
|
||||
* @see #delete(String, Object...)
|
||||
* @see #delete(String, Map)
|
||||
* @see #delete(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Long> deleteAll() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all entities of this type matching the given query, with optional indexed parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params optional sequence of indexed parameters
|
||||
* @return the number of entities deleted.
|
||||
* @see #deleteAll()
|
||||
* @see #delete(String, Map)
|
||||
* @see #delete(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Long> delete(String query, Object... params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all entities of this type matching the given query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Map} of named parameters
|
||||
* @return the number of entities deleted.
|
||||
* @see #deleteAll()
|
||||
* @see #delete(String, Object...)
|
||||
* @see #delete(String, Parameters)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Long> delete(String query, Map<String, Object> params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all entities of this type matching the given query, with named parameters.
|
||||
*
|
||||
* @param query a {@link io.quarkus.mongodb.panache query string}
|
||||
* @param params {@link Parameters} of named parameters
|
||||
* @return the number of entities deleted.
|
||||
* @see #deleteAll()
|
||||
* @see #delete(String, Object...)
|
||||
* @see #delete(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Long> delete(String query, Parameters params) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all entities of this type matching the given query
|
||||
*
|
||||
* @param query a {@link Document} query
|
||||
* @return he number of entities counted.
|
||||
* @see #count()
|
||||
* @see #count(String, Object...)
|
||||
* @see #count(String, Map)
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default CompletionStage<Long> delete(Document query) {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist all given entities.
|
||||
*
|
||||
* @param entities the entities to insert
|
||||
* @see #persist(Object)
|
||||
* @see #persist(Stream)
|
||||
* @see #persist(Object,Object...)
|
||||
*/
|
||||
public default CompletionStage<Void> persist(Iterable<Entity> entities) {
|
||||
return ReactiveMongoOperations.persist(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist all given entities.
|
||||
*
|
||||
* @param entities the entities to insert
|
||||
* @see #persist(Object)
|
||||
* @see #persist(Iterable)
|
||||
* @see #persist(Object,Object...)
|
||||
*/
|
||||
public default CompletionStage<Void> persist(Stream<Entity> entities) {
|
||||
return ReactiveMongoOperations.persist(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist all given entities.
|
||||
*
|
||||
* @param entities the entities to insert
|
||||
* @see #persist(Object)
|
||||
* @see #persist(Stream)
|
||||
* @see #persist(Iterable)
|
||||
*/
|
||||
public default CompletionStage<Void> persist(Entity firstEntity, @SuppressWarnings("unchecked") Entity... entities) {
|
||||
return ReactiveMongoOperations.persist(firstEntity, entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all given entities.
|
||||
*
|
||||
* @param entities the entities to update
|
||||
* @see #update(Object)
|
||||
* @see #update(Stream)
|
||||
* @see #update(Object,Object...)
|
||||
*/
|
||||
public default CompletionStage<Void> update(Iterable<Entity> entities) {
|
||||
return ReactiveMongoOperations.update(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all given entities.
|
||||
*
|
||||
* @param entities the entities to update
|
||||
* @see #update(Object)
|
||||
* @see #update(Iterable)
|
||||
* @see #update(Object,Object...)
|
||||
*/
|
||||
public default CompletionStage<Void> update(Stream<Entity> entities) {
|
||||
return ReactiveMongoOperations.update(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all given entities.
|
||||
*
|
||||
* @param entities the entities to update
|
||||
* @see #update(Object)
|
||||
* @see #update(Stream)
|
||||
* @see #update(Iterable)
|
||||
*/
|
||||
public default CompletionStage<Void> update(Entity firstEntity, @SuppressWarnings("unchecked") Entity... entities) {
|
||||
return ReactiveMongoOperations.update(firstEntity, entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist all given entities or update them if they already exist.
|
||||
*
|
||||
* @param entities the entities to update
|
||||
* @see #persistOrUpdate(Object)
|
||||
* @see #persistOrUpdate(Stream)
|
||||
* @see #persistOrUpdate(Object,Object...)
|
||||
*/
|
||||
public default CompletionStage<Void> persistOrUpdate(Iterable<Entity> entities) {
|
||||
return ReactiveMongoOperations.persistOrUpdate(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist all given entities or update them if they already exist.
|
||||
*
|
||||
* @param entities the entities to update
|
||||
* @see #persistOrUpdate(Object)
|
||||
* @see #persistOrUpdate(Iterable)
|
||||
* @see #persistOrUpdate(Object,Object...)
|
||||
*/
|
||||
public default CompletionStage<Void> persistOrUpdate(Stream<Entity> entities) {
|
||||
return ReactiveMongoOperations.persistOrUpdate(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist all given entities or update them if they already exist.
|
||||
*
|
||||
* @param entities the entities to update
|
||||
* @see #update(Object)
|
||||
* @see #update(Stream)
|
||||
* @see #update(Iterable)
|
||||
*/
|
||||
public default CompletionStage<Void> persistOrUpdate(Entity firstEntity,
|
||||
@SuppressWarnings("unchecked") Entity... entities) {
|
||||
return ReactiveMongoOperations.persistOrUpdate(firstEntity, entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to access the underlying Mongo Collection
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactiveMongoCollection<Entity> mongoCollection() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to access the underlying Mongo Database.
|
||||
*/
|
||||
@GenerateBridge
|
||||
public default ReactiveMongoDatabase mongoDatabase() {
|
||||
throw ReactiveMongoOperations.implementationInjectionMissing();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package io.quarkus.mongodb.panache.axle;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import io.quarkus.panache.common.Page;
|
||||
|
||||
/**
|
||||
* Interface representing an entity query, which abstracts the use of paging, getting the number of results, and
|
||||
* operating on {@link List} or {@link Stream}.
|
||||
*
|
||||
* Instances of this interface cannot mutate the query itself or its parameters: only paging information can be
|
||||
* modified, and instances of this interface can be reused to obtain multiple pages of results.
|
||||
*
|
||||
* @param <Entity> The entity type being queried
|
||||
*/
|
||||
public interface ReactivePanacheQuery<Entity> {
|
||||
|
||||
// Builder
|
||||
|
||||
/**
|
||||
* Sets the current page.
|
||||
*
|
||||
* @param page the new page
|
||||
* @return this query, modified
|
||||
* @see #page(int, int)
|
||||
* @see #page()
|
||||
*/
|
||||
public <T extends Entity> ReactivePanacheQuery<T> page(Page page);
|
||||
|
||||
/**
|
||||
* Sets the current page.
|
||||
*
|
||||
* @param pageIndex the page index
|
||||
* @param pageSize the page size
|
||||
* @return this query, modified
|
||||
* @see #page(Page)
|
||||
* @see #page()
|
||||
*/
|
||||
public <T extends Entity> ReactivePanacheQuery<T> page(int pageIndex, int pageSize);
|
||||
|
||||
/**
|
||||
* Sets the current page to the next page
|
||||
*
|
||||
* @return this query, modified
|
||||
* @see #previousPage()
|
||||
*/
|
||||
public <T extends Entity> ReactivePanacheQuery<T> nextPage();
|
||||
|
||||
/**
|
||||
* Sets the current page to the previous page (or the first page if there is no previous page)
|
||||
*
|
||||
* @return this query, modified
|
||||
* @see #nextPage()
|
||||
*/
|
||||
public <T extends Entity> ReactivePanacheQuery<T> previousPage();
|
||||
|
||||
/**
|
||||
* Sets the current page to the first page
|
||||
*
|
||||
* @return this query, modified
|
||||
* @see #lastPage()
|
||||
*/
|
||||
public <T extends Entity> ReactivePanacheQuery<T> firstPage();
|
||||
|
||||
/**
|
||||
* Sets the current page to the last page. This will cause reading of the entity count.
|
||||
*
|
||||
* @return this query, modified
|
||||
* @see #firstPage()
|
||||
* @see #count()
|
||||
*/
|
||||
public <T extends Entity> CompletionStage<ReactivePanacheQuery<T>> lastPage();
|
||||
|
||||
/**
|
||||
* Returns true if there is another page to read after the current one.
|
||||
* This will cause reading of the entity count.
|
||||
*
|
||||
* @return true if there is another page to read
|
||||
* @see #hasPreviousPage()
|
||||
* @see #count()
|
||||
*/
|
||||
public CompletionStage<Boolean> hasNextPage();
|
||||
|
||||
/**
|
||||
* Returns true if there is a page to read before the current one.
|
||||
*
|
||||
* @return true if there is a previous page to read
|
||||
* @see #hasNextPage()
|
||||
*/
|
||||
public boolean hasPreviousPage();
|
||||
|
||||
/**
|
||||
* Returns the total number of pages to be read using the current page size.
|
||||
* This will cause reading of the entity count.
|
||||
*
|
||||
* @return the total number of pages to be read using the current page size.
|
||||
*/
|
||||
public CompletionStage<Integer> pageCount();
|
||||
|
||||
/**
|
||||
* Returns the current page.
|
||||
*
|
||||
* @return the current page
|
||||
* @see #page(Page)
|
||||
* @see #page(int,int)
|
||||
*/
|
||||
public Page page();
|
||||
|
||||
// Results
|
||||
|
||||
/**
|
||||
* Reads and caches the total number of entities this query operates on. This causes a database
|
||||
* query with <code>SELECT COUNT(*)</code> and a query equivalent to the current query, minus
|
||||
* ordering.
|
||||
*
|
||||
* @return the total number of entities this query operates on, cached.
|
||||
*/
|
||||
public CompletionStage<Long> count();
|
||||
|
||||
/**
|
||||
* Returns the current page of results as a {@link List}.
|
||||
*
|
||||
* @return the current page of results as a {@link List}.
|
||||
* @see #page(Page)
|
||||
* @see #page()
|
||||
*/
|
||||
public <T extends Entity> CompletionStage<List<T>> list();
|
||||
|
||||
/**
|
||||
* Returns the current page of results as a {@link Stream}.
|
||||
*
|
||||
* @return the current page of results as a {@link Stream}.
|
||||
* @see #list()
|
||||
* @see #page(Page)
|
||||
* @see #page()
|
||||
*/
|
||||
public <T extends Entity> Publisher<T> stream();
|
||||
|
||||
/**
|
||||
* Returns the first result of the current page index. This ignores the current page size to fetch
|
||||
* a single result.
|
||||
*
|
||||
* @return the first result of the current page index, or null if there are no results.
|
||||
* @see #singleResult()
|
||||
*/
|
||||
public <T extends Entity> CompletionStage<T> firstResult();
|
||||
|
||||
/**
|
||||
* Returns the first result of the current page index. This ignores the current page size to fetch
|
||||
* a single result.
|
||||
*
|
||||
* @return if found, an optional containing the entity, else <code>Optional.empty()</code>.
|
||||
* @see #singleResultOptional()
|
||||
*/
|
||||
public <T extends Entity> CompletionStage<Optional<T>> firstResultOptional();
|
||||
|
||||
/**
|
||||
* Executes this query for the current page and return a single result.
|
||||
*
|
||||
* @return the single result.
|
||||
* @throws io.quarkus.panache.common.exception.PanacheQueryException if there are more than one result.
|
||||
* @see #firstResult()
|
||||
*/
|
||||
public <T extends Entity> CompletionStage<T> singleResult();
|
||||
|
||||
/**
|
||||
* Executes this query for the current page and return a single result.
|
||||
*
|
||||
* @return if found, an optional containing the entity, else <code>Optional.empty()</code>.
|
||||
* @throws io.quarkus.panache.common.exception.PanacheQueryException if there are more than one result.
|
||||
* @see #firstResultOptional()
|
||||
*/
|
||||
public <T extends Entity> CompletionStage<Optional<T>> singleResultOptional();
|
||||
}
|
||||
@@ -0,0 +1,577 @@
|
||||
package io.quarkus.mongodb.panache.axle.runtime;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.bson.BsonDocument;
|
||||
import org.bson.BsonDocumentWriter;
|
||||
import org.bson.BsonValue;
|
||||
import org.bson.Document;
|
||||
import org.bson.codecs.Codec;
|
||||
import org.bson.codecs.EncoderContext;
|
||||
import org.eclipse.microprofile.config.ConfigProvider;
|
||||
import org.eclipse.microprofile.context.ThreadContext;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import com.mongodb.client.model.InsertOneModel;
|
||||
import com.mongodb.client.model.ReplaceOneModel;
|
||||
import com.mongodb.client.model.ReplaceOptions;
|
||||
import com.mongodb.client.model.UpdateOptions;
|
||||
import com.mongodb.client.model.WriteModel;
|
||||
|
||||
import io.quarkus.arc.Arc;
|
||||
import io.quarkus.mongodb.ReactiveMongoClient;
|
||||
import io.quarkus.mongodb.ReactiveMongoCollection;
|
||||
import io.quarkus.mongodb.ReactiveMongoDatabase;
|
||||
import io.quarkus.mongodb.panache.MongoEntity;
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheQuery;
|
||||
import io.quarkus.mongodb.panache.binder.NativeQueryBinder;
|
||||
import io.quarkus.mongodb.panache.binder.PanacheQlQueryBinder;
|
||||
import io.quarkus.panache.common.Parameters;
|
||||
import io.quarkus.panache.common.Sort;
|
||||
|
||||
public class ReactiveMongoOperations {
|
||||
private static final Logger LOGGER = Logger.getLogger(ReactiveMongoOperations.class);
|
||||
public static final String ID = "_id";
|
||||
public static final String MONGODB_DATABASE = "quarkus.mongodb.database";
|
||||
//
|
||||
// Instance methods
|
||||
|
||||
public static CompletionStage<Void> persist(Object entity) {
|
||||
ReactiveMongoCollection collection = mongoCollection(entity);
|
||||
return persist(collection, entity);
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> persist(Iterable<?> entities) {
|
||||
// not all iterables are re-traversal, so we traverse it once for copying inside a list
|
||||
List<Object> objects = new ArrayList<>();
|
||||
for (Object entity : entities) {
|
||||
objects.add(entity);
|
||||
}
|
||||
|
||||
if (objects.size() > 0) {
|
||||
// get the first entity to be able to retrieve the collection with it
|
||||
Object firstEntity = objects.get(0);
|
||||
ReactiveMongoCollection collection = mongoCollection(firstEntity);
|
||||
return persist(collection, objects);
|
||||
}
|
||||
return nullFuture();
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> persist(Object firstEntity, Object... entities) {
|
||||
ReactiveMongoCollection collection = mongoCollection(firstEntity);
|
||||
if (entities == null || entities.length == 0) {
|
||||
return persist(collection, firstEntity);
|
||||
} else {
|
||||
List<Object> entityList = new ArrayList<>();
|
||||
entityList.add(firstEntity);
|
||||
entityList.addAll(Arrays.asList(entities));
|
||||
return persist(collection, entityList);
|
||||
}
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> persist(Stream<?> entities) {
|
||||
List<Object> objects = entities.collect(Collectors.toList());
|
||||
if (objects.size() > 0) {
|
||||
// get the first entity to be able to retrieve the collection with it
|
||||
Object firstEntity = objects.get(0);
|
||||
ReactiveMongoCollection collection = mongoCollection(firstEntity);
|
||||
return persist(collection, objects);
|
||||
}
|
||||
return nullFuture();
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> update(Object entity) {
|
||||
ReactiveMongoCollection collection = mongoCollection(entity);
|
||||
return update(collection, entity);
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> update(Iterable<?> entities) {
|
||||
// not all iterables are re-traversal, so we traverse it once for copying inside a list
|
||||
List<Object> objects = new ArrayList<>();
|
||||
for (Object entity : entities) {
|
||||
objects.add(entity);
|
||||
}
|
||||
|
||||
if (objects.size() > 0) {
|
||||
// get the first entity to be able to retrieve the collection with it
|
||||
Object firstEntity = objects.get(0);
|
||||
ReactiveMongoCollection collection = mongoCollection(firstEntity);
|
||||
return update(collection, objects);
|
||||
}
|
||||
return nullFuture();
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> update(Object firstEntity, Object... entities) {
|
||||
ReactiveMongoCollection collection = mongoCollection(firstEntity);
|
||||
if (entities == null || entities.length == 0) {
|
||||
return update(collection, firstEntity);
|
||||
} else {
|
||||
List<Object> entityList = new ArrayList<>();
|
||||
entityList.add(firstEntity);
|
||||
entityList.addAll(Arrays.asList(entities));
|
||||
return update(collection, entityList);
|
||||
}
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> update(Stream<?> entities) {
|
||||
List<Object> objects = entities.collect(Collectors.toList());
|
||||
if (objects.size() > 0) {
|
||||
// get the first entity to be able to retrieve the collection with it
|
||||
Object firstEntity = objects.get(0);
|
||||
ReactiveMongoCollection collection = mongoCollection(firstEntity);
|
||||
return update(collection, objects);
|
||||
}
|
||||
return nullFuture();
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> persistOrUpdate(Object entity) {
|
||||
ReactiveMongoCollection collection = mongoCollection(entity);
|
||||
return persistOrUpdate(collection, entity);
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> persistOrUpdate(Iterable<?> entities) {
|
||||
// not all iterables are re-traversal, so we traverse it once for copying inside a list
|
||||
List<Object> objects = new ArrayList<>();
|
||||
for (Object entity : entities) {
|
||||
objects.add(entity);
|
||||
}
|
||||
|
||||
if (objects.size() > 0) {
|
||||
// get the first entity to be able to retrieve the collection with it
|
||||
Object firstEntity = objects.get(0);
|
||||
ReactiveMongoCollection collection = mongoCollection(firstEntity);
|
||||
return persistOrUpdate(collection, objects);
|
||||
}
|
||||
return nullFuture();
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> persistOrUpdate(Object firstEntity, Object... entities) {
|
||||
ReactiveMongoCollection collection = mongoCollection(firstEntity);
|
||||
if (entities == null || entities.length == 0) {
|
||||
return persistOrUpdate(collection, firstEntity);
|
||||
} else {
|
||||
List<Object> entityList = new ArrayList<>();
|
||||
entityList.add(firstEntity);
|
||||
entityList.addAll(Arrays.asList(entities));
|
||||
return persistOrUpdate(collection, entityList);
|
||||
}
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> persistOrUpdate(Stream<?> entities) {
|
||||
List<Object> objects = entities.collect(Collectors.toList());
|
||||
if (objects.size() > 0) {
|
||||
// get the first entity to be able to retrieve the collection with it
|
||||
Object firstEntity = objects.get(0);
|
||||
ReactiveMongoCollection collection = mongoCollection(firstEntity);
|
||||
return persistOrUpdate(collection, objects);
|
||||
}
|
||||
return nullFuture();
|
||||
}
|
||||
|
||||
public static CompletionStage<Void> delete(Object entity) {
|
||||
ReactiveMongoCollection collection = mongoCollection(entity);
|
||||
BsonDocument document = getBsonDocument(collection, entity);
|
||||
BsonValue id = document.get(ID);
|
||||
BsonDocument query = new BsonDocument().append(ID, id);
|
||||
return collection.deleteOne(query).thenApply(r -> null);
|
||||
}
|
||||
|
||||
public static ReactiveMongoCollection mongoCollection(Class<?> entityClass) {
|
||||
MongoEntity mongoEntity = entityClass.getAnnotation(MongoEntity.class);
|
||||
ReactiveMongoDatabase database = mongoDatabase(mongoEntity);
|
||||
if (mongoEntity != null && !mongoEntity.collection().isEmpty()) {
|
||||
return database.getCollection(mongoEntity.collection(), entityClass);
|
||||
}
|
||||
return database.getCollection(entityClass.getSimpleName(), entityClass);
|
||||
}
|
||||
|
||||
public static ReactiveMongoDatabase mongoDatabase(Class<?> entityClass) {
|
||||
MongoEntity mongoEntity = entityClass.getAnnotation(MongoEntity.class);
|
||||
return mongoDatabase(mongoEntity);
|
||||
}
|
||||
|
||||
//
|
||||
// Private stuff
|
||||
|
||||
public static CompletableFuture<Void> nullFuture() {
|
||||
return completedFuture(null);
|
||||
}
|
||||
|
||||
public static <U> CompletableFuture<U> completedFuture(U value) {
|
||||
ThreadContext threadContext = Arc.container().instance(ThreadContext.class).get();
|
||||
return threadContext.withContextCapture(CompletableFuture.completedFuture(value));
|
||||
}
|
||||
|
||||
private static CompletionStage<Void> persist(ReactiveMongoCollection collection, Object entity) {
|
||||
return collection.insertOne(entity);
|
||||
}
|
||||
|
||||
private static CompletionStage<Void> persist(ReactiveMongoCollection collection, List<Object> entities) {
|
||||
return collection.insertMany(entities);
|
||||
}
|
||||
|
||||
private static CompletionStage<Void> update(ReactiveMongoCollection collection, Object entity) {
|
||||
//we transform the entity as a document first
|
||||
BsonDocument document = getBsonDocument(collection, entity);
|
||||
|
||||
//then we get its id field and create a new Document with only this one that will be our replace query
|
||||
BsonValue id = document.get(ID);
|
||||
BsonDocument query = new BsonDocument().append(ID, id);
|
||||
return collection.replaceOne(query, entity).thenApply(u -> null);
|
||||
}
|
||||
|
||||
private static CompletionStage<Void> update(ReactiveMongoCollection collection, List<Object> entities) {
|
||||
CompletionStage<Void> ret = nullFuture();
|
||||
for (Object entity : entities) {
|
||||
ret.thenCompose(v -> update(collection, entity));
|
||||
}
|
||||
return ret.thenApply(v -> null);
|
||||
}
|
||||
|
||||
private static CompletionStage<Void> persistOrUpdate(ReactiveMongoCollection collection, Object entity) {
|
||||
//we transform the entity as a document first
|
||||
BsonDocument document = getBsonDocument(collection, entity);
|
||||
|
||||
//then we get its id field and create a new Document with only this one that will be our replace query
|
||||
BsonValue id = document.get(ID);
|
||||
if (id == null) {
|
||||
//insert with autogenerated ID
|
||||
return collection.insertOne(entity);
|
||||
} else {
|
||||
//insert with user provided ID or update
|
||||
BsonDocument query = new BsonDocument().append(ID, id);
|
||||
return collection.replaceOne(query, entity, ReplaceOptions.createReplaceOptions(new UpdateOptions().upsert(true)))
|
||||
.thenApply(u -> null);
|
||||
}
|
||||
}
|
||||
|
||||
private static CompletionStage<Void> persistOrUpdate(ReactiveMongoCollection collection, List<Object> entities) {
|
||||
//this will be an ordered bulk: it's less performant than a unordered one but will fail at the first failed write
|
||||
List<WriteModel> bulk = new ArrayList<>();
|
||||
for (Object entity : entities) {
|
||||
//we transform the entity as a document first
|
||||
BsonDocument document = getBsonDocument(collection, entity);
|
||||
|
||||
//then we get its id field and create a new Document with only this one that will be our replace query
|
||||
BsonValue id = document.get(ID);
|
||||
if (id == null) {
|
||||
//insert with autogenerated ID
|
||||
bulk.add(new InsertOneModel(entity));
|
||||
} else {
|
||||
//insert with user provided ID or update
|
||||
BsonDocument query = new BsonDocument().append(ID, id);
|
||||
bulk.add(new ReplaceOneModel(query, entity,
|
||||
ReplaceOptions.createReplaceOptions(new UpdateOptions().upsert(true))));
|
||||
}
|
||||
}
|
||||
|
||||
return collection.bulkWrite(bulk).thenApply(b -> null);
|
||||
}
|
||||
|
||||
private static BsonDocument getBsonDocument(ReactiveMongoCollection collection, Object entity) {
|
||||
BsonDocument document = new BsonDocument();
|
||||
Codec codec = collection.getCodecRegistry().get(entity.getClass());
|
||||
codec.encode(new BsonDocumentWriter(document), entity, EncoderContext.builder().build());
|
||||
return document;
|
||||
}
|
||||
|
||||
private static ReactiveMongoCollection mongoCollection(Object entity) {
|
||||
Class<?> entityClass = entity.getClass();
|
||||
return mongoCollection(entityClass);
|
||||
}
|
||||
|
||||
private static ReactiveMongoDatabase mongoDatabase(MongoEntity entity) {
|
||||
ReactiveMongoClient mongoClient = Arc.container().instance(ReactiveMongoClient.class).get();
|
||||
if (entity != null && !entity.database().isEmpty()) {
|
||||
return mongoClient.getDatabase(entity.database());
|
||||
}
|
||||
String databaseName = ConfigProvider.getConfig()
|
||||
.getValue(MONGODB_DATABASE, String.class);
|
||||
return mongoClient.getDatabase(databaseName);
|
||||
}
|
||||
|
||||
//
|
||||
// Queries
|
||||
|
||||
public static CompletionStage<Object> findById(Class<?> entityClass, Object id) {
|
||||
CompletionStage<Optional> optionalEntity = findByIdOptional(entityClass, id);
|
||||
return optionalEntity.thenApply(optional -> optional.orElse(null));
|
||||
}
|
||||
|
||||
public static CompletionStage<Optional> findByIdOptional(Class<?> entityClass, Object id) {
|
||||
ReactiveMongoCollection collection = mongoCollection(entityClass);
|
||||
return collection.find(new Document(ID, id)).findFirst().run();
|
||||
}
|
||||
|
||||
public static ReactivePanacheQuery<?> find(Class<?> entityClass, String query, Object... params) {
|
||||
return find(entityClass, query, null, params);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static ReactivePanacheQuery<?> find(Class<?> entityClass, String query, Sort sort, Object... params) {
|
||||
String bindQuery = bindQuery(entityClass, query, params);
|
||||
Document docQuery = Document.parse(bindQuery);
|
||||
Document docSort = sortToDocument(sort);
|
||||
ReactiveMongoCollection collection = mongoCollection(entityClass);
|
||||
return new ReactivePanacheQueryImpl(collection, entityClass, docQuery, docSort);
|
||||
}
|
||||
|
||||
/**
|
||||
* We should have a query like <code>{'firstname': ?1, 'lastname': ?2}</code> for native one
|
||||
* and like <code>firstname = ?1</code> for PanacheQL one.
|
||||
*/
|
||||
static String bindQuery(Class<?> clazz, String query, Object[] params) {
|
||||
String bindQuery = null;
|
||||
|
||||
//determine the type of the query
|
||||
if (query.charAt(0) == '{') {
|
||||
//this is a native query
|
||||
bindQuery = NativeQueryBinder.bindQuery(query, params);
|
||||
} else {
|
||||
//this is a PanacheQL query
|
||||
bindQuery = PanacheQlQueryBinder.bindQuery(clazz, query, params);
|
||||
}
|
||||
|
||||
LOGGER.debug(bindQuery);
|
||||
return bindQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* We should have a query like <code>{'firstname': :firstname, 'lastname': :lastname}</code> for native one
|
||||
* and like <code>firstname = :firstname and lastname = :lastname</code> for PanacheQL one.
|
||||
*/
|
||||
static String bindQuery(Class<?> clazz, String query, Map<String, Object> params) {
|
||||
String bindQuery = null;
|
||||
|
||||
//determine the type of the query
|
||||
if (query.charAt(0) == '{') {
|
||||
//this is a native query
|
||||
bindQuery = NativeQueryBinder.bindQuery(query, params);
|
||||
} else {
|
||||
//this is a PanacheQL query
|
||||
bindQuery = PanacheQlQueryBinder.bindQuery(clazz, query, params);
|
||||
}
|
||||
|
||||
LOGGER.debug(bindQuery);
|
||||
return bindQuery;
|
||||
}
|
||||
|
||||
public static ReactivePanacheQuery<?> find(Class<?> entityClass, String query, Map<String, Object> params) {
|
||||
return find(entityClass, query, null, params);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static ReactivePanacheQuery<?> find(Class<?> entityClass, String query, Sort sort, Map<String, Object> params) {
|
||||
String bindQuery = bindQuery(entityClass, query, params);
|
||||
Document docQuery = Document.parse(bindQuery);
|
||||
Document docSort = sortToDocument(sort);
|
||||
ReactiveMongoCollection collection = mongoCollection(entityClass);
|
||||
return new ReactivePanacheQueryImpl(collection, entityClass, docQuery, docSort);
|
||||
}
|
||||
|
||||
public static ReactivePanacheQuery<?> find(Class<?> entityClass, String query, Parameters params) {
|
||||
return find(entityClass, query, null, params.map());
|
||||
}
|
||||
|
||||
public static ReactivePanacheQuery<?> find(Class<?> entityClass, String query, Sort sort, Parameters params) {
|
||||
return find(entityClass, query, sort, params.map());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static ReactivePanacheQuery<?> find(Class<?> entityClass, Document query, Sort sort) {
|
||||
ReactiveMongoCollection collection = mongoCollection(entityClass);
|
||||
Document sortDoc = sortToDocument(sort);
|
||||
return new ReactivePanacheQueryImpl(collection, entityClass, query, sortDoc);
|
||||
}
|
||||
|
||||
public static ReactivePanacheQuery<?> find(Class<?> entityClass, Document query, Document sort) {
|
||||
ReactiveMongoCollection collection = mongoCollection(entityClass);
|
||||
return new ReactivePanacheQueryImpl(collection, entityClass, query, sort);
|
||||
}
|
||||
|
||||
public static ReactivePanacheQuery<?> find(Class<?> entityClass, Document query) {
|
||||
return find(entityClass, query, (Document) null);
|
||||
}
|
||||
|
||||
public static CompletionStage<List<?>> list(Class<?> entityClass, String query, Object... params) {
|
||||
return (CompletionStage) find(entityClass, query, params).list();
|
||||
}
|
||||
|
||||
public static CompletionStage<List<?>> list(Class<?> entityClass, String query, Sort sort, Object... params) {
|
||||
return (CompletionStage) find(entityClass, query, sort, params).list();
|
||||
}
|
||||
|
||||
public static CompletionStage<List<?>> list(Class<?> entityClass, String query, Map<String, Object> params) {
|
||||
return (CompletionStage) find(entityClass, query, params).list();
|
||||
}
|
||||
|
||||
public static CompletionStage<List<?>> list(Class<?> entityClass, String query, Sort sort, Map<String, Object> params) {
|
||||
return (CompletionStage) find(entityClass, query, sort, params).list();
|
||||
}
|
||||
|
||||
public static CompletionStage<List<?>> list(Class<?> entityClass, String query, Parameters params) {
|
||||
return (CompletionStage) find(entityClass, query, params).list();
|
||||
}
|
||||
|
||||
public static CompletionStage<List<?>> list(Class<?> entityClass, String query, Sort sort, Parameters params) {
|
||||
return (CompletionStage) find(entityClass, query, sort, params).list();
|
||||
}
|
||||
|
||||
//specific Mongo query
|
||||
public static CompletionStage<List<?>> list(Class<?> entityClass, Document query) {
|
||||
return (CompletionStage) find(entityClass, query).list();
|
||||
}
|
||||
|
||||
//specific Mongo query
|
||||
public static CompletionStage<List<?>> list(Class<?> entityClass, Document query, Document sort) {
|
||||
return (CompletionStage) find(entityClass, query, sort).list();
|
||||
}
|
||||
|
||||
public static Publisher<?> stream(Class<?> entityClass, String query, Object... params) {
|
||||
return find(entityClass, query, params).stream();
|
||||
}
|
||||
|
||||
public static Publisher<?> stream(Class<?> entityClass, String query, Sort sort, Object... params) {
|
||||
return find(entityClass, query, sort, params).stream();
|
||||
}
|
||||
|
||||
public static Publisher<?> stream(Class<?> entityClass, String query, Map<String, Object> params) {
|
||||
return find(entityClass, query, params).stream();
|
||||
}
|
||||
|
||||
public static Publisher<?> stream(Class<?> entityClass, String query, Sort sort, Map<String, Object> params) {
|
||||
return find(entityClass, query, sort, params).stream();
|
||||
}
|
||||
|
||||
public static Publisher<?> stream(Class<?> entityClass, String query, Parameters params) {
|
||||
return find(entityClass, query, params).stream();
|
||||
}
|
||||
|
||||
public static Publisher<?> stream(Class<?> entityClass, String query, Sort sort, Parameters params) {
|
||||
return find(entityClass, query, sort, params).stream();
|
||||
}
|
||||
|
||||
//specific Mongo query
|
||||
public static Publisher<?> stream(Class<?> entityClass, Document query) {
|
||||
return find(entityClass, query).stream();
|
||||
}
|
||||
|
||||
//specific Mongo query
|
||||
public static Publisher<?> stream(Class<?> entityClass, Document query, Document sort) {
|
||||
return find(entityClass, query, sort).stream();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static ReactivePanacheQuery<?> findAll(Class<?> entityClass) {
|
||||
ReactiveMongoCollection collection = mongoCollection(entityClass);
|
||||
return new ReactivePanacheQueryImpl(collection, entityClass, null, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static ReactivePanacheQuery<?> findAll(Class<?> entityClass, Sort sort) {
|
||||
ReactiveMongoCollection collection = mongoCollection(entityClass);
|
||||
Document sortDoc = sortToDocument(sort);
|
||||
return new ReactivePanacheQueryImpl(collection, entityClass, null, sortDoc);
|
||||
}
|
||||
|
||||
private static Document sortToDocument(Sort sort) {
|
||||
if (sort == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Document sortDoc = new Document();
|
||||
for (Sort.Column col : sort.getColumns()) {
|
||||
sortDoc.append(col.getName(), col.getDirection() == Sort.Direction.Ascending ? 1 : -1);
|
||||
}
|
||||
return sortDoc;
|
||||
}
|
||||
|
||||
public static CompletionStage<List<?>> listAll(Class<?> entityClass) {
|
||||
return (CompletionStage) findAll(entityClass).list();
|
||||
}
|
||||
|
||||
public static CompletionStage<List<?>> listAll(Class<?> entityClass, Sort sort) {
|
||||
return (CompletionStage) findAll(entityClass, sort).list();
|
||||
}
|
||||
|
||||
public static Publisher<?> streamAll(Class<?> entityClass) {
|
||||
return findAll(entityClass).stream();
|
||||
}
|
||||
|
||||
public static Publisher<?> streamAll(Class<?> entityClass, Sort sort) {
|
||||
return findAll(entityClass, sort).stream();
|
||||
}
|
||||
|
||||
public static CompletionStage<Long> count(Class<?> entityClass) {
|
||||
ReactiveMongoCollection collection = mongoCollection(entityClass);
|
||||
return collection.countDocuments();
|
||||
}
|
||||
|
||||
public static CompletionStage<Long> count(Class<?> entityClass, String query, Object... params) {
|
||||
String bindQuery = bindQuery(entityClass, query, params);
|
||||
Document docQuery = Document.parse(bindQuery);
|
||||
ReactiveMongoCollection collection = mongoCollection(entityClass);
|
||||
return collection.countDocuments(docQuery);
|
||||
}
|
||||
|
||||
public static CompletionStage<Long> count(Class<?> entityClass, String query, Map<String, Object> params) {
|
||||
String bindQuery = bindQuery(entityClass, query, params);
|
||||
Document docQuery = Document.parse(bindQuery);
|
||||
ReactiveMongoCollection collection = mongoCollection(entityClass);
|
||||
return collection.countDocuments(docQuery);
|
||||
}
|
||||
|
||||
public static CompletionStage<Long> count(Class<?> entityClass, String query, Parameters params) {
|
||||
return count(entityClass, query, params.map());
|
||||
}
|
||||
|
||||
//specific Mongo query
|
||||
public static CompletionStage<Long> count(Class<?> entityClass, Document query) {
|
||||
ReactiveMongoCollection<?> collection = mongoCollection(entityClass);
|
||||
return collection.countDocuments(query);
|
||||
}
|
||||
|
||||
public static CompletionStage<Long> deleteAll(Class<?> entityClass) {
|
||||
ReactiveMongoCollection<?> collection = mongoCollection(entityClass);
|
||||
return collection.deleteMany(new Document()).thenApply(deleteResult -> deleteResult.getDeletedCount());
|
||||
}
|
||||
|
||||
public static CompletionStage<Long> delete(Class<?> entityClass, String query, Object... params) {
|
||||
String bindQuery = bindQuery(entityClass, query, params);
|
||||
Document docQuery = Document.parse(bindQuery);
|
||||
ReactiveMongoCollection<?> collection = mongoCollection(entityClass);
|
||||
return collection.deleteMany(docQuery).thenApply(deleteResult -> deleteResult.getDeletedCount());
|
||||
}
|
||||
|
||||
public static CompletionStage<Long> delete(Class<?> entityClass, String query, Map<String, Object> params) {
|
||||
String bindQuery = bindQuery(entityClass, query, params);
|
||||
Document docQuery = Document.parse(bindQuery);
|
||||
ReactiveMongoCollection<?> collection = mongoCollection(entityClass);
|
||||
return collection.deleteMany(docQuery).thenApply(deleteResult -> deleteResult.getDeletedCount());
|
||||
}
|
||||
|
||||
public static CompletionStage<Long> delete(Class<?> entityClass, String query, Parameters params) {
|
||||
return delete(entityClass, query, params.map());
|
||||
}
|
||||
|
||||
//specific Mongo query
|
||||
public static CompletionStage<Long> delete(Class<?> entityClass, Document query) {
|
||||
ReactiveMongoCollection<?> collection = mongoCollection(entityClass);
|
||||
return collection.deleteMany(query).thenApply(deleteResult -> deleteResult.getDeletedCount());
|
||||
}
|
||||
|
||||
public static IllegalStateException implementationInjectionMissing() {
|
||||
return new IllegalStateException(
|
||||
"This method is normally automatically overridden in subclasses");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package io.quarkus.mongodb.panache.axle.runtime;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.eclipse.microprofile.reactive.streams.operators.PublisherBuilder;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import io.quarkus.mongodb.FindOptions;
|
||||
import io.quarkus.mongodb.ReactiveMongoCollection;
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheQuery;
|
||||
import io.quarkus.panache.common.Page;
|
||||
import io.quarkus.panache.common.exception.PanacheQueryException;
|
||||
|
||||
public class ReactivePanacheQueryImpl<Entity> implements ReactivePanacheQuery<Entity> {
|
||||
private ReactiveMongoCollection collection;
|
||||
private Class<? extends Entity> entityClass;
|
||||
private Document mongoQuery;
|
||||
private Document sort;
|
||||
|
||||
/*
|
||||
* We store the pageSize and apply it for each request because getFirstResult()
|
||||
* sets the page size to 1
|
||||
*/
|
||||
private Page page;
|
||||
private CompletionStage<Long> count;
|
||||
|
||||
ReactivePanacheQueryImpl(ReactiveMongoCollection<? extends Entity> collection, Class<? extends Entity> entityClass,
|
||||
Document mongoQuery,
|
||||
Document sort) {
|
||||
this.collection = collection;
|
||||
this.entityClass = entityClass;
|
||||
this.mongoQuery = mongoQuery;
|
||||
this.sort = sort;
|
||||
page = new Page(0, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
// Builder
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Entity> ReactivePanacheQuery<T> page(Page page) {
|
||||
this.page = page;
|
||||
return (ReactivePanacheQuery<T>) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Entity> ReactivePanacheQuery<T> page(int pageIndex, int pageSize) {
|
||||
return page(Page.of(pageIndex, pageSize));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Entity> ReactivePanacheQuery<T> nextPage() {
|
||||
return page(page.next());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Entity> ReactivePanacheQuery<T> previousPage() {
|
||||
return page(page.previous());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Entity> ReactivePanacheQuery<T> firstPage() {
|
||||
return page(page.first());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Entity> CompletionStage<ReactivePanacheQuery<T>> lastPage() {
|
||||
return pageCount().thenApply(pageCount -> {
|
||||
return page(page.index(pageCount - 1));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Boolean> hasNextPage() {
|
||||
return pageCount().thenApply(pageCount -> {
|
||||
return page.index < (pageCount - 1);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPreviousPage() {
|
||||
return page.index > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Integer> pageCount() {
|
||||
return count().thenApply(count -> {
|
||||
if (count == 0)
|
||||
return 1; // a single page of zero results
|
||||
return (int) Math.ceil((double) count / (double) page.size);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page page() {
|
||||
return page;
|
||||
}
|
||||
|
||||
// Results
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public CompletionStage<Long> count() {
|
||||
if (count == null) {
|
||||
count = collection.countDocuments(mongoQuery);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Entity> CompletionStage<List<T>> list() {
|
||||
FindOptions options = new FindOptions();
|
||||
options.sort(sort).skip(page.index).limit(page.size);
|
||||
PublisherBuilder<T> results = mongoQuery == null ? collection.find(options) : collection.find(mongoQuery, options);
|
||||
return results.toList().run();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Entity> Publisher<T> stream() {
|
||||
FindOptions options = new FindOptions();
|
||||
options.sort(sort).skip(page.index).limit(page.size);
|
||||
return mongoQuery == null ? collection.find(options).buildRs() : collection.find(mongoQuery, options).buildRs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Entity> CompletionStage<T> firstResult() {
|
||||
CompletionStage<Optional<T>> optionalEntity = firstResultOptional();
|
||||
return optionalEntity.thenApply(optional -> optional.orElse(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Entity> CompletionStage<Optional<T>> firstResultOptional() {
|
||||
FindOptions options = new FindOptions();
|
||||
options.sort(sort).skip(page.index).limit(1);
|
||||
return mongoQuery == null ? collection.find(options).findFirst().run()
|
||||
: collection.find(mongoQuery, options).findFirst().run();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Entity> CompletionStage<T> singleResult() {
|
||||
FindOptions options = new FindOptions();
|
||||
options.sort(sort).skip(page.index).limit(2);
|
||||
PublisherBuilder<T> results = mongoQuery == null ? collection.find(options) : collection.find(mongoQuery, options);
|
||||
return results.toList().run().thenApply(list -> {
|
||||
if (list.size() == 0 || list.size() > 1) {
|
||||
throw new PanacheQueryException("There should be only one result");
|
||||
} else {
|
||||
return list.get(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Entity> CompletionStage<Optional<T>> singleResultOptional() {
|
||||
FindOptions options = new FindOptions();
|
||||
options.sort(sort).skip(page.index).limit(2);
|
||||
PublisherBuilder<T> results = mongoQuery == null ? collection.find(options) : collection.find(mongoQuery, options);
|
||||
return results.toList().run().thenApply(list -> {
|
||||
if (list.size() == 2) {
|
||||
throw new PanacheQueryException("There should be no more than one result");
|
||||
}
|
||||
return list.isEmpty() ? Optional.empty() : Optional.of(list.get(0));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.quarkus.mongodb.panache.runtime;
|
||||
package io.quarkus.mongodb.panache.binder;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.quarkus.mongodb.panache.runtime;
|
||||
package io.quarkus.mongodb.panache.binder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.quarkus.mongodb.panache.runtime;
|
||||
package io.quarkus.mongodb.panache.binder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
class NativeQueryBinder {
|
||||
public class NativeQueryBinder {
|
||||
|
||||
public static String bindQuery(String query, Object[] params) {
|
||||
String bindQuery = query;
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.quarkus.mongodb.panache.runtime;
|
||||
package io.quarkus.mongodb.panache.binder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -6,6 +6,7 @@ import java.util.Map;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
|
||||
import io.quarkus.mongodb.panache.runtime.MongoPropertyUtil;
|
||||
import io.quarkus.panacheql.internal.HqlLexer;
|
||||
import io.quarkus.panacheql.internal.HqlParser;
|
||||
import io.quarkus.panacheql.internal.HqlParserBaseVisitor;
|
||||
@@ -29,6 +29,8 @@ import com.mongodb.client.model.WriteModel;
|
||||
import io.quarkus.arc.Arc;
|
||||
import io.quarkus.mongodb.panache.MongoEntity;
|
||||
import io.quarkus.mongodb.panache.PanacheQuery;
|
||||
import io.quarkus.mongodb.panache.binder.NativeQueryBinder;
|
||||
import io.quarkus.mongodb.panache.binder.PanacheQlQueryBinder;
|
||||
import io.quarkus.panache.common.Parameters;
|
||||
import io.quarkus.panache.common.Sort;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ public final class MongoPropertyUtil {
|
||||
replacementCache = newReplacementCache;
|
||||
}
|
||||
|
||||
static Map<String, String> getReplacementMap(Class<?> clazz) {
|
||||
public static Map<String, String> getReplacementMap(Class<?> clazz) {
|
||||
return replacementCache.computeIfAbsent(clazz.getName(), s -> buildWithReflection(clazz));
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-mongodb-panache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-rest-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package io.quarkus.it.mongodb.panache.axle.book;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.json.bind.annotation.JsonbDateFormat;
|
||||
|
||||
import org.bson.codecs.pojo.annotations.BsonIgnore;
|
||||
import org.bson.codecs.pojo.annotations.BsonProperty;
|
||||
|
||||
import io.quarkus.it.mongodb.panache.book.BookDetail;
|
||||
import io.quarkus.mongodb.panache.MongoEntity;
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheMongoEntity;
|
||||
|
||||
@MongoEntity(collection = "TheBookEntity")
|
||||
public class ReactiveBookEntity extends ReactivePanacheMongoEntity {
|
||||
@BsonProperty("bookTitle")
|
||||
private String title;
|
||||
private String author;
|
||||
@BsonIgnore
|
||||
private String transientDescription;
|
||||
@JsonbDateFormat("yyyy-MM-dd")
|
||||
private LocalDate creationDate;
|
||||
|
||||
private List<String> categories = new ArrayList<>();
|
||||
|
||||
private BookDetail details;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public ReactiveBookEntity setTitle(String title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public ReactiveBookEntity setAuthor(String author) {
|
||||
this.author = author;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> getCategories() {
|
||||
return categories;
|
||||
}
|
||||
|
||||
public ReactiveBookEntity setCategories(List<String> categories) {
|
||||
this.categories = categories;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BookDetail getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public ReactiveBookEntity setDetails(BookDetail details) {
|
||||
this.details = details;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTransientDescription() {
|
||||
return transientDescription;
|
||||
}
|
||||
|
||||
public void setTransientDescription(String transientDescription) {
|
||||
this.transientDescription = transientDescription;
|
||||
}
|
||||
|
||||
public LocalDate getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public void setCreationDate(LocalDate creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package io.quarkus.it.mongodb.panache.axle.book;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.SseElementType;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import io.quarkus.panache.common.Parameters;
|
||||
import io.quarkus.panache.common.Sort;
|
||||
|
||||
@Path("/axle/books/entity")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class ReactiveBookEntityResource {
|
||||
private static final Logger LOGGER = Logger.getLogger(ReactiveBookEntityResource.class);
|
||||
|
||||
@PostConstruct
|
||||
void init() {
|
||||
String databaseName = ReactiveBookEntity.mongoDatabase().getName();
|
||||
String collectionName = ReactiveBookEntity.mongoCollection().getNamespace().getCollectionName();
|
||||
LOGGER.infov("Using BookEntity[database={0}, collection={1}]", databaseName, collectionName);
|
||||
}
|
||||
|
||||
@GET
|
||||
public CompletionStage<List<ReactiveBookEntity>> getBooks(@QueryParam("sort") String sort) {
|
||||
if (sort != null) {
|
||||
return ReactiveBookEntity.listAll(Sort.ascending(sort));
|
||||
}
|
||||
return ReactiveBookEntity.listAll();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/stream")
|
||||
@Produces(MediaType.SERVER_SENT_EVENTS)
|
||||
@SseElementType(MediaType.APPLICATION_JSON)
|
||||
public Publisher<ReactiveBookEntity> streamBooks(@QueryParam("sort") String sort) {
|
||||
if (sort != null) {
|
||||
return ReactiveBookEntity.streamAll(Sort.ascending(sort));
|
||||
}
|
||||
return ReactiveBookEntity.streamAll();
|
||||
}
|
||||
|
||||
@POST
|
||||
public CompletionStage<Response> addBook(ReactiveBookEntity book) {
|
||||
return book.persist().thenApply(v -> {
|
||||
//the ID is populated before sending it to the database
|
||||
String id = book.id.toString();
|
||||
return Response.created(URI.create("/books/entity" + id)).build();
|
||||
});
|
||||
}
|
||||
|
||||
@PUT
|
||||
public CompletionStage<Response> updateBook(ReactiveBookEntity book) {
|
||||
return book.update().thenApply(v -> Response.accepted().build());
|
||||
}
|
||||
|
||||
// PATCH is not correct here but it allows to test persistOrUpdate without a specific subpath
|
||||
@PATCH
|
||||
public CompletionStage<Response> upsertBook(ReactiveBookEntity book) {
|
||||
return book.persistOrUpdate().thenApply(v -> Response.accepted().build());
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
public CompletionStage<Void> deleteBook(@PathParam("id") String id) {
|
||||
return ReactiveBookEntity.findById(new ObjectId(id)).thenCompose(book -> book.delete());
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
public CompletionStage<ReactiveBookEntity> getBook(@PathParam("id") String id) {
|
||||
return ReactiveBookEntity.findById(new ObjectId(id));
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/search/{author}")
|
||||
public CompletionStage<List<ReactiveBookEntity>> getBooksByAuthor(@PathParam("author") String author) {
|
||||
return ReactiveBookEntity.list("author", author);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/search")
|
||||
public CompletionStage<ReactiveBookEntity> search(@QueryParam("author") String author, @QueryParam("title") String title,
|
||||
@QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo) {
|
||||
if (author != null) {
|
||||
return ReactiveBookEntity.find("{'author': ?1,'bookTitle': ?2}", author, title).firstResult();
|
||||
}
|
||||
|
||||
return ReactiveBookEntity
|
||||
.find("{'creationDate': {$gte: ?1}, 'creationDate': {$lte: ?2}}", LocalDate.parse(dateFrom),
|
||||
LocalDate.parse(dateTo))
|
||||
.firstResult();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/search2")
|
||||
public CompletionStage<ReactiveBookEntity> search2(@QueryParam("author") String author, @QueryParam("title") String title,
|
||||
@QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo) {
|
||||
if (author != null) {
|
||||
return ReactiveBookEntity.find("{'author': :author,'bookTitle': :title}",
|
||||
Parameters.with("author", author).and("title", title)).firstResult();
|
||||
}
|
||||
|
||||
return ReactiveBookEntity.find("{'creationDate': {$gte: :dateFrom}, 'creationDate': {$lte: :dateTo}}",
|
||||
Parameters.with("dateFrom", LocalDate.parse(dateFrom)).and("dateTo", LocalDate.parse(dateTo))).firstResult();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
public CompletionStage<Void> deleteAll() {
|
||||
return ReactiveBookEntity.deleteAll().thenApply(l -> null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.quarkus.it.mongodb.panache.axle.book;
|
||||
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
|
||||
import io.quarkus.it.mongodb.panache.book.Book;
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheMongoRepository;
|
||||
|
||||
@ApplicationScoped
|
||||
public class ReactiveBookRepository implements ReactivePanacheMongoRepository<Book> {
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package io.quarkus.it.mongodb.panache.axle.book;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.SseElementType;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import io.quarkus.it.mongodb.panache.book.Book;
|
||||
import io.quarkus.panache.common.Parameters;
|
||||
import io.quarkus.panache.common.Sort;
|
||||
|
||||
@Path("/axle/books/repository")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class ReactiveBookRepositoryResource {
|
||||
private static final Logger LOGGER = Logger.getLogger(ReactiveBookRepositoryResource.class);
|
||||
@Inject
|
||||
ReactiveBookRepository reactiveBookRepository;
|
||||
|
||||
@PostConstruct
|
||||
void init() {
|
||||
String databaseName = reactiveBookRepository.mongoDatabase().getName();
|
||||
String collectionName = reactiveBookRepository.mongoCollection().getNamespace().getCollectionName();
|
||||
LOGGER.infov("Using BookRepository[database={0}, collection={1}]", databaseName, collectionName);
|
||||
}
|
||||
|
||||
@GET
|
||||
public CompletionStage<List<Book>> getBooks(@QueryParam("sort") String sort) {
|
||||
if (sort != null) {
|
||||
return reactiveBookRepository.listAll(Sort.ascending(sort));
|
||||
}
|
||||
return reactiveBookRepository.listAll();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/stream")
|
||||
@Produces(MediaType.SERVER_SENT_EVENTS)
|
||||
@SseElementType(MediaType.APPLICATION_JSON)
|
||||
public Publisher<Book> streamBooks(@QueryParam("sort") String sort) {
|
||||
if (sort != null) {
|
||||
return reactiveBookRepository.streamAll(Sort.ascending(sort));
|
||||
}
|
||||
return reactiveBookRepository.streamAll();
|
||||
}
|
||||
|
||||
@POST
|
||||
public CompletionStage<Response> addBook(Book book) {
|
||||
return reactiveBookRepository.persist(book).thenApply(v -> {
|
||||
//the ID is populated before sending it to the database
|
||||
String id = book.getId().toString();
|
||||
return Response.created(URI.create("/books/entity" + id)).build();
|
||||
});
|
||||
}
|
||||
|
||||
@PUT
|
||||
public CompletionStage<Response> updateBook(Book book) {
|
||||
return reactiveBookRepository.update(book).thenApply(v -> Response.accepted().build());
|
||||
}
|
||||
|
||||
// PATCH is not correct here but it allows to test persistOrUpdate without a specific subpath
|
||||
@PATCH
|
||||
public CompletionStage<Response> upsertBook(Book book) {
|
||||
return reactiveBookRepository.persistOrUpdate(book).thenApply(v -> Response.accepted().build());
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
public CompletionStage<Void> deleteBook(@PathParam("id") String id) {
|
||||
return reactiveBookRepository.findById(new ObjectId(id)).thenCompose(book -> reactiveBookRepository.delete(book));
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
public CompletionStage<Book> getBook(@PathParam("id") String id) {
|
||||
return reactiveBookRepository.findById(new ObjectId(id));
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/search/{author}")
|
||||
public CompletionStage<List<Book>> getBooksByAuthor(@PathParam("author") String author) {
|
||||
return reactiveBookRepository.list("author", author);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/search")
|
||||
public CompletionStage<Book> search(@QueryParam("author") String author, @QueryParam("title") String title,
|
||||
@QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo) {
|
||||
if (author != null) {
|
||||
return reactiveBookRepository.find("{'author': ?1,'bookTitle': ?2}", author, title).firstResult();
|
||||
}
|
||||
|
||||
return reactiveBookRepository
|
||||
.find("{'creationDate': {$gte: ?1}, 'creationDate': {$lte: ?2}}", LocalDate.parse(dateFrom),
|
||||
LocalDate.parse(dateTo))
|
||||
.firstResult();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/search2")
|
||||
public CompletionStage<Book> search2(@QueryParam("author") String author, @QueryParam("title") String title,
|
||||
@QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo) {
|
||||
if (author != null) {
|
||||
return reactiveBookRepository.find("{'author': :author,'bookTitle': :title}",
|
||||
Parameters.with("author", author).and("title", title)).firstResult();
|
||||
}
|
||||
|
||||
return reactiveBookRepository.find("{'creationDate': {$gte: :dateFrom}, 'creationDate': {$lte: :dateTo}}",
|
||||
Parameters.with("dateFrom", LocalDate.parse(dateFrom)).and("dateTo", LocalDate.parse(dateTo))).firstResult();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
public CompletionStage<Void> deleteAll() {
|
||||
return reactiveBookRepository.deleteAll().thenApply(l -> null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package io.quarkus.it.mongodb.panache.axle.person;
|
||||
|
||||
import org.bson.codecs.pojo.annotations.BsonId;
|
||||
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheMongoEntityBase;
|
||||
|
||||
public class ReactivePersonEntity extends ReactivePanacheMongoEntityBase {
|
||||
@BsonId
|
||||
public Long id;
|
||||
public String firstname;
|
||||
public String lastname;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package io.quarkus.it.mongodb.panache.axle.person;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import io.quarkus.panache.common.Sort;
|
||||
|
||||
@Path("/axle/persons/entity")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class ReactivePersonEntityResource {
|
||||
@GET
|
||||
public CompletionStage<List<ReactivePersonEntity>> getPersons(@QueryParam("sort") String sort) {
|
||||
if (sort != null) {
|
||||
return ReactivePersonEntity.listAll(Sort.ascending(sort));
|
||||
}
|
||||
return ReactivePersonEntity.listAll();
|
||||
}
|
||||
|
||||
@POST
|
||||
public CompletionStage<Response> addPerson(ReactivePersonEntity person) {
|
||||
return person.persist().thenApply(v -> {
|
||||
//the ID is populated before sending it to the database
|
||||
String id = person.id.toString();
|
||||
return Response.created(URI.create("/persons/entity" + id)).build();
|
||||
});
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/multiple")
|
||||
public CompletionStage<Void> addPersons(List<ReactivePersonEntity> persons) {
|
||||
return ReactivePersonEntity.persist(persons);
|
||||
}
|
||||
|
||||
@PUT
|
||||
public CompletionStage<Response> updatePerson(ReactivePersonEntity person) {
|
||||
return person.update().thenApply(v -> Response.accepted().build());
|
||||
}
|
||||
|
||||
// PATCH is not correct here but it allows to test persistOrUpdate without a specific subpath
|
||||
@PATCH
|
||||
public CompletionStage<Response> upsertPerson(ReactivePersonEntity person) {
|
||||
return person.persistOrUpdate().thenApply(v -> Response.accepted().build());
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
public CompletionStage<Void> deletePerson(@PathParam("id") String id) {
|
||||
return ReactivePersonEntity.findById(Long.parseLong(id)).thenCompose(person -> person.delete());
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
public CompletionStage<ReactivePersonEntity> getPerson(@PathParam("id") String id) {
|
||||
return ReactivePersonEntity.findById(Long.parseLong(id));
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/count")
|
||||
public CompletionStage<Long> countAll() {
|
||||
return ReactivePersonEntity.count();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
public CompletionStage<Void> deleteAll() {
|
||||
return ReactivePersonEntity.deleteAll().thenAccept(l -> {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.quarkus.it.mongodb.panache.axle.person;
|
||||
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
|
||||
import io.quarkus.it.mongodb.panache.person.Person;
|
||||
import io.quarkus.mongodb.panache.axle.ReactivePanacheMongoRepositoryBase;
|
||||
|
||||
@ApplicationScoped
|
||||
public class ReactivePersonRepository implements ReactivePanacheMongoRepositoryBase<Person, Long> {
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package io.quarkus.it.mongodb.panache.axle.person;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import io.quarkus.it.mongodb.panache.person.Person;
|
||||
import io.quarkus.panache.common.Sort;
|
||||
|
||||
@Path("/axle/persons/repository")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class ReactivePersonRepositoryResource {
|
||||
|
||||
@Inject
|
||||
ReactivePersonRepository reactivePersonRepository;
|
||||
|
||||
@GET
|
||||
public CompletionStage<List<Person>> getPersons(@QueryParam("sort") String sort) {
|
||||
if (sort != null) {
|
||||
return reactivePersonRepository.listAll(Sort.ascending(sort));
|
||||
}
|
||||
return reactivePersonRepository.listAll();
|
||||
}
|
||||
|
||||
@POST
|
||||
public CompletionStage<Response> addPerson(Person person) {
|
||||
return reactivePersonRepository.persist(person).thenApply(v -> {
|
||||
//the ID is populated before sending it to the database
|
||||
String id = person.id.toString();
|
||||
return Response.created(URI.create("/persons/entity" + id)).build();
|
||||
});
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/multiple")
|
||||
public CompletionStage<Void> addPersons(List<Person> persons) {
|
||||
return reactivePersonRepository.persist(persons);
|
||||
}
|
||||
|
||||
@PUT
|
||||
public CompletionStage<Response> updatePerson(Person person) {
|
||||
return reactivePersonRepository.update(person).thenApply(v -> Response.accepted().build());
|
||||
}
|
||||
|
||||
// PATCH is not correct here but it allows to test persistOrUpdate without a specific subpath
|
||||
@PATCH
|
||||
public CompletionStage<Response> upsertPerson(Person person) {
|
||||
return reactivePersonRepository.persistOrUpdate(person).thenApply(v -> Response.accepted().build());
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
public CompletionStage<Void> deletePerson(@PathParam("id") String id) {
|
||||
return reactivePersonRepository.findById(Long.parseLong(id))
|
||||
.thenCompose(person -> reactivePersonRepository.delete(person));
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
public CompletionStage<Person> getPerson(@PathParam("id") String id) {
|
||||
return reactivePersonRepository.findById(Long.parseLong(id));
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/count")
|
||||
public CompletionStage<Long> countAll() {
|
||||
return reactivePersonRepository.count();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
public CompletionStage<Void> deleteAll() {
|
||||
return reactivePersonRepository.deleteAll().thenAccept(l -> {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -108,4 +108,9 @@ public class BookEntityResource {
|
||||
Parameters.with("dateFrom", LocalDate.parse(dateFrom)).and("dateTo", LocalDate.parse(dateTo))).firstResult();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
public void deleteAll() {
|
||||
BookEntity.deleteAll();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -111,4 +111,8 @@ public class BookRepositoryResource {
|
||||
Parameters.with("dateFrom", LocalDate.parse(dateFrom)).and("dateTo", LocalDate.parse(dateTo))).firstResult();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
public void deleteAll() {
|
||||
bookRepository.deleteAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ package io.quarkus.it.mongodb.panache;
|
||||
import static io.restassured.RestAssured.get;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
@@ -187,6 +185,13 @@ class MongodbPanacheResourceTest {
|
||||
//test some special characters
|
||||
list = get(endpoint + "/search/Victor'\\ Hugo").as(LIST_OF_BOOK_TYPE_REF);
|
||||
Assertions.assertEquals(0, list.size());
|
||||
|
||||
//delete all
|
||||
response = RestAssured
|
||||
.given()
|
||||
.delete(endpoint)
|
||||
.andReturn();
|
||||
Assertions.assertEquals(204, response.statusCode());
|
||||
}
|
||||
|
||||
private void callPersonEndpoint(String endpoint) {
|
||||
@@ -303,10 +308,6 @@ class MongodbPanacheResourceTest {
|
||||
return cal.getTime();
|
||||
}
|
||||
|
||||
private Date fromYear(int year) {
|
||||
return Date.from(LocalDate.of(year, 1, 1).atStartOfDay().toInstant(ZoneOffset.UTC));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug5274() {
|
||||
get("/bugs/5274").then().body(is("OK"));
|
||||
|
||||
@@ -3,6 +3,6 @@ package io.quarkus.it.mongodb.panache;
|
||||
import io.quarkus.test.junit.NativeImageTest;
|
||||
|
||||
@NativeImageTest
|
||||
class NativeBookResourceIT extends MongodbPanacheResourceTest {
|
||||
class NativeMongodbPanacheResourceIT extends MongodbPanacheResourceTest {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package io.quarkus.it.mongodb.panache.axle;
|
||||
|
||||
import io.quarkus.test.junit.NativeImageTest;
|
||||
|
||||
@NativeImageTest
|
||||
class NativeMongodbPanacheResourceIT extends ReactiveMongodbPanacheResourceTest {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
package io.quarkus.it.mongodb.panache.axle;
|
||||
|
||||
import static io.restassured.RestAssured.get;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.sse.SseEventSource;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
|
||||
import io.quarkus.it.mongodb.panache.BookDTO;
|
||||
import io.quarkus.it.mongodb.panache.MongoTestResource;
|
||||
import io.quarkus.it.mongodb.panache.book.BookDetail;
|
||||
import io.quarkus.it.mongodb.panache.person.Person;
|
||||
import io.quarkus.test.common.QuarkusTestResource;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.common.mapper.TypeRef;
|
||||
import io.restassured.config.ObjectMapperConfig;
|
||||
import io.restassured.parsing.Parser;
|
||||
import io.restassured.response.Response;
|
||||
|
||||
@QuarkusTest
|
||||
@QuarkusTestResource(MongoTestResource.class)
|
||||
class ReactiveMongodbPanacheResourceTest {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ReactiveMongodbPanacheResourceTest.class);
|
||||
private static final TypeRef<List<BookDTO>> LIST_OF_BOOK_TYPE_REF = new TypeRef<List<BookDTO>>() {
|
||||
};
|
||||
private static final TypeRef<List<Person>> LIST_OF_PERSON_TYPE_REF = new TypeRef<List<Person>>() {
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testReactiveBookEntity() throws InterruptedException {
|
||||
callReactiveBookEndpoint("/axle/books/entity");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReactiveBookRepository() throws InterruptedException {
|
||||
callReactiveBookEndpoint("/axle/books/repository");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReactivePersonEntity() {
|
||||
callReactivePersonEndpoint("/axle/persons/entity");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReactivePersonRepository() {
|
||||
callReactivePersonEndpoint("/axle/persons/repository");
|
||||
}
|
||||
|
||||
private void callReactiveBookEndpoint(String endpoint) throws InterruptedException {
|
||||
RestAssured.defaultParser = Parser.JSON;
|
||||
ObjectMapper objectMapper = new ObjectMapper()
|
||||
.registerModule(new Jdk8Module())
|
||||
.registerModule(new JavaTimeModule())
|
||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
RestAssured.config
|
||||
.objectMapperConfig(new ObjectMapperConfig().jackson2ObjectMapperFactory((type, s) -> objectMapper));
|
||||
|
||||
List<BookDTO> list = get(endpoint).as(LIST_OF_BOOK_TYPE_REF);
|
||||
assertEquals(0, list.size());
|
||||
|
||||
BookDTO book1 = new BookDTO().setAuthor("Victor Hugo").setTitle("Les Misérables")
|
||||
.setCreationDate(yearToDate(1886))
|
||||
.setCategories(Arrays.asList("long", "very long"))
|
||||
.setDetails(new BookDetail().setRating(3).setSummary("A very long book"));
|
||||
Response response = RestAssured
|
||||
.given()
|
||||
.header("Content-Type", "application/json")
|
||||
.body(book1)
|
||||
.post(endpoint)
|
||||
.andReturn();
|
||||
assertEquals(201, response.statusCode());
|
||||
Assertions.assertTrue(response.header("Location").length() > 20);//Assert that id has been populated
|
||||
|
||||
BookDTO book2 = new BookDTO().setAuthor("Victor Hugo").setTitle("Notre-Dame de Paris")
|
||||
.setCreationDate(yearToDate(1831))
|
||||
.setCategories(Arrays.asList("long", "quasimodo"))
|
||||
.setDetails(new BookDetail().setRating(4).setSummary("quasimodo and esmeralda"));
|
||||
response = RestAssured
|
||||
.given()
|
||||
.header("Content-Type", "application/json")
|
||||
.body(book2)
|
||||
.post(endpoint)
|
||||
.andReturn();
|
||||
assertEquals(201, response.statusCode());
|
||||
|
||||
list = get(endpoint).as(LIST_OF_BOOK_TYPE_REF);
|
||||
assertEquals(2, list.size());
|
||||
|
||||
BookDTO book3 = new BookDTO().setAuthor("Charles Baudelaire").setTitle("Les fleurs du mal")
|
||||
.setCreationDate(yearToDate(1857))
|
||||
.setCategories(Collections.singletonList("poem"))
|
||||
.setDetails(new BookDetail().setRating(2).setSummary("Les Fleurs du mal is a volume of poetry."));
|
||||
response = RestAssured
|
||||
.given()
|
||||
.header("Content-Type", "application/json")
|
||||
.body(book3)
|
||||
.post(endpoint)
|
||||
.andReturn();
|
||||
assertEquals(201, response.statusCode());
|
||||
|
||||
BookDTO book4 = new BookDTO().setAuthor("Charles Baudelaire").setTitle("Le Spleen de Paris")
|
||||
.setCreationDate(yearToDate(1869))
|
||||
.setCategories(Collections.singletonList("poem"))
|
||||
.setDetails(new BookDetail().setRating(2)
|
||||
.setSummary("Le Spleen de Paris is a collection of 50 short prose poems."));
|
||||
response = RestAssured
|
||||
.given()
|
||||
.header("Content-Type", "application/json")
|
||||
.body(book4)
|
||||
.patch(endpoint)
|
||||
.andReturn();
|
||||
assertEquals(202, response.statusCode());
|
||||
|
||||
list = get(endpoint).as(LIST_OF_BOOK_TYPE_REF);
|
||||
assertEquals(4, list.size());
|
||||
|
||||
//with sort
|
||||
list = get(endpoint + "?sort=author").as(LIST_OF_BOOK_TYPE_REF);
|
||||
assertEquals(4, list.size());
|
||||
|
||||
// magic query find("author", author)
|
||||
list = get(endpoint + "/search/Victor Hugo").as(LIST_OF_BOOK_TYPE_REF);
|
||||
assertEquals(2, list.size());
|
||||
|
||||
// magic query find("{'author':?1,'title':?1}", author, title)
|
||||
BookDTO book = get(endpoint + "/search?author=Victor Hugo&title=Notre-Dame de Paris").as(BookDTO.class);
|
||||
assertNotNull(book);
|
||||
|
||||
// date
|
||||
book = get(endpoint + "/search?dateFrom=1885-01-01&dateTo=1887-01-01").as(BookDTO.class);
|
||||
assertNotNull(book);
|
||||
|
||||
book = get(endpoint + "/search2?dateFrom=1885-01-01&dateTo=1887-01-01").as(BookDTO.class);
|
||||
assertNotNull(book);
|
||||
|
||||
// magic query find("{'author'::author,'title'::title}", Parameters.with("author", author).and("title", title))
|
||||
book = get(endpoint + "/search2?author=Victor Hugo&title=Notre-Dame de Paris").as(BookDTO.class);
|
||||
assertNotNull(book);
|
||||
assertNotNull(book.getId());
|
||||
assertNotNull(book.getDetails());
|
||||
|
||||
//update a book
|
||||
book.setTitle("Notre-Dame de Paris 2").setTransientDescription("should not be persisted");
|
||||
response = RestAssured
|
||||
.given()
|
||||
.header("Content-Type", "application/json")
|
||||
.body(book)
|
||||
.put(endpoint)
|
||||
.andReturn();
|
||||
assertEquals(202, response.statusCode());
|
||||
|
||||
//check that the title has been updated and the transient description ignored
|
||||
book = get(endpoint + "/" + book.getId().toString()).as(BookDTO.class);
|
||||
assertEquals("Notre-Dame de Paris 2", book.getTitle());
|
||||
Assertions.assertNull(book.getTransientDescription());
|
||||
|
||||
//delete a book
|
||||
response = RestAssured
|
||||
.given()
|
||||
.delete(endpoint + "/" + book.getId().toString())
|
||||
.andReturn();
|
||||
assertEquals(204, response.statusCode());
|
||||
|
||||
list = get(endpoint).as(LIST_OF_BOOK_TYPE_REF);
|
||||
assertEquals(3, list.size());
|
||||
|
||||
//test some special characters
|
||||
list = get(endpoint + "/search/Victor'\\ Hugo").as(LIST_OF_BOOK_TYPE_REF);
|
||||
assertEquals(0, list.size());
|
||||
|
||||
//test SSE : there is no JSON serialization for SSE so the test is not very elegant ...
|
||||
Client client = ClientBuilder.newClient();
|
||||
WebTarget target = client.target("http://localhost:8081" + endpoint + "/stream");
|
||||
try (SseEventSource source = SseEventSource.target(target).build()) {
|
||||
final IntegerAdder nbEvent = new IntegerAdder();
|
||||
source.register((inboundSseEvent) -> {
|
||||
try {
|
||||
BookDTO theBook = objectMapper.readValue(inboundSseEvent.readData(), BookDTO.class);
|
||||
assertNotNull(theBook);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
nbEvent.increment();
|
||||
});
|
||||
source.open();
|
||||
Thread.sleep(100);//wait a little for the events to comes in
|
||||
assertEquals(3, nbEvent.count());
|
||||
}
|
||||
|
||||
//delete all
|
||||
response = RestAssured
|
||||
.given()
|
||||
.delete(endpoint)
|
||||
.andReturn();
|
||||
Assertions.assertEquals(204, response.statusCode());
|
||||
}
|
||||
|
||||
private void callReactivePersonEndpoint(String endpoint) {
|
||||
RestAssured.defaultParser = Parser.JSON;
|
||||
RestAssured.config
|
||||
.objectMapperConfig(new ObjectMapperConfig().jackson2ObjectMapperFactory((type, s) -> new ObjectMapper()
|
||||
.registerModule(new Jdk8Module())
|
||||
.registerModule(new JavaTimeModule())
|
||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)));
|
||||
|
||||
List<Person> list = get(endpoint).as(LIST_OF_PERSON_TYPE_REF);
|
||||
assertEquals(0, list.size());
|
||||
|
||||
Person person1 = new Person();
|
||||
person1.id = 1L;
|
||||
person1.firstname = "John";
|
||||
person1.lastname = "Doe";
|
||||
Response response = RestAssured
|
||||
.given()
|
||||
.header("Content-Type", "application/json")
|
||||
.body(person1)
|
||||
.post(endpoint)
|
||||
.andReturn();
|
||||
assertEquals(201, response.statusCode());
|
||||
|
||||
Person person2 = new Person();
|
||||
person2.id = 2L;
|
||||
person2.firstname = "Jane";
|
||||
person2.lastname = "Doe";
|
||||
Person person3 = new Person();
|
||||
person3.id = 3L;
|
||||
person3.firstname = "Victor";
|
||||
person3.lastname = "Hugo";
|
||||
List<Person> persons = new ArrayList<>();
|
||||
persons.add(person2);
|
||||
persons.add(person3);
|
||||
response = RestAssured
|
||||
.given()
|
||||
.header("Content-Type", "application/json")
|
||||
.body(persons)
|
||||
.post(endpoint + "/multiple")
|
||||
.andReturn();
|
||||
assertEquals(204, response.statusCode());
|
||||
|
||||
Person person4 = new Person();
|
||||
person4.id = 4L;
|
||||
person4.firstname = "Charles";
|
||||
person4.lastname = "Baudelaire";
|
||||
response = RestAssured
|
||||
.given()
|
||||
.header("Content-Type", "application/json")
|
||||
.body(person4)
|
||||
.patch(endpoint)
|
||||
.andReturn();
|
||||
assertEquals(202, response.statusCode());
|
||||
|
||||
list = get(endpoint).as(LIST_OF_PERSON_TYPE_REF);
|
||||
assertEquals(4, list.size());
|
||||
|
||||
//with sort
|
||||
list = get(endpoint + "?sort=firstname").as(LIST_OF_PERSON_TYPE_REF);
|
||||
assertEquals(4, list.size());
|
||||
|
||||
//count
|
||||
Long count = get(endpoint + "/count").as(Long.class);
|
||||
assertEquals(4, count);
|
||||
|
||||
//update a person
|
||||
person3.lastname = "Webster";
|
||||
response = RestAssured
|
||||
.given()
|
||||
.header("Content-Type", "application/json")
|
||||
.body(person3)
|
||||
.put(endpoint)
|
||||
.andReturn();
|
||||
assertEquals(202, response.statusCode());
|
||||
|
||||
//check that the title has been updated
|
||||
person3 = get(endpoint + "/" + person3.id.toString()).as(Person.class);
|
||||
assertEquals(3L, person3.id);
|
||||
assertEquals("Webster", person3.lastname);
|
||||
|
||||
//delete a person
|
||||
response = RestAssured
|
||||
.given()
|
||||
.delete(endpoint + "/" + person3.id.toString())
|
||||
.andReturn();
|
||||
assertEquals(204, response.statusCode());
|
||||
|
||||
count = get(endpoint + "/count").as(Long.class);
|
||||
assertEquals(3, count);
|
||||
|
||||
//delete all
|
||||
response = RestAssured
|
||||
.given()
|
||||
.delete(endpoint)
|
||||
.andReturn();
|
||||
assertEquals(204, response.statusCode());
|
||||
|
||||
count = get(endpoint + "/count").as(Long.class);
|
||||
assertEquals(0, count);
|
||||
}
|
||||
|
||||
private Date yearToDate(int year) {
|
||||
Calendar cal = new GregorianCalendar();
|
||||
cal.set(year, 1, 1);
|
||||
return cal.getTime();
|
||||
}
|
||||
|
||||
private class IntegerAdder {
|
||||
int cpt = 0;
|
||||
|
||||
public void increment() {
|
||||
cpt++;
|
||||
}
|
||||
|
||||
public int count() {
|
||||
return cpt;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user