Skip to content

Commit

Permalink
Allow accessing the MongoDB ClientSession programmatively
Browse files Browse the repository at this point in the history
  • Loading branch information
loicmathieu authored and Sanne committed Oct 13, 2023
1 parent b3a623a commit a3c692c
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 2 deletions.
2 changes: 2 additions & 0 deletions docs/src/main/asciidoc/mongodb-panache.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,8 @@ MongoDB offers ACID transactions since version 4.0.

To use them with MongoDB with Panache you need to annotate the method that starts the transaction with the `@Transactional` annotation.

Check warning on line 771 in docs/src/main/asciidoc/mongodb-panache.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'. Raw Output: {"message": "[Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'.", "location": {"path": "docs/src/main/asciidoc/mongodb-panache.adoc", "range": {"start": {"line": 771, "column": 21}}}, "severity": "INFO"}

Check warning on line 771 in docs/src/main/asciidoc/mongodb-panache.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'. Raw Output: {"message": "[Quarkus.Fluff] Depending on the context, consider using 'Rewrite the sentence, or use 'must', instead of' rather than 'need to'.", "location": {"path": "docs/src/main/asciidoc/mongodb-panache.adoc", "range": {"start": {"line": 771, "column": 43}}}, "severity": "INFO"}

Inside methods annotated with `@Transactional` you can access the `ClientSession` with `Panache.getClientSession()` if needed.

In MongoDB, a transaction is only possible on a replicaset,

Check warning on line 775 in docs/src/main/asciidoc/mongodb-panache.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Spelling] Use correct American English spelling. Did you really mean 'replicaset'? Raw Output: {"message": "[Quarkus.Spelling] Use correct American English spelling. Did you really mean 'replicaset'?", "location": {"path": "docs/src/main/asciidoc/mongodb-panache.adoc", "range": {"start": {"line": 775, "column": 27}}}, "severity": "WARNING"}
luckily our xref:mongodb.adoc#dev-services[Dev Services for MongoDB] setups a single node replicaset so it is compatible with transactions.

Check warning on line 776 in docs/src/main/asciidoc/mongodb-panache.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Spelling] Use correct American English spelling. Did you really mean 'replicaset'? Raw Output: {"message": "[Quarkus.Spelling] Use correct American English spelling. Did you really mean 'replicaset'?", "location": {"path": "docs/src/main/asciidoc/mongodb-panache.adoc", "range": {"start": {"line": 776, "column": 69}}}, "severity": "WARNING"}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,23 +333,27 @@ ClientSession getSession(Object entity) {
return getSession(entity.getClass());
}

ClientSession getSession(Class<?> entityClass) {
public ClientSession getSession(Class<?> entityClass) {
ClientSession clientSession = null;
MongoEntity mongoEntity = entityClass.getAnnotation(MongoEntity.class);
InstanceHandle<TransactionSynchronizationRegistry> instance = Arc.container()
.instance(TransactionSynchronizationRegistry.class);
if (instance.isAvailable()) {
TransactionSynchronizationRegistry registry = instance.get();
if (registry.getTransactionStatus() == Status.STATUS_ACTIVE) {
clientSession = (ClientSession) registry.getResource(SESSION_KEY);
if (clientSession == null) {
MongoEntity mongoEntity = entityClass == null ? null : entityClass.getAnnotation(MongoEntity.class);
return registerClientSession(mongoEntity, registry);
}
}
}
return clientSession;
}

public ClientSession getSession() {
return getSession(null);
}

private ClientSession registerClientSession(MongoEntity mongoEntity,
TransactionSynchronizationRegistry registry) {
TransactionManager transactionManager = Arc.container().instance(TransactionManager.class).get();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.quarkus.mongodb.panache.kotlin

import com.mongodb.session.ClientSession
import io.quarkus.mongodb.panache.kotlin.runtime.KotlinMongoOperations

object Panache {
/**
* Access the current MongoDB ClientSession from the transaction context. Can be used inside a
* method annotated with `@Transactional` to manually access the client session.
*
* @return ClientSession or null if not in the context of a transaction.
*/
val session: ClientSession
get() = KotlinMongoOperations.INSTANCE.session

/**
* Access the current MongoDB ClientSession from the transaction context.
*
* @param entityClass the class of the MongoDB entity in case it is configured to use the
* non-default client.
* @return ClientSession or null if not in the context of a transaction.
* @see [session]
*/
fun getSession(entityClass: Class<*>?): ClientSession {
return KotlinMongoOperations.INSTANCE.getSession(entityClass)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.quarkus.mongodb.panache;

import com.mongodb.session.ClientSession;

import io.quarkus.mongodb.panache.runtime.JavaMongoOperations;

public class Panache {

/**
* Access the current MongoDB ClientSession from the transaction context.
* Can be used inside a method annotated with `@Transactional` to manually access the client session.
*
* @return ClientSession or null if not in the context of a transaction.
*/
public static ClientSession getSession() {
return JavaMongoOperations.INSTANCE.getSession();
}

/**
* Access the current MongoDB ClientSession from the transaction context.
*
* @see #getSession()
*
* @param entityClass the class of the MongoDB entity in case it is configured to use the non-default client.
* @return ClientSession or null if not in the context of a transaction.
*/
public static ClientSession getSession(Class<?> entityClass) {
return JavaMongoOperations.INSTANCE.getSession(entityClass);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.quarkus.it.mongodb.panache.transaction;

import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -14,6 +16,7 @@

import com.mongodb.client.MongoClient;

import io.quarkus.mongodb.panache.Panache;
import io.quarkus.runtime.StartupEvent;

@Path("/transaction")
Expand Down Expand Up @@ -42,6 +45,7 @@ public List<TransactionPerson> getPersons() {
@Transactional
public Response addPerson(TransactionPerson person) {
person.persist();
assertNotNull(Panache.getSession(TransactionPerson.class));
return Response.created(URI.create("/transaction/" + person.id.toString())).build();
}

Expand Down

0 comments on commit a3c692c

Please sign in to comment.