Skip to content

Commit 898df7f

Browse files
committed
feat: implement update with coalesce
1 parent 474f930 commit 898df7f

File tree

7 files changed

+327
-129
lines changed

7 files changed

+327
-129
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/sqlx_gen/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sqlx-gen"
3-
version = "0.5.0"
3+
version = "0.5.1"
44
edition = "2021"
55
description = "Generate Rust structs from database schema introspection"
66
license = "MIT"

crates/sqlx_gen/src/cli.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -550,13 +550,6 @@ mod tests {
550550
let m = Methods::from_list(&["overwrite".to_string()]).unwrap();
551551
assert!(m.overwrite);
552552
assert!(!m.update);
553-
assert!(!m.get);
554-
}
555-
556-
#[test]
557-
fn test_wildcard_includes_overwrite() {
558-
let m = Methods::from_list(&["*".to_string()]).unwrap();
559-
assert!(m.overwrite);
560553
}
561554

562555
// ========== module_path_from_file ==========

crates/sqlx_gen/src/codegen/crud_gen.rs

Lines changed: 252 additions & 111 deletions
Large diffs are not rendered by default.

crates/sqlx_gen/src/codegen/entity_parser.rs

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ pub struct ParsedField {
2121
pub sql_type: Option<String>,
2222
/// Whether the SQL type is an array (needs `[]` suffix in cast)
2323
pub is_sql_array: bool,
24+
/// Raw SQL default expression from the DB (e.g. "now()", "'idle'::task_status")
25+
pub column_default: Option<String>,
2426
}
2527

2628
/// Represents an entity parsed from a generated Rust file.
@@ -189,7 +191,7 @@ fn extract_field(field: &syn::Field) -> Result<ParsedField, String> {
189191
.to_string();
190192

191193
let column_name = get_sqlx_rename(&field.attrs).unwrap_or_else(|| rust_name.clone());
192-
let (is_primary_key, sql_type, is_sql_array) = parse_sqlx_gen_field_attrs(&field.attrs);
194+
let (is_primary_key, sql_type, is_sql_array, column_default) = parse_sqlx_gen_field_attrs(&field.attrs);
193195

194196
let rust_type = field.ty.to_token_stream().to_string();
195197
let (is_nullable, inner_type) = extract_option_type(&field.ty);
@@ -208,15 +210,17 @@ fn extract_field(field: &syn::Field) -> Result<ParsedField, String> {
208210
is_primary_key,
209211
sql_type,
210212
is_sql_array,
213+
column_default,
211214
})
212215
}
213216

