@@ -24,6 +24,13 @@ struct StructAttrs {
24
24
// This annotation only works if `enforce_order` is specified.
25
25
#[ darling( default ) ]
26
26
skip_name_checks : bool ,
27
+
28
+ // If true, then - if this field is missing from the UDT fields metadata
29
+ // - it will be initialized to Default::default().
30
+ // currently only supported with Flavor::MatchByName
31
+ #[ darling( default ) ]
32
+ #[ darling( rename = "allow_missing" ) ]
33
+ default_when_missing : bool ,
27
34
}
28
35
29
36
impl DeserializeCommonStructAttrs for StructAttrs {
@@ -51,6 +58,13 @@ struct Field {
51
58
#[ darling( default ) ]
52
59
default_when_null : bool ,
53
60
61
+ // If true, then - if this field is missing from the UDT fields metadata
62
+ // - it will be initialized to Default::default().
63
+ // currently only supported with Flavor::MatchByName
64
+ #[ darling( default ) ]
65
+ #[ darling( rename = "allow_missing" ) ]
66
+ default_when_missing : bool ,
67
+
54
68
ident : Option < syn:: Ident > ,
55
69
ty : syn:: Type ,
56
70
}
@@ -135,7 +149,7 @@ fn validate_attrs(attrs: &StructAttrs, fields: &[Field]) -> Result<(), darling::
135
149
impl Field {
136
150
// Returns whether this field is mandatory for deserialization.
137
151
fn is_required ( & self ) -> bool {
138
- !self . skip
152
+ !self . skip && ! self . default_when_missing
139
153
}
140
154
141
155
// The name of the column corresponding to this Rust struct field
@@ -209,13 +223,7 @@ impl TypeCheckAssumeOrderGenerator<'_> {
209
223
let macro_internal = self . 0 . struct_attrs ( ) . macro_internal_path ( ) ;
210
224
let ( frame_lifetime, metadata_lifetime) = self . 0 . constraint_lifetimes ( ) ;
211
225
212
- let required_fields_iter = || {
213
- self . 0
214
- . fields ( )
215
- . iter ( )
216
- . enumerate ( )
217
- . filter ( |( _, f) | f. is_required ( ) )
218
- } ;
226
+ let required_fields_iter = || self . 0 . fields ( ) . iter ( ) . enumerate ( ) . filter ( |( _, f) | !f. skip ) ;
219
227
let required_fields_count = required_fields_iter ( ) . count ( ) ;
220
228
let required_fields_idents: Vec < _ > = ( 0 ..required_fields_count)
221
229
. map ( |i| quote:: format_ident!( "f_{}" , i) )
@@ -394,7 +402,7 @@ impl TypeCheckUnorderedGenerator<'_> {
394
402
let visited_flag = Self :: visited_flag_variable ( field) ;
395
403
let typ = field. deserialize_target ( ) ;
396
404
let cql_name_literal = field. cql_name_literal ( ) ;
397
- let decrement_if_required: Option :: < syn:: Stmt > = field. is_required ( ) . then ( || parse_quote ! {
405
+ let decrement_if_required: Option :: < syn:: Stmt > = ( ! self . 0 . attrs . default_when_missing && field. is_required ( ) ) . then ( || parse_quote ! {
398
406
remaining_required_fields -= 1 ;
399
407
} ) ;
400
408
@@ -467,7 +475,11 @@ impl TypeCheckUnorderedGenerator<'_> {
467
475
. iter ( )
468
476
. filter ( |f| !f. skip )
469
477
. map ( |f| f. cql_name_literal ( ) ) ;
470
- let field_count_lit = fields. iter ( ) . filter ( |f| f. is_required ( ) ) . count ( ) ;
478
+ let field_count_lit = if self . 0 . attrs . default_when_missing {
479
+ 0
480
+ } else {
481
+ fields. iter ( ) . filter ( |f| f. is_required ( ) ) . count ( )
482
+ } ;
471
483
472
484
parse_quote ! {
473
485
fn type_check(
@@ -541,11 +553,18 @@ impl DeserializeUnorderedGenerator<'_> {
541
553
542
554
let deserialize_field = Self :: deserialize_field_variable ( field) ;
543
555
let cql_name_literal = field. cql_name_literal ( ) ;
544
- parse_quote ! {
545
- #deserialize_field. unwrap_or_else( || :: std:: panic!(
546
- "column {} missing in DB row - type check should have prevented this!" ,
547
- #cql_name_literal
548
- ) )
556
+ if self . 0 . attrs . default_when_missing || field. default_when_missing {
557
+ // Generate Default::default if the field was missing
558
+ parse_quote ! {
559
+ #deserialize_field. unwrap_or_default( )
560
+ }
561
+ } else {
562
+ parse_quote ! {
563
+ #deserialize_field. unwrap_or_else( || :: std:: panic!(
564
+ "column {} missing in DB row - type check should have prevented this!" ,
565
+ #cql_name_literal
566
+ ) )
567
+ }
549
568
}
550
569
}
551
570
0 commit comments