From 6b248e0d5f337c93bc751fd7eeb7f3d63b874b2c Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Wed, 13 May 2020 20:30:12 -0700 Subject: [PATCH] get offline macros working with todos example --- Cargo.lock | 15 +++++++ cargo-sqlx/Cargo.toml | 5 ++- cargo-sqlx/src/bin/cargo-sqlx.rs | 18 +++++++++ cargo-sqlx/src/bin/sqlx.rs | 8 ++++ cargo-sqlx/src/{main.rs => lib.rs} | 40 +++++++++---------- cargo-sqlx/src/prepare.rs | 36 +++++++++++++---- examples/postgres/todos/Cargo.toml | 3 +- sqlx-macros/src/database/mysql.rs | 24 ++++++------ sqlx-macros/src/database/postgres.rs | 50 ++++++++++++------------ sqlx-macros/src/database/sqlite.rs | 6 ++- sqlx-macros/src/lib.rs | 7 +--- sqlx-macros/src/query_macros/data.rs | 54 +++++++++++++------------- sqlx-macros/src/query_macros/input.rs | 25 +++--------- sqlx-macros/src/query_macros/mod.rs | 22 +++++++---- sqlx-macros/src/query_macros/output.rs | 2 +- 15 files changed, 186 insertions(+), 129 deletions(-) create mode 100644 cargo-sqlx/src/bin/cargo-sqlx.rs create mode 100644 cargo-sqlx/src/bin/sqlx.rs rename cargo-sqlx/src/{main.rs => lib.rs} (78%) diff --git a/Cargo.lock b/Cargo.lock index b2760f03..4cb7bd4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -304,6 +304,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", + "cargo_metadata", "chrono", "console", "dialoguer", @@ -318,6 +319,18 @@ dependencies = [ "url 2.1.1", ] +[[package]] +name = "cargo_metadata" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8de60b887edf6d74370fc8eb177040da4847d971d6234c7b13a6da324ef0caf" +dependencies = [ + "semver", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "cc" version = "1.0.50" @@ -1650,6 +1663,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ "semver-parser", + "serde", ] [[package]] @@ -1880,6 +1894,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-std", + "dotenv", "futures 0.3.4", "paw", "sqlx", diff --git a/cargo-sqlx/Cargo.toml b/cargo-sqlx/Cargo.toml index a372e617..bd94acf4 100644 --- a/cargo-sqlx/Cargo.toml +++ b/cargo-sqlx/Cargo.toml @@ -13,12 +13,12 @@ default-run = "sqlx" [[bin]] name = "sqlx" -path = "src/main.rs" +path = "src/bin/sqlx.rs" # enables invocation as `cargo sqlx`; required for `prepare` subcommand [[bin]] name = "cargo-sqlx" -path = "src/main.rs" +path = "src/bin/cargo-sqlx.rs" [dependencies] dotenv = "0.15" @@ -35,6 +35,7 @@ dialoguer = "0.5.0" serde_json = { version = "1.0.53", features = ["preserve_order"] } serde = "1.0.110" glob = "0.3.0" +cargo_metadata = "0.10.0" [features] default = [ "postgres", "sqlite", "mysql" ] diff --git a/cargo-sqlx/src/bin/cargo-sqlx.rs b/cargo-sqlx/src/bin/cargo-sqlx.rs new file mode 100644 index 00000000..89d2709f --- /dev/null +++ b/cargo-sqlx/src/bin/cargo-sqlx.rs @@ -0,0 +1,18 @@ +use cargo_sqlx::Command; +use structopt::{clap, StructOpt}; + +use std::env; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // when invoked as `cargo sqlx [...]` the args we see are `[...]/cargo-sqlx sqlx prepare` + // so we want to notch out that superfluous "sqlx" + let args = env::args_os().skip(2); + + let matches = Command::clap() + .bin_name("cargo sqlx") + .setting(clap::AppSettings::NoBinaryName) + .get_matches_from(args); + + cargo_sqlx::run(Command::from_clap(&matches)).await +} diff --git a/cargo-sqlx/src/bin/sqlx.rs b/cargo-sqlx/src/bin/sqlx.rs new file mode 100644 index 00000000..4d9b31a6 --- /dev/null +++ b/cargo-sqlx/src/bin/sqlx.rs @@ -0,0 +1,8 @@ +use cargo_sqlx::Command; +use structopt::StructOpt; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // no special handling here + cargo_sqlx::run(Command::from_args()).await +} diff --git a/cargo-sqlx/src/main.rs b/cargo-sqlx/src/lib.rs similarity index 78% rename from cargo-sqlx/src/main.rs rename to cargo-sqlx/src/lib.rs index 7fdd5664..3ccceea3 100644 --- a/cargo-sqlx/src/main.rs +++ b/cargo-sqlx/src/lib.rs @@ -1,16 +1,16 @@ -use std::env; -use std::fs; -use std::fs::File; -use std::io::prelude::*; -use url::Url; + + + + + use dotenv::dotenv; use structopt::StructOpt; -use anyhow::{anyhow, Context}; -use console::style; -use dialoguer::Confirmation; + + + mod migrator; @@ -18,12 +18,12 @@ mod db; mod migration; mod prepare; -use migrator::DatabaseMigrator; + /// Sqlx commandline tool #[derive(StructOpt, Debug)] #[structopt(name = "Sqlx")] -enum Opt { +pub enum Command { #[structopt(alias = "mig")] Migrate(MigrationCommand), @@ -54,7 +54,7 @@ enum Opt { /// Adds and runs migrations. Alias: mig #[derive(StructOpt, Debug)] #[structopt(name = "Sqlx migrator")] -enum MigrationCommand { +pub enum MigrationCommand { /// Add new migration with name _.sql Add { name: String }, @@ -68,7 +68,7 @@ enum MigrationCommand { /// Create or drops database depending on your connection string. Alias: db #[derive(StructOpt, Debug)] #[structopt(name = "Sqlx migrator")] -enum DatabaseCommand { +pub enum DatabaseCommand { /// Create database in url Create, @@ -76,26 +76,22 @@ enum DatabaseCommand { Drop, } -#[tokio::main] -async fn main() -> anyhow::Result<()> { +pub async fn run(cmd: Command) -> anyhow::Result<()> { dotenv().ok(); - let opt = Opt::from_args(); - - match opt { - Opt::Migrate(command) => match command { + match cmd { + Command::Migrate(migrate) => match migrate { MigrationCommand::Add { name } => migration::add_file(&name)?, MigrationCommand::Run => migration::run().await?, MigrationCommand::List => migration::list().await?, }, - Opt::Database(command) => match command { + Command::Database(database) => match database { DatabaseCommand::Create => db::run_create().await?, DatabaseCommand::Drop => db::run_drop().await?, }, - Opt::Prepare { check: false } => prepare::run()?, - Opt::Prepare { check: true } => prepare::check()?, + Command::Prepare { check: false } => prepare::run()?, + Command::Prepare { check: true } => prepare::check()?, }; - println!("All done!"); Ok(()) } diff --git a/cargo-sqlx/src/prepare.rs b/cargo-sqlx/src/prepare.rs index 600724ba..d701cb9f 100644 --- a/cargo-sqlx/src/prepare.rs +++ b/cargo-sqlx/src/prepare.rs @@ -2,9 +2,11 @@ use anyhow::{anyhow, bail, Context}; use std::process::Command; use std::{env, fs}; +use cargo_metadata::MetadataCommand; use std::collections::BTreeMap; use std::fs::File; -use std::path::Path; + +use std::time::SystemTime; use url::Url; type QueryData = BTreeMap; @@ -22,10 +24,17 @@ pub fn run() -> anyhow::Result<()> { let data = run_prepare_step()?; serde_json::to_writer_pretty( - File::create("sqlx-data.json")?, + File::create("sqlx-data.json").context("failed to create/open `sqlx-data.json`")?, &DataFile { db: db_kind, data }, ) - .map_err(Into::into) + .context("failed to write to `sqlx-data.json`")?; + + println!( + "query data written to `sqlx-data.json` in the current directory; \ + please check this into version control" + ); + + Ok(()) } pub fn check() -> anyhow::Result<()> { @@ -66,12 +75,25 @@ fn run_prepare_step() -> anyhow::Result { let cargo = env::var("CARGO") .context("`prepare` subcommand may only be invoked as `cargo sqlx prepare``")?; - if !Command::new(cargo).arg("check").status()?.success() { - bail!("`cargo check` failed"); + let check_status = Command::new(&cargo) + .arg("check") + // set an always-changing env var that the macros depend on via `env!()` + .env( + "__SQLX_RECOMPILE_TRIGGER", + SystemTime::UNIX_EPOCH.elapsed()?.as_millis().to_string(), + ) + .status()?; + + if !check_status.success() { + bail!("`cargo check` failed with status: {}", check_status); } - let save_dir = env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| "target/sqlx".into()); - let pattern = Path::new(&save_dir).join("/query-*.json"); + let metadata = MetadataCommand::new() + .cargo_path(cargo) + .exec() + .context("failed to execute `cargo metadata`")?; + + let pattern = metadata.target_directory.join("sqlx/query-*.json"); let mut data = BTreeMap::new(); diff --git a/examples/postgres/todos/Cargo.toml b/examples/postgres/todos/Cargo.toml index 8136d436..4295b6b0 100644 --- a/examples/postgres/todos/Cargo.toml +++ b/examples/postgres/todos/Cargo.toml @@ -9,5 +9,6 @@ anyhow = "1.0" async-std = { version = "1.4.0", features = [ "attributes" ] } futures = "0.3" paw = "1.0" -sqlx = { path = "../../../", features = ["postgres"] } +sqlx = { path = "../../../", features = ["postgres", "offline"] } structopt = { version = "0.3", features = ["paw"] } +dotenv = "0.15.0" diff --git a/sqlx-macros/src/database/mysql.rs b/sqlx-macros/src/database/mysql.rs index 3584a15e..a0294829 100644 --- a/sqlx-macros/src/database/mysql.rs +++ b/sqlx-macros/src/database/mysql.rs @@ -1,5 +1,7 @@ +use sqlx_core as sqlx; + impl_database_ext! { - sqlx_core::mysql::MySql { + sqlx::mysql::MySql { u8, u16, u32, @@ -18,34 +20,34 @@ impl_database_ext! { Vec, #[cfg(all(feature = "chrono", not(feature = "time")))] - sqlx_core::types::chrono::NaiveTime, + sqlx::types::chrono::NaiveTime, #[cfg(all(feature = "chrono", not(feature = "time")))] - sqlx_core::types::chrono::NaiveDate, + sqlx::types::chrono::NaiveDate, #[cfg(all(feature = "chrono", not(feature = "time")))] - sqlx_core::types::chrono::NaiveDateTime, + sqlx::types::chrono::NaiveDateTime, #[cfg(all(feature = "chrono", not(feature = "time")))] - sqlx_core::types::chrono::DateTime, + sqlx::types::chrono::DateTime, #[cfg(feature = "time")] - sqlx_core::types::time::Time, + sqlx::types::time::Time, #[cfg(feature = "time")] - sqlx_core::types::time::Date, + sqlx::types::time::Date, #[cfg(feature = "time")] - sqlx_core::types::time::PrimitiveDateTime, + sqlx::types::time::PrimitiveDateTime, #[cfg(feature = "time")] - sqlx_core::types::time::OffsetDateTime, + sqlx::types::time::OffsetDateTime, #[cfg(feature = "bigdecimal")] - sqlx_core::types::BigDecimal, + sqlx::types::BigDecimal, }, ParamChecking::Weak, feature-types: info => info.type_feature_gate(), - row = sqlx_core::mysql::MySqlRow, + row = sqlx::mysql::MySqlRow, name = "MySQL/MariaDB" } diff --git a/sqlx-macros/src/database/postgres.rs b/sqlx-macros/src/database/postgres.rs index a52da8cd..bee08445 100644 --- a/sqlx-macros/src/database/postgres.rs +++ b/sqlx-macros/src/database/postgres.rs @@ -1,5 +1,7 @@ +use sqlx_core as sqlx; + impl_database_ext! { - sqlx_core::postgres::Postgres { + sqlx::postgres::Postgres { bool, String | &str, i8, @@ -13,37 +15,37 @@ impl_database_ext! { Vec | &[u8], #[cfg(feature = "uuid")] - sqlx_core::types::Uuid, + sqlx::types::Uuid, #[cfg(feature = "chrono")] - sqlx_core::types::chrono::NaiveTime, + sqlx::types::chrono::NaiveTime, #[cfg(feature = "chrono")] - sqlx_core::types::chrono::NaiveDate, + sqlx::types::chrono::NaiveDate, #[cfg(feature = "chrono")] - sqlx_core::types::chrono::NaiveDateTime, + sqlx::types::chrono::NaiveDateTime, #[cfg(feature = "chrono")] - sqlx_core::types::chrono::DateTime | sqlx_core::types::chrono::DateTime<_>, + sqlx::types::chrono::DateTime | sqlx::types::chrono::DateTime<_>, #[cfg(feature = "time")] - sqlx_core::types::time::Time, + sqlx::types::time::Time, #[cfg(feature = "time")] - sqlx_core::types::time::Date, + sqlx::types::time::Date, #[cfg(feature = "time")] - sqlx_core::types::time::PrimitiveDateTime, + sqlx::types::time::PrimitiveDateTime, #[cfg(feature = "time")] - sqlx_core::types::time::OffsetDateTime, + sqlx::types::time::OffsetDateTime, #[cfg(feature = "bigdecimal")] - sqlx_core::types::BigDecimal, + sqlx::types::BigDecimal, #[cfg(feature = "ipnetwork")] - sqlx_core::types::ipnetwork::IpNetwork, + sqlx::types::ipnetwork::IpNetwork, #[cfg(feature = "json")] serde_json::Value, @@ -61,42 +63,42 @@ impl_database_ext! { #[cfg(feature = "uuid")] - Vec | &[sqlx_core::types::Uuid], + Vec | &[sqlx::types::Uuid], #[cfg(feature = "chrono")] - Vec | &[sqlx_core::types::sqlx_core::types::chrono::NaiveTime], + Vec | &[sqlx::types::sqlx::types::chrono::NaiveTime], #[cfg(feature = "chrono")] - Vec | &[sqlx_core::types::chrono::NaiveDate], + Vec | &[sqlx::types::chrono::NaiveDate], #[cfg(feature = "chrono")] - Vec | &[sqlx_core::types::chrono::NaiveDateTime], + Vec | &[sqlx::types::chrono::NaiveDateTime], // TODO // #[cfg(feature = "chrono")] - // Vec> | &[sqlx_core::types::chrono::DateTime<_>], + // Vec> | &[sqlx::types::chrono::DateTime<_>], #[cfg(feature = "time")] - Vec | &[sqlx_core::types::time::Time], + Vec | &[sqlx::types::time::Time], #[cfg(feature = "time")] - Vec | &[sqlx_core::types::time::Date], + Vec | &[sqlx::types::time::Date], #[cfg(feature = "time")] - Vec | &[sqlx_core::types::time::PrimitiveDateTime], + Vec | &[sqlx::types::time::PrimitiveDateTime], #[cfg(feature = "time")] - Vec | &[sqlx_core::types::time::OffsetDateTime], + Vec | &[sqlx::types::time::OffsetDateTime], #[cfg(feature = "bigdecimal")] - Vec | &[sqlx_core::types::BigDecimal], + Vec | &[sqlx::types::BigDecimal], #[cfg(feature = "ipnetwork")] - Vec | &[sqlx_core::types::ipnetwork::IpNetwork], + Vec | &[sqlx::types::ipnetwork::IpNetwork], }, ParamChecking::Strong, feature-types: info => info.type_feature_gate(), - row = sqlx_core::postgres::PgRow, + row = sqlx::postgres::PgRow, name = "PostgreSQL" } diff --git a/sqlx-macros/src/database/sqlite.rs b/sqlx-macros/src/database/sqlite.rs index 72cf2f6e..685b47f5 100644 --- a/sqlx-macros/src/database/sqlite.rs +++ b/sqlx-macros/src/database/sqlite.rs @@ -1,5 +1,7 @@ +use sqlx_core as sqlx; + impl_database_ext! { - sqlx_core::sqlite::Sqlite { + sqlx::sqlite::Sqlite { bool, i32, i64, @@ -10,6 +12,6 @@ impl_database_ext! { }, ParamChecking::Weak, feature-types: _info => None, - row = sqlx_core::sqlite::SqliteRow, + row = sqlx::sqlite::SqliteRow, name = "SQLite" } diff --git a/sqlx-macros/src/lib.rs b/sqlx-macros/src/lib.rs index 99b92a77..3b1dd716 100644 --- a/sqlx-macros/src/lib.rs +++ b/sqlx-macros/src/lib.rs @@ -1,5 +1,5 @@ #![cfg_attr( - not(any(feature = "postgres", feature = "mysql")), + not(any(feature = "postgres", feature = "mysql", feature = "offline")), allow(dead_code, unused_macros, unused_imports) )] extern crate proc_macro; @@ -8,11 +8,6 @@ use proc_macro::TokenStream; use quote::quote; -#[cfg(feature = "runtime-async-std")] -use async_std::task::block_on; - -use url::Url; - type Error = Box; type Result = std::result::Result; diff --git a/sqlx-macros/src/query_macros/data.rs b/sqlx-macros/src/query_macros/data.rs index aedf2c3a..eb52f235 100644 --- a/sqlx-macros/src/query_macros/data.rs +++ b/sqlx-macros/src/query_macros/data.rs @@ -1,15 +1,6 @@ -use sqlx_core::connection::{Connect, Connection}; use sqlx_core::database::Database; use sqlx_core::describe::Describe; -use sqlx_core::executor::{Executor, RefExecutor}; -use url::Url; - -use std::fmt::{self, Display, Formatter}; - -use crate::database::DatabaseExt; -use proc_macro2::TokenStream; -use std::fs::File; -use syn::export::Span; +use sqlx_core::executor::Executor; // TODO: enable serialization #[cfg_attr(feature = "offline", derive(serde::Deserialize, serde::Serialize))] @@ -21,6 +12,7 @@ use syn::export::Span; )) )] pub struct QueryData { + #[allow(dead_code)] pub(super) query: String, pub(super) describe: Describe, #[cfg(feature = "offline")] @@ -49,10 +41,9 @@ pub mod offline { use std::fmt::{self, Formatter}; use crate::database::DatabaseExt; - use proc_macro2::{Span, TokenStream}; - use serde::de::{Deserializer, MapAccess, Visitor}; + use proc_macro2::Span; + use serde::de::{Deserializer, IgnoredAny, MapAccess, Visitor}; use sqlx_core::describe::Describe; - use sqlx_core::query::query; use std::path::Path; #[derive(serde::Deserialize)] @@ -150,9 +141,16 @@ pub mod offline { { let mut db_name: Option = None; - // unfortunately we can't avoid this copy because deserializing from `io::Read` - // doesn't support deserializing borrowed values - while let Some(key) = map.next_key::()? { + let query_data = loop { + // unfortunately we can't avoid this copy because deserializing from `io::Read` + // doesn't support deserializing borrowed values + let key = map.next_key::()?.ok_or_else(|| { + serde::de::Error::custom(format_args!( + "failed to find data for query {}", + self.hash + )) + })?; + // lazily deserialize the query data only if key == "db" { db_name = Some(map.next_value::()?); @@ -163,23 +161,27 @@ pub mod offline { let mut query_data: DynQueryData = map.next_value()?; - return if query_data.query == self.query { + if query_data.query == self.query { query_data.db_name = db_name; - query_data.hash = self.hash; - Ok(query_data) + query_data.hash = self.hash.clone(); + break query_data; } else { - Err(serde::de::Error::custom(format_args!( + return Err(serde::de::Error::custom(format_args!( "hash collision for stored queries:\n{:?}\n{:?}", self.query, query_data.query - ))) + ))); }; + } else { + // we don't care about entries that don't match our hash + let _ = map.next_value::()?; } - } + }; - Err(serde::de::Error::custom(format_args!( - "failed to find data for query {}", - self.hash - ))) + // Serde expects us to consume the whole map; fortunately they've got a convenient + // type to let us do just that + while let Some(_) = map.next_entry::()? {} + + Ok(query_data) } } } diff --git a/sqlx-macros/src/query_macros/input.rs b/sqlx-macros/src/query_macros/input.rs index a9ce0857..0757f1dc 100644 --- a/sqlx-macros/src/query_macros/input.rs +++ b/sqlx-macros/src/query_macros/input.rs @@ -2,24 +2,17 @@ use std::env; use std::fs; use proc_macro2::{Ident, Span}; -use quote::{format_ident, ToTokens}; -use syn::parse::{Parse, ParseBuffer, ParseStream}; -use syn::punctuated::Punctuated; -use syn::spanned::Spanned; -use syn::token::Group; -use syn::{Error, Expr, ExprLit, ExprPath, Lit, LitBool, LitStr, Token}; -use syn::{ExprArray, ExprGroup, Type}; - -use sqlx_core::connection::Connection; -use sqlx_core::describe::Describe; +use quote::format_ident; +use syn::parse::{Parse, ParseStream}; +use syn::{Expr, LitBool, LitStr}; +use syn::{ExprArray, Type}; /// Macro input shared by `query!()` and `query_file!()` pub struct QueryMacroInput { pub(super) src: String, + #[cfg_attr(not(feature = "offline"), allow(dead_code))] pub(super) src_span: Span, - pub(super) data_src: DataSrc, - pub(super) record_type: RecordType, // `arg0 .. argN` for N arguments @@ -34,12 +27,6 @@ enum QuerySrc { File(String), } -pub enum DataSrc { - Env(String), - DbUrl(String), - File, -} - pub enum RecordType { Given(Type), Generated, @@ -48,7 +35,6 @@ pub enum RecordType { impl Parse for QueryMacroInput { fn parse(input: ParseStream) -> syn::Result { let mut query_src: Option<(QuerySrc, Span)> = None; - let mut data_src = DataSrc::Env("DATABASE_URL".into()); let mut args: Option> = None; let mut record_type = RecordType::Generated; let mut checked = true; @@ -97,7 +83,6 @@ impl Parse for QueryMacroInput { Ok(QueryMacroInput { src: src.resolve(src_span)?, src_span, - data_src, record_type, arg_names, arg_exprs, diff --git a/sqlx-macros/src/query_macros/mod.rs b/sqlx-macros/src/query_macros/mod.rs index 26f5b574..425a84c3 100644 --- a/sqlx-macros/src/query_macros/mod.rs +++ b/sqlx-macros/src/query_macros/mod.rs @@ -1,16 +1,13 @@ use std::borrow::Cow; use std::env; -use std::fmt::Display; -use std::path::PathBuf; -use proc_macro2::{Ident, Span, TokenStream}; +use proc_macro2::{Span, TokenStream}; use syn::Type; use url::Url; pub use input::QueryMacroInput; use quote::{format_ident, quote}; use sqlx_core::connection::Connect; -use sqlx_core::connection::Connection; use sqlx_core::database::Database; use sqlx_core::describe::Describe; @@ -102,7 +99,10 @@ fn expand_from_db(input: QueryMacroInput, db_url: &str) -> crate::Result crate::Result { +pub fn expand_from_file( + input: QueryMacroInput, + file: std::path::PathBuf, +) -> crate::Result { use data::offline::DynQueryData; let query_data = DynQueryData::from_data_file(file, &input.src)?; @@ -222,6 +222,9 @@ where (#($#arg_names:expr),*) => {{ use sqlx::arguments::Arguments as _; + // lets `cargo sqlx prepare` ensure that we can always trigger a recompile + const _: Option<&'static str> = option_env!("__SQLX_RECOMPILE_TRIGGER"); + #args_tokens #output @@ -231,8 +234,13 @@ where #[cfg(feature = "offline")] { - let save_dir = env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| "target/sqlx".into()); - std::fs::create_dir_all(&save_dir); + let mut save_dir = std::path::PathBuf::from( + env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| "target/".into()), + ); + + save_dir.push("sqlx"); + + std::fs::create_dir_all(&save_dir)?; data.save_in(save_dir, input.src_span)?; } diff --git a/sqlx-macros/src/query_macros/output.rs b/sqlx-macros/src/query_macros/output.rs index ee67751e..ad19161c 100644 --- a/sqlx-macros/src/query_macros/output.rs +++ b/sqlx-macros/src/query_macros/output.rs @@ -1,6 +1,6 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; -use syn::{Path, Type}; +use syn::Type; use sqlx_core::describe::Describe;