
* feat: create `sqlx.toml` format * feat: add support for ignored_chars config to sqlx_core::migrate * chore: test ignored_chars with `U+FEFF` (ZWNBSP/BOM) https://en.wikipedia.org/wiki/Byte_order_mark * refactor: make `Config` always compiled simplifies usage while still making parsing optional for less generated code * refactor: add origin information to `Column` * feat(macros): implement `type_override` and `column_override` from `sqlx.toml` * refactor(sqlx.toml): make all keys kebab-case, create `macros.preferred-crates` * feat: make macros aware of `macros.preferred-crates` * feat: make `sqlx-cli` aware of `database-url-var` * feat: teach macros about `migrate.table-name`, `migrations-dir` * feat: teach macros about `migrate.ignored-chars` * chore: delete unused source file `sqlx-cli/src/migration.rs` * feat: teach `sqlx-cli` about `migrate.defaults` * feat: teach `sqlx-cli` about `migrate.migrations-dir` * feat: teach `sqlx-cli` about `migrate.table-name` * feat: introduce `migrate.create-schemas` * WIP feat: create multi-tenant database example * fix(postgres): don't fetch `ColumnOrigin` for transparently-prepared statements * feat: progress on axum-multi-tenant example * feat(config): better errors for mislabeled fields * WIP feat: filling out axum-multi-tenant example * feat: multi-tenant example No longer Axum-based because filling out the request routes would have distracted from the purpose of the example. * chore(ci): test multi-tenant example * fixup after merge * fix(ci): enable `sqlx-toml` in CLI build for examples * fix: CI, README for `multi-tenant` * fix: clippy warnings * fix: multi-tenant README * fix: sequential versioning inference for migrations * fix: migration versioning with explicit overrides * fix: only warn on ambiguous crates if the invocation relies on it * fix: remove unused imports * fix: doctest * fix: `sqlx mig add` behavior and tests * fix: restore original type-checking order * fix: deprecation warning in `tests/postgres/macros.rs` * feat: create postgres/multi-database example * fix: examples/postgres/multi-database * fix: cargo fmt * chore: add tests for config `migrate.defaults` * fix: sqlx-cli/tests/add.rs * feat(cli): add `--config` override to all relevant commands * chore: run `sqlx mig add` test with `RUST_BACKTRACE=1` * fix: properly canonicalize config path for `sqlx mig add` test * fix: get `sqlx mig add` test passing * fix(cli): test `migrate.ignored-chars`, fix bugs * feat: create `macros.preferred-crates` example * fix(examples): use workspace `sqlx` * fix: examples * fix(sqlite): unexpected feature flags in `type_checking.rs` * fix: run `cargo fmt` * fix: more example fixes * fix(ci): preferred-crates setup * fix(examples): enable default-features for workspace `sqlx` * fix(examples): issues in `preferred-crates` * chore: adjust error message for missing param type in `query!()` * doc: mention new `sqlx.toml` configuration * chore: add `CHANGELOG` entry Normally I generate these when cutting the release, but I wanted to take time to editorialize this one. * doc: fix new example titles * refactor: make `sqlx-toml` feature non-default, improve errors * refactor: eliminate panics in `Config` read path * chore: remove unused `axum` dependency from new examples * fix(config): restore fallback to default config for macros * chore(config): remove use of `once_cell` (to match `main`)
3.2 KiB
Usage of macros.preferred-crates
in sqlx.toml
The Problem
SQLx has many optional features that enable integrations for external crates to map from/to SQL types.
In some cases, more than one optional feature applies to the same set of types:
- The
chrono
andtime
features enable mapping SQL date/time types to those in these crates. - Similarly,
bigdecimal
andrust_decimal
enable mapping for the SQLNUMERIC
type.
Throughout its existence, the query!()
family of macros has inferred which crate to use based on which optional
feature was enabled. If multiple features are enabled, one takes precedent over the other: time
over chrono
,
rust_decimal
over bigdecimal
, etc. The ordering is purely the result of historical happenstance and
does not indicate any specific preference for one crate over another. They each have their tradeoffs.
This works fine when only one crate in the dependency graph depends on SQLx, but can break down if another crate in the dependency graph also depends on SQLx. Because of Cargo's feature unification, any features enabled by this other crate are also forced on for all other crates that depend on the same version of SQLx in the same project.
This is intentional design on Cargo's part; features are meant to be purely additive, so it can build each transitive dependency just once no matter how many crates depend on it. Otherwise, this could result in combinatorial explosion.
Unfortunately for us, this means that if your project depends on SQLx and enables the chrono
feature, but also depends
on another crate that enables the time
feature, the query!()
macros will end up thinking that you want to use
the time
crate, because they don't know any better.
Fixing this has historically required patching the dependency, which is annoying to maintain long-term.
The Solution
However, as of 0.9.0, SQLx has gained the ability to configure the macros through the use of a sqlx.toml
file.
This includes the ability to tell the macros which crate you prefer, overriding the inference.
See the sqlx.toml
file in this directory for details.
A full reference sqlx.toml
is also available as sqlx-core/src/config/reference.toml
.
This Example
This example exists both to showcase the macro configuration and also serve as a test for the functionality.
It consists of three crates:
- The root crate, which depends on SQLx and enables the
chrono
andbigdecimal
features, uses-rust-decimal
, a dependency which also depends on SQLx and enables therust_decimal
feature,- and
uses-time
, a dependency which also depends on SQLx and enables thetime
feature.- This serves as a stand-in for
tower-sessions-sqlx-store
, which is one of the culprits for this issue.
- This serves as a stand-in for
Given that both dependencies enable features with higher precedence, they would historically have interfered
with the usage in the root crate. (Pretend that they're published to crates.io and cannot be easily changed.)
However, because the root crate uses a sqlx.toml
, the macros know exactly which crates it wants to use and everyone's happy.