214217
/// Parse `#[sqlx_gen(...)]` attributes on a field.
215-
/// Returns (is_primary_key, sql_type, is_sql_array).
216-
fn parse_sqlx_gen_field_attrs(attrs: &[syn::Attribute]) -> (bool, Option<String>, bool) {
218+
/// Returns (is_primary_key, sql_type, is_sql_array, column_default).
219+
fn parse_sqlx_gen_field_attrs(attrs: &[syn::Attribute]) -> (bool, Option<String>, bool, Option<String>) {
217220
let mut is_pk = false;
218221
let mut sql_type = None;
219222
let mut is_array = false;
223+
let mut column_default = None;
220224

221225
for attr in attrs {
222226
if attr.path().is_ident("sqlx_gen") {
@@ -230,10 +234,13 @@ fn parse_sqlx_gen_field_attrs(attrs: &[syn::Attribute]) -> (bool, Option<String>
230234
if tokens.contains("is_array") {
231235
is_array = true;
232236
}
237+
if let Some(d) = extract_attr_value(&tokens, "column_default") {
238+
column_default = Some(d);
239+
}
233240
}
234241
}
235242

236-
(is_pk, sql_type, is_array)
243+
(is_pk, sql_type, is_array, column_default)
237244
}
238245

239246
/// Extract `#[sqlx(rename = "...")]` value from field attributes.
@@ -607,4 +614,56 @@ mod tests {
607614
assert_eq!(entity.imports.len(), 1);
608615
assert!(entity.imports[0].contains("chrono"));
609616
}
617+
618+
// --- column_default parsing ---
619+
620+
#[test]
621+
fn test_parse_column_default() {
622+
let source = r#"
623+
#[derive(Debug, Clone, sqlx::FromRow)]
624+
#[sqlx_gen(kind = "table", table = "tasks")]
625+
pub struct Tasks {
626+
#[sqlx_gen(primary_key)]
627+
pub id: i32,
628+
#[sqlx_gen(column_default = "now()")]
629+
pub created_at: String,
630+
}
631+
"#;
632+
let entity = parse_entity_source(source).unwrap();
633+
let created_at = &entity.fields[1];
634+
assert_eq!(created_at.column_default, Some("now()".to_string()));
635+
}
636+
637+
#[test]
638+
fn test_parse_no_column_default() {
639+
let source = r#"
640+
#[derive(Debug, Clone, sqlx::FromRow)]
641+
#[sqlx_gen(kind = "table", table = "tasks")]
642+
pub struct Tasks {
643+
#[sqlx_gen(primary_key)]
644+
pub id: i32,
645+
pub title: String,
646+
}
647+
"#;
648+
let entity = parse_entity_source(source).unwrap();
649+
let title = &entity.fields[1];
650+
assert_eq!(title.column_default, None);
651+
}
652+
653+
#[test]
654+
fn test_parse_column_default_with_cast() {
655+
let source = r#"
656+
#[derive(Debug, Clone, sqlx::FromRow)]
657+
#[sqlx_gen(kind = "table", table = "tasks")]
658+
pub struct Tasks {
659+
#[sqlx_gen(primary_key)]
660+
pub id: i32,
661+
#[sqlx_gen(column_default = "'idle'::task_status")]
662+
pub status: String,
663+
}
664+
"#;
665+
let entity = parse_entity_source(source).unwrap();
666+
let status = &entity.fields[1];
667+
assert_eq!(status.column_default, Some("'idle'::task_status".to_string()));
668+
}
610669
}

crates/sqlx_gen/src/codegen/struct_gen.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,24 @@ pub fn generate_struct(
8080
quote! {}
8181
};
8282

83-
// Build #[sqlx_gen(...)] attribute with optional primary_key, sql_type, is_array
83+
// Build #[sqlx_gen(...)] attribute with optional primary_key, sql_type, is_array, column_default
8484
let (sql_type, is_sql_array) = detect_custom_sql_type(&col.udt_name, schema_info);
8585
let has_pk = col.is_primary_key;
8686
let has_sql_type = sql_type.is_some();
87+
let has_default = col.column_default.is_some();
8788

88-
let sqlx_gen_attr = if has_pk || has_sql_type {
89+
let sqlx_gen_attr = if has_pk || has_sql_type || has_default {
8990
let pk_part = if has_pk { quote! { primary_key, } } else { quote! {} };
9091
let sql_type_part = match &sql_type {
9192
Some(t) => quote! { sql_type = #t, },
9293
None => quote! {},
9394
};
9495
let array_part = if is_sql_array { quote! { is_array, } } else { quote! {} };
95-
quote! { #[sqlx_gen(#pk_part #sql_type_part #array_part)] }
96+
let default_part = match &col.column_default {
97+
Some(d) => quote! { column_default = #d, },
98+
None => quote! {},
99+
};
100+
quote! { #[sqlx_gen(#pk_part #sql_type_part #array_part #default_part)] }
96101
} else {
97102
quote! {}
98103
};

crates/sqlx_gen_macros/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sqlx-gen-macros"
3-
version = "0.5.0"
3+
version = "0.5.1"
44
edition = "2021"
55
description = "No-op attribute macros for sqlx-gen generated code"
66
license = "MIT"

0 commit comments

Comments
 (0)