Skip to content

Commit 0647f96

Browse files
committed
scylla-cql: Response/Result with deser metadata
We want to deserialize metadata of Result:Rows eagerly in `scylla`. The issue is that `scylla` operates on `Response` type, which is an enum that stores raw metadata. We can't change definition of this enum because of backwards compatibility. The solution here is to introduce another enum, ResponseWithDeserializedMetadata, and allow conversion of Response to it.
1 parent a8cc520 commit 0647f96

File tree

2 files changed

+164
-0
lines changed

2 files changed

+164
-0
lines changed

scylla-cql/src/frame/response/mod.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub use error::Error;
1313
pub use supported::Supported;
1414

1515
use crate::frame::TryFromPrimitiveError;
16+
use crate::frame::frame_errors::ResultMetadataAndRowsCountParseError;
1617
use crate::frame::protocol_features::ProtocolFeatures;
1718
use crate::frame::response::result::ResultMetadata;
1819

@@ -208,6 +209,28 @@ impl Response {
208209
Ok(response)
209210
}
210211

212+
pub fn deserialize_metadata(
213+
self,
214+
) -> Result<ResponseWithDeserializedMetadata, ResultMetadataAndRowsCountParseError> {
215+
let result = match self {
216+
Self::Error(e) => ResponseWithDeserializedMetadata::Error(e),
217+
Self::Ready => ResponseWithDeserializedMetadata::Ready,
218+
Self::Result(res) => {
219+
ResponseWithDeserializedMetadata::Result(res.deserialize_metadata()?)
220+
}
221+
Self::Authenticate(auth) => ResponseWithDeserializedMetadata::Authenticate(auth),
222+
Self::AuthSuccess(auth_succ) => {
223+
ResponseWithDeserializedMetadata::AuthSuccess(auth_succ)
224+
}
225+
Self::AuthChallenge(auth_chal) => {
226+
ResponseWithDeserializedMetadata::AuthChallenge(auth_chal)
227+
}
228+
Self::Supported(sup) => ResponseWithDeserializedMetadata::Supported(sup),
229+
Self::Event(eve) => ResponseWithDeserializedMetadata::Event(eve),
230+
};
231+
Ok(result)
232+
}
233+
211234
/// Converts this response into a `NonErrorResponse`, returning an error if it is an `Error` response.
212235
pub fn into_non_error_response(self) -> Result<NonErrorResponse, error::Error> {
213236
let non_error_response = match self {
@@ -225,6 +248,68 @@ impl Response {
225248
}
226249
}
227250

251+
/// A CQL response that has been received from the server.
252+
#[derive(Debug)]
253+
pub enum ResponseWithDeserializedMetadata {
254+
/// ERROR response, returned by the server when an error occurs.
255+
Error(Error),
256+
/// READY response, indicating that the server is ready to process requests,
257+
/// typically after a connection is established.
258+
Ready,
259+
/// RESULT response, containing the result of a statement execution.
260+
Result(result::ResultWithDeserializedMetadata),
261+
/// AUTHENTICATE response, indicating that the server requires authentication.
262+
Authenticate(authenticate::Authenticate),
263+
/// AUTH_SUCCESS response, indicating that the authentication was successful.
264+
AuthSuccess(authenticate::AuthSuccess),
265+
/// AUTH_CHALLENGE response, indicating that the server requires further authentication.
266+
AuthChallenge(authenticate::AuthChallenge),
267+
/// SUPPORTED response, containing the features supported by the server.
268+
Supported(Supported),
269+
/// EVENT response, containing an event that occurred on the server.
270+
Event(event::Event),
271+
}
272+
273+
impl ResponseWithDeserializedMetadata {
274+
/// Returns the kind of this response.
275+
pub fn to_response_kind(&self) -> CqlResponseKind {
276+
match self {
277+
Self::Error(_) => CqlResponseKind::Error,
278+
Self::Ready => CqlResponseKind::Ready,
279+
Self::Result(_) => CqlResponseKind::Result,
280+
Self::Authenticate(_) => CqlResponseKind::Authenticate,
281+
Self::AuthSuccess(_) => CqlResponseKind::AuthSuccess,
282+
Self::AuthChallenge(_) => CqlResponseKind::AuthChallenge,
283+
Self::Supported(_) => CqlResponseKind::Supported,
284+
Self::Event(_) => CqlResponseKind::Event,
285+
}
286+
}
287+
288+
/// Converts this response into a `NonErrorResponse`, returning an error if it is an `Error` response.
289+
pub fn into_non_error_response(
290+
self,
291+
) -> Result<NonErrorResponseWithDeserializedMetadata, error::Error> {
292+
let non_error_response = match self {
293+
Self::Error(e) => return Err(e),
294+
Self::Ready => NonErrorResponseWithDeserializedMetadata::Ready,
295+
Self::Result(res) => NonErrorResponseWithDeserializedMetadata::Result(res),
296+
Self::Authenticate(auth) => {
297+
NonErrorResponseWithDeserializedMetadata::Authenticate(auth)
298+
}
299+
Self::AuthSuccess(auth_succ) => {
300+
NonErrorResponseWithDeserializedMetadata::AuthSuccess(auth_succ)
301+
}
302+
Self::AuthChallenge(auth_chal) => {
303+
NonErrorResponseWithDeserializedMetadata::AuthChallenge(auth_chal)
304+
}
305+
Self::Supported(sup) => NonErrorResponseWithDeserializedMetadata::Supported(sup),
306+
Self::Event(eve) => NonErrorResponseWithDeserializedMetadata::Event(eve),
307+
};
308+
309+
Ok(non_error_response)
310+
}
311+
}
312+
228313
/// A CQL response that has been received from the server, excluding error responses.
229314
/// This is used to handle responses that are not errors, allowing for easier processing
230315
/// of valid responses without need to handle error case any later.
@@ -260,3 +345,41 @@ impl NonErrorResponse {
260345
}
261346
}
262347
}
348+
349+
/// A CQL response that has been received from the server, excluding error responses.
350+
/// This is used to handle responses that are not errors, allowing for easier processing
351+
/// of valid responses without need to handle error case any later.
352+
/// The difference from [NonErrorResponse] is that Result::Rows variant holds [result::DeserializedMetadataAndRawRows]
353+
/// instead of [result::RawMetadataAndRawRows].
354+
#[derive(Debug)]
355+
pub enum NonErrorResponseWithDeserializedMetadata {
356+
/// See [`Response::Ready`].
357+
Ready,
358+
/// See [`Response::Result`].
359+
Result(result::ResultWithDeserializedMetadata),
360+
/// See [`Response::Authenticate`].
361+
Authenticate(authenticate::Authenticate),
362+
/// See [`Response::AuthSuccess`].
363+
AuthSuccess(authenticate::AuthSuccess),
364+
/// See [`Response::AuthChallenge`].
365+
AuthChallenge(authenticate::AuthChallenge),
366+
/// See [`Response::Supported`].
367+
Supported(Supported),
368+
/// See [`Response::Event`].
369+
Event(event::Event),
370+
}
371+
372+
impl NonErrorResponseWithDeserializedMetadata {
373+
/// Returns the kind of this non-error response.
374+
pub fn to_response_kind(&self) -> CqlResponseKind {
375+
match self {
376+
Self::Ready => CqlResponseKind::Ready,
377+
Self::Result(_) => CqlResponseKind::Result,
378+
Self::Authenticate(_) => CqlResponseKind::Authenticate,
379+
Self::AuthSuccess(_) => CqlResponseKind::AuthSuccess,
380+
Self::AuthChallenge(_) => CqlResponseKind::AuthChallenge,
381+
Self::Supported(_) => CqlResponseKind::Supported,
382+
Self::Event(_) => CqlResponseKind::Event,
383+
}
384+
}
385+
}

