Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/imrafaelmerino/vertx-mongodb-effect
https://github.com/imrafaelmerino/vertx-mongodb-effect
functional-programming json-values mongo-values mongodb reactive-programming vertx
Last synced: about 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/imrafaelmerino/vertx-mongodb-effect
- Owner: imrafaelmerino
- Created: 2024-11-19T20:32:51.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2024-11-19T21:21:23.000Z (about 2 months ago)
- Last Synced: 2024-11-19T22:24:58.997Z (about 2 months ago)
- Language: Java
- Size: 5.08 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: docs/README.md
Awesome Lists containing this project
- vertx-awesome - MongoDB - Pure functional and reactive MongoDB client on top of [Vert.x Effect](https://github.com/imrafaelmerino/vertx-mongodb-effect). Full support for retry, fallback and recovery operations. (Database Clients)
README
- [Introduction](#introduction)
- [Supported types](#types)
- [Supported operations](#operations)
- [Defining modules](#defmodules)
- [Deploying modules](#depmodules)
- [Publishing events](#events)
- [Java Flight Recorder support](#jfr)
- [Requirements](#requirements)
- [Installation](#installation)[![Maven](https://img.shields.io/maven-central/v/com.github.imrafaelmerino/vertx-mongodb-effect/2.0.0)](https://search.maven.org/artifact/com.github.imrafaelmerino/vertx-mongodb-effect/2.0.0/jar)
**vertx-mongodb-effect** allows us to work with **MongoDB** following a purely functional and reactive style.
It requires to be familiar with [vertx-effect](https://github.com/imrafaelmerino/vertx-effect). Both
**vertx-effect** and **vertx-mongo-effect** use the immutable and persistent Json from
[json-values](https://github.com/imrafaelmerino/json-values). **Jsons travel across the event bus,
from verticle to verticle, back and forth, without being neither copied nor converted to BSON**.
The vertx codecs to send the Json from json-values to the event bus are in [vertx-values](https://github.com/imrafaelmerino/vertx-values),
which is a dependency of vertx-effect.
## Supported types
**json-values** supports the standard Json types: string, number, null, object, array;
There are five number specializations: int, long, double, decimal, and BigInteger.
**json-values adds support for instants and binary data**. It serializes Instants into
its string representation according to ISO-8601, and the binary type into a string encoded in base 64.**vertx-mongodb-effect** uses [mongo-values](https://github.com/imrafaelmerino/mongo-values).
It abstracts the processes of encoding to BSON and decoding from BSON.
Please find below the BSON types supported and their equivalent types in json-values.```code
Map> map = new HashMap<>();
map.put(BsonType.NULL, JsNull.class);
map.put(BsonType.ARRAY, JsArray.class);
map.put(BsonType.BINARY, JsBinary.class);
map.put(BsonType.BOOLEAN, JsBool.class);
map.put(BsonType.DATE_TIME, JsInstant.class);
map.put(BsonType.DOCUMENT, JsObj.class);
map.put(BsonType.DOUBLE, JsDouble.class);
map.put(BsonType.INT32, JsInt.class);
map.put(BsonType.INT64, JsLong.class);
map.put(BsonType.DECIMAL128, JsBigDec.class);
map.put(BsonType.STRING, JsStr.class);```
When defining the mongodb settings, **you have to specify the codec registry _JsValuesRegistry_ from mongo-values**:
```code
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import mongovalues.JsValuesRegistry;MongoClientSettings settings =
MongoClientSettings.builder()
.applyConnectionString(connString)
.codecRegistry(JsValuesRegistry.INSTANCE)
.build();```
## Supported operations
**Every method of the MongoDB driver has an associated lambda**.Since **vertx-mongodb-effect** uses the driver API directly, it can benefit from all its features and methods.
**It's an advantage over the official vertx-mongodb-client**.Please find below the types and constructors of the most essentials operations:
**Count :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.CountOptions;public Count(Supplier> collectionSupplier,
CountOptions options
)
```**DeleteMany :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.DeleteOptions;
import com.mongodb.client.result.DeleteResult;public DeleteMany(Supplier> collectionSupplier,
Function resultConverter,
DeleteOptions options
)
```
**DeleteOne :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.DeleteOptions;
import com.mongodb.client.result.DeleteResult;public DeleteOne(Supplier> collectionSupplier,
Function resultConverter,
DeleteOptions options
)
```**FindAll :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.FindIterable;public FindAll(Supplier> collectionSupplier,
Function, JsArray> converter
)
```**FindOne :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.FindIterable;public FindOne(Supplier> collectionSupplier,
Function, JsObj> converter
)
```**FindOneAndDelete :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.FindOneAndDeleteOptions;public FindOneAndDelete(Supplier> collectionSupplier,
FindOneAndDeleteOptions options
)
```**FindOneAndReplace :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.FindOneAndReplaceOptions;public FindOneAndReplace(Supplier> collectionSupplier,
FindOneAndReplaceOptions options
)
```**FindOneAndUpdate :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.FindOneAndUpdateOptions;public FindOneAndUpdate(Supplier> collectionSupplier,
FindOneAndUpdateOptions options
)
```**InsertMany :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.result.InsertManyResult;
import com.mongodb.client.model.InsertManyOptions;public InsertMany(Supplier> collectionSupplier,
Function resultConverter,
InsertManyOptions options
)
```**InsertOne :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.result.InsertOneResult;
import com.mongodb.client.model.InsertOneOptions;public InsertOne(Supplier> collectionSupplier,
Function resultConverter,
InsertOneOptions options
)
```**ReplaceOne :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.result.UpdateResult;
import com.mongodb.client.model.ReplaceOptions;public ReplaceOne(Supplier> collectionSupplier,
Function resultConverter,
ReplaceOptions options
)
```
**UpdateMany :: Lambdac**```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.result.UpdateResult;
import com.mongodb.client.model.UpdateOptionspublic UpdateMany(Supplier> collectionSupplier,
Function resultConverter,
UpdateOptions options
)
```**UpdateOne :: Lambdac**
```code
import com.mongodb.client.MongoCollection;
import com.mongodb.client.result.UpdateResult;
import com.mongodb.client.model.UpdateOptionspublic UpdateOne(Supplier> collectionSupplier,
Function resultConverter,
UpdateOptions options
)
```## Defining modules
Like with vertx-effect, [modules](https://vertx.effect.imrafaelmerino.dev/#modules) deploys
verticles and expose lambdas to communicate with them.
The typical scenario is to create a module per collection. We can deploy or spawn verticles.The following modules are just a couple of examples.
We create a module where all the lambdas make read operations and spawn verticles to reach a significant level of parallelization:
```code
import vertx.mongodb.effect.MongoModule;
import vertx.effect.Lambdac;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.ThreadingModel;public class ReadModule extends MongoModule {
public MyCollectionModule(final Supplier> collection) {
super(collection,
new DeploymentOptions().setThreadingModel(ThreadingModel.VIRTUAL_THREAD)
);
}public static Lambdac> findOne;
public static Lambdac findAll;
public static Lambdac count;
public static Lambdac aggregate;@Override
protected void deploy() {}@Override
protected void initialize() {
Lambdac findOneLambda = vertxRef.spawn("find_one",
new FindOne(collection)
);
this.findOne = (context,message) -> findOneLambda.apply(context,message)
.map(Optional::ofNullable);
this.findAll = vertxRef.spawn("find_all",
new FindAll(collection)
);
this.count = vertxRef.spawn("count",
new Count(collection)
);this.aggregate = vertxRef.spawn("aggregate",
new Aggregate<>(collection,
Converters.aggregateResult2JsArray
)
);
}
}
```We create a module where all the lambdas make delete, insert and update operations, and deploy only one
instance per verticle.```code
import vertx.mongodb.effect.MongoModule;
import vertx.effect.Lambdac;public class MyCollectionModule extends MongoModule {
public MyCollectionModule(final Supplier> collection) {
super(collection);
}public static Lambdac insertOne;
public static Lambdac deleteOne;
public static Lambdac replaceOne;
public static Lambdac updateOne;@Override
protected void deploy() {
this.deploy(INSERT_ONE_ADDRESS,
new InsertOne<>(collection,
Converters.insertOneResult2HexId
),
);
this.deploy(DELETE_ONE_ADDRESS,
new DeleteOne<>(collection,
Converters.deleteResult2JsObj
)
);this.deploy(REPLACE_ONE_ADDRESS,
new ReplaceOne<>(collection,
Converters.updateResult2JsObj
)
);
this.deploy(UPDATE_ONE_ADDRESS,
new UpdateOne<>(collection,
Converters.updateResult2JsObj
)
);
}@Override
protected void initialize() {
this.insertOne = this.trace(INSERT_ONE_ADDRESS);
this.deleteOne = this.trace(DELETE_ONE_ADDRESS);
this.replaceOne = this.trace(REPLACE_ONE_ADDRESS);
this.updateOne = this.trace(UPDATE_ONE_ADDRESS);
}private static final String DELETE_ONE_ADDRESS = "delete_one";
private static final String UPDATE_ONE_ADDRESS = "update_one";
private static final String REPLACE_ONE_ADDRESS = "replace_one";
private static final String INSERT_ONE_ADDRESS = "insert_one";
private static final String INSERT_MANY_ADDRESS = "insert_all";
private static final String DELETE_MANY_ADDRESS = "delete_all";}
The verticles _RegisterMongoEffectCodecs_ and _RegisterJsValuesCodecs_ need to be deployed to register the vertx message codecs.
Remember that you can't send any message to the event bus. If a message is not supported by Vertx you have to
create a _MessageCodec_.```code
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import vertx.mongodb.effect.MongoVertxClient;
import vertx.effect.VertxRef;// define every timeout if you wanna be reactive
int connectTimeoutMS = ???;
int socketTimeoutMS = ???;
int serverSelectionTimeoutMS = ???;String connectionUrl =
String.format("mongodb://localhost:27017/?connectTimeoutMS=%s&socketTimeoutMS=%s&serverSelectionTimeoutMS=%s",
connectTimeoutMS,
socketTimeoutMS,
serverSelectionTimeoutMS
);
ConnectionString connString = new ConnectionString(connectionUrl);MongoClientSettings settings =
MongoClientSettings.builder()
.applyConnectionString(connString)
.codecRegistry(JsValuesRegistry.INSTANCE)
.build();// one vertx client per database connection
MongoVertxClient mongoClient = new MongoVertxClient(settings);String database = ???;
String collection = ???;
MyCollectionModule collectionModule =
new MyCollectionModule(mongoClient.getCollection(database,
collection
)
);VertxRef vertxRef = new VertxRef(vertx);
Quadruple.sequential(vertxRef.deployVerticle(new RegisterJsValuesCodecs()),
vertxRef.deployVerticle(new RegisterMongoEffectCodecs()),
vertxRef.deployVerticle(mongoClient),
vertxRef.deployVerticle(collectionModule)
)
.get();
```Once everything is up and running, enjoy your lambdas!
```code
BiFunction>> findByCode = (attempts,code) ->
MyCollectionModule.findOne
.apply(FindMessage.ofFilter(JsObj.of("code",
JsStr.of(code)
)
)
)
.retry(e -> Failures.anyOf(MONGO_CONNECT_TIMEOUT_CODE,
MONGO_READ_TIMEOUT_CODE
),
attempts
)
.recoverWith(e -> Val.succeed(Optional.empty()));
```
## Publishing eventsSince **vertx-effect** publishes the most critical events into the address **vertx-effect-events**,
it' possible to register consumers to explode that information. You can disable this feature
with the Java system property **-Dpublish.events=false**. Thanks to Lambdac, it's possible to correlate
different events that belongs to the same transaction.
Go to the [vertx-effect doc](https://vertx.effect.imrafaelmerino.dev/#events) for further details.## JFR support
Since vertx-effect supports JFR, all the verticle messages have an associated event and can be visualized using
Java Mission Control.Fields of a verticle message event:
- address: Address of the Verticle where the message is sent to
- result: SUCCESS OR FAILURE, dependening on what the caller receives
- failure code: In case the failure is a ReplyException, it's the failure code
- failure type: In case the failure is a ReplyException, it's the failure type
- failure message: In case the failure is a ReplyException, it's the failure message
- exception class: In case the failure is not a ReplyException, it's the exception class name
- exception message: In case the failure is not a ReplyException, it's the exception message
- duration: time since the message is sent until the response is received- Java 17 or greater
- [vertx-effect](https://github.com/imrafaelmerino/vertx-effect)
- [mongo driver sync](https://mongodb.github.io/mongo-java-driver/4.1/whats-new/)
- [Mongo values](https://github.com/imrafaelmerino/mongo-values)For Java 17 or higher:
```xml
com.github.imrafaelmerino
vertx-mongodb-effect
2.0.0```
For Java 21 or higher:
```xml
com.github.imrafaelmerino
vertx-mongodb-effect
3.0.0```