#![allow(deprecated)]
use crate::frame::response::cql_to_rust::{FromRow, FromRowError};
use crate::frame::response::result::ColumnSpec;
use crate::frame::response::result::Row;
use scylla_cql::frame::frame_errors::ResultMetadataAndRowsCountParseError;
use scylla_cql::frame::response::result::{self, ResultMetadataHolder};
use scylla_cql::types::deserialize::{DeserializationError, TypeCheckError};
use thiserror::Error;
use uuid::Uuid;
#[deprecated(
since = "0.15.1",
note = "Legacy deserialization API is inefficient and is going to be removed soon"
)]
#[allow(deprecated)]
pub trait IntoTypedRows {
fn into_typed<RowT: FromRow>(self) -> TypedRowIter<RowT>;
}
impl IntoTypedRows for Vec<result::Row> {
fn into_typed<RowT: FromRow>(self) -> TypedRowIter<RowT> {
TypedRowIter {
row_iter: self.into_iter(),
phantom_data: Default::default(),
}
}
}
#[deprecated(
since = "0.15.1",
note = "Legacy deserialization API is inefficient and is going to be removed soon"
)]
pub struct TypedRowIter<RowT: FromRow> {
row_iter: std::vec::IntoIter<result::Row>,
phantom_data: std::marker::PhantomData<RowT>,
}
impl<RowT: FromRow> Iterator for TypedRowIter<RowT> {
type Item = Result<RowT, FromRowError>;
fn next(&mut self) -> Option<Self::Item> {
self.row_iter.next().map(RowT::from_row)
}
}
#[non_exhaustive]
#[derive(Default, Debug)]
#[deprecated(
since = "0.15.0",
note = "Legacy deserialization API is inefficient and is going to be removed soon"
)]
pub struct LegacyQueryResult {
pub rows: Option<Vec<Row>>,
pub warnings: Vec<String>,
pub tracing_id: Option<Uuid>,
pub(crate) metadata: Option<ResultMetadataHolder>,
pub serialized_size: usize,
}
impl LegacyQueryResult {
pub fn rows_num(&self) -> Result<usize, RowsExpectedError> {
match &self.rows {
Some(rows) => Ok(rows.len()),
None => Err(RowsExpectedError),
}
}
pub fn rows(self) -> Result<Vec<Row>, RowsExpectedError> {
match self.rows {
Some(rows) => Ok(rows),
None => Err(RowsExpectedError),
}
}
pub fn rows_typed<RowT: FromRow>(self) -> Result<TypedRowIter<RowT>, RowsExpectedError> {
Ok(self.rows()?.into_typed())
}
pub fn result_not_rows(&self) -> Result<(), RowsNotExpectedError> {
match self.rows {
Some(_) => Err(RowsNotExpectedError),
None => Ok(()),
}
}
pub fn rows_or_empty(self) -> Vec<Row> {
self.rows.unwrap_or_default()
}
pub fn rows_typed_or_empty<RowT: FromRow>(self) -> TypedRowIter<RowT> {
self.rows_or_empty().into_typed::<RowT>()
}
pub fn first_row(self) -> Result<Row, FirstRowError> {
match self.maybe_first_row()? {
Some(row) => Ok(row),
None => Err(FirstRowError::RowsEmpty),
}
}
pub fn first_row_typed<RowT: FromRow>(self) -> Result<RowT, FirstRowTypedError> {
Ok(self.first_row()?.into_typed()?)
}
pub fn maybe_first_row(self) -> Result<Option<Row>, RowsExpectedError> {
Ok(self.rows()?.into_iter().next())
}
pub fn maybe_first_row_typed<RowT: FromRow>(
self,
) -> Result<Option<RowT>, MaybeFirstRowTypedError> {
match self.maybe_first_row()? {
Some(row) => Ok(Some(row.into_typed::<RowT>()?)),
None => Ok(None),
}
}
pub fn single_row(self) -> Result<Row, SingleRowError> {
let rows: Vec<Row> = self.rows()?;
if rows.len() != 1 {
return Err(SingleRowError::BadNumberOfRows(rows.len()));
}
Ok(rows.into_iter().next().unwrap())
}
pub fn single_row_typed<RowT: FromRow>(self) -> Result<RowT, SingleRowTypedError> {
Ok(self.single_row()?.into_typed::<RowT>()?)
}
#[inline]
pub fn col_specs(&self) -> &[ColumnSpec<'_>] {
self.metadata
.as_ref()
.map(|metadata| metadata.inner().col_specs())
.unwrap_or_default()
}
#[inline]
pub fn get_column_spec<'a>(&'a self, name: &str) -> Option<(usize, &'a ColumnSpec<'a>)> {
self.col_specs()
.iter()
.enumerate()
.find(|(_id, spec)| spec.name() == name)
}
}
#[deprecated(
since = "0.15.1",
note = "Legacy deserialization API is inefficient and is going to be removed soon"
)]
#[non_exhaustive]
#[derive(Error, Clone, Debug)]
pub enum IntoLegacyQueryResultError {
#[error("Failed to lazily deserialize result metadata: {0}")]
ResultMetadataAndRowsCountParseError(#[from] ResultMetadataAndRowsCountParseError),
#[error("Typecheck error: {0}")]
TypecheckError(#[from] TypeCheckError),
#[error("Failed to deserialize rows: {0}")]
DeserializationError(#[from] DeserializationError),
}
#[deprecated(
since = "0.15.1",
note = "Legacy deserialization API is inefficient and is going to be removed soon"
)]
#[allow(deprecated)]
#[derive(Debug, Clone, Error, PartialEq, Eq)]
#[error(
"LegacyQueryResult::rows() or similar function called on a bad LegacyQueryResult.
Expected LegacyQueryResult.rows to be Some, but it was None.
LegacyQueryResult.rows is Some for queries that can return rows (e.g SELECT).
It is None for queries that can't return rows (e.g INSERT)."
)]
pub struct RowsExpectedError;
#[derive(Debug, Clone, Error, PartialEq, Eq)]
#[error(
"LegacyQueryResult::result_not_rows() called on a bad LegacyQueryResult.
Expected LegacyQueryResult.rows to be None, but it was Some.
LegacyQueryResult.rows is Some for queries that can return rows (e.g SELECT).
It is None for queries that can't return rows (e.g INSERT)."
)]
pub struct RowsNotExpectedError;
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum FirstRowError {
#[error(transparent)]
RowsExpected(#[from] RowsExpectedError),
#[error("Rows in LegacyQueryResult are empty")]
RowsEmpty,
}
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum FirstRowTypedError {
#[error(transparent)]
RowsExpected(#[from] RowsExpectedError),
#[error("Rows in LegacyQueryResult are empty")]
RowsEmpty,
#[error(transparent)]
FromRowError(#[from] FromRowError),
}
#[deprecated(
since = "0.15.1",
note = "Legacy deserialization API is inefficient and is going to be removed soon"
)]
#[allow(deprecated)]
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum MaybeFirstRowTypedError {
#[error(transparent)]
RowsExpected(#[from] RowsExpectedError),
#[error(transparent)]
FromRowError(#[from] FromRowError),
}
#[deprecated(
since = "0.15.1",
note = "Legacy deserialization API is inefficient and is going to be removed soon"
)]
#[allow(deprecated)]
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum SingleRowError {
#[error(transparent)]
RowsExpected(#[from] RowsExpectedError),
#[error("Expected a single row, found {0} rows")]
BadNumberOfRows(usize),
}
#[deprecated(
since = "0.15.1",
note = "Legacy deserialization API is inefficient and is going to be removed soon"
)]
#[allow(deprecated)]
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum SingleRowTypedError {
#[error(transparent)]
RowsExpected(#[from] RowsExpectedError),
#[error("Expected a single row, found {0} rows")]
BadNumberOfRows(usize),
#[error(transparent)]
FromRowError(#[from] FromRowError),
}
impl From<FirstRowError> for FirstRowTypedError {
fn from(err: FirstRowError) -> FirstRowTypedError {
match err {
FirstRowError::RowsExpected(e) => FirstRowTypedError::RowsExpected(e),
FirstRowError::RowsEmpty => FirstRowTypedError::RowsEmpty,
}
}
}
impl From<SingleRowError> for SingleRowTypedError {
fn from(err: SingleRowError) -> SingleRowTypedError {
match err {
SingleRowError::RowsExpected(e) => SingleRowTypedError::RowsExpected(e),
SingleRowError::BadNumberOfRows(r) => SingleRowTypedError::BadNumberOfRows(r),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
frame::response::result::{CqlValue, Row},
test_utils::setup_tracing,
};
use std::convert::TryInto;
use std::sync::Arc;
use assert_matches::assert_matches;
use scylla_cql::frame::response::result::{ColumnType, ResultMetadata, TableSpec};
fn make_rows(rows_num: usize) -> Vec<Row> {
let mut rows: Vec<Row> = Vec::with_capacity(rows_num);
for cur_value in 0..rows_num {
let int_val: i32 = cur_value.try_into().unwrap();
rows.push(Row {
columns: vec![Some(CqlValue::Int(int_val))],
});
}
rows
}
fn make_string_rows(rows_num: usize) -> Vec<Row> {
let mut rows: Vec<Row> = Vec::with_capacity(rows_num);
for cur_value in 0..rows_num {
rows.push(Row {
columns: vec![Some(CqlValue::Text(format!("val{}", cur_value)))],
});
}
rows
}
fn make_test_metadata() -> ResultMetadata<'static> {
let table_spec = TableSpec::borrowed("some_keyspace", "some_table");
let column_spec = ColumnSpec::borrowed("column0", ColumnType::Int, table_spec);
ResultMetadata::new_for_test(1, vec![column_spec])
}
fn make_not_rows_query_result() -> LegacyQueryResult {
LegacyQueryResult {
rows: None,
warnings: vec![],
tracing_id: None,
metadata: None,
serialized_size: 0,
}
}
fn make_rows_query_result(rows_num: usize) -> LegacyQueryResult {
let mut res = make_not_rows_query_result();
res.rows = Some(make_rows(rows_num));
res.metadata = Some(ResultMetadataHolder::SharedCached(Arc::new(
make_test_metadata(),
)));
res
}
fn make_string_rows_query_result(rows_num: usize) -> LegacyQueryResult {
let mut res = make_not_rows_query_result();
res.rows = Some(make_string_rows(rows_num));
res.metadata = Some(ResultMetadataHolder::SharedCached(Arc::new(
make_test_metadata(),
)));
res
}
#[test]
fn rows_num_test() {
setup_tracing();
assert_eq!(
make_not_rows_query_result().rows_num(),
Err(RowsExpectedError)
);
assert_eq!(make_rows_query_result(0).rows_num(), Ok(0));
assert_eq!(make_rows_query_result(1).rows_num(), Ok(1));
assert_eq!(make_rows_query_result(2).rows_num(), Ok(2));
assert_eq!(make_rows_query_result(3).rows_num(), Ok(3));
}
#[test]
fn rows_test() {
setup_tracing();
assert_eq!(make_not_rows_query_result().rows(), Err(RowsExpectedError));
assert_eq!(make_rows_query_result(0).rows(), Ok(vec![]));
assert_eq!(make_rows_query_result(1).rows(), Ok(make_rows(1)));
assert_eq!(make_rows_query_result(2).rows(), Ok(make_rows(2)));
}
#[test]
fn rows_typed_test() {
setup_tracing();
assert!(make_not_rows_query_result().rows_typed::<(i32,)>().is_err());
let rows0: Vec<(i32,)> = make_rows_query_result(0)
.rows_typed::<(i32,)>()
.unwrap()
.map(|r| r.unwrap())
.collect();
assert_eq!(rows0, vec![]);
let rows1: Vec<(i32,)> = make_rows_query_result(1)
.rows_typed::<(i32,)>()
.unwrap()
.map(|r| r.unwrap())
.collect();
assert_eq!(rows1, vec![(0,)]);
let rows2: Vec<(i32,)> = make_rows_query_result(2)
.rows_typed::<(i32,)>()
.unwrap()
.map(|r| r.unwrap())
.collect();
assert_eq!(rows2, vec![(0,), (1,)]);
}
#[test]
fn result_not_rows_test() {
setup_tracing();
assert_eq!(make_not_rows_query_result().result_not_rows(), Ok(()));
assert_eq!(
make_rows_query_result(0).result_not_rows(),
Err(RowsNotExpectedError)
);
assert_eq!(
make_rows_query_result(1).result_not_rows(),
Err(RowsNotExpectedError)
);
assert_eq!(
make_rows_query_result(2).result_not_rows(),
Err(RowsNotExpectedError)
);
}
#[test]
fn rows_or_empty_test() {
setup_tracing();
assert_eq!(make_not_rows_query_result().rows_or_empty(), vec![]);
assert_eq!(make_rows_query_result(0).rows_or_empty(), make_rows(0));
assert_eq!(make_rows_query_result(1).rows_or_empty(), make_rows(1));
assert_eq!(make_rows_query_result(2).rows_or_empty(), make_rows(2));
}
#[test]
fn rows_typed_or_empty() {
setup_tracing();
let rows_empty: Vec<(i32,)> = make_not_rows_query_result()
.rows_typed_or_empty::<(i32,)>()
.map(|r| r.unwrap())
.collect();
assert_eq!(rows_empty, vec![]);
let rows0: Vec<(i32,)> = make_rows_query_result(0)
.rows_typed_or_empty::<(i32,)>()
.map(|r| r.unwrap())
.collect();
assert_eq!(rows0, vec![]);
let rows1: Vec<(i32,)> = make_rows_query_result(1)
.rows_typed_or_empty::<(i32,)>()
.map(|r| r.unwrap())
.collect();
assert_eq!(rows1, vec![(0,)]);
let rows2: Vec<(i32,)> = make_rows_query_result(2)
.rows_typed_or_empty::<(i32,)>()
.map(|r| r.unwrap())
.collect();
assert_eq!(rows2, vec![(0,), (1,)]);
}
#[test]
fn first_row_test() {
setup_tracing();
assert_eq!(
make_not_rows_query_result().first_row(),
Err(FirstRowError::RowsExpected(RowsExpectedError))
);
assert_eq!(
make_rows_query_result(0).first_row(),
Err(FirstRowError::RowsEmpty)
);
assert_eq!(
make_rows_query_result(1).first_row(),
Ok(make_rows(1).into_iter().next().unwrap())
);
assert_eq!(
make_rows_query_result(2).first_row(),
Ok(make_rows(2).into_iter().next().unwrap())
);
assert_eq!(
make_rows_query_result(3).first_row(),
Ok(make_rows(3).into_iter().next().unwrap())
);
}
#[test]
fn first_row_typed_test() {
setup_tracing();
assert_eq!(
make_not_rows_query_result().first_row_typed::<(i32,)>(),
Err(FirstRowTypedError::RowsExpected(RowsExpectedError))
);
assert_eq!(
make_rows_query_result(0).first_row_typed::<(i32,)>(),
Err(FirstRowTypedError::RowsEmpty)
);
assert_eq!(
make_rows_query_result(1).first_row_typed::<(i32,)>(),
Ok((0,))
);
assert_eq!(
make_rows_query_result(2).first_row_typed::<(i32,)>(),
Ok((0,))
);
assert_eq!(
make_rows_query_result(3).first_row_typed::<(i32,)>(),
Ok((0,))
);
assert_matches!(
make_string_rows_query_result(2).first_row_typed::<(i32,)>(),
Err(FirstRowTypedError::FromRowError(_))
);
}
#[test]
fn maybe_first_row_test() {
setup_tracing();
assert_eq!(
make_not_rows_query_result().maybe_first_row(),
Err(RowsExpectedError)
);
assert_eq!(make_rows_query_result(0).maybe_first_row(), Ok(None));
assert_eq!(
make_rows_query_result(1).maybe_first_row(),
Ok(Some(make_rows(1).into_iter().next().unwrap()))
);
assert_eq!(
make_rows_query_result(2).maybe_first_row(),
Ok(Some(make_rows(2).into_iter().next().unwrap()))
);
assert_eq!(
make_rows_query_result(3).maybe_first_row(),
Ok(Some(make_rows(3).into_iter().next().unwrap()))
);
}
#[test]
fn maybe_first_row_typed_test() {
setup_tracing();
assert_eq!(
make_not_rows_query_result().maybe_first_row_typed::<(i32,)>(),
Err(MaybeFirstRowTypedError::RowsExpected(RowsExpectedError))
);
assert_eq!(
make_rows_query_result(0).maybe_first_row_typed::<(i32,)>(),
Ok(None)
);
assert_eq!(
make_rows_query_result(1).maybe_first_row_typed::<(i32,)>(),
Ok(Some((0,)))
);
assert_eq!(
make_rows_query_result(2).maybe_first_row_typed::<(i32,)>(),
Ok(Some((0,)))
);
assert_eq!(
make_rows_query_result(3).maybe_first_row_typed::<(i32,)>(),
Ok(Some((0,)))
);
assert_matches!(
make_string_rows_query_result(1).maybe_first_row_typed::<(i32,)>(),
Err(MaybeFirstRowTypedError::FromRowError(_))
)
}
#[test]
fn single_row_test() {
setup_tracing();
assert_eq!(
make_not_rows_query_result().single_row(),
Err(SingleRowError::RowsExpected(RowsExpectedError))
);
assert_eq!(
make_rows_query_result(0).single_row(),
Err(SingleRowError::BadNumberOfRows(0))
);
assert_eq!(
make_rows_query_result(1).single_row(),
Ok(make_rows(1).into_iter().next().unwrap())
);
assert_eq!(
make_rows_query_result(2).single_row(),
Err(SingleRowError::BadNumberOfRows(2))
);
assert_eq!(
make_rows_query_result(3).single_row(),
Err(SingleRowError::BadNumberOfRows(3))
);
}
#[test]
fn single_row_typed_test() {
setup_tracing();
assert_eq!(
make_not_rows_query_result().single_row_typed::<(i32,)>(),
Err(SingleRowTypedError::RowsExpected(RowsExpectedError))
);
assert_eq!(
make_rows_query_result(0).single_row_typed::<(i32,)>(),
Err(SingleRowTypedError::BadNumberOfRows(0))
);
assert_eq!(
make_rows_query_result(1).single_row_typed::<(i32,)>(),
Ok((0,))
);
assert_eq!(
make_rows_query_result(2).single_row_typed::<(i32,)>(),
Err(SingleRowTypedError::BadNumberOfRows(2))
);
assert_eq!(
make_rows_query_result(3).single_row_typed::<(i32,)>(),
Err(SingleRowTypedError::BadNumberOfRows(3))
);
assert_matches!(
make_string_rows_query_result(1).single_row_typed::<(i32,)>(),
Err(SingleRowTypedError::FromRowError(_))
);
}
}