diff --git a/docs/source/migration-guides/0.11-serialization.md b/docs/source/migration-guides/0.11-serialization.md index 601be0da2..d2450b031 100644 --- a/docs/source/migration-guides/0.11-serialization.md +++ b/docs/source/migration-guides/0.11-serialization.md @@ -6,7 +6,7 @@ When executing a statement through the CQL protocol, values for the bind markers Before 0.11, the driver couldn't do this kind of type checking. For example, in the case of non-batch queries, the only information about the user data it has is that it implements `ValueList` - defined as follows: -```rust +```rust,ignore # extern crate scylla; # extern crate bytes; # use scylla::frame::value::{SerializedResult, SerializeValuesError}; @@ -76,29 +76,8 @@ If you send simple statements along with non-empty lists of values, the slowdown In both cases, if the additional roundtrips are unacceptable, you should prepare the statements beforehand and reuse them - which aligns with our general recommendation against use of simple statements in performance sensitive scenarios. -### Migrating from old to new traits *gradually* - -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 `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`. - -Note that these wrappers are not zero cost and incur some overhead: in case of `ValueAdapter` and `ValueListAdapter`, the data is first written into a newly allocated buffer and then rewritten to the final buffer. In case of `LegacyBatchValuesAdapter` there shouldn't be any additional allocations unless the implementation has an efficient, non-default `Self::LegacyBatchValuesIterator::write_next_to_request` implementation (which is not the case for the built-in `impl`s). - -Naturally, the implementations provided by the wrappers are not type safe as they directly use methods from the old traits. - -Conversion in the other direction is not possible. - -#### Custom implementations of old traits - -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_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`, +### Migrating from old to new traits -The implementations are practically as those generated by the wrappers described in the previous section. +Up to 1.0 the driver offered a set of migration types and macros to allow adapting new API gradually. +Since 1.0 this is no longer the case and the old API is fully removed. In order to use 1.0 you have to +change your code to use new API. diff --git a/docs/source/migration-guides/0.15-deserialization.md b/docs/source/migration-guides/0.15-deserialization.md index bbc198f3b..5ca5493d1 100644 --- a/docs/source/migration-guides/0.15-deserialization.md +++ b/docs/source/migration-guides/0.15-deserialization.md @@ -1,20 +1,20 @@ # Adjusting code to changes in deserialization API introduced in 0.15 -In 0.15, a new deserialization API has been introduced. The new API improves type safety and performance of the old one, so it is highly recommended to switch to it. However, deserialization is an area of the API that users frequently interact with: deserialization traits appear in generic code and custom implementations have been written. In order to make migration easier, the driver still offers the old API, which - while opt-in - can be very easily switched to after version upgrade. Furthermore, a number of facilities have been introduced which help migrate the user code to the new API piece-by-piece. - -The old API and migration facilities will be removed in a future major release. +In 0.15, a new deserialization API has been introduced. The new API improves type safety and performance of the old one, so it is highly recommended to switch to it. However, deserialization is an area of the API that users frequently interact with: deserialization traits appear in generic code and custom implementations have been written. +In order to make migration easier, the driver 0.15 still offered the old API, which - while opt-in - can be very easily switched to after version upgrade. +Since 1.0 the old API (and thus the migration utilities too) have been fully removed. ## Introduction ### Old traits -The legacy API works by deserializing rows in the query response to a sequence of `Row`s. The `Row` is just a `Vec>`, where `CqlValue` is an enum that is able to represent any CQL value. +The legacy API worked by deserializing rows in the query response to a sequence of `Row`s. The `Row` is just a `Vec>`, where `CqlValue` is an enum that is able to represent any CQL value. -The user can request this type-erased representation to be converted into something useful. There are two traits that power this: +The user could request this type-erased representation to be converted into something useful. There were two traits that powered this: __`FromRow`__ -```rust +```rust,ignore # extern crate scylla; # use scylla::frame::response::cql_to_rust::FromRowError; # use scylla::frame::response::result::Row; @@ -25,7 +25,7 @@ pub trait FromRow: Sized { __`FromCqlVal`__ -```rust +```rust,ignore # extern crate scylla; # use scylla::frame::response::cql_to_rust::FromCqlValError; // The `T` parameter is supposed to be either `CqlValue` or `Option` @@ -34,21 +34,21 @@ pub trait FromCqlVal: Sized { } ``` -These traits are implemented for some common types: +These traits were implemented for some common types: -- `FromRow` is implemented for tuples up to 16 elements, -- `FromCqlVal` is implemented for a bunch of types, and each CQL type can be converted to one of them. +- `FromRow` was implemented for tuples up to 16 elements, +- `FromCqlVal` was implemented for a bunch of types, and each CQL type could be converted to one of them. -While it's possible to implement those manually, the driver provides procedural macros for automatic derivation in some cases: +While it was possible to implement those manually, the driver provided procedural macros for automatic derivation in some cases: -- `FromRow` - implements `FromRow` for a struct. +- `FromRow` - implemented `FromRow` for a struct. - `FromUserType` - generated an implementation of `FromCqlVal` for the struct, trying to parse the CQL value as a UDT. -Note: the macros above have a default behavior that is different than what `FromRow` and `FromUserType` do. +Note: the macros above had a default behavior that is different than what `FromRow` and `FromUserType` do. ### New traits -The new API introduce two analogous traits that, instead of consuming pre-parsed `Vec>`, are given raw, serialized data with full information about its type. This leads to better performance and allows for better type safety. +The new API introduces two analogous traits that, instead of consuming pre-parsed `Vec>`, are given raw, serialized data with full information about its type. This leads to better performance and allows for better type safety. The new traits are: @@ -106,7 +106,7 @@ Note that the `QueryResult::rows` field is not available anymore. If you used to Before: -```rust +```rust,ignore # extern crate scylla; # use scylla::client::session::LegacySession; # use std::error::Error; @@ -155,7 +155,7 @@ The `Session::query_iter` and `Session::execute_iter` have been adjusted, too. T Before: -```rust +```rust,ignore # extern crate scylla; # extern crate futures; # use scylla::client::session::LegacySession; @@ -209,11 +209,11 @@ As mentioned in the Introduction section, the driver provides new procedural mac __`FromRow` vs. `DeserializeRow`__ -The impl generated by `FromRow` expects columns to be in the same order as the struct fields. The `FromRow` trait does not have information about column names, so it cannot match them with the struct field names. You can use `enforce_order` and `skip_name_checks` attributes to achieve such behavior via `DeserializeRow` trait. +The impl generated by `FromRow` expected columns to be in the same order as the struct fields. The `FromRow` trait did not have information about column names, so it could not match them with the struct field names. You can use `enforce_order` and `skip_name_checks` attributes to achieve such behavior via `DeserializeRow` trait. __`FromUserType` vs. `DeserializeValue`__ -The impl generated by `FromUserType` expects UDT fields to be in the same order as the struct fields. Field names should be the same both in the UDT and in the struct. You can use the `enforce_order` attribute to achieve such behavior via the `DeserializeValue` trait. +The impl generated by `FromUserType` expected UDT fields to be in the same order as the struct fields. Field names should be the same both in the UDT and in the struct. You can use the `enforce_order` attribute to achieve such behavior via the `DeserializeValue` trait. ### Adjusting custom impls of deserialization traits @@ -221,77 +221,6 @@ If you have a custom type with a hand-written `impl FromRow` or `impl FromCqlVal ## Accessing the old API -Most important types related to deserialization of the old API have been renamed and contain a `Legacy` prefix in their names: - -- `Session` -> `LegacySession` -- `CachingSession` -> `LegacyCachingSession` -- `RowIterator` -> `LegacyRowIterator` -- `TypedRowIterator` -> `LegacyTypedRowIterator` -- `QueryResult` -> `LegacyQueryResult` - -If you intend to quickly migrate your application by using the old API, you can just import the legacy stuff and alias it as the new one, e.g.: - -```rust -# extern crate scylla; -use scylla::client::session::LegacySession as Session; -``` - -In order to create the `LegacySession` instead of the new `Session`, you need to use `SessionBuilder`'s `build_legacy()` method instead of `build()`: - -```rust -# extern crate scylla; -# use scylla::client::session::LegacySession; -# use scylla::client::session_builder::SessionBuilder; -# use std::error::Error; -# async fn check_only_compiles() -> Result<(), Box> { -let session: LegacySession = SessionBuilder::new() - .known_node("127.0.0.1") - .build_legacy() - .await?; -# Ok(()) -# } -``` - -## Mixing the old and the new API - -It is possible to use different APIs in different parts of the program. The `Session` allows to create a `LegacySession` object that has the old API but shares all resources with the session that has the new API (and vice versa - you can create a new API session from the old API session). - -```rust -# extern crate scylla; -# use scylla::client::session::{LegacySession, Session}; -# use std::error::Error; -# async fn check_only_compiles(new_api_session: &Session) -> Result<(), Box> { -// All of the session objects below will use the same resources: connections, -// metadata, current keyspace, etc. -let old_api_session: LegacySession = new_api_session.make_shared_session_with_legacy_api(); -let another_new_api_session: Session = old_api_session.make_shared_session_with_new_api(); -# Ok(()) -# } -``` - -In addition to that, it is possible to convert a `QueryResult` to `LegacyQueryResult`: - -```rust -# extern crate scylla; -# use scylla::response::query_result::QueryResult; -# use scylla::response::legacy_query_result::LegacyQueryResult; -# use std::error::Error; -# async fn check_only_compiles(result: QueryResult) -> Result<(), Box> { -let result: QueryResult = result; -let legacy_result: LegacyQueryResult = result.into_legacy_result()?; -# Ok(()) -# } -``` - -... and `QueryPager` into `LegacyRowIterator`: - -```rust -# extern crate scylla; -# use scylla::client::pager::{QueryPager, LegacyRowIterator}; -# use std::error::Error; -# async fn check_only_compiles(pager: QueryPager) -> Result<(), Box> { -let pager: QueryPager = pager; -let legacy_result: LegacyRowIterator = pager.into_legacy(); -# Ok(()) -# } -``` +In 0.15 version of the driver it was possible to access the old API, and to mix usages of the old and new APIs in order +to allow gradual migration. +Since 1.0 this is no longer the case. The application must migrate to the new API in order to use driver 1.0. \ No newline at end of file