1use corium_query::edn::Edn;
4
5use crate::ClientError;
6use crate::value::FromEdn;
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum ResultShape {
11 Relation,
13 Collection,
15 Tuple,
17 Scalar,
19}
20
21#[derive(Clone, Debug)]
24pub struct QueryResult {
25 shape: ResultShape,
26 value: Edn,
27}
28
29impl QueryResult {
30 #[must_use]
32 pub fn new(shape: ResultShape, value: Edn) -> Self {
33 Self { shape, value }
34 }
35
36 #[must_use]
38 pub fn shape(&self) -> ResultShape {
39 self.shape
40 }
41
42 #[must_use]
44 pub fn edn(&self) -> &Edn {
45 &self.value
46 }
47
48 #[must_use]
50 pub fn into_edn(self) -> Edn {
51 self.value
52 }
53
54 #[must_use]
56 pub fn rows(&self) -> Vec<Row<'_>> {
57 match (&self.shape, &self.value) {
58 (ResultShape::Relation, Edn::Vector(rows)) => rows
59 .iter()
60 .filter_map(|row| match row {
61 Edn::Vector(cells) => Some(Row(cells)),
62 _ => None,
63 })
64 .collect(),
65 _ => Vec::new(),
66 }
67 }
68
69 #[must_use]
71 pub fn values(&self) -> Vec<&Edn> {
72 match (&self.shape, &self.value) {
73 (ResultShape::Collection, Edn::Vector(items)) => items.iter().collect(),
74 _ => Vec::new(),
75 }
76 }
77
78 pub fn values_as<T: FromEdn>(&self) -> Result<Vec<T>, ClientError> {
83 self.values().into_iter().map(T::from_edn).collect()
84 }
85
86 #[must_use]
88 pub fn tuple(&self) -> Option<Row<'_>> {
89 match (&self.shape, &self.value) {
90 (ResultShape::Tuple, Edn::Vector(cells)) => Some(Row(cells)),
91 _ => None,
92 }
93 }
94
95 #[must_use]
97 pub fn scalar(&self) -> Option<&Edn> {
98 match (&self.shape, &self.value) {
99 (ResultShape::Scalar, Edn::Nil) => None,
100 (ResultShape::Scalar, value) => Some(value),
101 _ => None,
102 }
103 }
104
105 pub fn scalar_as<T: FromEdn>(&self) -> Result<Option<T>, ClientError> {
110 self.scalar().map(T::from_edn).transpose()
111 }
112
113 #[must_use]
115 pub fn is_empty(&self) -> bool {
116 match &self.value {
117 Edn::Nil => true,
118 Edn::Vector(items) => items.is_empty(),
119 _ => false,
120 }
121 }
122}
123
124#[derive(Clone, Copy, Debug)]
127pub struct Row<'a>(&'a [Edn]);
128
129impl<'a> Row<'a> {
130 #[must_use]
132 pub fn len(&self) -> usize {
133 self.0.len()
134 }
135
136 #[must_use]
138 pub fn is_empty(&self) -> bool {
139 self.0.is_empty()
140 }
141
142 #[must_use]
144 pub fn edn(&self, index: usize) -> Option<&'a Edn> {
145 self.0.get(index)
146 }
147
148 #[must_use]
150 pub fn cells(&self) -> &'a [Edn] {
151 self.0
152 }
153
154 pub fn get<T: FromEdn>(&self, index: usize) -> Result<T, ClientError> {
160 let cell = self
161 .0
162 .get(index)
163 .ok_or_else(|| ClientError::Decode(format!("row has no cell at index {index}")))?;
164 T::from_edn(cell)
165 }
166}