Skip to content

Commit 4b6ad84

Browse files
authored
Merge pull request #1137 from nrxus/fix-non-ident-column-names
Allow serialization of "columns" that are not valid rust identifiers
2 parents 62f96b3 + 8b579e6 commit 4b6ad84

File tree

5 files changed

+54
-10
lines changed

5 files changed

+54
-10
lines changed

scylla-cql/src/types/serialize/row.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,23 @@ pub(crate) mod tests {
15681568
assert_eq!(reference, row);
15691569
}
15701570

1571+
#[test]
1572+
fn test_row_serialization_with_not_rust_idents() {
1573+
#[derive(SerializeRow, Debug)]
1574+
#[scylla(crate = crate)]
1575+
struct RowWithTTL {
1576+
#[scylla(rename = "[ttl]")]
1577+
ttl: i32,
1578+
}
1579+
1580+
let spec = [col("[ttl]", ColumnType::Int)];
1581+
1582+
let reference = do_serialize((42i32,), &spec);
1583+
let row = do_serialize(RowWithTTL { ttl: 42 }, &spec);
1584+
1585+
assert_eq!(reference, row);
1586+
}
1587+
15711588
#[derive(SerializeRow, Debug)]
15721589
#[scylla(crate = crate)]
15731590
struct TestRowWithSkippedFields {

scylla-cql/src/types/serialize/value.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2824,4 +2824,32 @@ pub(crate) mod tests {
28242824

28252825
assert_eq!(reference, row);
28262826
}
2827+
2828+
#[test]
2829+
fn test_udt_with_non_rust_ident() {
2830+
#[derive(SerializeValue, Debug)]
2831+
#[scylla(crate = crate)]
2832+
struct UdtWithNonRustIdent {
2833+
#[scylla(rename = "a$a")]
2834+
a: i32,
2835+
}
2836+
2837+
let typ = ColumnType::UserDefinedType {
2838+
type_name: "typ".into(),
2839+
keyspace: "ks".into(),
2840+
field_types: vec![("a$a".into(), ColumnType::Int)],
2841+
};
2842+
let value = UdtWithNonRustIdent { a: 42 };
2843+
2844+
let mut reference = Vec::new();
2845+
// Total length of the struct
2846+
reference.extend_from_slice(&8i32.to_be_bytes());
2847+
// Field 'a'
2848+
reference.extend_from_slice(&(std::mem::size_of_val(&value.a) as i32).to_be_bytes());
2849+
reference.extend_from_slice(&value.a.to_be_bytes());
2850+
2851+
let udt = do_serialize(value, &typ);
2852+
2853+
assert_eq!(reference, udt);
2854+
}
28272855
}

scylla-macros/src/serialize/row.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ impl Generator for ColumnSortingGenerator<'_> {
223223
statements.push(self.ctx.generate_mk_ser_err());
224224

225225
// Generate a "visited" flag for each field
226-
let visited_flag_names = rust_field_names
226+
let visited_flag_names = rust_field_idents
227227
.iter()
228228
.map(|s| syn::Ident::new(&format!("visited_flag_{}", s), Span::call_site()))
229229
.collect::<Vec<_>>();

scylla-macros/src/serialize/value.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::collections::HashMap;
22

33
use darling::FromAttributes;
44
use proc_macro::TokenStream;
5-
use proc_macro2::Span;
65
use syn::parse_quote;
76

87
use crate::Flavor;
@@ -327,14 +326,14 @@ impl Generator for FieldSortingGenerator<'_> {
327326
.generate_udt_type_match(parse_quote!(#crate_path::UdtTypeCheckErrorKind::NotUdt)),
328327
);
329328

330-
fn make_visited_flag_ident(field_name: &str) -> syn::Ident {
331-
syn::Ident::new(&format!("visited_flag_{}", field_name), Span::call_site())
329+
fn make_visited_flag_ident(field_name: &syn::Ident) -> syn::Ident {
330+
syn::Ident::new(&format!("visited_flag_{}", field_name), field_name.span())
332331
}
333332

334333
// Generate a "visited" flag for each field
335-
let visited_flag_names = rust_field_names
334+
let visited_flag_names = rust_field_idents
336335
.iter()
337-
.map(|s| make_visited_flag_ident(s))
336+
.map(make_visited_flag_ident)
338337
.collect::<Vec<_>>();
339338
statements.extend::<Vec<_>>(parse_quote! {
340339
#(let mut #visited_flag_names = false;)*
@@ -347,11 +346,11 @@ impl Generator for FieldSortingGenerator<'_> {
347346
.fields
348347
.iter()
349348
.filter(|f| !f.attrs.ignore_missing)
350-
.map(|f| f.field_name());
349+
.map(|f| &f.ident);
351350
// An iterator over visited flags of Rust fields that can't be ignored
352351
// (i.e., if UDT misses a corresponding field, an error should be raised).
353352
let nonignorable_visited_flag_names =
354-
nonignorable_rust_field_names.map(|s| make_visited_flag_ident(&s));
353+
nonignorable_rust_field_names.map(make_visited_flag_ident);
355354

356355
// Generate a variable that counts down visited fields.
357356
let field_count = self.ctx.fields.len();

scylla/src/macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ pub use scylla_cql::macros::SerializeRow;
360360
/// If the value of the field received from DB is null, the field will be
361361
/// initialized with `Default::default()`.
362362
///
363-
/// `#[scylla(rename = "field_name")`
363+
/// `#[scylla(rename = "field_name")]`
364364
///
365365
/// By default, the generated implementation will try to match the Rust field
366366
/// to a UDT field with the same name. This attribute instead allows to match
@@ -475,7 +475,7 @@ pub use scylla_macros::DeserializeValue;
475475
/// The field will be completely ignored during deserialization and will
476476
/// be initialized with `Default::default()`.
477477
///
478-
/// `#[scylla(rename = "field_name")`
478+
/// `#[scylla(rename = "field_name")]`
479479
///
480480
/// By default, the generated implementation will try to match the Rust field
481481
/// to a column with the same name. This attribute allows to match to a column

0 commit comments

Comments
 (0)