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