sqlx-core 0.9.0-alpha.1

Core of SQLx, the rust SQL toolkit. Not intended to be used directly.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
use std::collections::BTreeMap;

/// Configuration for the `query!()` family of macros.
///
/// See also [`common::Config`][crate::config::common::Config] for renaming `DATABASE_URL`.
#[derive(Debug, Default)]
#[cfg_attr(
    feature = "sqlx-toml",
    derive(serde::Deserialize),
    serde(default, rename_all = "kebab-case", deny_unknown_fields)
)]
pub struct Config {
    /// Specify which crates' types to use when types from multiple crates apply.
    ///
    /// See [`PreferredCrates`] for details.
    pub preferred_crates: PreferredCrates,

    /// Specify global overrides for mapping SQL type names to Rust type names.
    ///
    /// Default type mappings are defined by the database driver.
    /// Refer to the `sqlx::types` module for details.
    ///
    /// ## Note: Case-Sensitive
    /// Currently, the case of the type name MUST match the name SQLx knows it by.
    /// Built-in types are spelled in all-uppercase to match SQL convention.
    ///
    /// However, user-created types in Postgres are all-lowercase unless quoted.
    ///
    /// ## 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).
    ///
    /// Schema qualification should not be used for types in the search path.
    ///
    /// ## Note: Quoted Identifiers (Postgres)
    /// Type names using [quoted identifiers in Postgres] 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 Postgres, 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.
    ///
    /// MySQL/MariaDB and SQLite do not support custom types, so quoting type names should
    /// never be necessary.
    ///
    /// [quoted identifiers in Postgres]: 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.)
    // TODO: allow specifying different types for input vs output
    // e.g. to accept `&[T]` on input but output `Vec<T>`
    pub type_overrides: BTreeMap<SqlType, RustType>,

    /// Specify per-table and per-column overrides for mapping SQL types to Rust types.
    ///
    /// Default type mappings are defined by the database driver.
    /// Refer to the `sqlx::types` module for details.
    ///
    /// 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.
    ///
    /// 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
    /// Table names may be schema-qualified. 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 tables in the search path.
    ///
    /// ## Note: Quoted Identifiers
    /// Schema, table, or column names using quoted identifiers ([MySQL], [Postgres], [SQLite])
    /// in SQL must also be specified with quotes here.
    ///
    /// Postgres and SQLite use double-quotes (`"Foo"`) while MySQL uses backticks (`\`Foo\`).
    ///
    /// Note, however, that the TOML format parses way the outer pair of quotes,
    /// so for quoted names in Postgres, double-quoting is necessary,
    /// e.g. `'"Foo"'` for SQL name `"Foo"`.
    ///
    /// To reference a schema-qualified table with a quoted name, use the appropriate quotation
    /// characters 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.
    ///
    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/identifiers.html
    /// [Postgres]: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
    /// [SQLite]: https://sqlite.org/lang_keywords.html
    // 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.'foo']
    /// # Map column `bar` of table `foo` to Rust type `crate::types::Foo`:
    /// 'bar' = "crate::types::Bar"
    ///
    /// # Quoted column name
    /// # Note: same quoting requirements as `macros.type_overrides`
    /// '"Bar"' = "crate::types::Bar"
    ///
    /// # Note: will NOT work (parses as `Bar`)
    /// # "Bar" = "crate::types::Bar"
    ///
    /// # Table name may be quoted (note the wrapping single-quotes)
    /// [macros.table-overrides.'"Foo"']
    /// 'bar' = "crate::types::Bar"
    /// '"Bar"' = "crate::types::Bar"
    ///
    /// # Table name may also be schema-qualified.
    /// # Note how the dot is inside the quotes.
    /// [macros.table-overrides.'my_schema.my_table']
    /// 'my_column' = "crate::types::MyType"
    ///
    /// # Quoted schema, table, and column names
    /// [macros.table-overrides.'"My Schema"."My Table"']
    /// '"My Column"' = "crate::types::MyType"
    /// ```
    pub table_overrides: BTreeMap<TableName, BTreeMap<ColumnName, RustType>>,
}

