-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
649 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,316 @@ | ||
use std::collections::BTreeMap; | ||
|
||
/// Configuration for the [`sqlx::query!()`] family of macros. | ||
#[derive(Debug, serde::Deserialize)] | ||
#[derive(Debug, Default, serde::Deserialize)] | ||
#[serde(default)] | ||
pub struct Config { | ||
/// Override the environment variable | ||
/// Override the database URL environment variable used by the macros. | ||
/// | ||
/// Case-sensitive. Defaults to `DATABASE_URL`. | ||
/// | ||
/// ### Example: Multi-Database Project | ||
/// You can use multiple databases in the same project by breaking it up into multiple crates, | ||
/// then using a different environment variable for each. | ||
/// | ||
/// For example, with two crates in the workspace named `foo` and `bar`: | ||
/// | ||
/// ##### `foo/sqlx.toml` | ||
/// ```toml | ||
/// [macros] | ||
/// database_url_var = "FOO_DATABASE_URL" | ||
/// ``` | ||
/// | ||
/// ##### `bar/sqlx.toml` | ||
/// ```toml | ||
/// [macros] | ||
/// database_url_var = "BAR_DATABASE_URL" | ||
/// ``` | ||
/// | ||
/// ##### `.env` | ||
/// ```text | ||
/// FOO_DATABASE_URL=postgres://postgres@localhost:5432/foo | ||
/// BAR_DATABASE_URL=postgres://postgres@localhost:5432/bar | ||
/// ``` | ||
/// | ||
/// The query macros used in `foo` will use `FOO_DATABASE_URL`, | ||
/// and the ones used in `bar` will use `BAR_DATABASE_URL`. | ||
pub database_url_var: Option<String>, | ||
} | ||
|
||
/// Specify the crate to use for mapping date/time types to Rust. | ||
/// | ||
/// The default behavior is to use whatever crate is enabled, | ||
/// [`chrono`] or [`time`] (the latter takes precedent). | ||
/// | ||
/// [`chrono`]: crate::types::chrono | ||
/// [`time`]: crate::types::time | ||
/// | ||
/// ### Example: Always Use Chrono | ||
/// Thanks to Cargo's [feature unification], a crate in the dependency graph may enable | ||
/// the `time` feature of SQLx which will force it on for all crates using SQLx, | ||
/// which will result in problems if your crate wants to use types from [`chrono`]. | ||
/// | ||
/// You can use the type override syntax (see `sqlx::query!` for details), | ||
/// or you can force an override globally by setting this option. | ||
/// | ||
/// ##### `sqlx.toml` | ||
/// ```toml | ||
/// [macros] | ||
/// datetime_crate = "chrono" | ||
/// ``` | ||
/// | ||
/// [feature unification]: https://doc.rust-lang.org/cargo/reference/features.html#feature-unification | ||
pub datetime_crate: DateTimeCrate, | ||
|
||
/// Specify global overrides for mapping SQL type names to Rust type names. | ||
/// | ||
/// ### Note: Orthogonal to Nullability | ||
/// These overrides do not affect whether `query!()` decides to wrap a column in `Option<_>` | ||
/// or not. They only override the inner type used. | ||
/// | ||
/// ### Note: Schema Qualification (Postgres) | ||
/// Type names may be schema-qualified in Postgres. If so, the schema should be part | ||
/// of the type string, e.g. `'foo.bar'` to reference type `bar` in schema `foo`. | ||
/// | ||
/// The schema and/or type name may additionally be quoted in the string | ||
/// for a quoted identifier (see next section). | ||
/// | ||
/// Postgres users: schema qualification should not be used for types in the search path. | ||
/// | ||
/// ### Note: Quoted Identifiers (Postgres) | ||
/// Type names using [quoted identifiers] in SQL must also be specified with quotes here. | ||
/// | ||
/// Note, however, that the TOML format parses way the outer pair of quotes, | ||
/// so for quoted names in SQL, double-quoting is necessary, | ||
/// e.g. `'"Foo"'` for SQL type `"Foo"`. | ||
/// | ||
/// To reference a schema-qualified type with a quoted name, use double-quotes after the | ||
/// dot, e.g. `'foo."Bar"'` to reference type `"Bar"` of schema `foo`, and vice versa for | ||
/// quoted schema names. | ||
/// | ||
/// We recommend wrapping all type names in single quotes, as shown below, | ||
/// to avoid confusion. | ||
/// | ||
/// [quoted identifiers]: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS | ||
// Note: we wanted to be able to handle this intelligently, | ||
// but the `toml` crate authors weren't interested: https://github.com/toml-rs/toml/issues/761 | ||
// | ||
// We decided to just encourage always quoting type names instead. | ||
/// ### Example: Custom Wrapper Types | ||
/// Does SQLx not support a type that you need? Do you want additional semantics not | ||
/// implemented on the built-in types? You can create a custom wrapper, | ||
/// or use an external crate. | ||
/// | ||
/// ##### `sqlx.toml` | ||
/// ```toml | ||
/// [macros.type_overrides] | ||
/// # Override a built-in type | ||
/// 'uuid' = "crate::types::MyUuid" | ||
/// | ||
/// # Support an external or custom wrapper type (e.g. from the `isn` Postgres extension) | ||
/// # (NOTE: FOR DOCUMENTATION PURPOSES ONLY; THIS CRATE/TYPE DOES NOT EXIST AS OF WRITING) | ||
/// 'isbn13' = "isn_rs::sqlx::ISBN13" | ||
/// | ||
/// ### Example: Custom Types in Postgres | ||
/// If you have a custom type in Postgres that you want to map without needing to use | ||
/// the type override syntax in `sqlx::query!()` every time, you can specify a global | ||
/// override here. | ||
/// | ||
/// For example, a custom enum type `foo`: | ||
/// | ||
/// ##### Migration or Setup SQL (e.g. `migrations/0_setup.sql`) | ||
/// ```sql | ||
/// CREATE TYPE foo AS ENUM ('Bar', 'Baz'); | ||
/// ``` | ||
/// | ||
/// ##### `src/types.rs` | ||
/// ```rust,no_run | ||
/// #[derive(sqlx::Type)] | ||
/// pub enum Foo { | ||
/// Bar, | ||
/// Baz | ||
/// } | ||
/// ``` | ||
/// | ||
/// If you're not using `PascalCase` in your enum variants then you'll want to use | ||
/// `#[sqlx(rename_all = "<strategy>")]` on your enum. | ||
/// See [`Type`][crate::type::Type] for details. | ||
/// | ||
/// ##### `sqlx.toml` | ||
/// ```toml | ||
/// [macros.type_overrides] | ||
/// # Map SQL type `foo` to `crate::types::Foo` | ||
/// 'foo' = "crate::types::Foo" | ||
/// ``` | ||
/// | ||
/// ### Example: Schema-Qualified Types | ||
/// (See `Note` section above for details.) | ||
/// | ||
/// ```toml | ||
/// [macros.type_overrides] | ||
/// # Map SQL type `foo.foo` to `crate::types::Foo` | ||
/// 'foo.foo' = "crate::types::Foo" | ||
/// ``` | ||
/// | ||
/// ### Example: Quoted Identifiers | ||
/// If a type or schema uses quoted identifiers, | ||
/// it must be wrapped in quotes _twice_ for SQLx to know the difference: | ||
/// | ||
/// ```toml | ||
/// [macros.type_overrides] | ||
/// # `"Foo"` in SQLx | ||
/// '"Foo"' = "crate::types::Foo" | ||
/// # **NOT** `"Foo"` in SQLx (parses as just `Foo`) | ||
/// "Foo" = "crate::types::Foo" | ||
/// | ||
/// # Schema-qualified | ||
/// '"foo".foo' = "crate::types::Foo" | ||
/// 'foo."Foo"' = "crate::types::Foo" | ||
/// '"foo"."Foo"' = "crate::types::Foo" | ||
/// ``` | ||
/// | ||
/// (See `Note` section above for details.) | ||
pub type_overrides: BTreeMap<SqlType, RustType>, | ||
|
||
/// Specify overrides for mapping SQL types to Rust types, per table and column. | ||
/// | ||
/// The supported syntax is similar to [`type_overrides`][Self::type_overrides], | ||
/// (with the same caveat for quoted names!) but column names must be qualified | ||
/// by a separately quoted table name, which may optionally be schema-qualified. | ||
/// | ||
/// For example, column `bar` of table `foo` should be written `'foo'.'bar'`. | ||
/// | ||
/// Multiple columns for the same SQL table may be written in the same table in TOML | ||
/// (see examples below). | ||
/// | ||
/// ### Note: Orthogonal to Nullability | ||
/// These overrides do not affect whether `query!()` decides to wrap a column in `Option<_>` | ||
/// or not. They only override the inner type used. | ||
/// | ||
/// ### Note: Schema Qualification (Postgres) | ||
/// Table names may be schema-qualified in Postgres. If so, the schema should be part | ||
/// of the table name string, e.g. `'foo.bar'` to reference table `bar` in schema `foo`. | ||
/// | ||
/// The schema and/or type name may additionally be quoted in the string | ||
/// for a quoted identifier (see next section). | ||
/// | ||
/// Postgres users: schema qualification should not be used for types in the search path. | ||
/// | ||
/// ### Note: Quoted Identifiers (Postgres) | ||
/// Schema, table, or column names using [quoted identifiers] in SQL | ||
/// must also be specified with quotes here. | ||
/// | ||
/// Note, however, that the TOML format parses way the outer pair of quotes, | ||
/// so for quoted names in SQL, double-quoting is necessary, | ||
/// e.g. `'"Foo"'` for SQL name `"Foo"`. | ||
/// | ||
/// To reference a schema-qualified table with a quoted name, use double-quotes after the | ||
/// dot, e.g. `'foo."Bar"'` to reference table `"Bar"` of schema `foo`, and vice versa for | ||
/// quoted schema names. | ||
/// | ||
/// We recommend wrapping all table and column names in single quotes, as shown below, | ||
/// to avoid confusion. | ||
/// | ||
/// [quoted identifiers]: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS | ||
// Note: we wanted to be able to handle this intelligently, | ||
// but the `toml` crate authors weren't interested: https://github.com/toml-rs/toml/issues/761 | ||
// | ||
// We decided to just encourage always quoting type names instead. | ||
/// | ||
/// ### Example | ||
/// | ||
/// ##### `sqlx.toml` | ||
/// ```toml | ||
/// [macros.table_overrides] | ||
/// # Map column `bar` of table `foo` to Rust type `crate::types::Foo`: | ||
/// 'foo'.'bar' = "crate::types::Bar" | ||
/// | ||
/// # Quoted column name | ||
/// # Note: same quoting requirements as `macros.type_overrides` | ||
/// 'foo'.'"Bar"' = "crate::types::Bar" | ||
/// | ||
/// # Schema-qualified | ||
/// # Note how the schema and table are together in a single string. | ||
/// # Map column `baz` of table `foo.bar` to Rust type `crate::types::Baz` | ||
/// 'foo.bar'.'baz' = "crate::types::Baz" | ||
/// | ||
/// # Schema, table and/or column names may be quoted | ||
/// '"Foo"."Bar"'.'"Baz"' = "crate::types::Baz" | ||
/// | ||
/// # Multiple columns in the same table (`bar`) | ||
/// [macros.table_overrides.'bar'] | ||
/// # bar.foo | ||
/// 'foo' = "crate::schema::bar::Foo" | ||
/// # bar."Bar" | ||
/// '"Bar"' = "crate::schema::bar::Bar" | ||
/// | ||
/// # May also be schema-qualified | ||
/// # Note how the schema and table are together in a single string. | ||
/// [macros.column_overrides.'my_schema.my_table'] | ||
/// # my_schema.my_table.my_column | ||
/// 'my_column' = "crate::types::MyType" | ||
/// | ||
/// # And quoted | ||
/// [macros.column_overrides.'"My Schema"."My Table"'] | ||
/// # "My Schema"."My Table"."My Column" | ||
/// '"My Column"' = "crate::types::MyType" | ||
/// ``` | ||
pub table_overrides: BTreeMap<TableName, BTreeMap<ColumnName, RustType>>, | ||
} | ||
|
||
/// The crate to use for mapping date/time types to Rust. | ||
#[derive(Debug, Default, PartialEq, Eq, serde::Deserialize)] | ||
#[serde(rename_all = "snake_case")] | ||
pub enum DateTimeCrate { | ||
/// Use whichever crate is enabled (`time` then `chrono`). | ||
#[default] | ||
Inferred, | ||
|
||
/// Always use types from [`chrono`][crate::types::chrono]. | ||
/// | ||
/// ```toml | ||
/// [macros] | ||
/// datetime_crate = "chrono" | ||
/// ``` | ||
Chrono, | ||
|
||
/// Always use types from [`time`][crate::types::time]. | ||
/// | ||
/// ```toml | ||
/// [macros] | ||
/// datetime_crate = "time" | ||
/// ``` | ||
Time | ||
} | ||
|
||
/// A SQL type name; may optionally be schema-qualified. | ||
/// | ||
/// See [`macros.type_overrides`][Config::type_overrides] for usages. | ||
pub type SqlType = Box<str>; | ||
|
||
/// A SQL table name; may optionally be schema-qualified. | ||
/// | ||
/// See [`macros.table_overrides`][Config::table_overrides] for usages. | ||
pub type TableName = Box<str>; | ||
|
||
/// A column in a SQL table. | ||
/// | ||
/// See [`macros.table_overrides`][Config::table_overrides] for usages. | ||
pub type ColumnName = Box<str>; | ||
|
||
/// A Rust type name or path. | ||
/// | ||
/// Should be a global path (not relative). | ||
pub type RustType = Box<str>; | ||
|
||
#[doc(hidden)] | ||
impl Config { | ||
pub fn type_override(&self, type_name: &str) -> Option<&str> { | ||
self.type_overrides.get(type_name).map(|s| &**s) | ||
} | ||
|
||
pub fn table_override(&self, table: &str, column: &str) -> Option<&str> { | ||
self.table_overrides.get(table) | ||
.and_then(|by_column| by_column.get(column)) | ||
.map(|s| &**s) | ||
} | ||
} |
Oops, something went wrong.