diff --git a/src/bin/main.rs b/src/bin/main.rs index ea4adf11..2f878980 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,7 +1,7 @@ use clap::{CommandFactory, Parser, Subcommand, ValueEnum}; use clap_complete::{generate, Shell}; use dsync::{error::IOErrorToError, GenerationConfig, TableOptions}; -use dsync::{BytesType, FileChangeStatus, StringType}; +use dsync::{BytesType, FileChangeStatus, GenerationConfigOpts, StringType}; use std::collections::HashMap; use std::io::{BufWriter, Write}; use std::path::PathBuf; @@ -79,11 +79,11 @@ pub struct MainOptions { pub no_serde: bool, /// Set custom schema use path - #[arg(long = "schema-path", default_value = "crate::schema::")] + #[arg(long = "schema-path", default_value = dsync::DEFAULT_SCHEMA_PATH)] pub schema_path: String, /// Set custom model use path - #[arg(long = "model-path", default_value = "crate::models::")] + #[arg(long = "model-path", default_value = dsync::DEFAULT_MODEL_PATH)] pub model_path: String, /// Do not generate the CRUD (impl) functions for generated models @@ -242,15 +242,17 @@ fn actual_main() -> dsync::Result<()> { &args.input, &args.output, GenerationConfig { - default_table_options, - table_options: HashMap::from([]), connection_type: args.connection_type, - schema_path: args.schema_path, - model_path: args.model_path, - once_common_structs: args.once_common_structs, - once_connection_type: args.once_connection_type, - readonly_prefixes: args.readonly_prefixes, - readonly_suffixes: args.readonly_suffixes, + options: GenerationConfigOpts { + default_table_options, + table_options: HashMap::from([]), + schema_path: args.schema_path, + model_path: args.model_path, + once_common_structs: args.once_common_structs, + once_connection_type: args.once_connection_type, + readonly_prefixes: args.readonly_prefixes, + readonly_suffixes: args.readonly_suffixes, + }, }, )?; diff --git a/src/code.rs b/src/code.rs index b2badce4..4fbd76d6 100644 --- a/src/code.rs +++ b/src/code.rs @@ -475,14 +475,14 @@ fn build_table_fns( let (async_keyword, await_keyword) = get_async(&table_options); let struct_name = &table.struct_name; - let schema_path = &config.schema_path; + let schema_path = config.get_schema_path(); let create_struct_identifier = &create_struct.identifier; let update_struct_identifier = &update_struct.identifier; let is_readonly = table_options.get_readonly(); let mut buffer = String::new(); - if !config.once_common_structs { + if !config.get_once_common_structs() { buffer.push_str(&generate_common_structs(&table_options)); buffer.push('\n'); } @@ -647,7 +647,7 @@ fn build_imports(table: &ParsedTableMacro, config: &GenerationConfig) -> String "use {model_path}{foreign_table_name_model}::{singular_struct_name};", foreign_table_name_model = get_table_module_name(&fk.0.to_string()), singular_struct_name = fk.0.to_string().to_pascal_case(), - model_path = config.model_path + model_path = config.get_model_path() ) })); #[cfg(feature = "async")] @@ -656,14 +656,14 @@ fn build_imports(table: &ParsedTableMacro, config: &GenerationConfig) -> String } // no "::" because that is already included in the schema_path - imports_vec.push(format!("use {}*;", config.schema_path)); + imports_vec.push(format!("use {}*;", config.get_schema_path())); - if config.once_common_structs || config.once_connection_type { - imports_vec.push(format!("use {}common::*;", config.model_path)); + if config.any_once_option() { + imports_vec.push(format!("use {}common::*;", config.get_model_path())); }; // this needs to be last, because it not really is a import, so it would split the import sections - if table_options.get_fns() && !config.once_connection_type { + if table_options.get_fns() && !config.get_once_connection_type() { imports_vec.push(String::new()); imports_vec.push(generate_connection_type(config)); }; diff --git a/src/global.rs b/src/global.rs index 93191623..f80ad413 100644 --- a/src/global.rs +++ b/src/global.rs @@ -306,22 +306,12 @@ impl<'a> Default for TableOptions<'a> { } } -/// Global config, not table specific #[derive(Debug, Clone)] -pub struct GenerationConfig<'a> { +pub struct GenerationConfigOpts<'a> { /// Specific Table options for a given table pub table_options: HashMap<&'a str, TableOptions<'a>>, /// Default table options, used when not in `table_options` pub default_table_options: TableOptions<'a>, - /// Connection type to insert - /// - /// For example: - /// - `diesel::pg::PgConnection` - /// - `diesel::sqlite::SqliteConnection` - /// - `diesel::mysql::MysqlConnection` - /// - `diesel::r2d2::PooledConnection>` - /// - or, your custom diesel connection type (struct which implements `diesel::connection::Connection`) - pub connection_type: String, /// Diesel schema import path /// /// by default `crate::schema::` @@ -340,7 +330,7 @@ pub struct GenerationConfig<'a> { pub readonly_suffixes: Vec, } -impl GenerationConfig<'_> { +impl GenerationConfigOpts<'_> { pub fn table(&self, name: &str) -> TableOptions<'_> { let table = self .table_options @@ -358,3 +348,112 @@ impl GenerationConfig<'_> { table } } + +pub const DEFAULT_SCHEMA_PATH: &str = "crate::schema::"; +pub const DEFAULT_MODEL_PATH: &str = "crate::models::"; + +impl Default for GenerationConfigOpts<'_> { + fn default() -> Self { + Self { + table_options: HashMap::default(), + default_table_options: Default::default(), + schema_path: String::from(DEFAULT_SCHEMA_PATH), + model_path: String::from(DEFAULT_MODEL_PATH), + once_common_structs: false, + once_connection_type: false, + readonly_prefixes: Vec::default(), + readonly_suffixes: Vec::default(), + } + } +} + +/// Global config, not table specific +#[derive(Debug, Clone)] +pub struct GenerationConfig<'a> { + /// Connection type to insert + /// + /// For example: + /// - `diesel::pg::PgConnection` + /// - `diesel::sqlite::SqliteConnection` + /// - `diesel::mysql::MysqlConnection` + /// - `diesel::r2d2::PooledConnection>` + /// - or, your custom diesel connection type (struct which implements `diesel::connection::Connection`) + pub connection_type: String, + + /// Optional Options + /// ``` + /// GenerationConfig { + /// // ... all required options + /// # connection_type: String::default() + /// options: Default::default(), + /// } + /// // or + /// GenerationConfig { + /// // ... all required options + /// # connection_type: String::default() + /// options: GenerationConfigOpts { + /// ..Default::default() + /// }, + /// } + /// ``` + pub options: GenerationConfigOpts<'a>, +} + +impl<'a> GenerationConfig<'a> { + /// Create a new Instance with default [GenerationConfigOpts] + /// + /// Builder + pub fn new>(connection_type: C) -> Self { + Self { + connection_type: connection_type.into(), + options: GenerationConfigOpts::default(), + } + } + + /// Replace the options with the new options + /// + /// Builder + #[inline] + pub fn with_options(mut self, options: GenerationConfigOpts<'a>) -> Self { + self.options = options; + + self + } + + // Wrapper for [GenerationConfigOpts::table()] + #[inline] + pub fn table(&self, name: &str) -> TableOptions<'_> { + self.options.table(name) + } + + #[inline] + pub fn get_schema_path(&self) -> &str { + &self.options.schema_path + } + + #[inline] + pub fn get_model_path(&self) -> &str { + &self.options.model_path + } + + #[inline] + pub fn get_once_common_structs(&self) -> bool { + self.options.once_common_structs + } + + #[inline] + pub fn get_once_connection_type(&self) -> bool { + self.options.once_connection_type + } + + #[inline] + pub fn get_default_table_options(&self) -> &TableOptions<'_> { + &self.options.default_table_options + } + + /// Get if any of the "once-*" options is active / if the common-file is active + #[inline] + pub fn any_once_option(&self) -> bool { + self.get_once_common_structs() || self.get_once_connection_type() + } +} diff --git a/src/lib.rs b/src/lib.rs index 5cc7df91..572bda9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,10 @@ mod file; mod global; mod parser; -pub use global::{BytesType, GenerationConfig, StringType, TableOptions}; +pub use global::{ + BytesType, GenerationConfig, GenerationConfigOpts, StringType, TableOptions, + DEFAULT_MODEL_PATH, DEFAULT_SCHEMA_PATH, +}; use error::IOErrorToError; pub use error::{Error, Result}; @@ -128,17 +131,17 @@ pub fn generate_files( // check that the mod.rs file exists let mut mod_rs = MarkedFile::new(output_models_dir.join("mod.rs"))?; - if config.once_common_structs || config.once_connection_type { + if config.any_once_option() { let mut common_file = MarkedFile::new(output_models_dir.join("common.rs"))?; common_file.ensure_file_signature()?; common_file.change_file_contents({ let mut tmp = format!("{FILE_SIGNATURE}\n"); - if config.once_common_structs { + if config.get_once_common_structs() { tmp.push_str(&code::generate_common_structs( - &config.default_table_options, + config.get_default_table_options(), )); } - if config.once_connection_type { + if config.get_once_connection_type() { tmp.push('\n'); tmp.push_str(&code::generate_connection_type(&config)); @@ -157,7 +160,7 @@ pub fn generate_files( // pass 1: add code for new tables for table in generated.iter() { - if config.once_common_structs && table.name == "common" { + if config.get_once_common_structs() && table.name == "common" { return Err(Error::other("Cannot have a table named \"common\" while having option \"once_common_structs\" enabled")); } let table_name = table.name.to_string(); diff --git a/src/parser.rs b/src/parser.rs index b2d3e3d1..9e742507 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -523,7 +523,7 @@ fn schema_type_to_rust_type(schema_type: String, config: &GenerationConfig) -> R _ => panic!("Unknown type found '{schema_type}', please report this!") */ _ => { - let schema_path = &config.schema_path; + let schema_path = config.get_schema_path(); // return the schema type if no type is found (this means generation is broken for this particular schema) let _type = format!("{schema_path}sql_types::{schema_type}"); return Ok(_type);