#[derive(Debug, Default)]
#[cfg_attr(
    feature = "sqlx-toml",
    derive(serde::Deserialize),
    serde(default, rename_all = "kebab-case")
)]
pub struct PreferredCrates {
    /// 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.preferred-crates]
    /// date-time = "chrono"
    /// ```
    ///
    /// [feature unification]: https://doc.rust-lang.org/cargo/reference/features.html#feature-unification
    pub date_time: DateTimeCrate,

    /// Specify the crate to use for mapping `NUMERIC` types to Rust.
    ///
    /// The default behavior is to use whatever crate is enabled,
    /// [`bigdecimal`] or [`rust_decimal`] (the latter takes precedent).
    ///
    /// [`bigdecimal`]: crate::types::bigdecimal
    /// [`rust_decimal`]: crate::types::rust_decimal
    ///
    /// Example: Always Use `bigdecimal`
    /// -------
    /// Thanks to Cargo's [feature unification], a crate in the dependency graph may enable
    /// the `rust_decimal` 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 [`bigdecimal`].
    ///
    /// 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.preferred-crates]
    /// numeric = "bigdecimal"
    /// ```
    ///
    /// [feature unification]: https://doc.rust-lang.org/cargo/reference/features.html#feature-unification
    pub numeric: NumericCrate,
}

/// The preferred crate to use for mapping date/time types to Rust.
#[derive(Debug, Default, PartialEq, Eq)]
#[cfg_attr(
    feature = "sqlx-toml",
    derive(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.preferred-crates]
    /// date-time = "chrono"
    /// ```
    Chrono,

    /// Always use types from [`time`][crate::types::time].
    ///
    /// ```toml
    /// [macros.preferred-crates]
    /// date-time = "time"
    /// ```
    Time,
}

/// The preferred crate to use for mapping `NUMERIC` types to Rust.
#[derive(Debug, Default, PartialEq, Eq)]
#[cfg_attr(
    feature = "sqlx-toml",
    derive(serde::Deserialize),
    serde(rename_all = "snake_case")
)]
pub enum NumericCrate {
    /// Use whichever crate is enabled (`rust_decimal` then `bigdecimal`).
    #[default]
    Inferred,

    /// Always use types from [`bigdecimal`][crate::types::bigdecimal].
    ///
    /// ```toml
    /// [macros.preferred-crates]
    /// numeric = "bigdecimal"
    /// ```
    #[cfg_attr(feature = "sqlx-toml", serde(rename = "bigdecimal"))]
    BigDecimal,

    /// Always use types from [`rust_decimal`][crate::types::rust_decimal].
    ///
    /// ```toml
    /// [macros.preferred-crates]
    /// numeric = "rust_decimal"
    /// ```
    RustDecimal,
}

/// 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>;

/// Internal getter methods.
impl Config {
    /// Get the override for a given type name (optionally schema-qualified).
    pub fn type_override(&self, type_name: &str) -> Option<&str> {
        // TODO: make this case-insensitive
        self.type_overrides.get(type_name).map(|s| &**s)
    }

    /// Get the override for a given column and table name (optionally schema-qualified).
    pub fn column_override(&self, table: &str, column: &str) -> Option<&str> {
        self.table_overrides
            .get(table)
            .and_then(|by_column| by_column.get(column))
            .map(|s| &**s)
    }
}

impl DateTimeCrate {
    /// Returns `self == Self::Inferred`
    #[inline(always)]
    pub fn is_inferred(&self) -> bool {
        *self == Self::Inferred
    }

    #[inline(always)]
    pub fn crate_name(&self) -> Option<&str> {
        match self {
            Self::Inferred => None,
            Self::Chrono => Some("chrono"),
            Self::Time => Some("time"),
        }
    }
}

impl NumericCrate {
    /// Returns `self == Self::Inferred`
    #[inline(always)]
    pub fn is_inferred(&self) -> bool {
        *self == Self::Inferred
    }

    #[inline(always)]
    pub fn crate_name(&self) -> Option<&str> {
        match self {
            Self::Inferred => None,
            Self::BigDecimal => Some("bigdecimal"),
            Self::RustDecimal => Some("rust_decimal"),
        }
    }
}