Skip to content

Commit

Permalink
Merge pull request #1000 from muzarski/rename_serialize_cql
Browse files Browse the repository at this point in the history
Rename `SerializeCql` to `SerializeValue`
  • Loading branch information
wprzytula authored Jun 4, 2024
2 parents 5dbb10b + 7440d3d commit 4b1eca9
Show file tree
Hide file tree
Showing 20 changed files with 237 additions and 228 deletions.
16 changes: 8 additions & 8 deletions docs/source/data-types/udt.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,24 @@ CREATE TYPE ks.my_type (int_val int, text_val text)
```

To use this type in the driver, create a matching struct and derive:
- `SerializeCql`: in order to be able to use this struct in query parameters. \
- `SerializeValue`: in order to be able to use this struct in query parameters. \
This macro requires fields of UDT and struct to have matching names, but the order
of the fields is not required to be the same. \
Note: you can use different name using `rename` attribute - see `SerializeCql` macro documentation.
Note: you can use different name using `rename` attribute - see `SerializeValue` macro documentation.
- `FromUserType`: in order to be able to use this struct in query results. \
This macro requires fields of UDT and struct to be in the same *ORDER*. \
This mismatch between `SerializeCql` and `FromUserType` requirements is a temporary situation - in the future `FromUserType` (or the macro that replaces it) will also require matching names.
This mismatch between `SerializeValue` and `FromUserType` requirements is a temporary situation - in the future `FromUserType` (or the macro that replaces it) will also require matching names.

```rust
# extern crate scylla;
# async fn check_only_compiles() {
use scylla::macros::{FromUserType, SerializeCql};
use scylla::macros::{FromUserType, SerializeValue};

