From 60c3ece6710549f48a32f8b2760614ed823df317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Thu, 23 Jul 2020 12:57:48 -0400 Subject: [PATCH 1/7] Edit Migration and Migrator to make embedded migrations possible --- sqlx-core/src/migrate/migration.rs | 18 ++++-------------- sqlx-core/src/migrate/migrator.rs | 12 ++++++++++-- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/sqlx-core/src/migrate/migration.rs b/sqlx-core/src/migrate/migration.rs index 52396a11..0aec8ffb 100644 --- a/sqlx-core/src/migrate/migration.rs +++ b/sqlx-core/src/migrate/migration.rs @@ -2,18 +2,8 @@ use std::borrow::Cow; #[derive(Debug, Clone)] pub struct Migration { - pub(crate) version: i64, - pub(crate) description: Cow<'static, str>, - pub(crate) sql: Cow<'static, str>, - pub(crate) checksum: Cow<'static, [u8]>, -} - -impl Migration { - pub fn version(&self) -> i64 { - self.version - } - - pub fn description(&self) -> &str { - &*self.description - } + pub version: i64, + pub description: Cow<'static, str>, + pub sql: Cow<'static, str>, + pub checksum: Cow<'static, [u8]>, } diff --git a/sqlx-core/src/migrate/migrator.rs b/sqlx-core/src/migrate/migrator.rs index ba602a38..33491e4e 100644 --- a/sqlx-core/src/migrate/migrator.rs +++ b/sqlx-core/src/migrate/migrator.rs @@ -1,11 +1,12 @@ use crate::acquire::Acquire; use crate::migrate::{Migrate, MigrateError, Migration, MigrationSource}; +use std::borrow::Cow; use std::ops::Deref; use std::slice; #[derive(Debug)] pub struct Migrator { - migrations: Vec, + migrations: Cow<'static, [Migration]>, } impl Migrator { @@ -31,10 +32,17 @@ impl Migrator { S: MigrationSource<'s>, { Ok(Self { - migrations: source.resolve().await.map_err(MigrateError::Source)?, + migrations: Cow::Owned(source.resolve().await.map_err(MigrateError::Source)?), }) } + /// Creates a new instance from a static slice of migrations. + pub async fn from_static(migrations: &'static [Migration]) -> Self { + Self { + migrations: Cow::Borrowed(migrations), + } + } + /// Get an iterator over all known migrations. pub fn iter(&self) -> slice::Iter<'_, Migration> { self.migrations.iter() From e5e9665bd9f84dc9a1e016a8ce1cdf120c9bd7c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Thu, 23 Jul 2020 14:22:50 -0400 Subject: [PATCH 2/7] Add migrate! macro for embedded migrations --- Cargo.toml | 2 +- sqlx-cli/src/migrate.rs | 4 +- sqlx-core/src/migrate/migrator.rs | 2 +- sqlx-macros/Cargo.toml | 3 +- sqlx-macros/src/lib.rs | 26 +++++++++ sqlx-macros/src/migrate.rs | 91 +++++++++++++++++++++++++++++++ src/lib.rs | 4 ++ 7 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 sqlx-macros/src/migrate.rs diff --git a/Cargo.toml b/Cargo.toml index e5706e39..fd37a64d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = [ "macros", "runtime-async-std", "migrate" ] macros = [ "sqlx-macros" ] -migrate = [ "sqlx-core/migrate" ] +migrate = [ "sqlx-macros/migrate", "sqlx-core/migrate" ] # [deprecated] TLS is not possible to disable due to it being conditional on multiple features # Hopefully Cargo can handle this in the future diff --git a/sqlx-cli/src/migrate.rs b/sqlx-cli/src/migrate.rs index 45dead33..08dccf82 100644 --- a/sqlx-cli/src/migrate.rs +++ b/sqlx-cli/src/migrate.rs @@ -50,7 +50,7 @@ pub async fn info(uri: &str) -> anyhow::Result<()> { } else { style("pending").yellow() }, - migration.description(), + migration.description, ); } @@ -77,7 +77,7 @@ pub async fn run(uri: &str) -> anyhow::Result<()> { "{}/{} {} {}", style(migration.version()).cyan(), style("migrate").green(), - migration.description(), + migration.description, style(format!("({:?})", elapsed)).dim() ); } else { diff --git a/sqlx-core/src/migrate/migrator.rs b/sqlx-core/src/migrate/migrator.rs index 33491e4e..916a8df0 100644 --- a/sqlx-core/src/migrate/migrator.rs +++ b/sqlx-core/src/migrate/migrator.rs @@ -71,7 +71,7 @@ impl Migrator { } for migration in self.iter() { - if migration.version() > version { + if migration.version > version { conn.apply(migration).await?; } else { conn.validate(migration).await?; diff --git a/sqlx-macros/Cargo.toml b/sqlx-macros/Cargo.toml index 0566655d..28c7fecb 100644 --- a/sqlx-macros/Cargo.toml +++ b/sqlx-macros/Cargo.toml @@ -16,7 +16,8 @@ authors = [ proc-macro = true [features] -default = [ "runtime-async-std" ] +default = [ "runtime-async-std", "migrate" ] +migrate = [ "sha2" ] # runtimes runtime-async-std = [ "sqlx-core/runtime-async-std", "sqlx-rt/runtime-async-std" ] diff --git a/sqlx-macros/src/lib.rs b/sqlx-macros/src/lib.rs index e7d848d3..d1d64cec 100644 --- a/sqlx-macros/src/lib.rs +++ b/sqlx-macros/src/lib.rs @@ -16,6 +16,9 @@ mod database; mod derives; mod query; +#[cfg(feature = "migrate")] +mod migrate; + fn macro_result(tokens: proc_macro2::TokenStream) -> TokenStream { quote!( macro_rules! macro_result { @@ -79,6 +82,29 @@ pub fn derive_from_row(input: TokenStream) -> TokenStream { } } +#[cfg(feature = "migrate")] +#[proc_macro] +pub fn migrate(input: TokenStream) -> TokenStream { + use syn::LitStr; + + let input = syn::parse_macro_input!(input as Option); + let dir = input + .as_ref() + .map_or("migrations".to_owned(), LitStr::value); + + match migrate::expand_migrator_from_dir(dir) { + Ok(ts) => ts.into(), + Err(e) => { + if let Some(parse_err) = e.downcast_ref::() { + macro_result(parse_err.to_compile_error()) + } else { + let msg = e.to_string(); + macro_result(quote!(compile_error!(#msg))) + } + } + } +} + #[doc(hidden)] #[proc_macro_attribute] pub fn test(_attr: TokenStream, input: TokenStream) -> TokenStream { diff --git a/sqlx-macros/src/migrate.rs b/sqlx-macros/src/migrate.rs new file mode 100644 index 00000000..1b1ac224 --- /dev/null +++ b/sqlx-macros/src/migrate.rs @@ -0,0 +1,91 @@ +use proc_macro2::TokenStream; +use quote::{quote, ToTokens, TokenStreamExt}; +use sha2::{Digest, Sha384}; +use std::fs; +use std::fs::DirEntry; +use std::path::Path; + +struct QuotedMigration { + version: i64, + description: String, + sql: String, + checksum: Vec, +} + +impl ToTokens for QuotedMigration { + fn to_tokens(&self, tokens: &mut TokenStream) { + let QuotedMigration { + version, + description, + sql, + checksum, + } = &self; + + let ts = quote! { + sqlx::migrate::Migration { + version: #version, + description: std::borrow::Cow::Borrowed(#description), + sql: std::borrow::Cow::Borrowed(#sql), + checksum: std::borow::Cow::Borrowed(&[ + #(#checksum),* + ]), + } + }; + + tokens.append_all(ts.into_iter()); + } +} + +// mostly copied from sqlx-core/src/migrate/source.rs +pub(crate) fn expand_migrator_from_dir>( + dir: P, +) -> crate::Result { + let mut s = fs::read_dir(dir.as_ref().canonicalize()?)?; + let mut migrations = Vec::new(); + + while let Some(entry) = s.next() { + let entry = entry?; + if !entry.metadata()?.is_file() { + // not a file; ignore + continue; + } + + let file_name = entry.file_name(); + let file_name = file_name.to_string_lossy(); + + let parts = file_name.splitn(2, '_').collect::>(); + + if parts.len() != 2 || !parts[1].ends_with(".sql") { + // not of the format: _.sql; ignore + continue; + } + + let version: i64 = parts[0].parse()?; + + // remove the `.sql` and replace `_` with ` ` + let description = parts[1] + .trim_end_matches(".sql") + .replace('_', " ") + .to_owned(); + + let sql = fs::read_to_string(&entry.path())?; + + let checksum = Vec::from(Sha384::digest(sql.as_bytes()).as_slice()); + + migrations.push(QuotedMigration { + version, + description, + sql, + checksum, + }) + } + + // ensure that we are sorted by `VERSION ASC` + migrations.sort_by_key(|m| m.version); + + Ok(quote! { + sqlx::migrate::Migrator::from_static(&[ + #(#migrations),* + ]) + }) +} diff --git a/src/lib.rs b/src/lib.rs index 125342ba..53b01bd9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,6 +61,10 @@ pub extern crate sqlx_macros; #[doc(hidden)] pub use sqlx_macros::{FromRow, Type}; +// embedded migrations +#[cfg(all(feature = "migrate", features = "macros"))] +pub use sqlx_macros::migrate; + #[cfg(feature = "macros")] mod macros; From 8381e87d4a368433dbf2e78532c6bbbee250811a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Thu, 23 Jul 2020 15:25:13 -0400 Subject: [PATCH 3/7] Document migrate! (and small fixes) --- sqlx-core/src/migrate/migrator.rs | 2 +- sqlx-macros/src/lib.rs | 8 ++---- sqlx-macros/src/migrate.rs | 1 - src/lib.rs | 4 --- src/macros.rs | 43 +++++++++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/sqlx-core/src/migrate/migrator.rs b/sqlx-core/src/migrate/migrator.rs index 916a8df0..0ee4773d 100644 --- a/sqlx-core/src/migrate/migrator.rs +++ b/sqlx-core/src/migrate/migrator.rs @@ -37,7 +37,7 @@ impl Migrator { } /// Creates a new instance from a static slice of migrations. - pub async fn from_static(migrations: &'static [Migration]) -> Self { + pub fn from_static(migrations: &'static [Migration]) -> Self { Self { migrations: Cow::Borrowed(migrations), } diff --git a/sqlx-macros/src/lib.rs b/sqlx-macros/src/lib.rs index d1d64cec..7dc5c53e 100644 --- a/sqlx-macros/src/lib.rs +++ b/sqlx-macros/src/lib.rs @@ -87,12 +87,8 @@ pub fn derive_from_row(input: TokenStream) -> TokenStream { pub fn migrate(input: TokenStream) -> TokenStream { use syn::LitStr; - let input = syn::parse_macro_input!(input as Option); - let dir = input - .as_ref() - .map_or("migrations".to_owned(), LitStr::value); - - match migrate::expand_migrator_from_dir(dir) { + let input = syn::parse_macro_input!(input as LitStr); + match migrate::expand_migrator_from_dir(input.value()) { Ok(ts) => ts.into(), Err(e) => { if let Some(parse_err) = e.downcast_ref::() { diff --git a/sqlx-macros/src/migrate.rs b/sqlx-macros/src/migrate.rs index 1b1ac224..b0ebd0eb 100644 --- a/sqlx-macros/src/migrate.rs +++ b/sqlx-macros/src/migrate.rs @@ -2,7 +2,6 @@ use proc_macro2::TokenStream; use quote::{quote, ToTokens, TokenStreamExt}; use sha2::{Digest, Sha384}; use std::fs; -use std::fs::DirEntry; use std::path::Path; struct QuotedMigration { diff --git a/src/lib.rs b/src/lib.rs index 53b01bd9..125342ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,10 +61,6 @@ pub extern crate sqlx_macros; #[doc(hidden)] pub use sqlx_macros::{FromRow, Type}; -// embedded migrations -#[cfg(all(feature = "migrate", features = "macros"))] -pub use sqlx_macros::migrate; - #[cfg(feature = "macros")] mod macros; diff --git a/src/macros.rs b/src/macros.rs index 6cb4e635..574eee79 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -573,3 +573,46 @@ macro_rules! query_file_as_unchecked ( macro_result!($($args),*) }) ); + +/// Creates a static [Migrator][crate::migrate::Migrator] by embedding the migrations in the binary. +/// +/// The macro takes an optional migrations directory and defaults to `"migrations"` if it's not specified. +/// +/// ```rust,ignore +/// sqlx::migrate!("migrations") // same as sqlx::migrate!() +/// .run(&pool) +/// .await?; +/// ``` +/// +/// It can also be used as a static constructor. +/// +/// ```rust,ignore +/// use sqlx::migrate::Migrator; +/// +/// static MIGRATOR: Migrator = sqlx::migrate!(); +/// ``` +#[cfg(feature = "migrate")] +#[macro_export] +macro_rules! migrate { + ($dir:literal) => { + #[allow(dead_code)] + { + #[macro_use] + mod _macro_result { + $crate::sqlx_macros::migrate!($dir); + } + macro_result!() + } + }; + + () => { + #[allow(dead_code)] + { + #[macro_use] + mod _macro_result { + $crate::sqlx_macros::migrate!("migrations"); + } + macro_result!() + } + }; +} From 0eb63b7eae2a752c490ce35aac111af880c2646b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Thu, 23 Jul 2020 16:47:32 -0400 Subject: [PATCH 4/7] Fix migrate! and improve docs --- sqlx-macros/src/migrate.rs | 10 +++++++--- src/macros.rs | 14 +++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/sqlx-macros/src/migrate.rs b/sqlx-macros/src/migrate.rs index b0ebd0eb..8e18f014 100644 --- a/sqlx-macros/src/migrate.rs +++ b/sqlx-macros/src/migrate.rs @@ -83,8 +83,12 @@ pub(crate) fn expand_migrator_from_dir>( migrations.sort_by_key(|m| m.version); Ok(quote! { - sqlx::migrate::Migrator::from_static(&[ - #(#migrations),* - ]) + macro_rules! macro_result { + () => { + sqlx::migrate::Migrator::from_static(&[ + #(#migrations),* + ]) + } + } }) } diff --git a/src/macros.rs b/src/macros.rs index 574eee79..d43b2097 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -574,23 +574,23 @@ macro_rules! query_file_as_unchecked ( }) ); -/// Creates a static [Migrator][crate::migrate::Migrator] by embedding the migrations in the binary. -/// -/// The macro takes an optional migrations directory and defaults to `"migrations"` if it's not specified. +/// Embeds migrations into the binary by expanding to a static instance of [Migrator][crate::migrate::Migrator]. /// /// ```rust,ignore -/// sqlx::migrate!("migrations") // same as sqlx::migrate!() +/// sqlx::migrate!("db/migrations") /// .run(&pool) /// .await?; /// ``` /// -/// It can also be used as a static constructor. -/// /// ```rust,ignore /// use sqlx::migrate::Migrator; /// -/// static MIGRATOR: Migrator = sqlx::migrate!(); +/// static MIGRATOR: Migrator = sqlx::migrate!(); // defaults to "migrations" /// ``` +/// +/// The directory must be relative to the project root (the directory containing `Cargo.toml`), +/// unlike `include_str!()` which uses compiler internals to get the path of the file where it +/// was invoked. #[cfg(feature = "migrate")] #[macro_export] macro_rules! migrate { From 39b3e4a966aa360231e9d48afecc50e7e9f0215d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Thu, 23 Jul 2020 17:11:35 -0400 Subject: [PATCH 5/7] Normalise path resolution accross migrate! and query_file! --- sqlx-macros/src/common.rs | 37 ++++++++++++++++++++++++++++++++++ sqlx-macros/src/lib.rs | 4 +++- sqlx-macros/src/migrate.rs | 9 +++++---- sqlx-macros/src/query/input.rs | 35 +------------------------------- 4 files changed, 46 insertions(+), 39 deletions(-) create mode 100644 sqlx-macros/src/common.rs diff --git a/sqlx-macros/src/common.rs b/sqlx-macros/src/common.rs new file mode 100644 index 00000000..1e4dc374 --- /dev/null +++ b/sqlx-macros/src/common.rs @@ -0,0 +1,37 @@ +use proc_macro2::Span; +use std::env; +use std::path::{Path, PathBuf}; + +pub(crate) fn resolve_path(path: &str, err_span: Span) -> syn::Result { + let path = Path::new(path); + + if path.is_absolute() { + return Err(syn::Error::new( + err_span, + "absolute paths will only work on the current machine", + )); + } + + // requires `proc_macro::SourceFile::path()` to be stable + // https://github.com/rust-lang/rust/issues/54725 + if path.is_relative() + && !path + .parent() + .map_or(false, |parent| !parent.as_os_str().is_empty()) + { + return Err(syn::Error::new( + err_span, + "paths relative to the current file's directory are not currently supported", + )); + } + + let base_dir = env::var("CARGO_MANIFEST_DIR").map_err(|_| { + syn::Error::new( + err_span, + "CARGO_MANIFEST_DIR is not set; please use Cargo to build", + ) + })?; + let base_dir_path = Path::new(&base_dir); + + Ok(base_dir_path.join(path)) +} diff --git a/sqlx-macros/src/lib.rs b/sqlx-macros/src/lib.rs index 7dc5c53e..5c5f1c63 100644 --- a/sqlx-macros/src/lib.rs +++ b/sqlx-macros/src/lib.rs @@ -16,6 +16,8 @@ mod database; mod derives; mod query; +mod common; + #[cfg(feature = "migrate")] mod migrate; @@ -88,7 +90,7 @@ pub fn migrate(input: TokenStream) -> TokenStream { use syn::LitStr; let input = syn::parse_macro_input!(input as LitStr); - match migrate::expand_migrator_from_dir(input.value()) { + match migrate::expand_migrator_from_dir(input) { Ok(ts) => ts.into(), Err(e) => { if let Some(parse_err) = e.downcast_ref::() { diff --git a/sqlx-macros/src/migrate.rs b/sqlx-macros/src/migrate.rs index 8e18f014..fc4245f1 100644 --- a/sqlx-macros/src/migrate.rs +++ b/sqlx-macros/src/migrate.rs @@ -3,6 +3,7 @@ use quote::{quote, ToTokens, TokenStreamExt}; use sha2::{Digest, Sha384}; use std::fs; use std::path::Path; +use syn::LitStr; struct QuotedMigration { version: i64, @@ -36,10 +37,10 @@ impl ToTokens for QuotedMigration { } // mostly copied from sqlx-core/src/migrate/source.rs -pub(crate) fn expand_migrator_from_dir>( - dir: P, -) -> crate::Result { - let mut s = fs::read_dir(dir.as_ref().canonicalize()?)?; +pub(crate) fn expand_migrator_from_dir(dir: LitStr) -> crate::Result { + let path = crate::common::resolve_path(&dir.value(), dir.span())?; + let mut s = fs::read_dir(path)?; + let mut migrations = Vec::new(); while let Some(entry) = s.next() { diff --git a/sqlx-macros/src/query/input.rs b/sqlx-macros/src/query/input.rs index 7cd060df..bded9f94 100644 --- a/sqlx-macros/src/query/input.rs +++ b/sqlx-macros/src/query/input.rs @@ -108,40 +108,7 @@ impl QuerySrc { } fn read_file_src(source: &str, source_span: Span) -> syn::Result { - use std::path::Path; - - let path = Path::new(source); - - if path.is_absolute() { - return Err(syn::Error::new( - source_span, - "absolute paths will only work on the current machine", - )); - } - - // requires `proc_macro::SourceFile::path()` to be stable - // https://github.com/rust-lang/rust/issues/54725 - if path.is_relative() - && !path - .parent() - .map_or(false, |parent| !parent.as_os_str().is_empty()) - { - return Err(syn::Error::new( - source_span, - "paths relative to the current file's directory are not currently supported", - )); - } - - let base_dir = env::var("CARGO_MANIFEST_DIR").map_err(|_| { - syn::Error::new( - source_span, - "CARGO_MANIFEST_DIR is not set; please use Cargo to build", - ) - })?; - - let base_dir_path = Path::new(&base_dir); - - let file_path = base_dir_path.join(path); + let file_path = crate::common::resolve_path(source, source_span)?; fs::read_to_string(&file_path).map_err(|e| { syn::Error::new( From 92646e00b83f5c2b24e93062adbee36f148c20ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Thu, 23 Jul 2020 17:46:27 -0400 Subject: [PATCH 6/7] Fix migrate! and add migration test --- .github/workflows/sqlx.yml | 14 ++++----- Cargo.toml | 9 ++++++ sqlx-cli/src/migrate.rs | 8 ++--- sqlx-macros/src/migrate.rs | 3 +- sqlx-macros/src/query/input.rs | 1 - src/macros.rs | 30 ++++++++----------- tests/migrate/macro.rs | 17 +++++++++++ .../migrations/20200723212833_tweet.sql | 6 ++++ .../migrations/20200723212841_accounts.sql | 5 ++++ 9 files changed, 61 insertions(+), 32 deletions(-) create mode 100644 tests/migrate/macro.rs create mode 100644 tests/migrate/migrations/20200723212833_tweet.sql create mode 100644 tests/migrate/migrations/20200723212841_accounts.sql diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index de783b67..b5fa4417 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -48,14 +48,14 @@ jobs: args: > --manifest-path sqlx-core/Cargo.toml --no-default-features - --features offline,all-databases,all-types,runtime-${{ matrix.runtime }} + --features offline,all-databases,all-types,migrate,runtime-${{ matrix.runtime }} - uses: actions-rs/cargo@v1 with: command: check args: > --no-default-features - --features offline,all-databases,all-types,runtime-${{ matrix.runtime }},macros + --features offline,all-databases,all-types,migrate,runtime-${{ matrix.runtime }},macros test: name: Unit Test @@ -97,7 +97,7 @@ jobs: command: test args: > --no-default-features - --features any,macros,sqlite,all-types,runtime-${{ matrix.runtime }} + --features any,macros,migrate,sqlite,all-types,runtime-${{ matrix.runtime }} -- --test-threads=1 env: @@ -143,7 +143,7 @@ jobs: command: test args: > --no-default-features - --features any,postgres,macros,all-types,runtime-${{ matrix.runtime }} + --features any,postgres,macros,migrate,all-types,runtime-${{ matrix.runtime }} env: DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt @@ -178,7 +178,7 @@ jobs: command: test args: > --no-default-features - --features any,mysql,macros,all-types,runtime-${{ matrix.runtime }} + --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }} env: DATABASE_URL: mysql://root:password@localhost:3306/sqlx @@ -213,7 +213,7 @@ jobs: command: test args: > --no-default-features - --features any,mysql,macros,all-types,runtime-${{ matrix.runtime }} + --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }} env: DATABASE_URL: mysql://root:password@localhost:3306/sqlx @@ -248,6 +248,6 @@ jobs: command: test args: > --no-default-features - --features any,mssql,macros,all-types,runtime-${{ matrix.runtime }} + --features any,mssql,macros,migrate,all-types,runtime-${{ matrix.runtime }} env: DATABASE_URL: mssql://sa:Password123!@localhost/sqlx diff --git a/Cargo.toml b/Cargo.toml index fd37a64d..92271951 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,6 +107,15 @@ name = "any-pool" path = "tests/any/pool.rs" required-features = [ "any" ] +# +# Migrations +# + +[[test]] +name = "migrate-macro" +path = "tests/migrate/macro.rs" +required-features = [ "macros", "migrate" ] + # # SQLite # diff --git a/sqlx-cli/src/migrate.rs b/sqlx-cli/src/migrate.rs index 08dccf82..8fe7d656 100644 --- a/sqlx-cli/src/migrate.rs +++ b/sqlx-cli/src/migrate.rs @@ -44,8 +44,8 @@ pub async fn info(uri: &str) -> anyhow::Result<()> { for migration in migrator.iter() { println!( "{}/{} {}", - style(migration.version()).cyan(), - if version >= migration.version() { + style(migration.version).cyan(), + if version >= migration.version { style("installed").green() } else { style("pending").yellow() @@ -70,12 +70,12 @@ pub async fn run(uri: &str) -> anyhow::Result<()> { } for migration in migrator.iter() { - if migration.version() > version { + if migration.version > version { let elapsed = conn.apply(migration).await?; println!( "{}/{} {} {}", - style(migration.version()).cyan(), + style(migration.version).cyan(), style("migrate").green(), migration.description, style(format!("({:?})", elapsed)).dim() diff --git a/sqlx-macros/src/migrate.rs b/sqlx-macros/src/migrate.rs index fc4245f1..6d4c1f58 100644 --- a/sqlx-macros/src/migrate.rs +++ b/sqlx-macros/src/migrate.rs @@ -2,7 +2,6 @@ use proc_macro2::TokenStream; use quote::{quote, ToTokens, TokenStreamExt}; use sha2::{Digest, Sha384}; use std::fs; -use std::path::Path; use syn::LitStr; struct QuotedMigration { @@ -26,7 +25,7 @@ impl ToTokens for QuotedMigration { version: #version, description: std::borrow::Cow::Borrowed(#description), sql: std::borrow::Cow::Borrowed(#sql), - checksum: std::borow::Cow::Borrowed(&[ + checksum: std::borrow::Cow::Borrowed(&[ #(#checksum),* ]), } diff --git a/sqlx-macros/src/query/input.rs b/sqlx-macros/src/query/input.rs index bded9f94..f48373cf 100644 --- a/sqlx-macros/src/query/input.rs +++ b/sqlx-macros/src/query/input.rs @@ -1,4 +1,3 @@ -use std::env; use std::fs; use proc_macro2::{Ident, Span}; diff --git a/src/macros.rs b/src/macros.rs index d43b2097..76c01831 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -594,25 +594,19 @@ macro_rules! query_file_as_unchecked ( #[cfg(feature = "migrate")] #[macro_export] macro_rules! migrate { - ($dir:literal) => { - #[allow(dead_code)] - { - #[macro_use] - mod _macro_result { - $crate::sqlx_macros::migrate!($dir); - } - macro_result!() + ($dir:literal) => {{ + #[macro_use] + mod _macro_result { + $crate::sqlx_macros::migrate!($dir); } - }; + macro_result!() + }}; - () => { - #[allow(dead_code)] - { - #[macro_use] - mod _macro_result { - $crate::sqlx_macros::migrate!("migrations"); - } - macro_result!() + () => {{ + #[macro_use] + mod _macro_result { + $crate::sqlx_macros::migrate!("migrations"); } - }; + macro_result!() + }}; } diff --git a/tests/migrate/macro.rs b/tests/migrate/macro.rs new file mode 100644 index 00000000..3b5e49fc --- /dev/null +++ b/tests/migrate/macro.rs @@ -0,0 +1,17 @@ +use sqlx::migrate::Migrator; +use std::path::Path; + +#[sqlx_macros::test] +async fn same_output() -> anyhow::Result<()> { + let embedded = sqlx::migrate!("tests/migrate/migrations"); + let runtime = Migrator::new(Path::new("tests/migrate/migrations")).await?; + + for (e, r) in embedded.iter().zip(runtime.iter()) { + assert_eq!(e.version, r.version); + assert_eq!(e.description, r.description); + assert_eq!(e.sql, r.sql); + assert_eq!(e.checksum, r.checksum); + } + + Ok(()) +} diff --git a/tests/migrate/migrations/20200723212833_tweet.sql b/tests/migrate/migrations/20200723212833_tweet.sql new file mode 100644 index 00000000..45c09606 --- /dev/null +++ b/tests/migrate/migrations/20200723212833_tweet.sql @@ -0,0 +1,6 @@ +CREATE TABLE tweet ( + id BIGINT NOT NULL PRIMARY KEY, + text TEXT NOT NULL, + is_sent BOOLEAN NOT NULL DEFAULT TRUE, + owner_id BIGINT +); diff --git a/tests/migrate/migrations/20200723212841_accounts.sql b/tests/migrate/migrations/20200723212841_accounts.sql new file mode 100644 index 00000000..f2c0a739 --- /dev/null +++ b/tests/migrate/migrations/20200723212841_accounts.sql @@ -0,0 +1,5 @@ +CREATE TABLE accounts ( + id INTEGER NOT NULL PRIMARY KEY, + name TEXT NOT NULL, + is_active BOOLEAN +); From 435445fbd0a569fcff348c07c80f105f5f103a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Th=C3=A9riault?= Date: Thu, 23 Jul 2020 17:54:05 -0400 Subject: [PATCH 7/7] Edit migrator to make it possible to create static instances --- sqlx-core/src/migrate/migrator.rs | 9 +-------- sqlx-macros/src/migrate.rs | 8 +++++--- tests/migrate/macro.rs | 5 +++-- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/sqlx-core/src/migrate/migrator.rs b/sqlx-core/src/migrate/migrator.rs index 0ee4773d..36b38423 100644 --- a/sqlx-core/src/migrate/migrator.rs +++ b/sqlx-core/src/migrate/migrator.rs @@ -6,7 +6,7 @@ use std::slice; #[derive(Debug)] pub struct Migrator { - migrations: Cow<'static, [Migration]>, + pub migrations: Cow<'static, [Migration]>, } impl Migrator { @@ -36,13 +36,6 @@ impl Migrator { }) } - /// Creates a new instance from a static slice of migrations. - pub fn from_static(migrations: &'static [Migration]) -> Self { - Self { - migrations: Cow::Borrowed(migrations), - } - } - /// Get an iterator over all known migrations. pub fn iter(&self) -> slice::Iter<'_, Migration> { self.migrations.iter() diff --git a/sqlx-macros/src/migrate.rs b/sqlx-macros/src/migrate.rs index 6d4c1f58..29e05308 100644 --- a/sqlx-macros/src/migrate.rs +++ b/sqlx-macros/src/migrate.rs @@ -85,9 +85,11 @@ pub(crate) fn expand_migrator_from_dir(dir: LitStr) -> crate::Result { - sqlx::migrate::Migrator::from_static(&[ - #(#migrations),* - ]) + sqlx::migrate::Migrator { + migrations: std::borrow::Cow::Borrowed(&[ + #(#migrations),* + ]) + } } } }) diff --git a/tests/migrate/macro.rs b/tests/migrate/macro.rs index 3b5e49fc..9a3c1615 100644 --- a/tests/migrate/macro.rs +++ b/tests/migrate/macro.rs @@ -1,12 +1,13 @@ use sqlx::migrate::Migrator; use std::path::Path; +static EMBEDDED: Migrator = sqlx::migrate!("tests/migrate/migrations"); + #[sqlx_macros::test] async fn same_output() -> anyhow::Result<()> { - let embedded = sqlx::migrate!("tests/migrate/migrations"); let runtime = Migrator::new(Path::new("tests/migrate/migrations")).await?; - for (e, r) in embedded.iter().zip(runtime.iter()) { + for (e, r) in EMBEDDED.iter().zip(runtime.iter()) { assert_eq!(e.version, r.version); assert_eq!(e.description, r.description); assert_eq!(e.sql, r.sql);