Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQLite extension loading via sqlx.toml for CLI and query macros #3713

Open
wants to merge 4 commits into
base: sqlx-toml
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sqlx-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pub async fn run(opt: Opt) -> Result<()> {

/// Attempt to connect to the database server, retrying up to `ops.connect_timeout`.
async fn connect(opts: &ConnectOpts) -> anyhow::Result<AnyConnection> {
retry_connect_errors(opts, AnyConnection::connect).await
retry_connect_errors(opts, AnyConnection::connect_with_config).await
}

/// Attempt an operation that may return errors like `ConnectionRefused`,
Expand Down
14 changes: 14 additions & 0 deletions sqlx-core/src/any/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ impl AnyConnection {
})
}

/// UNSTABLE: for use with `sqlx-cli`
///
/// Connect to the database, and instruct the nested driver to
/// read options from the sqlx.toml file as appropriate.
#[doc(hidden)]
pub fn connect_with_config(url: &str) -> BoxFuture<'static, Result<Self, Error>>
where
Self: Sized,
{
let options: Result<AnyConnectOptions, Error> = url.parse();

Box::pin(async move { Self::connect_with(&options?.allow_config_file()).await })
}

pub(crate) fn connect_with_db<DB: Database>(
options: &AnyConnectOptions,
) -> BoxFuture<'_, crate::Result<Self>>
Expand Down
15 changes: 15 additions & 0 deletions sqlx-core/src/any/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use url::Url;
pub struct AnyConnectOptions {
pub database_url: Url,
pub log_settings: LogSettings,
pub enable_config: bool,
}
impl FromStr for AnyConnectOptions {
type Err = Error;
Expand All @@ -29,6 +30,7 @@ impl FromStr for AnyConnectOptions {
.parse::<Url>()
.map_err(|e| Error::Configuration(e.into()))?,
log_settings: LogSettings::default(),
enable_config: false,
})
}
}
Expand All @@ -40,6 +42,7 @@ impl ConnectOptions for AnyConnectOptions {
Ok(AnyConnectOptions {
database_url: url.clone(),
log_settings: LogSettings::default(),
enable_config: false,
})
}

Expand All @@ -63,3 +66,15 @@ impl ConnectOptions for AnyConnectOptions {
self
}
}

impl AnyConnectOptions {
/// UNSTABLE: for use with `sqlx-cli`
///
/// Allow nested drivers to extract configuration information from
/// the sqlx.toml file.
#[doc(hidden)]
pub fn allow_config_file(mut self) -> Self {
self.enable_config = true;
self
}
}
39 changes: 39 additions & 0 deletions sqlx-core/src/config/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,49 @@ pub struct Config {
/// 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>,

/// Settings for specific database drivers.
///
/// These settings apply when checking queries, or when applying
/// migrations via `sqlx-cli`. These settings *do not* apply when
/// applying migrations via the macro, as that uses the run-time
/// database connection configured by the application.
pub drivers: Drivers,
}

impl Config {
pub fn database_url_var(&self) -> &str {
self.database_url_var.as_deref().unwrap_or("DATABASE_URL")
}
}

/// Configuration for specific database drivers.
#[derive(Debug, Default)]
#[cfg_attr(
feature = "sqlx-toml",
derive(serde::Deserialize),
serde(default, rename_all = "kebab-case")
)]
pub struct Drivers {
/// Specify options for the SQLite driver.
pub sqlite: SQLite,
}

/// Configuration for the SQLite database driver.
#[derive(Debug, Default)]
#[cfg_attr(
feature = "sqlx-toml",
derive(serde::Deserialize),
serde(default, rename_all = "kebab-case")
)]
pub struct SQLite {
/// Specify extensions to load.
///
/// ### Example: Load the "uuid" and "vsv" extensions
/// `sqlx.toml`:
/// ```toml
/// [common.drivers.sqlite]
/// load-extensions = ["uuid", "vsv"]
/// ```
pub load_extensions: Vec<String>,
}
6 changes: 6 additions & 0 deletions sqlx-core/src/config/reference.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
# If not specified, defaults to `DATABASE_URL`
database-url-var = "FOO_DATABASE_URL"

[common.drivers.sqlite]
# Load extensions into SQLite when running macros or migrations
#
# Defaults to an empty list, which has no effect.
load-extensions = ["uuid", "vsv"]

###############################################################################################

# Configuration for the `query!()` family of macros.
Expand Down
8 changes: 8 additions & 0 deletions sqlx-sqlite/src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ impl<'a> TryFrom<&'a AnyConnectOptions> for SqliteConnectOptions {
fn try_from(opts: &'a AnyConnectOptions) -> Result<Self, Self::Error> {
let mut opts_out = SqliteConnectOptions::from_url(&opts.database_url)?;
opts_out.log_settings = opts.log_settings.clone();

if opts.enable_config {
let config = sqlx_core::config::Config::from_crate();
for extension in config.common.drivers.sqlite.load_extensions.iter() {
opts_out = opts_out.extension(extension);
}
}

Ok(opts_out)
}
}
Expand Down
9 changes: 8 additions & 1 deletion sqlx-sqlite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,15 @@ pub static CREATE_DB_WAL: AtomicBool = AtomicBool::new(true);
/// UNSTABLE: for use by `sqlite-macros-core` only.
#[doc(hidden)]
pub fn describe_blocking(query: &str, database_url: &str) -> Result<Describe<Sqlite>, Error> {
let opts: SqliteConnectOptions = database_url.parse()?;
let mut opts: SqliteConnectOptions = database_url.parse()?;

let config = sqlx_core::config::Config::from_crate();
for extension in config.common.drivers.sqlite.load_extensions.iter() {
opts = opts.extension(extension);
}

let params = EstablishParams::from_options(&opts)?;

let mut conn = params.establish()?;

// Execute any ancillary `PRAGMA`s
Expand Down
Loading