use crate::frame::response::cql_to_rust::{FromRow, FromRowError};
use crate::frame::response::result::ColumnSpec;
use crate::frame::response::result::Row;
use crate::transport::session::{IntoTypedRows, TypedRowIter};
use bytes::Bytes;
use thiserror::Error;
use uuid::Uuid;
#[non_exhaustive]
#[derive(Default, Debug)]
pub struct QueryResult {
pub rows: Option<Vec<Row>>,
pub warnings: Vec<String>,
pub tracing_id: Option<Uuid>,
pub paging_state: Option<Bytes>,
pub col_specs: Vec<ColumnSpec>,
pub serialized_size: usize,
}
impl QueryResult {
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>()?)
}
pub fn get_column_spec<'a>(&'a self, name: &str) -> Option<(usize, &'a ColumnSpec)> {
self.col_specs
.iter()
.enumerate()
.find(|(_id, spec)| spec.name == name)
}
}
#[derive(Debug, Clone, Error, PartialEq, Eq)]
#[error(
"QueryResult::rows() or similar function called on a bad QueryResult.
Expected QueryResult.rows to be Some, but it was None.
QueryResult.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(
"QueryResult::result_not_rows() called on a bad QueryResult.
Expected QueryResult.rows to be None, but it was Some.
QueryResult.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 QueryResult are empty")]
RowsEmpty,
}
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum FirstRowTypedError {
#[error(transparent)]
RowsExpected(#[from] RowsExpectedError),
#[error("Rows in QueryResult are empty")]
RowsEmpty,
#[error(transparent)]
FromRowError(#[from] FromRowError),
}
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum MaybeFirstRowTypedError {
#[error(transparent)]
RowsExpected(#[from] RowsExpectedError),
#[error(transparent)]
FromRowError(#[from] FromRowError),
}
#[derive(Debug, Clone, Error, PartialEq, Eq)]
pub enum SingleRowError {
#[error(transparent)]
RowsExpected(#[from] RowsExpectedError),
#[error("Expected a single row, found {0} rows")]
BadNumberOfRows(usize),
}
#[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::{ColumnSpec, ColumnType, CqlValue, Row, TableSpec};
use std::convert::TryInto;
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_not_rows_query_result() -> QueryResult {
let table_spec = TableSpec {
ks_name: "some_keyspace".to_string(),
table_name: "some_table".to_string(),
};
let column_spec = ColumnSpec {
table_spec,
name: "column0".to_string(),
typ: ColumnType::Int,
};
QueryResult {
rows: None,
warnings: vec![],
tracing_id: None,
paging_state: None,
col_specs: vec![column_spec],
serialized_size: 0,
}
}
fn make_rows_query_result(rows_num: usize) -> QueryResult {
let mut res = make_not_rows_query_result();
res.rows = Some(make_rows(rows_num));
res
}
fn make_string_rows_query_result(rows_num: usize) -> QueryResult {
let mut res = make_not_rows_query_result();
res.rows = Some(make_string_rows(rows_num));
res
}
#[test]
fn rows_num_test() {
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() {
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() {
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() {
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() {
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() {
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() {
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() {
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() {
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() {
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() {
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() {
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(_))
));
}
}