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