From 644d37a8d11ec30c5ceed08b36f2a5175bcd5b04 Mon Sep 17 00:00:00 2001 From: Virgiel <> Date: Tue, 15 Nov 2022 15:44:18 +0100 Subject: [PATCH 1/3] Use Path/PathBuf for fs paths --- bench/codegen.rs | 6 +++--- bench/usage/main.rs | 2 +- cornucopia/src/cli.rs | 10 ++++++---- cornucopia/src/error.rs | 4 +++- cornucopia/src/lib.rs | 16 +++++++++------- cornucopia/src/load_schema.rs | 10 ++++++---- cornucopia/src/parser.rs | 2 +- cornucopia/src/read_queries.rs | 25 ++++++++++++++++--------- examples/auto_build/_build.rs | 2 +- integration/src/main.rs | 12 ++++++------ 10 files changed, 52 insertions(+), 37 deletions(-) diff --git a/bench/codegen.rs b/bench/codegen.rs index c9578333..e496894b 100644 --- a/bench/codegen.rs +++ b/bench/codegen.rs @@ -6,12 +6,12 @@ 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".into()]).unwrap(); c.bench_function("codegen_sync", |b| { b.iter(|| { cornucopia::generate_live( client, - "../codegen_test/queries", + "../codegen_test/queries".as_ref(), None, CodegenSettings { is_async: false, @@ -25,7 +25,7 @@ fn bench(c: &mut Criterion) { b.iter(|| { cornucopia::generate_live( client, - "../codegen_test/queries", + "../codegen_test/queries".as_ref(), None, CodegenSettings { is_async: true, diff --git a/bench/usage/main.rs b/bench/usage/main.rs index f6b1722c..e33a5b2a 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".into()]).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..804d86a4 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, }, } @@ -67,7 +69,7 @@ pub fn run() -> Result<(), Error> { // Run the generate command. If the command is unsuccessful, cleanup Cornucopia's container if let Err(e) = generate_managed( &queries_path, - schema_files, + &schema_files, Some(&destination), podman, CodegenSettings { 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..b1084d27 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, PathBuf}; + use postgres::Client; use codegen::generate as generate_internal; @@ -41,8 +43,8 @@ pub struct CodegenSettings { /// set using the `settings` parameter. pub fn generate_live( client: &mut Client, - queries_path: &str, - destination: Option<&str>, + queries_path: &Path, + destination: Option<&Path>, settings: CodegenSettings, ) -> Result { // Read @@ -69,9 +71,9 @@ 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>, + queries_path: &Path, + schema_files: &[PathBuf], + destination: Option<&Path>, podman: bool, settings: CodegenSettings, ) -> Result { @@ -94,11 +96,11 @@ pub fn generate_managed( 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..7af5a90c 100644 --- a/cornucopia/src/load_schema.rs +++ b/cornucopia/src/load_schema.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use miette::NamedSource; use postgres::Client; @@ -8,15 +10,15 @@ 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: &[PathBuf]) -> Result<(), Error> { for path in paths { - let sql = std::fs::read_to_string(&path).map_err(|err| Error::Io { - path: path.clone(), + 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..b456ca1a 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.into()], Some(destination), false, settings, diff --git a/integration/src/main.rs b/integration/src/main.rs index eb42a1b2..2e32e2ad 100644 --- a/integration/src/main.rs +++ b/integration/src/main.rs @@ -153,10 +153,10 @@ 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".into()])?; cornucopia::generate_live( client, - "queries", + "queries".as_ref(), None, CodegenSettings { is_async: false, @@ -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.into()])?; // If `--apply`, then the code will be regenerated. // Otherwise, it is only checked. @@ -230,8 +230,8 @@ fn run_codegen_test( // Generate cornucopia::generate_live( client, - queries_path, - Some(destination), + queries_path.as_ref(), + Some(destination.as_ref()), CodegenSettings { is_async, derive_ser, @@ -249,7 +249,7 @@ fn run_codegen_test( // Generate new file let new_codegen = cornucopia::generate_live( client, - queries_path, + queries_path.as_ref(), None, CodegenSettings { is_async, From 7ac1025528cc190b1290e9edc179aa618e10c662 Mon Sep 17 00:00:00 2001 From: Virgiel <> Date: Sat, 10 Dec 2022 21:02:54 +0100 Subject: [PATCH 2/3] More ergonomic API --- bench/codegen.rs | 6 +++--- bench/usage/main.rs | 2 +- cornucopia/src/lib.rs | 20 ++++++++++---------- cornucopia/src/load_schema.rs | 5 +++-- integration/src/main.rs | 12 ++++++------ 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/bench/codegen.rs b/bench/codegen.rs index e496894b..75993b55 100644 --- a/bench/codegen.rs +++ b/bench/codegen.rs @@ -6,12 +6,12 @@ fn bench(c: &mut Criterion) { cornucopia::container::setup(false).unwrap(); let client = &mut cornucopia_conn().unwrap(); - cornucopia::load_schema(client, &["../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( client, - "../codegen_test/queries".as_ref(), + "../codegen_test/queries", None, CodegenSettings { is_async: false, @@ -25,7 +25,7 @@ fn bench(c: &mut Criterion) { b.iter(|| { cornucopia::generate_live( client, - "../codegen_test/queries".as_ref(), + "../codegen_test/queries", None, CodegenSettings { is_async: true, diff --git a/bench/usage/main.rs b/bench/usage/main.rs index e33a5b2a..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, &["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/lib.rs b/cornucopia/src/lib.rs index b1084d27..a2cbc881 100644 --- a/cornucopia/src/lib.rs +++ b/cornucopia/src/lib.rs @@ -41,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: &Path, - destination: Option<&Path>, + 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::>()?; @@ -57,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) @@ -70,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: &Path, +pub fn generate_managed>( + queries_path: P, schema_files: &[PathBuf], - destination: Option<&Path>, + 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::>()?; @@ -90,7 +90,7 @@ 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) diff --git a/cornucopia/src/load_schema.rs b/cornucopia/src/load_schema.rs index 7af5a90c..e9f8ea58 100644 --- a/cornucopia/src/load_schema.rs +++ b/cornucopia/src/load_schema.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::path::Path; use miette::NamedSource; use postgres::Client; @@ -10,8 +10,9 @@ 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: &[PathBuf]) -> Result<(), Error> { +pub fn load_schema>(client: &mut Client, paths: &[P]) -> Result<(), Error> { for path in paths { + 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, diff --git a/integration/src/main.rs b/integration/src/main.rs index 2e32e2ad..f57257b8 100644 --- a/integration/src/main.rs +++ b/integration/src/main.rs @@ -153,10 +153,10 @@ fn run_errors_test( // Run codegen let result: Result<(), cornucopia::Error> = (|| { - cornucopia::load_schema(client, &["schema.sql".into()])?; + cornucopia::load_schema(client, &["schema.sql"])?; cornucopia::generate_live( client, - "queries".as_ref(), + "queries", None, CodegenSettings { is_async: false, @@ -222,7 +222,7 @@ fn run_codegen_test( // Load schema reset_db(client)?; - cornucopia::load_schema(client, &[schema_path.into()])?; + cornucopia::load_schema(client, &[schema_path])?; // If `--apply`, then the code will be regenerated. // Otherwise, it is only checked. @@ -230,8 +230,8 @@ fn run_codegen_test( // Generate cornucopia::generate_live( client, - queries_path.as_ref(), - Some(destination.as_ref()), + queries_path, + Some(destination), CodegenSettings { is_async, derive_ser, @@ -249,7 +249,7 @@ fn run_codegen_test( // Generate new file let new_codegen = cornucopia::generate_live( client, - queries_path.as_ref(), + queries_path, None, CodegenSettings { is_async, From 6e4f3347111cacab02d149ca1448d6ec78131b8b Mon Sep 17 00:00:00 2001 From: Virgiel <> Date: Sat, 10 Dec 2022 23:16:02 +0100 Subject: [PATCH 3/3] More ergonomic API --- cornucopia/src/cli.rs | 4 ++-- cornucopia/src/lib.rs | 4 ++-- examples/auto_build/_build.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cornucopia/src/cli.rs b/cornucopia/src/cli.rs index 804d86a4..66c5c193 100644 --- a/cornucopia/src/cli.rs +++ b/cornucopia/src/cli.rs @@ -68,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, + queries_path, &schema_files, - Some(&destination), + Some(destination), podman, CodegenSettings { is_async: !sync, diff --git a/cornucopia/src/lib.rs b/cornucopia/src/lib.rs index a2cbc881..1fafda66 100644 --- a/cornucopia/src/lib.rs +++ b/cornucopia/src/lib.rs @@ -14,7 +14,7 @@ pub mod conn; /// High-level interfaces to work with Cornucopia's container manager. pub mod container; -use std::path::{Path, PathBuf}; +use std::path::Path; use postgres::Client; @@ -72,7 +72,7 @@ pub fn generate_live>( /// `podman` parameter to `true`. pub fn generate_managed>( queries_path: P, - schema_files: &[PathBuf], + schema_files: &[P], destination: Option

, podman: bool, settings: CodegenSettings, diff --git a/examples/auto_build/_build.rs b/examples/auto_build/_build.rs index b456ca1a..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, - &[schema_file.into()], + &[schema_file], Some(destination), false, settings,