What's new in Exposed 1.6.0
R2DBC DAO support
Exposed 1.6.0 introduces experimental R2DBC support for the DAO API through the exposed-dao-r2dbc artifact. You can now use Exposed DAO with R2DBC for non-blocking database access while retaining the DAO entity model and familiar query and relationship APIs.
R2DBC DAO provides the same core DAO concepts as JDBC DAO, including entities, references, queries, and transactions, with APIs adapted for suspending database operations.
For example, to create and insert an entity with R2DBC DAO, use the newSuspend() function inside a suspendTransaction {} block:
R2DBC DAO introduces several API differences required by its suspending nature:
While the
new()function schedules the insert until the next flush, thenewSuspend()function creates and immediately inserts an entity before returning it. ThenewSuspend()function should be used if the returned entity's ID or other database-generated values need to be accessed before scheduled flushing. Continuing to usenew()and accessing these fields throws an exception.Reference properties, such as
referencedOn, use accessors, so a referenced entity is retrieved by invocation such asfilmRating.film(). Referenced entities are set by invoking the.set()function.DAO collections are exposed as Kotlin
Flow, so use terminal operations such as.toList()when a collection is required.Entities created or loaded in one transaction must be attached using the
attach()function before they can be modified in another R2DBC transaction.
Non-null column transformations
You can now use the new .nonNullTransform() function to represent a nullable database column as a non-nullable Exposed column.
Use this function when a database column allows null, but your application has a meaningful non-null representation for that value.
In the following example, the UNSCHEDULED enum entry represents a missing meal time:
Tableless SELECT queries
Exposed 1.6.0 introduces tableless SELECT queries, allowing you to select expressions without specifying a table or a FROM clause.
Use the top-level select() function to create a query that returns a single row by default. A WHERE condition can filter out that row, resulting in an empty result:
For queries that select a single expression, use the selectValue() function to execute the query immediately and return the typed result without requiring an expression as a result-row key. The function also accepts supported Kotlin scalar values directly and wraps them as SQL literals:
Tableless queries are regular Query objects and support existing query operations, such as filtering, set operations, derived-table aliases, and insert-from-select operations.
Configure multiple table packages in migration plugins
You can configure the Exposed Gradle and Maven plugins to use multiple table packages when generating migrations. This is useful when your table definitions are organized into separate packages.
For example, in the Gradle configuration, use the tablesPackage property to specify a single package or the tablesPackages property to specify multiple packages: