Skip to content

Commit 98fc02a

Browse files
authored
Merge pull request #1119 from wprzytula/unify-ser-deser-macro-attrs
Unify macro attributes between serialization and deserialization derive macros
2 parents 8ccc597 + 0c9a8cc commit 98fc02a

File tree

18 files changed

+630
-134
lines changed

18 files changed

+630
-134
lines changed

docs/source/data-types/udt.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ and `DeserializeValue` macros documentation.
2020
```rust
2121
# extern crate scylla;
2222
# async fn check_only_compiles() {
23-
use scylla::macros::{FromUserType, SerializeValue};
23+
use scylla::macros::{DeserializeValue, SerializeValue};
2424

2525
// Define a custom struct that matches the User Defined Type created earlier.
26-
// Fields must be in the same order as they are in the database and also
27-
// have the same names.
26+
// Fields don't have to be in the same order as they are in the database.
27+
// By default, they must have the same names, but this can be worked around
28+
// using `#[rename] field attribute.
2829
// Wrapping a field in Option will gracefully handle null field values.
29-
#[derive(Debug, FromUserType, SerializeValue)]
30+
#[derive(Debug, DeserializeValue, SerializeValue)]
3031
struct MyType {
3132
int_val: i32,
3233
text_val: Option<String>,

docs/source/migration-guides/0.11-serialization.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ The driver comes a set of `impl`s of those traits which allow to represent any C
4242

4343
By default, the `SerializeRow` and `SerializeValue` **will match the fields in the Rust struct by name to bind marker names** (in case of `SerializeRow`) **or UDT field names** (in case of `SerializeValue`). This is different from the old `ValueList` and `IntoUserType` macros which did not look at the field names at all and would expect the user to order the fields correctly. While the new behavior is much more ergonomic, you might have reasons not to use it.
4444

45-
> **NOTE:** The deserialization macro counterparts `FromRow` and `FromUserType` have the same limitation as the old serialization macros - they require struct fields to be properly ordered. While a similar rework is planned for the deserialization traits in a future release, for the time being it might not be worth keeping the column names in sync with the database.
46-
4745
In order to bring the old behavior to the new macros (the only difference being type checking which cannot be disabled right now) you can configure it using attributes, as shown in the snippet below:
4846

4947
```rust

scylla-cql/src/types/deserialize/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ macro_rules! make_error_replace_rust_name {
323323
use make_error_replace_rust_name;
324324

325325
#[cfg(test)]
326-
mod tests {
326+
pub(crate) mod tests {
327327
use bytes::{Bytes, BytesMut};
328328

329329
use crate::frame::response::result::{ColumnSpec, ColumnType, TableSpec};
@@ -342,7 +342,7 @@ mod tests {
342342
bytes.freeze()
343343
}
344344

345-
pub(super) const fn spec<'a>(name: &'a str, typ: ColumnType<'a>) -> ColumnSpec<'a> {
345+
pub(crate) const fn spec<'a>(name: &'a str, typ: ColumnType<'a>) -> ColumnSpec<'a> {
346346
ColumnSpec::borrowed(name, typ, TableSpec::borrowed("ks", "tbl"))
347347
}
348348
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ impl Display for BuiltinDeserializationErrorKind {
496496

497497
#[cfg(test)]
498498
#[path = "row_tests.rs"]
499-
mod tests;
499+
pub(crate) mod tests;
500500

501501
/// ```compile_fail
502502
///

scylla-cql/src/types/deserialize/row_tests.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ struct TestUdtWithNoFieldsUnordered {}
9191

9292
#[allow(unused)]
9393
#[derive(DeserializeRow)]
94-
#[scylla(crate = crate, enforce_order)]
94+
#[scylla(crate = crate, flavor = "enforce_order")]
9595
struct TestUdtWithNoFieldsOrdered {}
9696

9797
#[test]
@@ -143,7 +143,7 @@ fn test_struct_deserialization_loose_ordering() {
143143
#[test]
144144
fn test_struct_deserialization_strict_ordering() {
145145
#[derive(DeserializeRow, PartialEq, Eq, Debug)]
146-
#[scylla(crate = "crate", enforce_order)]
146+
#[scylla(crate = "crate", flavor = "enforce_order")]
147147
struct MyRow<'a> {
148148
a: &'a str,
149149
b: Option<i32>,
@@ -180,7 +180,7 @@ fn test_struct_deserialization_strict_ordering() {
180180
#[test]
181181
fn test_struct_deserialization_no_name_check() {
182182
#[derive(DeserializeRow, PartialEq, Eq, Debug)]
183-
#[scylla(crate = "crate", enforce_order, skip_name_checks)]
183+
#[scylla(crate = "crate", flavor = "enforce_order", skip_name_checks)]
184184
struct MyRow<'a> {
185185
a: &'a str,
186186
b: Option<i32>,
@@ -251,7 +251,7 @@ fn val_str(s: &str) -> Option<Vec<u8>> {
251251
Some(s.as_bytes().to_vec())
252252
}
253253

254-
fn deserialize<'frame, 'metadata, R>(
254+
pub(crate) fn deserialize<'frame, 'metadata, R>(
255255
specs: &'metadata [ColumnSpec<'metadata>],
256256
byts: &'frame Bytes,
257257
) -> Result<R, DeserializationError>
@@ -623,7 +623,7 @@ fn test_struct_deserialization_errors() {
623623
// Strict ordering
624624
{
625625
#[derive(scylla_macros::DeserializeRow, PartialEq, Eq, Debug)]
626-
#[scylla(crate = "crate", enforce_order)]
626+
#[scylla(crate = "crate", flavor = "enforce_order")]
627627
struct MyRow<'a> {
628628
a: &'a str,
629629
#[scylla(skip)]

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,7 +1950,7 @@ impl From<UdtDeserializationErrorKind> for BuiltinDeserializationErrorKind {
19501950

19511951
#[cfg(test)]
19521952
#[path = "value_tests.rs"]
1953-
pub(super) mod tests;
1953+
pub(crate) mod tests;
19541954

19551955
/// ```compile_fail
19561956
///
@@ -1963,7 +1963,7 @@ fn _test_udt_bad_attributes_skip_name_check_requires_enforce_order() {}
19631963
/// ```compile_fail
19641964
///
19651965
/// #[derive(scylla_macros::DeserializeValue)]
1966-
/// #[scylla(crate = scylla_cql, enforce_order, skip_name_checks)]
1966+
/// #[scylla(crate = scylla_cql, flavor = "enforce_order", skip_name_checks)]
19671967
/// struct TestUdt {
19681968
/// #[scylla(rename = "b")]
19691969
/// a: i32,
@@ -1999,7 +1999,7 @@ fn _test_udt_bad_attributes_rename_collision_with_another_rename() {}
19991999
/// ```compile_fail
20002000
///
20012001
/// #[derive(scylla_macros::DeserializeValue)]
2002-
/// #[scylla(crate = scylla_cql, enforce_order, skip_name_checks)]
2002+
/// #[scylla(crate = scylla_cql, flavor = "enforce_order", skip_name_checks)]
20032003
/// struct TestUdt {
20042004
/// a: i32,
20052005
/// #[scylla(allow_missing)]

scylla-cql/src/types/deserialize/value_tests.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ fn test_tuples() {
585585
);
586586
}
587587

588-
fn udt_def_with_fields(
588+
pub(crate) fn udt_def_with_fields(
589589
fields: impl IntoIterator<Item = (impl Into<Cow<'static, str>>, ColumnType<'static>)>,
590590
) -> ColumnType<'static> {
591591
ColumnType::UserDefinedType {
@@ -632,7 +632,7 @@ struct TestUdtWithNoFieldsUnordered {}
632632

633633
#[allow(unused)]
634634
#[derive(scylla_macros::DeserializeValue)]
635-
#[scylla(crate = crate, enforce_order)]
635+
#[scylla(crate = crate, flavor = "enforce_order")]
636636
struct TestUdtWithNoFieldsOrdered {}
637637

638638
#[test]
@@ -786,7 +786,7 @@ fn test_udt_loose_ordering() {
786786
#[test]
787787
fn test_udt_strict_ordering() {
788788
#[derive(scylla_macros::DeserializeValue, PartialEq, Eq, Debug)]
789-
#[scylla(crate = "crate", enforce_order)]
789+
#[scylla(crate = "crate", flavor = "enforce_order")]
790790
struct Udt<'a> {
791791
#[scylla(default_when_null)]
792792
a: &'a str,
@@ -860,7 +860,7 @@ fn test_udt_strict_ordering() {
860860
// An excess field at the end of UDT, when such are forbidden
861861
{
862862
#[derive(scylla_macros::DeserializeValue, PartialEq, Eq, Debug)]
863-
#[scylla(crate = "crate", enforce_order, forbid_excess_udt_fields)]
863+
#[scylla(crate = "crate", flavor = "enforce_order", forbid_excess_udt_fields)]
864864
struct Udt<'a> {
865865
a: &'a str,
866866
#[scylla(skip)]
@@ -934,7 +934,7 @@ fn test_udt_strict_ordering() {
934934
#[test]
935935
fn test_udt_no_name_check() {
936936
#[derive(scylla_macros::DeserializeValue, PartialEq, Eq, Debug)]
937-
#[scylla(crate = "crate", enforce_order, skip_name_checks)]
937+
#[scylla(crate = "crate", flavor = "enforce_order", skip_name_checks)]
938938
struct Udt<'a> {
939939
a: &'a str,
940940
#[scylla(skip)]
@@ -1044,7 +1044,7 @@ fn test_custom_type_parser() {
10441044
assert_eq!(tup, SwappedPair("foo", 42));
10451045
}
10461046

1047-
fn deserialize<'frame, 'metadata, T>(
1047+
pub(crate) fn deserialize<'frame, 'metadata, T>(
10481048
typ: &'metadata ColumnType<'metadata>,
10491049
bytes: &'frame Bytes,
10501050
) -> Result<T, DeserializationError>
@@ -1762,7 +1762,7 @@ fn test_udt_errors() {
17621762
// Strict ordering
17631763
{
17641764
#[derive(scylla_macros::DeserializeValue, PartialEq, Eq, Debug)]
1765-
#[scylla(crate = "crate", enforce_order, forbid_excess_udt_fields)]
1765+
#[scylla(crate = "crate", flavor = "enforce_order", forbid_excess_udt_fields)]
17661766
struct Udt<'a> {
17671767
a: &'a str,
17681768
#[scylla(skip)]

scylla-cql/src/types/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
pub mod deserialize;
22
pub mod serialize;
3+
4+
#[cfg(test)]
5+
mod types_tests;

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

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -867,8 +867,55 @@ impl<'a> Iterator for SerializedValuesIterator<'a> {
867867
}
868868
}
869869

870+
mod doctests {
871+
872+
/// ```compile_fail
873+
///
874+
/// #[derive(scylla_macros::SerializeRow)]
875+
/// #[scylla(crate = scylla_cql, skip_name_checks)]
876+
/// struct TestRow {}
877+
/// ```
878+
fn _test_struct_deserialization_name_check_skip_requires_enforce_order() {}
879+
880+
/// ```compile_fail
881+
///
882+
/// #[derive(scylla_macros::SerializeRow)]
883+
/// #[scylla(crate = scylla_cql, skip_name_checks)]
884+
/// struct TestRow {
885+
/// #[scylla(rename = "b")]
886+
/// a: i32,
887+
/// }
888+
/// ```
889+
fn _test_struct_deserialization_skip_name_check_conflicts_with_rename() {}
890+
891+
/// ```compile_fail
892+
///
893+
/// #[derive(scylla_macros::SerializeRow)]
894+
/// #[scylla(crate = scylla_cql)]
895+
/// struct TestRow {
896+
/// #[scylla(rename = "b")]
897+
/// a: i32,
898+
/// b: String,
899+
/// }
900+
/// ```
901+
fn _test_struct_deserialization_skip_rename_collision_with_field() {}
902+
903+
/// ```compile_fail
904+
///
905+
/// #[derive(scylla_macros::SerializeRow)]
906+
/// #[scylla(crate = scylla_cql)]
907+
/// struct TestRow {
908+
/// #[scylla(rename = "c")]
909+
/// a: i32,
910+
/// #[scylla(rename = "c")]
911+
/// b: String,
912+
/// }
913+
/// ```
914+
fn _test_struct_deserialization_rename_collision_with_another_rename() {}
915+
}
916+
870917
#[cfg(test)]
871-
mod tests {
918+
pub(crate) mod tests {
872919
use std::borrow::Cow;
873920
use std::collections::BTreeMap;
874921

@@ -990,7 +1037,7 @@ mod tests {
9901037
assert_eq!(typed_data, erased_data);
9911038
}
9921039

993-
fn do_serialize<T: SerializeRow>(t: T, columns: &[ColumnSpec]) -> Vec<u8> {
1040+
pub(crate) fn do_serialize<T: SerializeRow>(t: T, columns: &[ColumnSpec]) -> Vec<u8> {
9941041
let ctx = RowSerializationContext { columns };
9951042
let mut ret = Vec::new();
9961043
let mut builder = RowWriter::new(&mut ret);

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

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,8 +1496,105 @@ pub enum ValueToSerializeValueAdapterError {
14961496
},
14971497
}
14981498

1499+
mod doctests {
1500+
/// ```compile_fail
1501+
///
1502+
/// #[derive(scylla_macros::SerializeValue)]
1503+
/// #[scylla(crate = scylla_cql, skip_name_checks)]
1504+
/// struct TestUdt {}
1505+
/// ```
1506+
fn _test_udt_bad_attributes_skip_name_check_requires_enforce_order() {}
1507+
1508+
/// ```compile_fail
1509+
///
1510+
/// #[derive(scylla_macros::SerializeValue)]
1511+
/// #[scylla(crate = scylla_cql, flavor = "enforce_order", skip_name_checks)]
1512+
/// struct TestUdt {
1513+
/// #[scylla(rename = "b")]
1514+
/// a: i32,
1515+
/// }
1516+
/// ```
1517+
fn _test_udt_bad_attributes_skip_name_check_conflicts_with_rename() {}
1518+
1519+
/// ```compile_fail
1520+
///
1521+
/// #[derive(scylla_macros::SerializeValue)]
1522+
/// #[scylla(crate = scylla_cql)]
1523+
/// struct TestUdt {
1524+
/// #[scylla(rename = "b")]
1525+
/// a: i32,
1526+
/// b: String,
1527+
/// }
1528+
/// ```
1529+
fn _test_udt_bad_attributes_rename_collision_with_field() {}
1530+
1531+
/// ```compile_fail
1532+
///
1533+
/// #[derive(scylla_macros::SerializeValue)]
1534+
/// #[scylla(crate = scylla_cql)]
1535+
/// struct TestUdt {
1536+
/// #[scylla(rename = "c")]
1537+
/// a: i32,
1538+
/// #[scylla(rename = "c")]
1539+
/// b: String,
1540+
/// }
1541+
/// ```
1542+
fn _test_udt_bad_attributes_rename_collision_with_another_rename() {}
1543+
1544+
/// ```compile_fail
1545+
///
1546+
/// #[derive(scylla_macros::SerializeValue)]
1547+
/// #[scylla(crate = scylla_cql, flavor = "enforce_order", skip_name_checks)]
1548+
/// struct TestUdt {
1549+
/// a: i32,
1550+
/// #[scylla(allow_missing)]
1551+
/// b: bool,
1552+
/// c: String,
1553+
/// }
1554+
/// ```
1555+
fn _test_udt_bad_attributes_name_skip_name_checks_limitations_on_allow_missing() {}
1556+
1557+
/// ```
1558+
///
1559+
/// #[derive(scylla_macros::SerializeValue)]
1560+
/// #[scylla(crate = scylla_cql, flavor = "enforce_order", skip_name_checks)]
1561+
/// struct TestUdt {
1562+
/// a: i32,
1563+
/// #[scylla(allow_missing)]
1564+
/// b: bool,
1565+
/// #[scylla(allow_missing)]
1566+
/// c: String,
1567+
/// }
1568+
/// ```
1569+
fn _test_udt_good_attributes_name_skip_name_checks_limitations_on_allow_missing() {}
1570+
1571+
/// ```
1572+
/// #[derive(scylla_macros::SerializeValue)]
1573+
/// #[scylla(crate = scylla_cql)]
1574+
/// struct TestUdt {
1575+
/// a: i32,
1576+
/// #[scylla(allow_missing)]
1577+
/// b: bool,
1578+
/// c: String,
1579+
/// }
1580+
/// ```
1581+
fn _test_udt_unordered_flavour_no_limitations_on_allow_missing() {}
1582+
1583+
/// ```
1584+
/// #[derive(scylla_macros::SerializeValue)]
1585+
/// #[scylla(crate = scylla_cql)]
1586+
/// struct TestUdt {
1587+
/// a: i32,
1588+
/// #[scylla(default_when_null)]
1589+
/// b: bool,
1590+
/// c: String,
1591+
/// }
1592+
/// ```
1593+
fn _test_udt_default_when_null_is_accepted() {}
1594+
}
1595+
14991596
#[cfg(test)]
1500-
mod tests {
1597+
pub(crate) mod tests {
15011598
use std::collections::BTreeMap;
15021599

15031600
use crate::frame::response::result::{ColumnType, CqlValue};
@@ -1557,7 +1654,7 @@ mod tests {
15571654
t.serialize(typ, writer).map(|_| ()).map(|()| ret)
15581655
}
15591656

1560-
fn do_serialize<T: SerializeValue>(t: T, typ: &ColumnType) -> Vec<u8> {
1657+
pub(crate) fn do_serialize<T: SerializeValue>(t: T, typ: &ColumnType) -> Vec<u8> {
15611658
do_serialize_result(t, typ).unwrap()
15621659
}
15631660

@@ -2591,7 +2688,7 @@ mod tests {
25912688
}
25922689

25932690
#[derive(SerializeValue, Debug, PartialEq, Eq, Default)]
2594-
#[scylla(crate = crate, force_exact_match)]
2691+
#[scylla(crate = crate, forbid_excess_udt_fields)]
25952692
struct TestStrictUdtWithFieldSorting {
25962693
a: String,
25972694
b: i32,
@@ -2647,7 +2744,7 @@ mod tests {
26472744
}
26482745

26492746
#[derive(SerializeValue, Debug, PartialEq, Eq, Default)]
2650-
#[scylla(crate = crate, flavor = "enforce_order", force_exact_match)]
2747+
#[scylla(crate = crate, flavor = "enforce_order", forbid_excess_udt_fields)]
26512748
struct TestStrictUdtWithEnforcedOrder {
26522749
a: String,
26532750
b: i32,

0 commit comments

Comments
 (0)