scylla-cql/src/frame/response/result.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,47 @@ pub enum Result {
760760
SchemaChange(SchemaChange),
761761
}
762762

763+
impl Result {
764+
pub fn deserialize_metadata(
765+
self,
766+
) -> StdResult<ResultWithDeserializedMetadata, ResultMetadataAndRowsCountParseError> {
767+
let res = match self {
768+
Result::Void => ResultWithDeserializedMetadata::Void,
769+
Result::Rows((metadata, paging_state)) => ResultWithDeserializedMetadata::Rows((
770+
metadata.deserialize_metadata()?,
771+
paging_state,
772+
)),
773+
Result::SetKeyspace(set_keyspace) => {
774+
ResultWithDeserializedMetadata::SetKeyspace(set_keyspace)
775+
}
776+
Result::Prepared(prepared) => ResultWithDeserializedMetadata::Prepared(prepared),
777+
Result::SchemaChange(schema_change) => {
778+
ResultWithDeserializedMetadata::SchemaChange(schema_change)
779+
}
780+
};
781+
782+
Ok(res)
783+
}
784+
}
785+
786+
/// Represents the result of a CQL `RESULT` response.
787+
#[derive(Debug)]
788+
pub enum ResultWithDeserializedMetadata {
789+
/// A result with no associated data.
790+
Void,
791+
/// A result with metadata and rows.
792+
Rows((DeserializedMetadataAndRawRows, PagingStateResponse)),
793+
/// A result indicating that a keyspace was set as an effect
794+
/// of the executed request.
795+
SetKeyspace(SetKeyspace),
796+
/// A result indicating that a statement was prepared
797+
/// as an effect of the `PREPARE` request.
798+
Prepared(Prepared),
799+
/// A result indicating that a schema change occurred
800+
/// as an effect of the executed request.
801+
SchemaChange(SchemaChange),
802+
}
803+
763804
fn deser_type_generic<'frame, 'result, StrT: Into<Cow<'result, str>>>(
764805
buf: &mut &'frame [u8],
765806
read_string: fn(&mut &'frame [u8]) -> StdResult<StrT, LowLevelDeserializationError>,

0 commit comments

Comments
 (0)