Diesel 2.0 introduces substantial changes to Diesel’s inner workings. In some cases this impacts code written using Diesel 1.4.x. This document outlines notable changes and presents potential update strategies. We recommend to start the upgrade by removing the usage of all items that are marked as deprecated in Diesel 1.4.x.
Any code base migrating to Diesel 2.0 is expected to be affected at least by the following changes:
diesel_migration are additionally affected by the following change:
BoxableExpression might be affected by the following change:
Users of tables containing a column of the type
Array<T> are affected by the following change:
Users that implement support for their SQL types or type mappings are affected by the following changes:
no_arg_sql_function! macro is now pending deprecation. Users of the macro are advised to consider
eq_any on the PostgreSQL backend might hit type rejection error in rare cases.
Users that update generic Diesel code will also be affected by the following changes:
Additionally this release contains many changes for users that implemented a custom backend/connection. We do not provide explicit migration steps but we encourage users to reach out with questions pertaining to these changes.
We expect this to be a straightforward change as the connection already can execute only one query at a time.
We have updated all of our Diesel derive attributes to follow the patterns that are used widely in the Rust’s ecosystem. This means that all of them need to be wrapped by
#[diesel()] now. You can now specify multiple attributes on the same line using
This is backward compatible and thus all of your old attributes will still work, but with warnings. The attributes can be upgraded by either looking at the warnings or by reading diesel derive documentation reference.
We have completely rewritten the
diesel_migration crate. As a part of this rewrite all free standing functions are removed from
diesel_migration. Equivalent functionality is now provided by the
MigrationHarness trait, which is implemented for any
Connection type and for
HarnessWithOutput. Refer to their documentations for details.
Additionally, this rewrite changed the way we provide migrations. Instead of having our own implementation for file based and embedded migration we now provide a unified
MigrationSource trait to abstract over the differences.
diesel_migration provides two implementations:
FileBasedMigrations, which mirrors the existing behaviour to load raw sql migrations at run time form a specific directory
EmbeddedMigrations, which mirrors the existing
embed_migrations!() macro itself changed. Instead of generating a magical embedded module it now generates an instance of
EmbeddedMigrations, that could be stored in a constant for example.
That means code using
embed_migrations!() needs to be changed from
We changed the way how we handle the propagation of null values through binary operators. Diesel 1.x always assumed that the result of a binary operation
value_a > value_b is not nullable, which does not match the behaviour of the underlying databases.
value_a > null may return a
NULL value there. With Diesel 2.0 we changed this to match more closely the behaviour of the underlying databases. We expect this change to have the biggest impact on existing usages of
BoxableExpression as it may change the resulting sql type there. As a possible workaround for divering sql types there we recommend to use one of the following functions:
We changed the inferred SQL type for columns with array types for the PostgreSQL backend. Instead of using
Array<ST> we now infer
Array<Nullable<ST>> to support arrays containing
NULL values. This change implies a change mapping of columns of the corresponding types. It is possible to handle this change using one of the following strategies:
Vec<Option<T>>as rust side type instead of
Array<ST>in your schema, to signal that this array does not contain null values. You may want to use the
patch_filekey for diesel CLI for this.
#[diesel(deserialize_as = "…")]to explicitly overwrite the deserialization implementation used for this specific struct field. Checkout the documentation of
We changed how we mark sql types as nullable at type level. For this we replaced the
NonNull trait with a more generic
SqlType trait, which allows to mark a sql type as (non-) nullable. This may affect custom sql type implementations.
Users that already use the existing
#[derive(SqlType)] do not need to change any code. The derive internally generates the correct code after the update. Users that use a manual implementation of
NonNull need to replace it with a corresponding
Additionally, the diesel CLI tool was changed so that it automatically generates the Rust side definition of custom SQL types as long as they appear on any table. This feature currently only supports the PostgreSQL backend, as all other supported backends do not support real custom types at SQL level at all.
We restructured the way Diesel serializes Rust values to their backend specific representation. This enables us to skip copying the value at all if the specific backend supports writing to a shared buffer. Unfortunately, this feature requires changes to the
ToSql trait. This change introduces a lifetime that ensures that a value implementing
ToSql outlives the underlying serialisation buffer. Additionally we separated the output buffer type for Sqlite from the type used for PostgreSQL and Mysql.
This has the implication that for generic implementations using a inner existing
ToSql implementation you cannot create temporary values anymore and forward them to the inner implementation.
For backend concrete implementations, the following functions allow You to work around this limitation:
Sqlitebackend (Refer to the documentation of
SqliteBindValuefor accepted values)
We changed the raw value representation for both PostgreSQL and MySQL backends, from a
&[u8] to an opaque type. This allows us to include additional information like the database side type there. This change enables users to write
FromSql implementations that decide dynamically what kind of value was received. The new value types for both backends expose a
as_bytes() method to access the underlying byte buffer.
Any affected backend needs to perform the following changes:
no_arg_sql_function! was deprecated without direct replacement. At the same time the
sql_function! macro gained support for sql functions without argument. This support generates slightly different code. Instead of representing the sql function as zero sized struct,
sql_function! will generate an ordinary function call without arguments. This requires changing any usage of the generated dsl. This change affects all of the usages of the
no_arg_sql_function! in third party crates.
Diesel 2.0 introduces an optimisation that replaces the
IN($1, ..., $n) expression generated previously by
.eq_any() with the more optimised
= ANY($1) which binds the parameter as single array instead of binding each element separately. This improves the performance of large lists and allows us to keep such queries in the prepared statement cache, which enables future performance improvements. Unfortunately not all previously accepted arguments are accepted now. Newly rejected cases include:
col.eq_any(values)has the type
.eq_any()on several columns at one via
Both cases can be worked around by using boxed queries and repeated chained equality checks.
Diesel now fully enforces the aggregation rules, which required us to change the way we represent the aggregation at the type system level. This is used to provide
group_by support. Diesel’s aggregation rules match the semantics of PostgreSQL or MySQL with the
ONLY_FULL_GROUP_BY option enabled.
As part of this change we removed the
NonAggregate trait in favor of a new, more expressive
ValidGrouping trait. Existing implementations of
NonAggregate must be replaced with an equivalent
The following change shows how to replace an existing implementation with a strictly equivalent implementation.
Additional changes may be required to adapt custom query ast implementations to fully support
group_by clauses. Refer to the documentation of
ValidGrouping for details.
In addition, any occurrence of
NonAggregate in trait bounds needs to be replaced. Again, the following change shows the strictly equivalent version:
In addition to the changes listed above, we changed numerous internal details of Diesel. This will have impact on most codebases that include non-trivial generic code abstracting over Diesel. This section tries to list as much of those changes as possible
With Diesel 2.0 we removed most of the API which was marked with
#[doc(hidden)]. Technically these parts of the API have always been private to Diesel. This change enforces this distinction in stricter way. In addition, some parts of these formerly hidden API are now documented and exposed behind the
i-implement-a-third-party-backend-and-opt-into-breaking-changes crate feature. As the name already implies we reserve the right to change these APIs between different Diesel 2.x minor releases, so you should always pin a concrete minor release version if you use these APIs. If you depended on such an API and you cannot find a suitable replacement we invite you to work with us on exposing the corresponding feature as part of the stable API.
We changed the internal structure of the
QueryableByName trait family used for deserialization. This change allows us to unify our deserialization code. We hopefully put sufficient wild card implementations in place so that old trait bounds imply the right trait anyway. For cases where this does not hold true, the following changes may be required:
Queryable<ST, DB> is now equivalent to
FromSqlRow<ST, DB>. The latter is used as an actual trait bound on the corresponding [
QueryableByName<DB> is now equivalent to
FromSqlRow<Untyped, DB>. The latter is used as an actual trait on the corresponding [
With Diesel 2.0, we introduced a way to specialise
QueryFragment implementations for specific backend, while providing a generic implementation for other backends. To be able to use this feature in the future we marked existing wild card
QueryFragment implementations with an additional
DieselReserveSpecialization. Rustc suggests just adding an additional trait bound on this trait. It’s not possible to add a bound on this trait without opting into breaking changes and it’s almost never required to actually do that. Any occurrence of an error mentioning this trait can simply be fixed by adding a trait bound like follows:
This rule has one notable exception: Third party backend implementations. We expect those backends to opt into the
i-implement-a-third-party-backend-and-opt-into-breaking-changes feature anyway, as it’s otherwise not possible to implement a third party backend.