[!IMPORTANT]
When upgrading, please skip 1.0.0-RC6. It is considered a broken release due to issues with unexpected implicit prioritization, which we've fixed in RC7.
Apologies to those that updated RC6 when it first came out!
Release notes below include all changes since 1.0.0-RC5.
Notable features / changes
Query Cancellation
Query cancellation has been implemented via calling PreparedStatement#close() on fiber cancellation.
Big thanks to @TalkingFoxMid and contributions from @satorg @armanbilge!
Related PRs: #2079 #2088
Opt-in automatic derivation
Automatic derivation has been the (non-configurable) default in Doobie since the start. While convenient, it can lead to long compile times because Read/Write/Get/Put instances are derived every time it is needed.
We have significantly reworked the internals of Read/Write derivation to allow opt-in semi-auto and automatic derivation.
import doobie.implicits.* will enable automatic derivation (maintaining source compatibility to ease migration).
v1.0.0-RC7 - doobie Release Notes | AnnounceHQ
import doobie.generic.auto.* to explicitly enable automatic derivation. Compared to import doobie.implicits.* this brings just the implicits/givens necessary for automatic derivation
Instances for tuples are still automatically derived for convenience
To switch to explicitly derived instances, change import doobie.implicits.* to import doobie.syntax.all.* and gradually fix compile errors by deriving instances explicitly (see below):
To derive instances explicitly:
Scala 3:
case class Foo(a: String, b: Int) derives Read
[!IMPORTANT]
For Scala 3, we highly recommend using explicit derivation and avoid any automatic derivation (i.e. no imports of doobie.implicits.* or import doobie.generic.auto.*). Scala 3's implicit search algorithm doesn't seem to follow implicit prioritization the same way as Scala 2 compile, which means its implicit search is very expensive with automatic derivation (Leading to long compile times and "Implicit search problem too large." error for bigger case classes). See #2214 for more information.
Scala 2+:
case class Foo(a: String, b: Int)
object Foo {
implicit val read: Read[Foo] = Read.derived
}
As part of this derivatino rework, it is now possible to obtain a Read[Option[A]]/Write[Option[A]] instance
directly from Read[A]/Write[A].
Related PRs:
Opt in auto derivation by @guymers / @jatcwang in https://github.com/tpolecat/doobie/pull/1967
Rework Read/Write & Fix derivation to use custom instances by @jatcwang in https://github.com/typelevel/doobie/pull/2136
Fix instance derivation by @jatcwang in https://github.com/tpolecat/doobie/pull/2037
Make tuple Read/Write instances available without an import by @jatcwang in https://github.com/tpolecat/doobie/pull/2070
Better type-checking with JDBC vendor types (For Postgres java.time.* and enums)
In previous releases, doobie typecheck only checks against the integer (enum) returned by java.sql.ResultSetMetaData#getColumnType (java.sql.Types). However this is inadequate for two reasons:
java.sql.Types doesn't cover many other possible database-specific types (e.g. JSON column type)
JDBC drivers often return the wrong java.sql.Types for legacy reasons
For example, for a TIMESTAMP WITH TIME ZONE column Postgres JDBC driver will report that it has the type java.sql.Types.TIMESTAMP (surprising as java.sql.Types.TIMESTAMP_WITH_TIMEZONE exists).
| PostgreSQL Data Type | getColumnType() | getColumnTypeName() |
|:---------------------|:-----------------|:--------------------|
| TIMESTAMP | Types.TIMESTAMP | "TIMESTAMP" |
| TIMESTAMP WITH TIME ZONE | Types.TIMESTAMP | "TIMESTAMPTZ" |
This means by just using the result from getColumnType typechecking couldn't differentiate between a TIMESTAMP WITH TIME ZONE column vs TIMESTAMP (WITHOUT TIMEZONE) column - which has serious implications for correctness of your program if one uses the wrong column type!
Fortunately, we can see that getColumnTypeName does differentiate between the two column types.
To help improve typechecking for java.time.* types (and generally), we have made the following changes:
1. Get and Put can now specify vendor column type name
When creating a Get or Put instance, the vendor type name can now be specified so typechecking will check against it.
When constructing instances (e.g. Get.Basic.one(..)) you can pass the expected vendor type to checkedVendorType parameter, or None if you don't need or want to check against the vendor type.
2. Move java.time.* instances into database modules
java.time.* instances are moved to their database-specific modules to handle differences in databases and their drivers.
For other databases that support Java 8 time types, you can continue to use import doobie.implicits.javatimedrivernative.* but there's no check against vendor type names.
3. Make doobie.implicits.javasql instances available by default
doobie.implicits.javasql has now been removed. You can safely remove any import doobie.implicits.javasql.* as these instances are now available without any import.
If you have a column which is an array of enum type, you should switch to use doobie.postgres.implicits.arrayOfEnum
to define the Meta instance on the application side for better typechecking.
Related PRs:
More precise typechecking using vendor types by @jatcwang in https://github.com/tpolecat/doobie/pull/2023
Improve Java time meta experience by @guymers in https://github.com/tpolecat/doobie/pull/1789
Add MySQL java.time instances by @jatcwang in https://github.com/tpolecat/doobie/pull/2024
Better postgres array of enum support by @jatcwang in https://github.com/typelevel/doobie/pull/2179
Logging for streaming and updateMany queries
Query/Update which now allow queries ran through Query#stream and Update#withGeneratedKeys to be logged. As part of this work, doobie.hi.FC module also have 3 new functions: stream, executeWithResultSet and executeWithoutResultSet. Old functions that does not log (such as doobie.hi.FC.updateWithGeneratedKeys) has been deprecated and will be removed by 1.0.
Related PRs:
Fix logging for streaming and updateMany by @jatcwang in https://github.com/tpolecat/doobie/pull/2064
Other changes
Allow for different effects of HikariTransactor and its creation by @sideeffffect in https://github.com/tpolecat/doobie/pull/1939
Split methods for HikariTransactor constructed with two effects by @jatcwang in https://github.com/tpolecat/doobie/pull/1961
Add parenthesis around each expression in and/or combinator by @jatcwang in https://github.com/tpolecat/doobie/pull/2044
PostgreSQL Range Types by @tomohavvk in https://github.com/tpolecat/doobie/pull/2008
Remove lazy initialization of modules to fix potential initialization deadlocks by @jatcwang in https://github.com/tpolecat/doobie/pull/2046
Add withLogHandler method to Transactor by @sideeffffect in https://github.com/tpolecat/doobie/pull/1977
Ensure backward compatibility of Hikari Config by @sideeffffect in https://github.com/tpolecat/doobie/pull/1842
Improve analysis message + Small optimizations https://github.com/typelevel/doobie/pull/2091