// Define a custom struct that matches the User Defined Type created earlier.
// Fields must be in the same order as they are in the database and also
// have the same names.
// Wrapping a field in Option will gracefully handle null field values.
#[derive(Debug, FromUserType, SerializeCql)]
#[derive(Debug, FromUserType, SerializeValue)]
struct MyType {
int_val: i32,
text_val: Option<String>,
Expand All @@ -41,7 +41,7 @@ struct MyType {
> ***Important***\
> For serialization, by default fields in the Rust struct must be defined with the same names as they are in the database.
> The driver will serialize the fields in the order defined by the UDT, matching Rust fields by name.
> You can change this behaviour using macro attributes, see `SerializeCql` macro documentation for more information.
> You can change this behaviour using macro attributes, see `SerializeValue` macro documentation for more information.
Now it can be sent and received just like any other CQL value:
```rust
Expand All @@ -50,10 +50,10 @@ Now it can be sent and received just like any other CQL value:
# use std::error::Error;
# async fn check_only_compiles(session: &Session) -> Result<(), Box<dyn Error>> {
use scylla::IntoTypedRows;
use scylla::macros::{FromUserType, SerializeCql};
use scylla::macros::{FromUserType, SerializeValue};
use scylla::cql_to_rust::FromCqlVal;

#[derive(Debug, FromUserType, SerializeCql)]
#[derive(Debug, FromUserType, SerializeValue)]
struct MyType {
int_val: i32,
text_val: Option<String>,
Expand Down
22 changes: 11 additions & 11 deletions docs/source/migration-guides/0.11-serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,31 @@ In version 0.11, a new set of traits is introduced and the old ones are deprecat

Both the old and the new APIs are based on three core traits:

- `Value` - called `SerializeCql` in the new API. A type that can serialize itself to a single CQL value. For example, `i32` serializes itself into a representation that is compatible with the CQL `int` type.
- `Value` - called `SerializeValue` in the new API. A type that can serialize itself to a single CQL value. For example, `i32` serializes itself into a representation that is compatible with the CQL `int` type.
- `ValueList` - called `SerializeRow` in the new API. A type that can serialize itself as a list of values for a CQL statement. For example, a `(i32, &str)` produces a list of two values which can be used in a query with two bind markers, e.g. `SELECT * FROM table WHERE pk = ? AND ck = ?`. Optionally, values in the produced list may be associated with names which is useful when using it with a query with named bind markers, e.g. `SELECT * FROM table WHERE pk = :pk AND ck = :ck`.
- `LegacyBatchValues`, previously named `BatchValues` - in new API replaced with new trait called (again) `BatchValues`. Represents a source of data for a batch request. It is essentially equivalent to a list of `ValueList`, one for each statement in the batch. For example, `((1, 2), (3, 4, 5))` can be used for a batch with two statements, the first one having two bind markers and the second one having three.

All methods which take one of the old traits were changed to take the new trait - notably, this includes `Session::query`, `(Caching)Session::execute`, `(Caching)Session::batch`.

The driver comes a set of `impl`s of those traits which allow to represent any CQL type (for example, see [Data Types](../data-types/data-types.md) page for a list of for which `Value` and `SerializeCql` is implemented). If the driver implements an old trait for some type, then it also provides implements the new trait for the same type.
The driver comes a set of `impl`s of those traits which allow to represent any CQL type (for example, see [Data Types](../data-types/data-types.md) page for a list of for which `Value` and `SerializeValue` is implemented). If the driver implements an old trait for some type, then it also provides implements the new trait for the same type.

## Migration scenarios

### Different default behavior in `SerializeRow`/`SerializeCql` macros
### Different default behavior in `SerializeRow`/`SerializeValue` macros

By default, the `SerializeRow` and `SerializeCql` **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 `SerializeCql`). 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.
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.

> **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.
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:

```rust
# extern crate scylla;
use scylla::SerializeCql;
use scylla::SerializeValue;

// The exact same attributes apply to the `SerializeRow` macro and their
// effect is completely analogous.
#[derive(SerializeCql)]
#[derive(SerializeValue)]
#[scylla(flavor = "enforce_order", skip_name_checks)]
struct Person {
name: String,
Expand All @@ -61,7 +61,7 @@ struct Person {
}
```

Refer to the API reference page for the `SerializeRow` and `SerializeCql` macros in the `scylla` crate to learn more about the supported attributes and their meaning.
Refer to the API reference page for the `SerializeRow` and `SerializeValue` macros in the `scylla` crate to learn more about the supported attributes and their meaning.

### Preparing is mandatory with a non-empty list of values

Expand All @@ -80,13 +80,13 @@ In both cases, if the additional roundtrips are unacceptable, you should prepare

### Migrating from old to new traits *gradually*

In some cases, migration will be as easy as changing occurrences of `IntoUserType` to `SerializeCql` and `ValueList` to `SerializeRow` and adding some atributes for procedural macros. However, if you have a large enough codebase or some custom, complicated implementations of the old traits then you might not want to migrate everything at once. To support gradual migration, the old traits were not removed but rather deprecated, and we introduced some additional utilities.
In some cases, migration will be as easy as changing occurrences of `IntoUserType` to `SerializeValue` and `ValueList` to `SerializeRow` and adding some atributes for procedural macros. However, if you have a large enough codebase or some custom, complicated implementations of the old traits then you might not want to migrate everything at once. To support gradual migration, the old traits were not removed but rather deprecated, and we introduced some additional utilities.

#### Converting an object implementing an old trait to a new trait

We provide a number of newtype wrappers:

- `ValueAdapter` - implements `SerializeCql` if the type wrapped over implements `Value`,
- `ValueAdapter` - implements `SerializeValue` if the type wrapped over implements `Value`,
- `ValueListAdapter` - implements `SerializeRow` if the type wrapped over implements `ValueList`,
- `LegacyBatchValuesAdapter` - implements `BatchValues` if the type wrapped over implements `LegacyBatchValues`.

Expand All @@ -98,9 +98,9 @@ Conversion in the other direction is not possible.

#### Custom implementations of old traits

It is possible to directly generate an `impl` of `SerializeRow` and `SerializeCql` on a type which implements, respectively, `ValueList` or `Value`, without using the wrappers from the previous section. The following macros are provided:
It is possible to directly generate an `impl` of `SerializeRow` and `SerializeValue` on a type which implements, respectively, `ValueList` or `Value`, without using the wrappers from the previous section. The following macros are provided:

- `impl_serialize_cql_via_value` - implements `SerializeCql` if the type wrapped over implements `Value`,
- `impl_serialize_value_via_value` - implements `SerializeValue` if the type wrapped over implements `Value`,
- `impl_serialize_row_via_value_list` - implements `SerializeRow` if the type wrapped over implements `ValueList`,

The implementations are practically as those generated by the wrappers described in the previous section.
4 changes: 2 additions & 2 deletions examples/user-defined-type.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anyhow::Result;
use scylla::macros::FromUserType;
use scylla::{SerializeCql, Session, SessionBuilder};
use scylla::{SerializeValue, Session, SessionBuilder};
use std::env;

#[tokio::main]
Expand Down Expand Up @@ -29,7 +29,7 @@ async fn main() -> Result<()> {

// Define custom struct that matches User Defined Type created earlier
// wrapping field in Option will gracefully handle null field values
#[derive(Debug, FromUserType, SerializeCql)]
#[derive(Debug, FromUserType, SerializeValue)]
struct MyType {
int_val: i32,
text_val: Option<String>,
Expand Down
2 changes: 1 addition & 1 deletion examples/value_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ async fn main() {

// You can also use type generics:
#[derive(scylla::SerializeRow)]
struct MyTypeWithGenerics<S: scylla::serialize::value::SerializeCql> {
struct MyTypeWithGenerics<S: scylla::serialize::value::SerializeValue> {
k: i32,
my: Option<S>,
}
Expand Down
14 changes: 7 additions & 7 deletions scylla-cql/src/frame/value_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::frame::value::{CqlTimeuuid, CqlVarint};
use crate::frame::{response::result::CqlValue, types::RawValue, value::LegacyBatchValuesIterator};
use crate::types::serialize::batch::{BatchValues, BatchValuesIterator, LegacyBatchValuesAdapter};
use crate::types::serialize::row::{RowSerializationContext, SerializeRow};
use crate::types::serialize::value::SerializeCql;
use crate::types::serialize::value::SerializeValue;
use crate::types::serialize::{CellWriter, RowWriter};

use super::response::result::{ColumnSpec, ColumnType, TableSpec};
Expand All @@ -23,24 +23,24 @@ use uuid::Uuid;

fn serialized<T>(val: T, typ: ColumnType) -> Vec<u8>
where
T: Value + SerializeCql,
T: Value + SerializeValue,
{
let mut result: Vec<u8> = Vec::new();
Value::serialize(&val, &mut result).unwrap();

let mut new_result: Vec<u8> = Vec::new();
let writer = CellWriter::new(&mut new_result);
SerializeCql::serialize(&val, &typ, writer).unwrap();
SerializeValue::serialize(&val, &typ, writer).unwrap();

assert_eq!(result, new_result);

result
}

fn serialized_only_new<T: SerializeCql>(val: T, typ: ColumnType) -> Vec<u8> {
fn serialized_only_new<T: SerializeValue>(val: T, typ: ColumnType) -> Vec<u8> {
let mut result: Vec<u8> = Vec::new();
let writer = CellWriter::new(&mut result);
SerializeCql::serialize(&val, &typ, writer).unwrap();
SerializeValue::serialize(&val, &typ, writer).unwrap();
result
}

Expand Down Expand Up @@ -169,7 +169,7 @@ fn varint_test_cases_from_spec() -> Vec<(i64, Vec<u8>)> {
#[cfg(any(feature = "num-bigint-03", feature = "num-bigint-04"))]
fn generic_num_bigint_serialization<B>()
where
B: From<i64> + Value + SerializeCql,
B: From<i64> + Value + SerializeValue,
{
let cases_from_the_spec: &[(i64, Vec<u8>)] = &varint_test_cases_from_spec();

Expand Down Expand Up @@ -824,7 +824,7 @@ fn cqlvalue_serialization() {
]
);

// Unlike the legacy Value trait, SerializeCql takes case of reordering
// Unlike the legacy Value trait, SerializeValue takes case of reordering
// the fields
let udt = CqlValue::UserDefinedType {
keyspace: "ks".to_string(),
Expand Down
4 changes: 2 additions & 2 deletions scylla-cql/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ pub mod macros {
pub use scylla_macros::FromRow;
pub use scylla_macros::FromUserType;
pub use scylla_macros::IntoUserType;
pub use scylla_macros::SerializeCql;
pub use scylla_macros::SerializeRow;
pub use scylla_macros::SerializeValue;
pub use scylla_macros::ValueList;

// Reexports for derive(IntoUserType)
Expand Down Expand Up @@ -44,7 +44,7 @@ pub mod _macro_internal {
BuiltinSerializationError as BuiltinTypeSerializationError,
BuiltinSerializationErrorKind as BuiltinTypeSerializationErrorKind,
BuiltinTypeCheckError as BuiltinTypeTypeCheckError,
BuiltinTypeCheckErrorKind as BuiltinTypeTypeCheckErrorKind, SerializeCql,
BuiltinTypeCheckErrorKind as BuiltinTypeTypeCheckErrorKind, SerializeValue,
UdtSerializationErrorKind, UdtTypeCheckErrorKind,
};
pub use crate::types::serialize::writers::WrittenCellProof;
Expand Down
4 changes: 2 additions & 2 deletions scylla-cql/src/types/serialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ pub use writers::{CellValueBuilder, CellWriter, RowWriter};
/// one of types with an impl built into the driver fails. It is also returned
/// from impls generated by the `SerializeRow` macro.
/// - [`value::BuiltinSerializationError`] is analogous to the above but is
/// returned from [`SerializeCql::serialize`](value::SerializeCql::serialize)
/// returned from [`SerializeValue::serialize`](value::SerializeValue::serialize)
/// instead both in the case of builtin impls and impls generated by the
/// `SerializeCql` macro. It won't be returned by the `Session` directly,
/// `SerializeValue` macro. It won't be returned by the `Session` directly,
/// but it might be nested in the [`row::BuiltinSerializationError`].
/// - [`row::ValueListToSerializeRowAdapterError`] is returned in case when
/// a list of named values encoded with the legacy `ValueList` trait is passed
Expand Down
Loading

0 comments on commit 4b1eca9

Please sign in to comment.