Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ pub struct MainOptions {
/// See `crate::GenerationConfig::diesel_backend` for more details.
#[arg(short = 'b', long = "diesel-backend")]
pub diesel_backend: String,

/// Generate the "default" function in an `impl Default`
#[arg(long)]
pub default_impl: bool,
}

#[derive(Debug, ValueEnum, Clone, PartialEq, Default)]
Expand Down Expand Up @@ -265,6 +269,7 @@ fn actual_main() -> dsync::Result<()> {
once_connection_type: args.once_connection_type,
readonly_prefixes: args.readonly_prefixes,
readonly_suffixes: args.readonly_suffixes,
default_impl: args.default_impl,
},
},
)?;
Expand Down
87 changes: 83 additions & 4 deletions src/code.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::parser::{ParsedColumnMacro, ParsedTableMacro, FILE_SIGNATURE};
use crate::{get_table_module_name, GenerationConfig, TableOptions};
use heck::ToPascalCase;
use indoc::formatdoc;
use std::borrow::Cow;

use crate::parser::{ParsedColumnMacro, ParsedTableMacro, FILE_SIGNATURE};
use crate::{get_table_module_name, GenerationConfig, TableOptions};
use std::iter::Map;
use std::slice::Iter;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum StructType {
Expand Down Expand Up @@ -209,6 +210,7 @@ impl<'a> Struct<'a> {
derives::SELECTABLE,
#[cfg(feature = "derive-queryablebyname")]
derives::QUERYABLEBYNAME,
derives::PARTIALEQ,
]);

if !self.table.foreign_keys.is_empty() {
Expand Down Expand Up @@ -761,9 +763,58 @@ fn build_imports(table: &ParsedTableMacro, config: &GenerationConfig) -> String
imports_vec.join("\n")
}

/// Get default for type
fn default_for_type(typ: String) -> &'static str {
match typ.as_str() {
"i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | "i128" | "u128" | "isize"
| "usize" => "0",
"f32" | "f64" => "0.0",
// https://doc.rust-lang.org/std/primitive.bool.html#method.default
"bool" => "false",
"String" => "String::new()",
"&str" | "&'static str" => "\"\"",
_ => "Default::default()",
}
}

/// Generate default (insides of the `impl Default for StructName { fn default() -> Self {} }`)
fn build_default_impl_fn(struct_name: &str, columns: &Vec<ParsedColumnMacro>) -> String {
let mut buffer = String::with_capacity(struct_name.len() + columns.len() * 4);
buffer.push_str(&format!(
"impl Default for {struct_name} {{\n fn default() -> Self {{\n",
struct_name = struct_name
));
let column_name_type_nullable: Map<
Iter<ParsedColumnMacro>,
fn(&ParsedColumnMacro) -> (String, String, bool),
> = columns
.iter()
.map(|col| (col.name.to_string(), col.ty.to_string(), col.is_nullable));

buffer.push_str(" Self {\n");
let fields_to_defaults = column_name_type_nullable
.map(|(name, typ, nullable)| {
format!(
" {name}: {typ_default}",
name = name,
typ_default = if nullable {
"None"
} else {
default_for_type(typ)
}
)
})
.collect::<Vec<String>>()
.join(",\n");
buffer.push_str(fields_to_defaults.as_str());
buffer.push_str("\n }\n }\n}");
buffer
}

/// Generate a full file for a given diesel table
pub fn generate_for_table(table: &ParsedTableMacro, config: &GenerationConfig) -> String {
// early to ensure the table options are set for the current table
let struct_name = table.struct_name.to_string();
let table_options = config.table(&table.name.to_string());

let mut ret_buffer = format!("{FILE_SIGNATURE}\n\n");
Expand All @@ -780,20 +831,48 @@ pub fn generate_for_table(table: &ParsedTableMacro, config: &GenerationConfig) -
if create_struct.has_code() {
ret_buffer.push('\n');
ret_buffer.push_str(create_struct.code());
if config.options.default_impl {
ret_buffer.push('\n');
ret_buffer.push_str(
build_default_impl_fn(
&format!("Create{struct_name}"),
&create_struct.table.columns,
)
.as_str(),
);
}
ret_buffer.push('\n');
}

let update_struct = Struct::new(StructType::Update, table, config);

if update_struct.has_code() {
ret_buffer.push('\n');
ret_buffer.push_str(update_struct.code());
if config.options.default_impl {
ret_buffer.push('\n');
ret_buffer.push_str(
build_default_impl_fn(
&format!("Update{struct_name}"),
&update_struct.table.columns,
)
.as_str(),
);
}
ret_buffer.push('\n');
}

// third and lastly, push functions - if enabled
// third, push functions - if enabled
if table_options.get_fns() {
ret_buffer.push('\n');
ret_buffer.push_str(build_table_fns(table, config, create_struct, update_struct).as_str());
}

if config.options.default_impl {
ret_buffer.push('\n');
ret_buffer.push_str(build_default_impl_fn(&struct_name, &table.columns).as_str());
ret_buffer.push('\n');
}

ret_buffer
}
3 changes: 3 additions & 0 deletions src/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,8 @@ pub struct GenerationConfigOpts<'a> {
pub readonly_prefixes: Vec<String>,
/// Suffixes to treat tables as readonly
pub readonly_suffixes: Vec<String>,
/// Generate the "default" function in an `impl Default`
pub default_impl: bool,
}

impl GenerationConfigOpts<'_> {
Expand Down Expand Up @@ -363,6 +365,7 @@ impl Default for GenerationConfigOpts<'_> {
once_connection_type: false,
readonly_prefixes: Vec::default(),
readonly_suffixes: Vec::default(),
default_impl: false,
}
}
}
Expand Down
Loading