Skip to content

docs: Add docs for R2DBC DAO - #2949

Open
Vik Nikolova (vnikolova) wants to merge 12 commits into
mainfrom
vnikolova/r2dbc-dao-docs
Open

Vik Nikolova (vnikolova) wants to merge 12 commits into
mainfrom
vnikolova/r2dbc-dao-docs

Conversation

@vnikolova

@vnikolova Vik Nikolova (vnikolova) commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Worked on top of the existing/generated docs from the obabichev/r2dbc-dao-docs branch

  • Edited and restructured the migration guide.
  • Add 2 new snippets projects for R2DBC DAO.
  • Introduce tabs for JDBC/R2DBC examples in relevant topics.
  • Convert the DAO topic files to MD.
  • Add link summaries on updated topics (shows on link hover).
  • Add a "What's new in Exposed 1.6.0" topic.
  • Use a tldr element for API links, and labels for JDBC-only/R2DBC-only features.

    Note: There's a current inconsistency with how the tldr element is formatted in the DSL topics - this will be addressed post-review.

Preview on staging


Type of Change

  • Documentation update

Related Issues

EXPOSED-1086 Documentation for Enable usage of DAO approach with R2DBC

Documentation split out of the exposed-dao-r2dbc implementation PR
(#2831) so that it can be reviewed in parallel:

- Migration-Guide-DAO-JDBC-to-R2DBC.md: new guide, from swapping the
  dependency to the per-API differences (newSuspend, reference
  accessors, Flow-based referrers, attach())
- DAO-CRUD-Operations, DAO-Entity-definition, DAO-Relationships,
  DAO-Table-Types: R2DBC variants alongside the JDBC snippets
- lib.topic: reusable experimental-preview warning with the
  @ExperimentalR2dbcDaoApi opt-in
- hi.tree: the new guide in the migration section
- Adding-dependencies.md: "Database access modules" now lists both DAO
  modules and warns against mixing them in one source set
- README.md, exposed-version-catalog/README.md: exposed-dao-r2dbc rows,
  and the exposed-dao row now points at it
- CLAUDE.md, .junie/guidelines.md, .claude/skills/fix-bug: the new
  module and its test module in the module lists and test commands

The module it documents landed in main with #2831, so this no longer has
to wait on that PR and can be merged on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vnikolova
Vik Nikolova (vnikolova) marked this pull request as ready for review October 7, 2026 16:27
@vnikolova Vik Nikolova (vnikolova) changed the title docs: WIP Add docs for R2DBC DAO docs: Add docs for R2DBC DAO Oct 7, 2026
<toc-element topic="dao-entity-definition.md" accepts-web-file-names="dao-field-transformations.html"/>
<toc-element topic="dao-crud-operations.md"/>
<toc-element topic="dao-relationships.md"/>
<toc-element topic="migrating-from-jdbc-to-r2dbc-dao.md"/>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor (or just opinion): I was a bit surprised to see this page in this location. Thought it would be under Releases, like the other migration guide, since it's technically attached to a release. But I can understand it being here, if that was what was requested.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That depends if the intention is to deprecate the JDBC DAO, then it would fit better under Releases. If the JDBC DAO API will remain alongside R2DBC DAO, then I believe this is the correct placement for the migration guide.

Comment thread documentation-website/Writerside/hi.tree Outdated
Comment thread documentation-website/Writerside/topics/Adding-dependencies.md
Comment thread documentation-website/Writerside/topics/dao-entity-definition.md Outdated
Comment thread documentation-website/Writerside/topics/dao-crud-operations.md Outdated
Comment thread documentation-website/Writerside/topics/migrating-from-jdbc-to-r2dbc-dao.md Outdated
Comment thread documentation-website/Writerside/topics/migrating-from-jdbc-to-r2dbc-dao.md Outdated
[references](dao-relationships.md), [queries](dao-crud-operations.md), and [transactions](Transactions.md),
with APIs adapted for suspending database operations.

To use R2DBC DAO, replace the JDBC DAO dependency with `exposed-dao-r2dbc` and use the `suspendTransaction()` function

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's implicit/obvious that this means switching driver dependencies too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still don't think this is clear, especially since exposed-jdbc does actually provide suspendTransaction(). Users could easily argue that they should be able to use exposed-dao-r2dbc + exposed-jdbc/suspendTransaction.

Comment thread documentation-website/Writerside/topics/whats-new-160.md Outdated
Comment thread documentation-website/Writerside/topics/whats-new-160.md Outdated
Comment thread documentation-website/Writerside/topics/dao-relationships.md Outdated

// returns all UserRatingWithOptionalUserEntity objects with this movie as film
val filmRatings = starWarsFilm.ratings
println(filmRatings)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It prints Flow object. Also toList() could be added on the line above

{style="tip"}

When an update occurs, the `modified` column is populated with the current UTC time using the `nowUTC()` method. However,
the update only happens if the `modified` field has not already been set. This is checked by using `Entity.writeValues`,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

writeValues is not available in r2dbc.

the values are stored in EntityCache:

    /** Uncommitted column values, kept off the entity so a rollback drops exactly what this scope staged. */
    private val staged = IdentityHashMap<Entity<*>, StagedValues>()

@@ -0,0 +1,30 @@
package org.example.examples

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this snipped dead code? I don't see any usages of it. Probably I'm wrong, but right now I can't find it in the docs.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm it indeed seems like it's no referenced anywhere..

in the same way you would get any other field:

```kotlin
movie.director // returns a Director object

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be movie.director(), because it's invocable now

You can then access this field on a `DirectorCompositeIDEntity` object, `director`:

```kotlin
director.films // returns all StarWarsFilm objects that reference this director

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also should be director.films()

@vnikolova

Copy link
Copy Markdown
Collaborator Author

Thank you for the thorough reviews Chantal Loncle (@bog-walk) and Oleg Babichev (@obabichevjb) 🙏
I've applied the suggested modifications and included the remaining "what's new" entries.

[references](dao-relationships.md), [queries](dao-crud-operations.md), and [transactions](Transactions.md),
with APIs adapted for suspending database operations.

To use R2DBC DAO, replace the JDBC DAO dependency with `exposed-dao-r2dbc` and use the `suspendTransaction()` function

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still don't think this is clear, especially since exposed-jdbc does actually provide suspendTransaction(). Users could easily argue that they should be able to use exposed-dao-r2dbc + exposed-jdbc/suspendTransaction.

The `.new()` function schedules the entity for insert in the transaction's cache. The insert is flushed when you
explicitly call the `flushCache()` function, when another statement is executed in the same transaction, or when the transaction is committed.

* With JDBC, the entity's ID and any database-generated columns are available when the function returns.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically no, depending on how "available when the function returns" reads.

It may seem this way to a naive user, because when they access these fields, the values will be successfully returned from the entity with no issues.
But technically (and it will be obvious if the user has a logger or statement interceptor enabled) what will happen is that the insert will be (quietly-ish) flushed in order to access the returned statement's generated values.

I think this should be made clear, but we can always fix/clarify later.

The pending inserts are flushed when required by subsequent database operations or when the transaction commits. Call
`flushCache()` when you need to explicitly control when the pending inserts are sent to the database.

> The `new()` function exists in both JDBC and R2DBC DAO but its behavior differs. During migration, review every `new{}`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still don't agree with this. The behavior of the 2 .new() methods doesn't actually differ. It's the behavior of the property getters that truly differs. So continuing to use old new() with r2dbc would cause no issue & would act the same if the user never attempts to access id or generated values immediate after.

I'd suggest something like:

Even though the new() function exists in both JDBC and R2DBC DAO and both result in scheduled inserts, the behavior of the new entity's property getters differs. During migration, review every new() call that expects the row or its generated ID to exist immediately. Continuing to use new() in these cases will throw an exception and they should be replaced with newSuspend().

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants