gofabian / spring-boot-data-r2dbc-jooq Goto Github PK
View Code? Open in Web Editor NEWReactive JOOQ - an R2DBC adapter for Spring Boot
License: MIT License
Reactive JOOQ - an R2DBC adapter for Spring Boot
License: MIT License
This is copy/paste code from JOOQ project. We should check whether it is still relevant for us.
This is intended as alternative to the @Transactional
annotations and is more the JOOQ approach.
Something like ReactiveJooq.transaction(dslContext, () -> Mono.empty())
Spring Data R2DBC docs: https://github.com/spring-projects/spring-data-r2dbc/blob/master/src/main/asciidoc/reference/r2dbc-transactions.adoc
JOOQ docs: https://www.jooq.org/doc/latest/manual/sql-execution/transaction-management/
Introduce two new classes that contain the whole logic:
The main class should not contain any logic but only invoke the executors:
This could also be an alternative for Kotlin extensions but with Vanilla Java.
ReactiveJooq.executeReturning(DeleteResultStep) -> Flux<Record>
ReactiveJooq.executeReturningOne(DeleteResultStep) -> Mono<Record>
While fetchOne
is returning at most 1 record it also fails if more than 1 record is returned by the query.
The latter is not true for executeReturningOne
, it actually behaves like fetchAny
.
Should be trivial to change executeReturningOne
to return Mono.error
in case of more than 1 record or maybe just replace the whole method with return executeReturning(query).singleOrEmpty()
.
Reactive counterparts to UpdatableRecord methods:
When a query yields records then fetchExists
behaves as expected (returns Mono
containing true
).
However, when there are no records fetchExists
returns an empty Mono
instead of Mono
containing false
.
In particular the code return fetchOne(existsQuery).map(Objects::nonNull)
should be changed to return fetchOne(existsQuery).hasElement()
. A Mono
's element is never null
so .map(Objects::nonNull)
either does nothing (for empty Mono
) or maps to true
.
It is only intended to generate SQL strings which is given to the R2DBC database client for execution.
... strings.. is given...
Hello Fabian, hope you are great!,
I have spent a lot of time trying to get some answers about jooq + reactive programming, I have look into R2DBC, but since a have all my repositories running with jooq I dont want to change to R2DBC directly, so my question is do you have some plans in future about this library? Also is this library was deployed in some production env?
Hi @gofabian I do have some comments/suggestions if you want to discuss, is all related to verbosity and functional style
You can turn that into this, since this is all a lazy evaluation when the first match happen the execution is completed, you can also another indirection layer with Optional.ofNullable(configuration.data())
I know that method is unused so is perfect because we can avoid side effects
return configuration.data().keySet().stream() .filter(keyString::equals) .findFirst();
boolean executeUpdate = Arrays.stream(record.getTable().getPrimaryKey().getFieldsArray()) .noneMatch(field -> isNewRecord(record, field));
Hi there, and thanks a lot for your efforts!
jOOQ 3.15 will support R2DBC out of the box: jOOQ/jOOQ#11700. Have you been able to play with the current integration? I'd be curious to hear your thoughts and get your opinion on any potential missing features (see also known limitations: jOOQ/jOOQ#11717) here or on the jOOQ issue tracker.
Copy unit tests from JOOQ project and find an easy way to run them with Reactive JOOQ.
In JOOQ there are 2 general ways to declare the returning clause (for update/insert/delete). Those are [Insert|Update|Delete]ResultStep#returning
and [Insert|Update|Delete]ResultStep#returningResult
where the latter is to allow returning different record type than the one representing the table (e.g. Record1<UUID>
instead of UserRecord
with just one field actually present (if that's all you need)).
Currently only the first approach is supported. It would be useful to support the latter as well because it currently fails with ClassCastException
at runtime. Example output: java.lang.ClassCastException: class com...model.tables.records.UserRecord cannot be cast to class org.jooq.Record1
ReactiveJooq.executeReturning(InsertResultStep) -> Flux<Record>
ReactiveJooq.executeReturning(UpdateResultStep) -> Flux<Record>
ReactiveJooq.executeReturningOne(InsertResultStep) -> Mono<Record>
ReactiveJooq.executeReturningOne(UpdateResultStep) -> Mono<Record>
e. g. auto incremented primary key is not available after insert. That's a blocker as you cannot fetch the inserted row by primary key manually afterwards as the key is unknown.
since you always decode an object with the target Object.class type, io.r2dbc.postgresql.codec.AbstractCodec doesn't work anymore with extra registred codec based on this implementation since io.r2dbc.postgresql.codec.AbstractCodec#canDecode is based on field type and you always pass Object.class type.
For example between org.jooq.JSONB
and io.r2dbc.postgresql.codec.Json
. There should be a general mechanism to add further adapters.
Current project depends on Spring Boot 2.3.0.M4, which makes it necessary to add https://repo.spring.io/milestone
as a repository. Spring Boot 2.3 already went GA, thus it will be more convenience to use if the project's dependency is updated.
e. g. query.fetchR2dbc() -> Flux
I've been trying to convert my jooq based application from jdbc to r2dbc using this library. However I encountered an issue regarding r2dbc-postgresql. Here is the response of Netty to one of my select queries to the database containing one JSONB data type in PostgreSQL.
{ "timestamp": "time_stamp_here", "path": "request_path_here", "status": 500, "error": "Internal Server Error", "message": "Cannot convert from JsonOutput{{database_json_content_ere}} (class io.r2dbc.postgresql.codec.Json$JsonOutput) to class org.jooq.JSONB", "requestId": "request_id_here" }
Any ideas on how to fix this?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.