diff --git a/bench/codegen.rs b/bench/codegen.rs index c9578333..75993b55 100644 --- a/bench/codegen.rs +++ b/bench/codegen.rs @@ -6,7 +6,7 @@ fn bench(c: &mut Criterion) { cornucopia::container::setup(false).unwrap(); let client = &mut cornucopia_conn().unwrap(); - cornucopia::load_schema(client, vec!["../codegen_test/schema.sql".into()]).unwrap(); + cornucopia::load_schema(client, &["../codegen_test/schema.sql"]).unwrap(); c.bench_function("codegen_sync", |b| { b.iter(|| { cornucopia::generate_live( diff --git a/bench/usage/main.rs b/bench/usage/main.rs index f6b1722c..8768c904 100644 --- a/bench/usage/main.rs +++ b/bench/usage/main.rs @@ -143,7 +143,7 @@ fn bench(c: &mut Criterion) { let conn = &mut PgConnection::establish("postgresql://postgres:postgres@127.0.0.1:5435/postgres") .unwrap(); - cornucopia::load_schema(client, vec!["usage/cornucopia_benches/schema.sql".into()]).unwrap(); + cornucopia::load_schema(client, &["usage/cornucopia_benches/schema.sql"]).unwrap(); { let mut group = c.benchmark_group("bench_trivial_query"); for size in QUERY_SIZE { diff --git a/cornucopia/src/cli.rs b/cornucopia/src/cli.rs index e83efda3..66c5c193 100644 --- a/cornucopia/src/cli.rs +++ b/cornucopia/src/cli.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use clap::{Parser, Subcommand}; use crate::{conn, container, error::Error, generate_live, generate_managed, CodegenSettings}; @@ -11,10 +13,10 @@ struct Args { podman: bool, /// Folder containing the queries #[clap(short, long, default_value = "queries/")] - queries_path: String, + queries_path: PathBuf, /// Destination folder for generated modules #[clap(short, long, default_value = "src/cornucopia.rs")] - destination: String, + destination: PathBuf, #[clap(subcommand)] action: Action, /// Generate synchronous rust code. Async otherwise. @@ -35,7 +37,7 @@ enum Action { /// Generate your modules against schema files Schema { /// SQL files containing the database schema - schema_files: Vec, + schema_files: Vec, }, } @@ -66,9 +68,9 @@ pub fn run() -> Result<(), Error> { Action::Schema { schema_files } => { // Run the generate command. If the command is unsuccessful, cleanup Cornucopia's container if let Err(e) = generate_managed( - &queries_path, - schema_files, - Some(&destination), + queries_path, + &schema_files, + Some(destination), podman, CodegenSettings { is_async: !sync, diff --git a/cornucopia/src/error.rs b/cornucopia/src/error.rs index 2bf3e918..011b343c 100644 --- a/cornucopia/src/error.rs +++ b/cornucopia/src/error.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use miette::{Diagnostic, GraphicalReportHandler, GraphicalTheme}; use thiserror::Error as ThisError; @@ -39,6 +41,6 @@ impl Error { #[derive(Debug, ThisError, Diagnostic)] #[error("Could not write your queries to destination file `{file_path}`: ({err})")] pub struct WriteOutputError { - pub(crate) file_path: String, + pub(crate) file_path: PathBuf, pub(crate) err: std::io::Error, } diff --git a/cornucopia/src/lib.rs b/cornucopia/src/lib.rs index 6547d04f..1fafda66 100644 --- a/cornucopia/src/lib.rs +++ b/cornucopia/src/lib.rs @@ -14,6 +14,8 @@ pub mod conn; /// High-level interfaces to work with Cornucopia's container manager. pub mod container; +use std::path::Path; + use postgres::Client; use codegen::generate as generate_internal; @@ -39,14 +41,14 @@ pub struct CodegenSettings { /// using a live database managed by you. If some `destination` is given, /// the generated code will be written at that path. Code generation settings are /// set using the `settings` parameter. -pub fn generate_live( +pub fn generate_live>( client: &mut Client, - queries_path: &str, - destination: Option<&str>, + queries_path: P, + destination: Option

, settings: CodegenSettings, ) -> Result { // Read - let modules = read_query_modules(queries_path)? + let modules = read_query_modules(queries_path.as_ref())? .into_iter() .map(parse_query_module) .collect::>()?; @@ -55,7 +57,7 @@ pub fn generate_live( let generated_code = generate_internal(prepared_modules, settings); // Write if let Some(d) = destination { - write_generated_code(d, &generated_code)?; + write_generated_code(d.as_ref(), &generated_code)?; }; Ok(generated_code) @@ -68,15 +70,15 @@ pub fn generate_live( /// /// By default, the container manager is Docker, but Podman can be used by setting the /// `podman` parameter to `true`. -pub fn generate_managed( - queries_path: &str, - schema_files: Vec, - destination: Option<&str>, +pub fn generate_managed>( + queries_path: P, + schema_files: &[P], + destination: Option

, podman: bool, settings: CodegenSettings, ) -> Result { // Read - let modules = read_query_modules(queries_path)? + let modules = read_query_modules(queries_path.as_ref())? .into_iter() .map(parse_query_module) .collect::>()?; @@ -88,17 +90,17 @@ pub fn generate_managed( container::cleanup(podman)?; if let Some(destination) = destination { - write_generated_code(destination, &generated_code)?; + write_generated_code(destination.as_ref(), &generated_code)?; }; Ok(generated_code) } -fn write_generated_code(destination: &str, generated_code: &str) -> Result<(), Error> { +fn write_generated_code(destination: &Path, generated_code: &str) -> Result<(), Error> { Ok( std::fs::write(destination, generated_code).map_err(|err| WriteOutputError { err, - file_path: String::from(destination), + file_path: destination.to_owned(), })?, ) } diff --git a/cornucopia/src/load_schema.rs b/cornucopia/src/load_schema.rs index bc60c854..e9f8ea58 100644 --- a/cornucopia/src/load_schema.rs +++ b/cornucopia/src/load_schema.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use miette::NamedSource; use postgres::Client; @@ -8,15 +10,16 @@ use self::error::Error; /// Loads PostgreSQL schemas into a database. /// /// Takes a list of file paths as parameter and loads them in their given order. -pub fn load_schema(client: &mut Client, paths: Vec) -> Result<(), Error> { +pub fn load_schema>(client: &mut Client, paths: &[P]) -> Result<(), Error> { for path in paths { - let sql = std::fs::read_to_string(&path).map_err(|err| Error::Io { - path: path.clone(), + let path = path.as_ref(); + let sql = std::fs::read_to_string(path).map_err(|err| Error::Io { + path: path.to_string_lossy().to_string(), err, })?; client.batch_execute(&sql).map_err(|err| { let msg = format!("{:#}", err); - let src = NamedSource::new(path, sql); + let src = NamedSource::new(path.to_string_lossy(), sql); if let Some((position, msg, help)) = db_err(&err) { Error::Postgres { msg, diff --git a/cornucopia/src/parser.rs b/cornucopia/src/parser.rs index ac954dfe..13fdad97 100644 --- a/cornucopia/src/parser.rs +++ b/cornucopia/src/parser.rs @@ -375,7 +375,7 @@ pub(crate) fn parse_query_module(info: ModuleInfo) -> Result { }) } Err(e) => Err(Error { - src: info.into(), + src: (&info).into(), err_span: e[0].span().into(), help: e[0].to_string().replace('\n', "\\n"), }), diff --git a/cornucopia/src/read_queries.rs b/cornucopia/src/read_queries.rs index 75449fa8..31ae2c41 100644 --- a/cornucopia/src/read_queries.rs +++ b/cornucopia/src/read_queries.rs @@ -1,23 +1,28 @@ +use std::{ + path::{Path, PathBuf}, + sync::Arc, +}; + use miette::NamedSource; use self::error::Error; #[derive(Debug, Clone)] pub(crate) struct ModuleInfo { - pub(crate) path: String, + pub(crate) path: PathBuf, pub(crate) name: String, - pub(crate) content: String, + pub(crate) content: Arc, } impl From for NamedSource { fn from(m: ModuleInfo) -> Self { - Self::new(m.path, m.content) + Self::new(m.path.to_string_lossy(), m.content) } } impl From<&ModuleInfo> for NamedSource { fn from(m: &ModuleInfo) -> Self { - Self::new(&m.path, m.content.clone()) + Self::new(&m.path.to_string_lossy(), m.content.clone()) } } @@ -25,11 +30,11 @@ impl From<&ModuleInfo> for NamedSource { /// /// # Error /// Returns an error if `dir_path` does not point to a valid directory or if a query file cannot be parsed. -pub(crate) fn read_query_modules(dir_path: &str) -> Result, Error> { +pub(crate) fn read_query_modules(dir_path: &Path) -> Result, Error> { let mut modules_info = Vec::new(); for entry_result in std::fs::read_dir(dir_path).map_err(|err| Error { err, - path: String::from(dir_path), + path: dir_path.to_owned(), })? { // Directory entry let entry = entry_result.map_err(|err| Error { @@ -57,9 +62,9 @@ pub(crate) fn read_query_modules(dir_path: &str) -> Result, Erro })?; modules_info.push(ModuleInfo { - path: String::from(path_buf.to_string_lossy()), + path: path_buf, name: module_name, - content: file_contents, + content: Arc::new(file_contents), }); } } @@ -69,6 +74,8 @@ pub(crate) fn read_query_modules(dir_path: &str) -> Result, Erro } pub(crate) mod error { + use std::path::PathBuf; + use miette::Diagnostic; use thiserror::Error as ThisError; @@ -76,6 +83,6 @@ pub(crate) mod error { #[error("[{path}] : {err:#}")] pub struct Error { pub(crate) err: std::io::Error, - pub(crate) path: String, + pub(crate) path: PathBuf, } } diff --git a/examples/auto_build/_build.rs b/examples/auto_build/_build.rs index 8652e278..700b9bf9 100644 --- a/examples/auto_build/_build.rs +++ b/examples/auto_build/_build.rs @@ -17,7 +17,7 @@ fn main() -> Result<(), Error> { println!("cargo:rerun-if-changed={schema_file}"); cornucopia::generate_managed( queries_path, - vec![schema_file.into()], + &[schema_file], Some(destination), false, settings, diff --git a/integration/src/main.rs b/integration/src/main.rs index eb42a1b2..f57257b8 100644 --- a/integration/src/main.rs +++ b/integration/src/main.rs @@ -153,7 +153,7 @@ fn run_errors_test( // Run codegen let result: Result<(), cornucopia::Error> = (|| { - cornucopia::load_schema(client, vec!["schema.sql".into()])?; + cornucopia::load_schema(client, &["schema.sql"])?; cornucopia::generate_live( client, "queries", @@ -222,7 +222,7 @@ fn run_codegen_test( // Load schema reset_db(client)?; - cornucopia::load_schema(client, vec![schema_path.to_string()])?; + cornucopia::load_schema(client, &[schema_path])?; // If `--apply`, then the code will be regenerated. // Otherwise, it is only checked.