3.17.0 Release with Computed Columns, Audit Columns, Pattern Matching, Reactive Transactions and Kotlin Coroutine Support – Java, SQL and jOOQ.
This release contiues the work from previous releases around more sophisticated SQL transformation capabilities, including:
- Client side computed columns for both read and write operations
- Audit columns
- Pattern matching SQL transformations
- More implicit JOIN capabilities
Client side computed columns
A ground breaking new core feature available in all commercial distributions is
the new client side computed columns feature, building on top of jOOQ 3.16’s
commercial support for readonly columns and server side computed columns.
Not all RDBMS support computed columns (e.g. using the standard SQL syntaxGENERATED ALWAYS AS
), and if they do, they might not support them in both STORED
(computed on write) and VIRTUAL
(computed on read) variants. jOOQ can now emulate both features at the client side, by transforming your SQL queries:
STORED
affectsINSERT
,UPDATE
,DELETE
, andMERGE
VIRTUAL
affectsSELECT
and theRETURNING
clause of DML statements. To make use of these, combine them with the new synthetic column generation feature.
Unlike their server side counterparts, these client side features can produce arbitrary expressions, including:
- Implicit joins
- Scalar subqueries
MULTISET
subqueries- Much more
Think of this as “views” written in jOOQ, on a per-column basis. An expecially useful feature combination is to combine these computed columns with the new visibility modifier that allows for keeping computed columns (or the underlying base columns) private and thus invisible to user code.
More about this feature here
Audit columns
A special case of STORED
client side computed columns are audit columns, whose most basic implementation comes in the form of:
CREATED_AT
CREATED_BY
MODIFIED_AT
MODIFIED_BY
Other approaches to auditing exist, including soft deletion, additional meta data, (bi)temporal versioning, but these columns are among the most popular approaches, making this commercial only convenience feature very useful to a lot of customers.
More about this feature here
Java 17 baseline for the jOOQ Open Source Edition
Java 17 has been the latest LTS, and it includes a lot of really cool features, including:
- sealed types (essential for pattern matching)
- records
- instanceof pattern matching
- text blocks
- switch expressions
jOOQ 3.16’s experimental new Query Object Model (QOM) API experiments with sealed types, which will be adopted more generally once the QOM API is finalized.
To get broader user feedback on these improvements, as well as to embrace Java’s new LTS update cadence, we’ve decided to make Java 17 the baseline for the jOOQ 3.17 Open Source Edition, continuing our Java 8 and 11 support in the commercial jOOQ distributions.
The following older jOOQ releases will continue to receive upgrades for a while:
- jOOQ 3.14: The last release with Java 8 support in the jOOQ Open Source
Edition and Java 6 support in the jOOQ Enterprise Edition - jOOQ 3.15 and 3.16: The last releases with Java 11 support in the jOOQ Open
Source Edition.
PostgreSQL data type support
The jooq-postgres-extensions module, which contained support for the HSTORE
type, now has a lot more support for PostgreSQL specific data types, including array types of each of:
CIDR
CITEXT
LTREE
HSTORE
INET
RANGE
(including all the specialisations forINT4
,INT8
, etc.)
In order to profit from these data types, just add the org.jooq:jooq-postgres-extensions
module to your code generation and runtime dependencies, and the types are generated automatically.
Implicit JOIN improvements
In this release, we experimented with a few new implicit JOIN features, including support for implicit JOIN in DML statements. The current implementation produces correlated subqueries where JOIN isn’t supported in DML statements.
We’ve also experimented with creating a “convenience syntax” for other commonly used correlated subqueries, such as EXISTS(...)
subqueries or MULTISET(...)
subqueries. The experiment has been very interesting. The prototype, however, was rejected. See the discussions here:
Future jOOQ versions will implement the desired convenience in the form of more implicit JOIN functionality, offering the feature also as an implicit to-many JOIN.
A leftover from the prototype is the fact that you can now more easily project expressions other than classic Field<T>
in your SELECT
clause, namely:
Table<R>
now extendsSelectField<R>
Condition
now extendsField<Boolean>
This means you can write a query like this:
Result<Record3<CustomerRecord, AddressRecord, Boolean>> result =
ctx.select(
// Project a CustomerRecord directly
CUSTOMER,
// Project an AddressRecord from an implicit JOIN
CUSTOMER.address(),
// Project a boolean expression, instead of wrapping it with field()
exists(
selectOne()
.from(PAYMENT)
.where(PAYMENT.CUSTOMER_ID.eq(CUSTOMER.CUSTOMER_ID))
)
.from(CUSTOMER)
.fetch();
Pattern matching SQL Transformations
SQL transformations have been a strategic feature set to recent jOOQ releases, offering additional compatibility between SQL dialects to commercial customers, such as, for example:
- Transforming Oracle’s
ROWNUM
into equivalent window functions orLIMIT
clauses. - Turning table lists including Oracle’s
(+)
operator into ANSI JOIN syntax.
This release ships with a new commercial only feature that directly transforms the new Query Object Model (QOM)’s expression tree prior to rendering. It does so by applying pattern matching to the expression tree. Some assorted examples include:
LTRIM(RTRIM(x))
intoTRIM(x)
x != a AND x != b
intox NOT IN (a, b)
x IN (a, b, c) AND x IN (b, c, d)
intox IN (b, c)
NOT (NOT (x = 1))
intox = 1
NOT (x = 1)
intox != 1
And much more. The primary use-cases for this functionality are:
- SQL linting, e.g. as part of an
ExecuteListener
- SQL auto cleanup, including in a
ParsingConnection
- Dialect migration, when upgrading database versions, or moving between dialects
- Patching specific SQL features
For more information about the feature, see here
Note that this feature is also available for free online at https://www.jooq.org/translate
Reactive and kotlin coroutine support
A lot of minor improvements have been implemented. A few more significant ones
include:
- R2DBC 0.9.1.RELEASE is now supported
- A new reactive transaction API has been added, which offers the same nested
transaction semantics as the existing blocking transaction API, see also:
https://blog.jooq.org/nested-transactions-in-jooq/ - jOOQ’s reactive streams bindings via the
Publisher
SPI are now
bridged automatically to kotlin coroutines in the neworg.jooq:jooq-kotlin-coroutines
module using the usual utilitesorg.jetbrains.kotlinx:kotlinx-coroutines-core
andorg.jetbrains.kotlinx:kotlinx-coroutines-reactor
- The
org.jooq:jooq-kotlin
extensions module now has additional
extension functions for moreMULTISET
and other nesting related
convenience. - The entire blocking execution API is now annotated with
org.jetbrains.annotations.Blocking
to help reactive jOOQ users
avoid accidentally blocking on a query, when using IntelliJ. In addition, we
now annotate experimental and internal API with theApiStatus
annotation from the same package.
Full release notes here