1- /// Configuration for the [`sqlx::query!()`] family of macros.
2- #[ derive( Debug , serde:: Deserialize ) ]
1+ use std:: collections:: BTreeMap ;
2+
3+ /// Configuration for the `query!()` family of macros.
4+ #[ derive( Debug , Default , serde:: Deserialize ) ]
5+ #[ serde( default ) ]
36pub struct Config {
4- /// Override the environment variable
5- pub database_url_var : Option < String > ,
6- }
7+ /// Specify the crate to use for mapping date/time types to Rust.
8+ ///
9+ /// The default behavior is to use whatever crate is enabled,
10+ /// [`chrono`] or [`time`] (the latter takes precedent).
11+ ///
12+ /// [`chrono`]: crate::types::chrono
13+ /// [`time`]: crate::types::time
14+ ///
15+ /// Example: Always Use Chrono
16+ /// -------
17+ /// Thanks to Cargo's [feature unification], a crate in the dependency graph may enable
18+ /// the `time` feature of SQLx which will force it on for all crates using SQLx,
19+ /// which will result in problems if your crate wants to use types from [`chrono`].
20+ ///
21+ /// You can use the type override syntax (see `sqlx::query!` for details),
22+ /// or you can force an override globally by setting this option.
23+ ///
24+ /// #### `sqlx.toml`
25+ /// ```toml
26+ /// [macros]
27+ /// datetime_crate = "chrono"
28+ /// ```
29+ ///
30+ /// [feature unification]: https://doc.rust-lang.org/cargo/reference/features.html#feature-unification
31+ pub datetime_crate : DateTimeCrate ,
32+
33+ /// Specify global overrides for mapping SQL type names to Rust type names.
34+ ///
35+ /// Default type mappings are defined by the database driver.
36+ /// Refer to the `sqlx::types` module for details.
37+ ///
38+ /// ## Note: Orthogonal to Nullability
39+ /// These overrides do not affect whether `query!()` decides to wrap a column in `Option<_>`
40+ /// or not. They only override the inner type used.
41+ ///
42+ /// ## Note: Schema Qualification (Postgres)
43+ /// Type names may be schema-qualified in Postgres. If so, the schema should be part
44+ /// of the type string, e.g. `'foo.bar'` to reference type `bar` in schema `foo`.
45+ ///
46+ /// The schema and/or type name may additionally be quoted in the string
47+ /// for a quoted identifier (see next section).
48+ ///
49+ /// Schema qualification should not be used for types in the search path.
50+ ///
51+ /// ## Note: Quoted Identifiers (Postgres)
52+ /// Type names using [quoted identifiers in Postgres] must also be specified with quotes here.
53+ ///
54+ /// Note, however, that the TOML format parses way the outer pair of quotes,
55+ /// so for quoted names in Postgres, double-quoting is necessary,
56+ /// e.g. `'"Foo"'` for SQL type `"Foo"`.
57+ ///
58+ /// To reference a schema-qualified type with a quoted name, use double-quotes after the
59+ /// dot, e.g. `'foo."Bar"'` to reference type `"Bar"` of schema `foo`, and vice versa for
60+ /// quoted schema names.
61+ ///
62+ /// We recommend wrapping all type names in single quotes, as shown below,
63+ /// to avoid confusion.
64+ ///
65+ /// MySQL/MariaDB and SQLite do not support custom types, so quoting type names should
66+ /// never be necessary.
67+ ///
68+ /// [quoted identifiers in Postgres]: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
69+ // Note: we wanted to be able to handle this intelligently,
70+ // but the `toml` crate authors weren't interested: https://github.com/toml-rs/toml/issues/761
71+ //
72+ // We decided to just encourage always quoting type names instead.
73+ /// Example: Custom Wrapper Types
74+ /// -------
75+ /// Does SQLx not support a type that you need? Do you want additional semantics not
76+ /// implemented on the built-in types? You can create a custom wrapper,
77+ /// or use an external crate.
78+ ///
79+ /// #### `sqlx.toml`
80+ /// ```toml
81+ /// [macros.type_overrides]
82+ /// # Override a built-in type
83+ /// 'uuid' = "crate::types::MyUuid"
84+ ///
85+ /// # Support an external or custom wrapper type (e.g. from the `isn` Postgres extension)
86+ /// # (NOTE: FOR DOCUMENTATION PURPOSES ONLY; THIS CRATE/TYPE DOES NOT EXIST AS OF WRITING)
87+ /// 'isbn13' = "isn_rs::sqlx::ISBN13"
88+ /// ```
89+ ///
90+ /// Example: Custom Types in Postgres
91+ /// -------
92+ /// If you have a custom type in Postgres that you want to map without needing to use
93+ /// the type override syntax in `sqlx::query!()` every time, you can specify a global
94+ /// override here.
95+ ///
96+ /// For example, a custom enum type `foo`:
97+ ///
98+ /// #### Migration or Setup SQL (e.g. `migrations/0_setup.sql`)
99+ /// ```sql
100+ /// CREATE TYPE foo AS ENUM ('Bar', 'Baz');
101+ /// ```
102+ ///
103+ /// #### `src/types.rs`
104+ /// ```rust,no_run
105+ /// #[derive(sqlx::Type)]
106+ /// pub enum Foo {
107+ /// Bar,
108+ /// Baz
109+ /// }
110+ /// ```
111+ ///
112+ /// If you're not using `PascalCase` in your enum variants then you'll want to use
113+ /// `#[sqlx(rename_all = "<strategy>")]` on your enum.
114+ /// See [`Type`][crate::type::Type] for details.
115+ ///
116+ /// #### `sqlx.toml`
117+ /// ```toml
118+ /// [macros.type_overrides]
119+ /// # Map SQL type `foo` to `crate::types::Foo`
120+ /// 'foo' = "crate::types::Foo"
121+ /// ```
122+ ///
123+ /// Example: Schema-Qualified Types
124+ /// -------
125+ /// (See `Note` section above for details.)
126+ ///
127+ /// ```toml
128+ /// [macros.type_overrides]
129+ /// # Map SQL type `foo.foo` to `crate::types::Foo`
130+ /// 'foo.foo' = "crate::types::Foo"
131+ /// ```
132+ ///
133+ /// Example: Quoted Identifiers
134+ /// -------
135+ /// If a type or schema uses quoted identifiers,
136+ /// it must be wrapped in quotes _twice_ for SQLx to know the difference:
137+ ///
138+ /// ```toml
139+ /// [macros.type_overrides]
140+ /// # `"Foo"` in SQLx
141+ /// '"Foo"' = "crate::types::Foo"
142+ /// # **NOT** `"Foo"` in SQLx (parses as just `Foo`)
143+ /// "Foo" = "crate::types::Foo"
144+ ///
145+ /// # Schema-qualified
146+ /// '"foo".foo' = "crate::types::Foo"
147+ /// 'foo."Foo"' = "crate::types::Foo"
148+ /// '"foo"."Foo"' = "crate::types::Foo"
149+ /// ```
150+ ///
151+ /// (See `Note` section above for details.)
152+ pub type_overrides : BTreeMap < SqlType , RustType > ,
153+
154+ /// Specify per-column overrides for mapping SQL types to Rust types.
155+ ///
156+ /// Default type mappings are defined by the database driver.
157+ /// Refer to the `sqlx::types` module for details.
158+ ///
159+ /// The supported syntax is similar to [`type_overrides`][Self::type_overrides],
160+ /// (with the same caveat for quoted names!) but column names must be qualified
161+ /// by a separately quoted table name, which may optionally be schema-qualified.
162+ ///
163+ /// Multiple columns for the same SQL table may be written in the same table in TOML
164+ /// (see examples below).
165+ ///
166+ /// ## Note: Orthogonal to Nullability
167+ /// These overrides do not affect whether `query!()` decides to wrap a column in `Option<_>`
168+ /// or not. They only override the inner type used.
169+ ///
170+ /// ## Note: Schema Qualification
171+ /// Table names may be schema-qualified. If so, the schema should be part
172+ /// of the table name string, e.g. `'foo.bar'` to reference table `bar` in schema `foo`.
173+ ///
174+ /// The schema and/or type name may additionally be quoted in the string
175+ /// for a quoted identifier (see next section).
176+ ///
177+ /// Postgres users: schema qualification should not be used for tables in the search path.
178+ ///
179+ /// ## Note: Quoted Identifiers
180+ /// Schema, table, or column names using quoted identifiers ([MySQL], [Postgres], [SQLite])
181+ /// in SQL must also be specified with quotes here.
182+ ///
183+ /// Postgres and SQLite use double-quotes (`"Foo"`) while MySQL uses backticks (`\`Foo\`).
184+ ///
185+ /// Note, however, that the TOML format parses way the outer pair of quotes,
186+ /// so for quoted names in Postgres, double-quoting is necessary,
187+ /// e.g. `'"Foo"'` for SQL name `"Foo"`.
188+ ///
189+ /// To reference a schema-qualified table with a quoted name, use the appropriate quotation
190+ /// characters after the dot, e.g. `'foo."Bar"'` to reference table `"Bar"` of schema `foo`,
191+ /// and vice versa for quoted schema names.
192+ ///
193+ /// We recommend wrapping all table and column names in single quotes, as shown below,
194+ /// to avoid confusion.
195+ ///
196+ /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/identifiers.html
197+ /// [Postgres]: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
198+ /// [SQLite]: https://sqlite.org/lang_keywords.html
199+ // Note: we wanted to be able to handle this intelligently,
200+ // but the `toml` crate authors weren't interested: https://github.com/toml-rs/toml/issues/761
201+ //
202+ // We decided to just encourage always quoting type names instead.
203+ ///
204+ /// Example
205+ /// -------
206+ ///
207+ /// #### `sqlx.toml`
208+ /// ```toml
209+ /// [macros.column_overrides.'foo']
210+ /// # Map column `bar` of table `foo` to Rust type `crate::types::Foo`:
211+ /// 'bar' = "crate::types::Bar"
212+ ///
213+ /// # Quoted column name
214+ /// # Note: same quoting requirements as `macros.type_overrides`
215+ /// '"Bar"' = "crate::types::Bar"
216+ ///
217+ /// # Note: will NOT work (parses as `Bar`)
218+ /// # "Bar" = "crate::types::Bar"
219+ ///
220+ /// # Table name may be quoted (note the wrapping single-quotes)
221+ /// [macros.column_overrides.'"Foo"']
222+ /// 'bar' = "crate::types::Bar"
223+ /// '"Bar"' = "crate::types::Bar"
224+ ///
225+ /// # Table name may also be schema-qualified.
226+ /// # Note how the dot is inside the quotes.
227+ /// [macros.column_overrides.'my_schema.my_table']
228+ /// 'my_column' = "crate::types::MyType"
229+ ///
230+ /// # Quoted schema, table, and column names
231+ /// [macros.column_overrides.'"My Schema"."My Table"']
232+ /// '"My Column"' = "crate::types::MyType"
233+ /// ```
234+ pub column_overrides : BTreeMap < TableName , BTreeMap < ColumnName , RustType > > ,
235+ }
236+
237+ /// The crate to use for mapping date/time types to Rust.
238+ #[ derive( Debug , Default , PartialEq , Eq , serde:: Deserialize ) ]
239+ #[ serde( rename_all = "snake_case" ) ]
240+ pub enum DateTimeCrate {
241+ /// Use whichever crate is enabled (`time` then `chrono`).
242+ #[ default]
243+ Inferred ,
244+
245+ /// Always use types from [`chrono`][crate::types::chrono].
246+ ///
247+ /// ```toml
248+ /// [macros]
249+ /// datetime_crate = "chrono"
250+ /// ```
251+ Chrono ,
252+
253+ /// Always use types from [`time`][crate::types::time].
254+ ///
255+ /// ```toml
256+ /// [macros]
257+ /// datetime_crate = "time"
258+ /// ```
259+ Time ,
260+ }
261+
262+ /// A SQL type name; may optionally be schema-qualified.
263+ ///
264+ /// See [`macros.type_overrides`][Config::type_overrides] for usages.
265+ pub type SqlType = Box < str > ;
266+
267+ /// A SQL table name; may optionally be schema-qualified.
268+ ///
269+ /// See [`macros.column_overrides`][Config::column_overrides] for usages.
270+ pub type TableName = Box < str > ;
271+
272+ /// A column in a SQL table.
273+ ///
274+ /// See [`macros.column_overrides`][Config::column_overrides] for usages.
275+ pub type ColumnName = Box < str > ;
276+
277+ /// A Rust type name or path.
278+ ///
279+ /// Should be a global path (not relative).
280+ pub type RustType = Box < str > ;
281+
282+ /// Internal getter methods.
283+ impl Config {
284+ /// Get the override for a given type name (optionally schema-qualified).
285+ pub fn type_override ( & self , type_name : & str ) -> Option < & str > {
286+ self . type_overrides . get ( type_name) . map ( |s| & * * s)
287+ }
288+
289+ /// Get the override for a given column and table name (optionally schema-qualified).
290+ pub fn column_override ( & self , table : & str , column : & str ) -> Option < & str > {
291+ self . column_overrides
292+ . get ( table)
293+ . and_then ( |by_column| by_column. get ( column) )
294+ . map ( |s| & * * s)
295+ }
296+ }
0 commit comments