Skip to main content

sqlx_macros_core/
lib.rs

1//! Support crate for SQLx's proc macros.
2//!
3//! ### Note: Semver Exempt API
4//! The API of this crate is not meant for general use and does *not* follow Semantic Versioning.
5//! The only crate that follows Semantic Versioning in the project is the `sqlx` crate itself.
6//! If you are building a custom SQLx driver, you should pin an exact version of this and
7//! `sqlx-core` to avoid breakages:
8//!
9//! ```toml
10//! sqlx-core = "=0.6.2"
11//! sqlx-macros-core = "=0.6.2"
12//! ```
13//!
14//! And then make releases in lockstep with `sqlx-core`. We recommend all driver crates, in-tree
15//! or otherwise, use the same version numbers as `sqlx-core` to avoid confusion.
16
17#![cfg_attr(
18    any(sqlx_macros_unstable, procmacro2_semver_exempt),
19    feature(proc_macro_tracked_path, proc_macro_tracked_env)
20)]
21
22#[cfg(any(sqlx_macros_unstable, procmacro2_semver_exempt))]
23extern crate proc_macro;
24
25use cfg_if::cfg_if;
26use std::path::PathBuf;
27
28#[cfg(feature = "macros")]
29use crate::query::QueryDriver;
30
31pub type Error = Box<dyn std::error::Error>;
32
33pub type Result<T, E = Error> = std::result::Result<T, E>;
34
35mod common;
36pub mod database;
37
38#[cfg(feature = "derive")]
39pub mod derives;
40#[cfg(feature = "macros")]
41pub mod query;
42
43#[cfg(feature = "macros")]
44// The compiler gives misleading help messages about `#[cfg(test)]` when this is just named `test`.
45pub mod test_attr;
46
47#[cfg(feature = "migrate")]
48pub mod migrate;
49
50#[cfg(feature = "macros")]
51pub const FOSS_DRIVERS: &[QueryDriver] = &[
52    #[cfg(feature = "mysql")]
53    QueryDriver::new::<sqlx_mysql::MySql>(),
54    #[cfg(feature = "postgres")]
55    QueryDriver::new::<sqlx_postgres::Postgres>(),
56    #[cfg(feature = "_sqlite")]
57    QueryDriver::new::<sqlx_sqlite::Sqlite>(),
58];
59
60pub fn block_on<F>(f: F) -> F::Output
61where
62    F: std::future::Future,
63{
64    cfg_if! {
65        if #[cfg(feature = "_rt-async-global-executor")] {
66            sqlx_core::rt::test_block_on(f)
67        } else if #[cfg(feature = "_rt-async-std")] {
68            async_std::task::block_on(f)
69        } else if #[cfg(feature = "_rt-smol")] {
70            sqlx_core::rt::test_block_on(f)
71        } else if #[cfg(feature = "_rt-tokio")] {
72            use std::sync::LazyLock;
73
74            use tokio::runtime::{self, Runtime};
75
76            // We need a single, persistent Tokio runtime since we're caching connections,
77            // otherwise we'll get "IO driver has terminated" errors.
78            static TOKIO_RT: LazyLock<Runtime> = LazyLock::new(|| {
79                runtime::Builder::new_current_thread()
80                    .enable_all()
81                    .build()
82                    .expect("failed to start Tokio runtime")
83            });
84
85            TOKIO_RT.block_on(f)
86        } else {
87            sqlx_core::rt::missing_rt(f)
88        }
89    }
90}
91
92pub fn env(var: &str) -> Result<String> {
93    env_opt(var)?
94        .ok_or_else(|| format!("env var {var:?} must be set to use the query macros").into())
95}
96
97#[allow(clippy::disallowed_methods)]
98pub fn env_opt(var: &str) -> Result<Option<String>> {
99    use std::env::VarError;
100
101    #[cfg(any(sqlx_macros_unstable, procmacro2_semver_exempt))]
102    let res: Result<String, VarError> = proc_macro::tracked::env_var(var);
103
104    #[cfg(not(any(sqlx_macros_unstable, procmacro2_semver_exempt)))]
105    let res: Result<String, VarError> = std::env::var(var);
106
107    match res {
108        Ok(val) => Ok(Some(val)),
109        Err(VarError::NotPresent) => Ok(None),
110        Err(VarError::NotUnicode(_)) => Err(format!("env var {var:?} is not valid UTF-8").into()),
111    }
112}
113
114pub fn manifest_dir() -> Result<PathBuf> {
115    Ok(env("CARGO_MANIFEST_DIR")?.into())
116}