use corium_query::edn::Edn;
use crate::ClientError;
use crate::value::FromEdn;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ResultShape {
Relation,
Collection,
Tuple,
Scalar,
}
#[derive(Clone, Debug)]
pub struct QueryResult {
shape: ResultShape,
value: Edn,
}
impl QueryResult {
#[must_use]
pub fn new(shape: ResultShape, value: Edn) -> Self {
Self { shape, value }
}
#[must_use]
pub fn shape(&self) -> ResultShape {
self.shape
}
#[must_use]
pub fn edn(&self) -> &Edn {
&self.value
}
#[must_use]
pub fn into_edn(self) -> Edn {
self.value
}
#[must_use]
pub fn rows(&self) -> Vec<Row<'_>> {
match (&self.shape, &self.value) {
(ResultShape::Relation, Edn::Vector(rows)) => rows
.iter()
.filter_map(|row| match row {
Edn::Vector(cells) => Some(Row(cells)),
_ => None,
})
.collect(),
_ => Vec::new(),
}
}
#[must_use]
pub fn values(&self) -> Vec<&Edn> {
match (&self.shape, &self.value) {
(ResultShape::Collection, Edn::Vector(items)) => items.iter().collect(),
_ => Vec::new(),
}
}
pub fn values_as<T: FromEdn>(&self) -> Result<Vec<T>, ClientError> {
self.values().into_iter().map(T::from_edn).collect()
}
#[must_use]
pub fn tuple(&self) -> Option<Row<'_>> {
match (&self.shape, &self.value) {
(ResultShape::Tuple, Edn::Vector(cells)) => Some(Row(cells)),
_ => None,
}
}
#[must_use]
pub fn scalar(&self) -> Option<&Edn> {
match (&self.shape, &self.value) {
(ResultShape::Scalar, Edn::Nil) => None,
(ResultShape::Scalar, value) => Some(value),
_ => None,
}
}
pub fn scalar_as<T: FromEdn>(&self) -> Result<Option<T>, ClientError> {
self.scalar().map(T::from_edn).transpose()
}
#[must_use]
pub fn is_empty(&self) -> bool {
match &self.value {
Edn::Nil => true,
Edn::Vector(items) => items.is_empty(),
_ => false,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Row<'a>(&'a [Edn]);
impl<'a> Row<'a> {
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[must_use]
pub fn edn(&self, index: usize) -> Option<&'a Edn> {
self.0.get(index)
}
#[must_use]
pub fn cells(&self) -> &'a [Edn] {
self.0
}
pub fn get<T: FromEdn>(&self, index: usize) -> Result<T, ClientError> {
let cell = self
.0
.get(index)
.ok_or_else(|| ClientError::Decode(format!("row has no cell at index {index}")))?;
T::from_edn(cell)
}
}