mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-12-29 21:00:54 +00:00
feat: create sqlx.toml format
This commit is contained in:
parent
6b337668de
commit
afa3a930d2
11
Cargo.toml
11
Cargo.toml
@ -50,16 +50,21 @@ authors.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["all-databases", "_unstable-all-types"]
|
||||
features = ["all-databases", "_unstable-all-types", "_unstable-doc"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[features]
|
||||
default = ["any", "macros", "migrate", "json"]
|
||||
default = ["any", "macros", "migrate", "json", "config-all"]
|
||||
|
||||
derive = ["sqlx-macros/derive"]
|
||||
macros = ["derive", "sqlx-macros/macros"]
|
||||
migrate = ["sqlx-core/migrate", "sqlx-macros?/migrate", "sqlx-mysql?/migrate", "sqlx-postgres?/migrate", "sqlx-sqlite?/migrate"]
|
||||
|
||||
# Enable parsing of `sqlx.toml` for configuring macros, migrations, or both.
|
||||
config-macros = ["sqlx-macros?/config-macros"]
|
||||
config-migrate = ["sqlx-macros?/config-migrate"]
|
||||
config-all = ["config-macros", "config-migrate"]
|
||||
|
||||
# intended mainly for CI and docs
|
||||
all-databases = ["mysql", "sqlite", "postgres", "any"]
|
||||
_unstable-all-types = [
|
||||
@ -73,6 +78,8 @@ _unstable-all-types = [
|
||||
"uuid",
|
||||
"bit-vec",
|
||||
]
|
||||
# Render documentation that wouldn't otherwise be shown (e.g. `sqlx_core::config`).
|
||||
_unstable-doc = ["config-all", "sqlx-core/_unstable-doc"]
|
||||
|
||||
# Base runtime features without TLS
|
||||
runtime-async-std = ["_rt-async-std", "sqlx-core/_rt-async-std", "sqlx-macros?/_rt-async-std"]
|
||||
|
||||
@ -12,7 +12,7 @@ features = ["offline"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
migrate = ["sha2", "crc"]
|
||||
migrate = ["sha2", "crc", "config-migrate"]
|
||||
|
||||
any = []
|
||||
|
||||
@ -31,6 +31,12 @@ _tls-none = []
|
||||
# support offline/decoupled building (enables serialization of `Describe`)
|
||||
offline = ["serde", "either/serde"]
|
||||
|
||||
config = ["serde", "toml/parse"]
|
||||
config-macros = ["config"]
|
||||
config-migrate = ["config"]
|
||||
|
||||
_unstable-doc = ["config-macros", "config-migrate"]
|
||||
|
||||
[dependencies]
|
||||
# Runtimes
|
||||
async-std = { workspace = true, optional = true }
|
||||
@ -70,6 +76,7 @@ percent-encoding = "2.1.0"
|
||||
regex = { version = "1.5.5", optional = true }
|
||||
serde = { version = "1.0.132", features = ["derive", "rc"], optional = true }
|
||||
serde_json = { version = "1.0.73", features = ["raw_value"], optional = true }
|
||||
toml = { version = "0.8.16", optional = true }
|
||||
sha2 = { version = "0.10.0", default-features = false, optional = true }
|
||||
#sqlformat = "0.2.0"
|
||||
thiserror = "2.0.0"
|
||||
|
||||
38
sqlx-core/src/config/common.rs
Normal file
38
sqlx-core/src/config/common.rs
Normal file
@ -0,0 +1,38 @@
|
||||
/// Configuration shared by multiple components.
|
||||
#[derive(Debug, Default, serde::Deserialize)]
|
||||
pub struct Config {
|
||||
/// Override the database URL environment variable.
|
||||
///
|
||||
/// This is used by both the macros and `sqlx-cli`.
|
||||
///
|
||||
/// 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>,
|
||||
}
|
||||
296
sqlx-core/src/config/macros.rs
Normal file
296
sqlx-core/src/config/macros.rs
Normal file
@ -0,0 +1,296 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Configuration for the `query!()` family of macros.
|
||||
#[derive(Debug, Default, serde::Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct Config {
|
||||
/// 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.
|
||||
///
|
||||
/// Default type mappings are defined by the database driver.
|
||||
/// Refer to the `sqlx::types` module for details.
|
||||
///
|
||||
/// ## 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.)
|
||||
pub type_overrides: BTreeMap<SqlType, RustType>,
|
||||
|
||||
/// Specify 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.column_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.column_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.column_overrides.'my_schema.my_table']
|
||||
/// 'my_column' = "crate::types::MyType"
|
||||
///
|
||||
/// # Quoted schema, table, and column names
|
||||
/// [macros.column_overrides.'"My Schema"."My Table"']
|
||||
/// '"My Column"' = "crate::types::MyType"
|
||||
/// ```
|
||||
pub column_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.column_overrides`][Config::column_overrides] for usages.
|
||||
pub type TableName = Box<str>;
|
||||
|
||||
/// A column in a SQL table.
|
||||
///
|
||||
/// See [`macros.column_overrides`][Config::column_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> {
|
||||
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.column_overrides
|
||||
.get(table)
|
||||
.and_then(|by_column| by_column.get(column))
|
||||
.map(|s| &**s)
|
||||
}
|
||||
}
|
||||
158
sqlx-core/src/config/migrate.rs
Normal file
158
sqlx-core/src/config/migrate.rs
Normal file
@ -0,0 +1,158 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
/// Configuration for migrations when executed using `sqlx::migrate!()` or through `sqlx-cli`.
|
||||
///
|
||||
/// ### Note
|
||||
/// A manually constructed [`Migrator`][crate::migrate::Migrator] will not be aware of these
|
||||
/// configuration options. We recommend using `sqlx::migrate!()` instead.
|
||||
///
|
||||
/// ### Warning: Potential Data Loss or Corruption!
|
||||
/// Many of these options, if changed after migrations are set up,
|
||||
/// can result in data loss or corruption of a production database
|
||||
/// if the proper precautions are not taken.
|
||||
///
|
||||
/// Be sure you know what you are doing and that you read all relevant documentation _thoroughly_.
|
||||
#[derive(Debug, Default, serde::Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct Config {
|
||||
/// Override the name of the table used to track executed migrations.
|
||||
///
|
||||
/// May be schema-qualified and/or contain quotes. Defaults to `_sqlx_migrations`.
|
||||
///
|
||||
/// Potentially useful for multi-tenant databases.
|
||||
///
|
||||
/// ### Warning: Potential Data Loss or Corruption!
|
||||
/// Changing this option for a production database will likely result in data loss or corruption
|
||||
/// as the migration machinery will no longer be aware of what migrations have been applied
|
||||
/// and will attempt to re-run them.
|
||||
///
|
||||
/// You should create the new table as a copy of the existing migrations table (with contents!),
|
||||
/// and be sure all instances of your application have been migrated to the new
|
||||
/// table before deleting the old one.
|
||||
///
|
||||
/// ### Example
|
||||
/// `sqlx.toml`:
|
||||
/// ```toml
|
||||
/// [migrate]
|
||||
/// # Put `_sqlx_migrations` in schema `foo`
|
||||
/// table_name = "foo._sqlx_migrations"
|
||||
/// ```
|
||||
pub table_name: Option<Box<str>>,
|
||||
|
||||
/// Override the directory used for migrations files.
|
||||
///
|
||||
/// Relative to the crate root for `sqlx::migrate!()`, or the current directory for `sqlx-cli`.
|
||||
pub migrations_dir: Option<Box<str>>,
|
||||
|
||||
/// Specify characters that should be ignored when hashing migrations.
|
||||
///
|
||||
/// Any characters contained in the given array will be dropped when a migration is hashed.
|
||||
///
|
||||
/// ### Warning: May Change Hashes for Existing Migrations
|
||||
/// Changing the characters considered in hashing migrations will likely
|
||||
/// change the output of the hash.
|
||||
///
|
||||
/// This may require manual rectification for deployed databases.
|
||||
///
|
||||
/// ### Example: Ignore Carriage Return (`<CR>` | `\r`)
|
||||
/// Line ending differences between platforms can result in migrations having non-repeatable
|
||||
/// hashes. The most common culprit is the carriage return (`<CR>` | `\r`), which Windows
|
||||
/// uses in its line endings alongside line feed (`<LF>` | `\n`), often written `CRLF` or `\r\n`,
|
||||
/// whereas Linux and macOS use only line feeds.
|
||||
///
|
||||
/// `sqlx.toml`:
|
||||
/// ```toml
|
||||
/// [migrate]
|
||||
/// ignored_chars = ["\r"]
|
||||
/// ```
|
||||
///
|
||||
/// For projects using Git, this can also be addressed using [`.gitattributes`]:
|
||||
///
|
||||
/// ```text
|
||||
/// # Force newlines in migrations to be line feeds on all platforms
|
||||
/// migrations/*.sql text eol=lf
|
||||
/// ```
|
||||
///
|
||||
/// This may require resetting or re-checking out the migrations files to take effect.
|
||||
///
|
||||
/// [`.gitattributes`]: https://git-scm.com/docs/gitattributes
|
||||
///
|
||||
/// ### Example: Ignore all Whitespace Characters
|
||||
/// To make your migrations amenable to reformatting, you may wish to tell SQLx to ignore
|
||||
/// _all_ whitespace characters in migrations.
|
||||
///
|
||||
/// ##### Warning: Beware Syntatically Significant Whitespace!
|
||||
/// If your migrations use string literals or quoted identifiers which contain whitespace,
|
||||
/// this configuration will cause the migration machinery to ignore some changes to these.
|
||||
/// This may result in a mismatch between the development and production versions of
|
||||
/// your database.
|
||||
///
|
||||
/// `sqlx.toml`:
|
||||
/// ```toml
|
||||
/// [migrate]
|
||||
/// # Ignore common whitespace characters when hashing
|
||||
/// ignored_chars = [" ", "\t", "\r", "\n"] # Space, tab, CR, LF
|
||||
/// ```
|
||||
// Likely lower overhead for small sets than `HashSet`.
|
||||
pub ignored_chars: BTreeSet<char>,
|
||||
|
||||
/// Specify the default type of migration that `sqlx migrate create` should create by default.
|
||||
///
|
||||
/// ### Example: Use Reversible Migrations by Default
|
||||
/// `sqlx.toml`:
|
||||
/// ```toml
|
||||
/// [migrate]
|
||||
/// default_type = "reversible"
|
||||
/// ```
|
||||
pub default_type: DefaultMigrationType,
|
||||
|
||||
/// Specify the default scheme that `sqlx migrate create` should use for version integers.
|
||||
///
|
||||
/// ### Example: Use Sequential Versioning by Default
|
||||
/// `sqlx.toml`:
|
||||
/// ```toml
|
||||
/// [migrate]
|
||||
/// default_versioning = "sequential"
|
||||
/// ```
|
||||
pub default_versioning: DefaultVersioning,
|
||||
}
|
||||
|
||||
/// The default type of migration that `sqlx migrate create` should create by default.
|
||||
#[derive(Debug, Default, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum DefaultMigrationType {
|
||||
/// Create the same migration type as that of the latest existing migration,
|
||||
/// or `Simple` otherwise.
|
||||
#[default]
|
||||
Inferred,
|
||||
|
||||
/// Create a non-reversible migration (`<VERSION>_<DESCRIPTION>.sql`).
|
||||
Simple,
|
||||
|
||||
/// Create a reversible migration (`<VERSION>_<DESCRIPTION>.up.sql` and `[...].down.sql`).
|
||||
Reversible,
|
||||
}
|
||||
|
||||
/// The default scheme that `sqlx migrate create` should use for version integers.
|
||||
#[derive(Debug, Default, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum DefaultVersioning {
|
||||
/// Infer the versioning scheme from existing migrations:
|
||||
///
|
||||
/// * If the versions of the last two migrations differ by `1`, infer `Sequential`.
|
||||
/// * If only one migration exists and has version `1`, infer `Sequential`.
|
||||
/// * Otherwise, infer `Timestamp`.
|
||||
#[default]
|
||||
Inferred,
|
||||
|
||||
/// Use UTC timestamps for migration versions.
|
||||
///
|
||||
/// This is the recommended versioning format as it's less likely to collide when multiple
|
||||
/// developers are creating migrations on different branches.
|
||||
///
|
||||
/// The exact timestamp format is unspecified.
|
||||
Timestamp,
|
||||
|
||||
/// Use sequential integers for migration versions.
|
||||
Sequential,
|
||||
}
|
||||
206
sqlx-core/src/config/mod.rs
Normal file
206
sqlx-core/src/config/mod.rs
Normal file
@ -0,0 +1,206 @@
|
||||
//! (Exported for documentation only) Guide and reference for `sqlx.toml` files.
|
||||
//!
|
||||
//! To use, create a `sqlx.toml` file in your crate root (the same directory as your `Cargo.toml`).
|
||||
//! The configuration in a `sqlx.toml` configures SQLx *only* for the current crate.
|
||||
//!
|
||||
//! See the [`Config`] type and its fields for individual configuration options.
|
||||
//!
|
||||
//! See the [reference][`_reference`] for the full `sqlx.toml` file.
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
// `std::sync::OnceLock` doesn't have a stable `.get_or_try_init()`
|
||||
// because it's blocked on a stable `Try` trait.
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
/// Configuration shared by multiple components.
|
||||
///
|
||||
/// See [`common::Config`] for details.
|
||||
pub mod common;
|
||||
|
||||
/// Configuration for the `query!()` family of macros.
|
||||
///
|
||||
/// See [`macros::Config`] for details.
|
||||
#[cfg(feature = "config-macros")]
|
||||
pub mod macros;
|
||||
|
||||
/// Configuration for migrations when executed using `sqlx::migrate!()` or through `sqlx-cli`.
|
||||
///
|
||||
/// See [`migrate::Config`] for details.
|
||||
#[cfg(feature = "config-migrate")]
|
||||
pub mod migrate;
|
||||
|
||||
/// Reference for `sqlx.toml` files
|
||||
///
|
||||
/// Source: `sqlx-core/src/config/reference.toml`
|
||||
///
|
||||
/// ```toml
|
||||
#[doc = include_str!("reference.toml")]
|
||||
/// ```
|
||||
pub mod _reference {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// The parsed structure of a `sqlx.toml` file.
|
||||
#[derive(Debug, Default, serde::Deserialize)]
|
||||
pub struct Config {
|
||||
/// Configuration shared by multiple components.
|
||||
///
|
||||
/// See [`common::Config`] for details.
|
||||
pub common: common::Config,
|
||||
|
||||
/// Configuration for the `query!()` family of macros.
|
||||
///
|
||||
/// See [`macros::Config`] for details.
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(any(feature = "config-all", feature = "config-macros")))
|
||||
)]
|
||||
#[cfg(feature = "config-macros")]
|
||||
pub macros: macros::Config,
|
||||
|
||||
/// Configuration for migrations when executed using `sqlx::migrate!()` or through `sqlx-cli`.
|
||||
///
|
||||
/// See [`migrate::Config`] for details.
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(any(feature = "config-all", feature = "config-migrate")))
|
||||
)]
|
||||
#[cfg(feature = "config-migrate")]
|
||||
pub migrate: migrate::Config,
|
||||
}
|
||||
|
||||
/// Error returned from various methods of [`Config`].
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum ConfigError {
|
||||
/// The loading method expected `CARGO_MANIFEST_DIR` to be set and it wasn't.
|
||||
///
|
||||
/// This is necessary to locate the root of the crate currently being compiled.
|
||||
///
|
||||
/// See [the "Environment Variables" page of the Cargo Book][cargo-env] for details.
|
||||
///
|
||||
/// [cargo-env]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
|
||||
#[error("environment variable `CARGO_MANIFEST_DIR` must be set and valid")]
|
||||
Env(
|
||||
#[from]
|
||||
#[source]
|
||||
std::env::VarError,
|
||||
),
|
||||
|
||||
/// An I/O error occurred while attempting to read the config file at `path`.
|
||||
///
|
||||
/// This includes [`io::ErrorKind::NotFound`].
|
||||
///
|
||||
/// [`Self::not_found_path()`] will return the path if the file was not found.
|
||||
#[error("error reading config file {path:?}")]
|
||||
Read {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
error: io::Error,
|
||||
},
|
||||
|
||||
/// An error in the TOML was encountered while parsing the config file at `path`.
|
||||
///
|
||||
/// The error gives line numbers and context when printed with `Display`/`ToString`.
|
||||
#[error("error parsing config file {path:?}")]
|
||||
Parse {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
error: toml::de::Error,
|
||||
},
|
||||
}
|
||||
|
||||
impl ConfigError {
|
||||
/// If this error means the file was not found, return the path that was attempted.
|
||||
pub fn not_found_path(&self) -> Option<&Path> {
|
||||
match self {
|
||||
ConfigError::Read { path, error } if error.kind() == io::ErrorKind::NotFound => {
|
||||
Some(path)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static CACHE: OnceCell<Config> = OnceCell::new();
|
||||
|
||||
/// Internal methods for loading a `Config`.
|
||||
#[allow(clippy::result_large_err)]
|
||||
impl Config {
|
||||
/// Get the cached config, or attempt to read `$CARGO_MANIFEST_DIR/sqlx.toml`.
|
||||
///
|
||||
/// On success, the config is cached in a `static` and returned by future calls.
|
||||
///
|
||||
/// Returns `Config::default()` if the file does not exist.
|
||||
///
|
||||
/// ### Panics
|
||||
/// If the file exists but an unrecoverable error was encountered while parsing it.
|
||||
pub fn from_crate() -> &'static Self {
|
||||
Self::try_from_crate().unwrap_or_else(|e| {
|
||||
if let Some(path) = e.not_found_path() {
|
||||
// Non-fatal
|
||||
tracing::debug!("Not reading config, file {path:?} not found (error: {e})");
|
||||
CACHE.get_or_init(Config::default)
|
||||
} else {
|
||||
// In the case of migrations,
|
||||
// we can't proceed with defaults as they may be completely wrong.
|
||||
panic!("failed to read sqlx config: {e}")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the cached config, or to read `$CARGO_MANIFEST_DIR/sqlx.toml`.
|
||||
///
|
||||
/// On success, the config is cached in a `static` and returned by future calls.
|
||||
///
|
||||
/// Errors if `CARGO_MANIFEST_DIR` is not set, or if the config file could not be read.
|
||||
pub fn try_from_crate() -> Result<&'static Self, ConfigError> {
|
||||
Self::try_get_with(|| {
|
||||
let mut path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR")?);
|
||||
path.push("sqlx.toml");
|
||||
Ok(path)
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the cached config, or attempt to read `sqlx.toml` from the current working directory.
|
||||
///
|
||||
/// On success, the config is cached in a `static` and returned by future calls.
|
||||
///
|
||||
/// Errors if the config file does not exist, or could not be read.
|
||||
pub fn try_from_current_dir() -> Result<&'static Self, ConfigError> {
|
||||
Self::try_get_with(|| Ok("sqlx.toml".into()))
|
||||
}
|
||||
|
||||
/// Get the cached config, or attempt to read it from the path returned by the closure.
|
||||
///
|
||||
/// On success, the config is cached in a `static` and returned by future calls.
|
||||
///
|
||||
/// Errors if the config file does not exist, or could not be read.
|
||||
pub fn try_get_with(
|
||||
make_path: impl FnOnce() -> Result<PathBuf, ConfigError>,
|
||||
) -> Result<&'static Self, ConfigError> {
|
||||
CACHE.get_or_try_init(|| {
|
||||
let path = make_path()?;
|
||||
Self::read_from(path)
|
||||
})
|
||||
}
|
||||
|
||||
fn read_from(path: PathBuf) -> Result<Self, ConfigError> {
|
||||
// The `toml` crate doesn't provide an incremental reader.
|
||||
let toml_s = match std::fs::read_to_string(&path) {
|
||||
Ok(toml) => toml,
|
||||
Err(error) => {
|
||||
return Err(ConfigError::Read { path, error });
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: parse and lint TOML structure before deserializing
|
||||
// Motivation: https://github.com/toml-rs/toml/issues/761
|
||||
tracing::debug!("read config TOML from {path:?}:\n{toml_s}");
|
||||
|
||||
toml::from_str(&toml_s).map_err(|error| ConfigError::Parse { path, error })
|
||||
}
|
||||
}
|
||||
175
sqlx-core/src/config/reference.toml
Normal file
175
sqlx-core/src/config/reference.toml
Normal file
@ -0,0 +1,175 @@
|
||||
# `sqlx.toml` reference.
|
||||
#
|
||||
# Note: shown values are *not* defaults.
|
||||
# They are explicitly set to non-default values to test parsing.
|
||||
# Refer to the comment for a given option for its default value.
|
||||
|
||||
###############################################################################################
|
||||
|
||||
# Configuration shared by multiple components.
|
||||
[common]
|
||||
# Change the environment variable to get the database URL.
|
||||
#
|
||||
# This is used by both the macros and `sqlx-cli`.
|
||||
#
|
||||
# If not specified, defaults to `DATABASE_URL`
|
||||
database_url_var = "FOO_DATABASE_URL"
|
||||
|
||||
###############################################################################################
|
||||
|
||||
# Configuration for the `query!()` family of macros.
|
||||
[macros]
|
||||
# Force the macros to use the `chrono` crate for date/time types, even if `time` is enabled.
|
||||
#
|
||||
# Defaults to "inferred": use whichever crate is enabled (`time` takes precedence over `chrono`).
|
||||
datetime_crate = "chrono"
|
||||
|
||||
# Or, ensure the macros always prefer `time`
|
||||
# in case new date/time crates are added in the future:
|
||||
# datetime_crate = "time"
|
||||
|
||||
# Set global 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.
|
||||
#
|
||||
# Postgres users: schema qualification should not be used for types in the search path.
|
||||
#
|
||||
# ### 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.
|
||||
[macros.type_overrides]
|
||||
# Override a built-in type (map all `UUID` columns to `crate::types::MyUuid`)
|
||||
'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::isbn::ISBN13"
|
||||
|
||||
# SQL type `foo` to Rust type `crate::types::Foo`:
|
||||
'foo' = "crate::types::Foo"
|
||||
|
||||
# SQL type `"Bar"` to Rust type `crate::types::Bar`; notice the extra pair of quotes:
|
||||
'"Bar"' = "crate::types::Bar"
|
||||
|
||||
# Will NOT work (the first pair of quotes are parsed by TOML)
|
||||
# "Bar" = "crate::types::Bar"
|
||||
|
||||
# Schema qualified
|
||||
'foo.bar' = "crate::types::Bar"
|
||||
|
||||
# Schema qualified and quoted
|
||||
'foo."Bar"' = "crate::schema::foo::Bar"
|
||||
|
||||
# Quoted schema name
|
||||
'"Foo".bar' = "crate::schema::foo::Bar"
|
||||
|
||||
# Quoted schema and type name
|
||||
'"Foo"."Bar"' = "crate::schema::foo::Bar"
|
||||
|
||||
# Set per-column overrides for mapping SQL types to Rust types.
|
||||
#
|
||||
# Note: table name is required in the header.
|
||||
#
|
||||
# Postgres users: schema qualification should not be used for types in the search path.
|
||||
#
|
||||
# ### 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.
|
||||
[macros.column_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.column_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.column_overrides.'my_schema.my_table']
|
||||
'my_column' = "crate::types::MyType"
|
||||
|
||||
# Quoted schema, table, and column names
|
||||
[macros.column_overrides.'"My Schema"."My Table"']
|
||||
'"My Column"' = "crate::types::MyType"
|
||||
|
||||
###############################################################################################
|
||||
|
||||
# Configuration for migrations when executed using `sqlx::migrate!()` or through `sqlx-cli`.
|
||||
#
|
||||
# ### Note
|
||||
# A manually constructed [`Migrator`][crate::migrate::Migrator] will not be aware of these
|
||||
# configuration options. We recommend using `sqlx::migrate!()` instead.
|
||||
#
|
||||
# ### Warning: Potential Data Loss or Corruption!
|
||||
# Many of these options, if changed after migrations are set up,
|
||||
# can result in data loss or corruption of a production database
|
||||
# if the proper precautions are not taken.
|
||||
#
|
||||
# Be sure you know what you are doing and that you read all relevant documentation _thoroughly_.
|
||||
[migrate]
|
||||
# Override the name of the table used to track executed migrations.
|
||||
#
|
||||
# May be schema-qualified and/or contain quotes. Defaults to `_sqlx_migrations`.
|
||||
#
|
||||
# Potentially useful for multi-tenant databases.
|
||||
#
|
||||
# ### Warning: Potential Data Loss or Corruption!
|
||||
# Changing this option for a production database will likely result in data loss or corruption
|
||||
# as the migration machinery will no longer be aware of what migrations have been applied
|
||||
# and will attempt to re-run them.
|
||||
#
|
||||
# You should create the new table as a copy of the existing migrations table (with contents!),
|
||||
# and be sure all instances of your application have been migrated to the new
|
||||
# table before deleting the old one.
|
||||
table_name = "foo._sqlx_migrations"
|
||||
|
||||
# Override the directory used for migrations files.
|
||||
#
|
||||
# Relative to the crate root for `sqlx::migrate!()`, or the current directory for `sqlx-cli`.
|
||||
migrations_dir = "foo/migrations"
|
||||
|
||||
# Specify characters that should be ignored when hashing migrations.
|
||||
#
|
||||
# Any characters contained in the given set will be dropped when a migration is hashed.
|
||||
#
|
||||
# Defaults to an empty array (don't drop any characters).
|
||||
#
|
||||
# ### Warning: May Change Hashes for Existing Migrations
|
||||
# Changing the characters considered in hashing migrations will likely
|
||||
# change the output of the hash.
|
||||
#
|
||||
# This may require manual rectification for deployed databases.
|
||||
# ignored_chars = []
|
||||
|
||||
# Ignore Carriage Returns (`<CR>` | `\r`)
|
||||
# Note that the TOML format requires double-quoted strings to process escapes.
|
||||
# ignored_chars = ["\r"]
|
||||
|
||||
# Ignore common whitespace characters (beware syntatically significant whitespace!)
|
||||
ignored_chars = [" ", "\t", "\r", "\n"] # Space, tab, CR, LF
|
||||
|
||||
# Specify reversible migrations by default (for `sqlx migrate create`).
|
||||
#
|
||||
# Defaults to "inferred": uses the type of the last migration, or "simple" otherwise.
|
||||
default_type = "reversible"
|
||||
|
||||
# Specify simple (non-reversible) migrations by default.
|
||||
# default_type = "simple"
|
||||
|
||||
# Specify sequential versioning by default (for `sqlx migrate create`).
|
||||
#
|
||||
# Defaults to "inferred": guesses the versioning scheme from the latest migrations,
|
||||
# or "timestamp" otherwise.
|
||||
default_versioning = "sequential"
|
||||
|
||||
# Specify timestamp versioning by default.
|
||||
# default_versioning = "timestamp"
|
||||
90
sqlx-core/src/config/tests.rs
Normal file
90
sqlx-core/src/config/tests.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use crate::config::{self, Config};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[test]
|
||||
fn reference_parses_as_config() {
|
||||
let config: Config = toml::from_str(include_str!("reference.toml"))
|
||||
// The `Display` impl of `toml::Error` is *actually* more useful than `Debug`
|
||||
.unwrap_or_else(|e| panic!("expected reference.toml to parse as Config: {e}"));
|
||||
|
||||
assert_common_config(&config.common);
|
||||
|
||||
#[cfg(feature = "config-macros")]
|
||||
assert_macros_config(&config.macros);
|
||||
|
||||
#[cfg(feature = "config-migrate")]
|
||||
assert_migrate_config(&config.migrate);
|
||||
}
|
||||
|
||||
fn assert_common_config(config: &config::common::Config) {
|
||||
assert_eq!(config.database_url_var.as_deref(), Some("FOO_DATABASE_URL"));
|
||||
}
|
||||
|
||||
#[cfg(feature = "config-macros")]
|
||||
fn assert_macros_config(config: &config::macros::Config) {
|
||||
use config::macros::*;
|
||||
|
||||
assert_eq!(config.datetime_crate, DateTimeCrate::Chrono);
|
||||
|
||||
// Type overrides
|
||||
// Don't need to cover everything, just some important canaries.
|
||||
assert_eq!(config.type_override("foo"), Some("crate::types::Foo"));
|
||||
|
||||
assert_eq!(config.type_override(r#""Bar""#), Some("crate::types::Bar"),);
|
||||
|
||||
assert_eq!(
|
||||
config.type_override(r#""Foo".bar"#),
|
||||
Some("crate::schema::foo::Bar"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
config.type_override(r#""Foo"."Bar""#),
|
||||
Some("crate::schema::foo::Bar"),
|
||||
);
|
||||
|
||||
// Column overrides
|
||||
assert_eq!(
|
||||
config.column_override("foo", "bar"),
|
||||
Some("crate::types::Bar"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
config.column_override("foo", r#""Bar""#),
|
||||
Some("crate::types::Bar"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
config.column_override(r#""Foo""#, "bar"),
|
||||
Some("crate::types::Bar"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
config.column_override(r#""Foo""#, r#""Bar""#),
|
||||
Some("crate::types::Bar"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
config.column_override("my_schema.my_table", "my_column"),
|
||||
Some("crate::types::MyType"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
config.column_override(r#""My Schema"."My Table""#, r#""My Column""#),
|
||||
Some("crate::types::MyType"),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "config-migrate")]
|
||||
fn assert_migrate_config(config: &config::migrate::Config) {
|
||||
use config::migrate::*;
|
||||
|
||||
assert_eq!(config.table_name.as_deref(), Some("foo._sqlx_migrations"));
|
||||
assert_eq!(config.migrations_dir.as_deref(), Some("foo/migrations"));
|
||||
|
||||
let ignored_chars = BTreeSet::from([' ', '\t', '\r', '\n']);
|
||||
|
||||
assert_eq!(config.ignored_chars, ignored_chars);
|
||||
|
||||
assert_eq!(config.default_type, DefaultMigrationType::Reversible);
|
||||
assert_eq!(config.default_versioning, DefaultVersioning::Sequential);
|
||||
}
|
||||
@ -91,6 +91,9 @@ pub mod any;
|
||||
#[cfg(feature = "migrate")]
|
||||
pub mod testing;
|
||||
|
||||
#[cfg(feature = "config")]
|
||||
pub mod config;
|
||||
|
||||
pub use error::{Error, Result};
|
||||
|
||||
pub use either::Either;
|
||||
|
||||
@ -26,6 +26,10 @@ derive = []
|
||||
macros = []
|
||||
migrate = ["sqlx-core/migrate"]
|
||||
|
||||
config = ["sqlx-core/config"]
|
||||
config-macros = ["config", "sqlx-core/config-macros"]
|
||||
config-migrate = ["config", "sqlx-core/config-migrate"]
|
||||
|
||||
# database
|
||||
mysql = ["sqlx-mysql"]
|
||||
postgres = ["sqlx-postgres"]
|
||||
|
||||
@ -27,6 +27,9 @@ derive = ["sqlx-macros-core/derive"]
|
||||
macros = ["sqlx-macros-core/macros"]
|
||||
migrate = ["sqlx-macros-core/migrate"]
|
||||
|
||||
config-macros = ["sqlx-macros-core/config-macros"]
|
||||
config-migrate = ["sqlx-macros-core/config-migrate"]
|
||||
|
||||
# database
|
||||
mysql = ["sqlx-macros-core/mysql"]
|
||||
postgres = ["sqlx-macros-core/postgres"]
|
||||
|
||||
@ -164,3 +164,6 @@ pub mod prelude {
|
||||
pub use super::Statement;
|
||||
pub use super::Type;
|
||||
}
|
||||
|
||||
#[cfg(feature = "_unstable-doc")]
|
||||
pub use sqlx_core::config;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user