Skip to content

Commit 5b095dc

Browse files
committed
Add support for generating insertable structs in diesel_ext
- Updated README.md to reflect the addition of insertable options. - Modified main.rs to include command-line options for generating insertable structs. - Enhanced parse.rs to handle insertable struct generation logic. - Created expected output for insertable structs in schema_insertable.rs.
1 parent 489edf7 commit 5b095dc

5 files changed

Lines changed: 304 additions & 8 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "diesel_cli_ext"
3-
version = "0.3.16"
3+
version = "0.3.17"
44
authors = ["Abby <i@abby.md>"]
55
license = "MIT OR Apache-2.0"
66
description = "Provides different tools for projects using the diesel_cli."

README.md

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ Diesel CLI Extension is a tool-belt that aids Diesel CLI after it built schema.r
66
[![Crates.io](https://img.shields.io/crates/v/diesel_cli_ext.svg)](https://crates.io/crates/diesel_cli_ext)
77
<!-- [![Coverage Status](https://coveralls.io/repos/github/abbychau/diesel_cli_ext/badge.svg?branch=master)](https://coveralls.io/github/abbychau/diesel_cli_ext?branch=master) -->
88

9-
It contains 4 functions at this moment.
9+
It contains 5 functions at this moment.
1010
1. Generate protobuf file.(`diesel_ext proto`)
1111
2. Generate model rust structs.(`diesel_ext model`)
12-
3. Generate conversion implementations.(`diesel_ext into_proto`, and `diesel_ext from_proto`)
12+
3. Generate insertable rust structs.(`diesel_ext insertable`)
13+
4. Generate conversion implementations.(`diesel_ext into_proto`, and `diesel_ext from_proto`)
1314

1415
## Installation
1516
`cargo install diesel_cli_ext`
@@ -40,16 +41,36 @@ Model Options:
4041
(NOT ready)This field adds derives for certain tables.
4142
(can be set multiple times) e.g. --derive-mod
4243
"table_name +Debug" --derive-mod "table_name2 -Debug"
44+
-n, --struct-name-override "STRUCT NAME OVERRIDE"
45+
This field overrides the generated struct name for
46+
certain tables. (can be set multiple times)
47+
48+
Insertable Options:
4349
-d, --derive DERIVES
4450
set struct derives
51+
-t, --add-table-name
52+
Add #[table_name = x] before structs
4553
-r, --rust_styled_model_fields
4654
set struct field names to be styled according to Rust guidelines
55+
-g, --insertable Generate insertable structs for database inserts
56+
(omits auto-increment/default fields)
57+
-S, --skip-fields "FIELD_NAME"
58+
Fields to skip in insertable structs (can be set
59+
multiple times) e.g. --skip-fields "id"
60+
-O, --optional-fields "FIELD_NAME"
61+
Fields to make optional in insertable structs even if
62+
NOT NULL (can be set multiple times)
63+
-P, --insertable-prefix PREFIX
64+
Prefix for insertable struct names (default: New)
4765
4866
Proto Options:
49-
-t, --add-table-name
50-
Add #[table_name = x] before structs
5167
-p, --proto Set as proto output
5268
-i, --into_proto Set as into_proto output
69+
-f, --from_proto Set as from_proto output
70+
-c, --class_name CLASS_NAME
71+
Set proto class name
72+
-v, --diesel_version 1 or 2
73+
Set diesel version (default:2)
5374
```
5475

5576
(You can see it again by `diesel_ext --help`)
@@ -80,6 +101,54 @@ pub struct Order {
80101
}
81102
```
82103

104+
### To generate insertable structs:
105+
`diesel_ext -g > src/insertable.rs`, `diesel_ext --insertable > src/insertable.rs`
106+
107+
Insertable structs are perfect for database inserts as they omit auto-increment and default value columns. This follows Diesel's recommended pattern of using separate structs for querying and inserting data.
108+
109+
**Key Features:**
110+
- Automatically skips common auto-generated fields (`id`, `created_at`, `updated_at`)
111+
- Uses string references (`&'a str`) for better performance
112+
- Supports custom field skipping and optional field configuration
113+
- Generates proper `#[derive(Insertable)]` annotations
114+
115+
**Basic usage:**
116+
```bash
117+
diesel_ext -g -s schema.rs
118+
```
119+
120+
**Advanced usage:**
121+
```bash
122+
# Skip custom fields
123+
diesel_ext -g -s schema.rs -S user_id -S account_id
124+
125+
# Make fields optional (useful for database defaults)
126+
diesel_ext -g -s schema.rs -O status -O version
127+
128+
# Custom struct name prefix
129+
diesel_ext -g -s schema.rs -P Create # generates CreateUser instead of NewUser
130+
```
131+
132+
Sample output:
133+
``` rust
134+
#[derive(Insertable)]
135+
#[diesel(table_name = users)]
136+
pub struct NewUser<'a> {
137+
pub name: &'a str,
138+
pub email: &'a str,
139+
pub status: Option<&'a str>, // Made optional with -O
140+
// id, created_at, updated_at automatically skipped
141+
}
142+
143+
#[derive(Insertable)]
144+
#[diesel(table_name = orders)]
145+
pub struct NewOrder<'a> {
146+
pub user_id: i64,
147+
pub amount: BigDecimal,
148+
pub description: Option<&'a str>,
149+
}
150+
```
151+
83152
### To generate prelimiting proto file:
84153
`diesel_ext -p > myproto.proto`, `diesel_ext --proto > myproto.proto`
85154

src/main.rs

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ pub fn custom_opts_usage(iopts: Options, brief: &str) -> String {
1414
iopts.usage_with_format(|opts| {
1515
let full_param = opts.collect::<Vec<String>>();
1616
format!(
17-
"{}\n\nCommon Options:\n{}\n\nModel Options:\n{}\n\nProto Options:\n{}\n",
17+
"{}\n\nCommon Options:\n{}\n\nModel Options:\n{}\n\nInsertable Options:\n{}\n\nProto Options:\n{}\n",
1818
brief,
1919
full_param[0..2].join("\n"),
2020
full_param[2..7].join("\n"),
21-
full_param[7..10].join("\n"),
21+
full_param[7..14].join("\n"),
22+
full_param[14..19].join("\n"),
2223
)
2324
})
2425
}
@@ -135,6 +136,31 @@ fn main() {
135136
"rust_styled_model_fields",
136137
"When creating models fields, will use rust styled names instead of database styled names",
137138
);
139+
140+
// Insertable struct options
141+
opts.optflag(
142+
"g",
143+
"insertable",
144+
"Generate insertable structs for database inserts (omits auto-increment/default fields)",
145+
);
146+
opts.optmulti(
147+
"S",
148+
"skip-fields",
149+
"Fields to skip in insertable structs (can be set multiple times) e.g. --skip-fields \"id\" --skip-fields \"created_at\"",
150+
"\"FIELD_NAME\"",
151+
);
152+
opts.optmulti(
153+
"O",
154+
"optional-fields",
155+
"Fields to make optional in insertable structs even if NOT NULL (can be set multiple times) e.g. --optional-fields \"status\"",
156+
"\"FIELD_NAME\"",
157+
);
158+
opts.optopt(
159+
"P",
160+
"insertable-prefix",
161+
"Prefix for insertable struct names (default: New)",
162+
"PREFIX",
163+
);
138164

139165
opts.optflag("p", "proto", "Set as proto output");
140166
opts.optflag("i", "into_proto", "Set as into_proto output");
@@ -180,9 +206,27 @@ fn main() {
180206
if diesel_version != "1" && diesel_version != "2" {
181207
panic!("diesel_version must be 1 or 2");
182208
}
209+
// Parse insertable struct options
210+
let skip_fields: Vec<String> = if matches.opt_present("S") {
211+
matches.opt_strs("S")
212+
} else {
213+
vec!["id".to_string(), "created_at".to_string(), "updated_at".to_string()]
214+
};
215+
216+
let optional_fields: Vec<String> = if matches.opt_present("O") {
217+
matches.opt_strs("O")
218+
} else {
219+
vec![]
220+
};
221+
222+
let insertable_prefix = matches.opt_str("P").unwrap_or("New".to_string());
223+
183224
let action = if matches.opt_present("m") {
184225
model_derives = matches.opt_str("d");
185226
"model"
227+
} else if matches.opt_present("g") {
228+
model_derives = matches.opt_str("d");
229+
"insertable"
186230
} else if matches.opt_present("i") {
187231
class_name = matches
188232
.opt_str("c")
@@ -242,6 +286,9 @@ fn main() {
242286
diesel_version,
243287
rust_styled_fields,
244288
struct_name_override,
289+
skip_fields,
290+
optional_fields,
291+
insertable_prefix,
245292
});
246293

247294
//imported types
@@ -270,6 +317,19 @@ fn main() {
270317
print_normal_dependencies(&parse_output);
271318
println!("{}", parse_output.str_model);
272319
}
320+
"insertable" => {
321+
println!("// Generated by diesel_ext (insertable structs)\n");
322+
323+
println!("#![allow(unused)]");
324+
println!("#![allow(clippy::all)]\n");
325+
326+
println!("{}", import_type_string);
327+
print_normal_dependencies(&parse_output);
328+
if parse_output.diesel_macro_use {
329+
println!("use diesel::prelude::*;");
330+
}
331+
println!("{}", parse_output.str_insertable);
332+
}
273333
"from_proto" => {
274334
print_conversion_dependencies();
275335
print_conversion_methods(&parse_output);

0 commit comments

Comments
 (0)