1use crate::client_type_error;
2use crate::errors::GraphResult;
3use crate::generated::*;
4
5pub const CAPID_GRAPHDB: &str = "wasmcloud:graphdb";
6
7pub fn num_columns(rs: &ResultSet) -> usize {
9 rs.columns.len()
10}
11
12pub fn num_rows(rs: &ResultSet) -> usize {
14 if let Some(col) = rs.columns.get(0) {
15 col.scalars.as_ref().unwrap_or(&vec![]).len()
16 + col.relations.as_ref().unwrap_or(&vec![]).len()
17 + col.nodes.as_ref().unwrap_or(&vec![]).len()
18 } else {
19 0
20 }
21}
22
23pub fn get_scalar(rs: &ResultSet, row_idx: usize, column_idx: usize) -> GraphResult<Scalar> {
28 match rs.columns.get(column_idx) {
29 Some(column) => match column.scalars.as_ref().unwrap_or(&vec![]).get(row_idx) {
30 Some(scalar) => Ok(scalar.clone()),
31 None => client_type_error!(
32 "failed to get scalar: row index out of bounds: the len is {:?} but the index is {:?}", column.scalars.as_ref().unwrap_or(&vec![]).len(), row_idx,
33 ),
34 },
35 None => client_type_error!(
36 "failed to get scalar: column index out of bounds: the len is {:?} but the index is {:?}", rs.columns.len(), column_idx,
37 ),
38 }
39}
40
41pub fn get_node(rs: &ResultSet, row_idx: usize, column_idx: usize) -> GraphResult<Node> {
46 match rs.columns.get(column_idx) {
47 Some(column) => match column.nodes.as_ref().unwrap_or(&vec![]).get(row_idx) {
48 Some(node) => Ok(node.clone()),
49 None => client_type_error!(
50 "failed to get node: row index out of bounds: the len is {:?} but the index is {:?}", column.nodes.as_ref().unwrap_or(&vec![]).len(), row_idx,
51 ),
52 },
53 None => client_type_error!(
54 "failed to get node: column index out of bounds: the len is {:?} but the index is {:?}", rs.columns.len(), column_idx,
55 ),
56 }
57}
58
59pub fn get_relation(rs: &ResultSet, row_idx: usize, column_idx: usize) -> GraphResult<Relation> {
64 match rs.columns.get(column_idx) {
65 Some(column) => match column.relations.as_ref().unwrap_or(&vec![]).get(row_idx) {
66 Some(relation) => Ok(relation.clone()),
67 None => client_type_error!(
68 "failed to get relation: row index out of bounds: the len is {:?} but the index is {:?}", column.relations.as_ref().unwrap_or(&vec![]).len(), row_idx,
69 ),
70 },
71 None => client_type_error!(
72 "failed to get relation: column index out of bounds: the len is {:?} but the index is {:?}", rs.columns.len(), column_idx,
73 ),
74 }
75}
76
77impl FromTable for ResultSet {
78 fn from_table(result_set: &ResultSet) -> GraphResult<Self> {
79 Ok(result_set.clone())
80 }
81}
82
83impl<T: FromRow> FromTable for Vec<T> {
84 fn from_table(result_set: &ResultSet) -> GraphResult<Self> {
85 let num_rows = num_rows(result_set);
86 let mut ret = Self::with_capacity(num_rows);
87
88 for i in 0..num_rows {
89 ret.push(T::from_row(result_set, i)?);
90 }
91
92 Ok(ret)
93 }
94}
95
96impl FromTable for () {
97 fn from_table(result_set: &ResultSet) -> GraphResult<Self> {
98 Ok(())
99 }
100}
101
102pub trait FromTable: Sized {
103 fn from_table(result_set: &ResultSet) -> GraphResult<Self>;
104}
105
106pub trait FromRow: Sized {
108 fn from_row(result_set: &ResultSet, row_idx: usize) -> GraphResult<Self>;
109}
110
111pub trait FromCell: Sized {
113 fn from_cell(result_set: &ResultSet, row_idx: usize, column_idx: usize) -> GraphResult<Self>;
114}
115
116macro_rules! impl_row_for_tuple {
121 () => ();
122 ($($name:ident,)+) => (
123 #[doc(hidden)]
124 impl<$($name: FromCell),*> FromRow for ($($name,)*) {
125 #[allow(non_snake_case, unused_variables, clippy::eval_order_dependence)]
128 fn from_row(result_set: &ResultSet, row_idx: usize) -> GraphResult<($($name,)*)> {
129 let mut n = 0;
131 $(let $name = (); n += 1;)*
132 if num_columns(result_set) != n {
133 return client_type_error!(
134 "failed to construct tuple: tuple has {:?} entries but result table has {:?} columns",
135 n,
136 num_columns(result_set)
137 );
138 }
139
140 let mut i = 0;
143 Ok(($({let $name = (); $name::from_cell(result_set, row_idx, { i += 1; i - 1 })?},)*))
144 }
145 }
146 impl_row_for_tuple_peel!($($name,)*);
147 )
148}
149
150macro_rules! impl_row_for_tuple_peel {
152 ($name:ident, $($other:ident,)*) => (impl_row_for_tuple!($($other,)*);)
153}
154
155impl_row_for_tuple! { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
157
158impl<T: FromCell> FromRow for T {
160 fn from_row(result_set: &ResultSet, row_idx: usize) -> GraphResult<Self> {
161 T::from_cell(result_set, row_idx, 0)
162 }
163}
164
165impl<T: FromRow> FromTable for T {
166 fn from_table(result_set: &ResultSet) -> GraphResult<Self> {
167 T::from_row(result_set, 0)
168 }
169}
170
171#[cfg(test)]
172mod test {
173 use super::*;
174 use crate::generated::*;
175
176 #[test]
179 fn tuple_extraction_test() {
180 let (name, birth_year): (String, u32) = fake_query("fake query").unwrap();
181 assert_eq!("tester", name);
182 assert_eq!(1985, birth_year);
183 }
184
185 #[test]
186 fn vec_tuple_extraction_test() {
187 let res: Vec<(String, u32)> = fake_vec_query("foo").unwrap();
188 assert_eq!(("tester".to_string(), 1985), res[0]);
189 assert_eq!(("test2".to_string(), 1986), res[1]);
190 }
191
192 fn fake_vec_query<T: FromTable>(_query: &str) -> GraphResult<T> {
193 query_with_statistics2().map(|(value, _)| value)
194 }
195
196 fn fake_query<T: FromTable>(_query: &str) -> GraphResult<T> {
197 query_with_statistics().map(|(value, _)| value)
198 }
199
200 fn query_with_statistics<T: FromTable>() -> GraphResult<(T, Vec<String>)> {
201 let result_set = get_result_set()?;
202 let value = T::from_table(&result_set)?;
203 Ok((value, result_set.statistics))
204 }
205
206 fn query_with_statistics2<T: FromTable>() -> GraphResult<(T, Vec<String>)> {
207 let result_set = get_result_set2()?;
208 let value = T::from_table(&result_set)?;
209 Ok((value, result_set.statistics))
210 }
211
212 fn get_result_set() -> GraphResult<ResultSet> {
213 Ok(ResultSet {
214 statistics: vec![],
215 columns: vec![
216 Column {
217 scalars: Some(vec![Scalar {
218 bool_value: None,
219 double_value: None,
220 int_value: None,
221 string_value: Some("tester".to_string()),
222 }]),
223 nodes: Some(vec![]),
224 relations: Some(vec![]),
225 },
226 Column {
227 scalars: Some(vec![Scalar {
228 bool_value: None,
229 double_value: None,
230 int_value: Some(1985),
231 string_value: None,
232 }]),
233 nodes: Some(vec![]),
234 relations: Some(vec![]),
235 },
236 ],
237 })
238 }
239
240 fn get_result_set2() -> GraphResult<ResultSet> {
241 Ok(ResultSet {
242 statistics: vec![],
243 columns: vec![
244 Column {
245 scalars: Some(vec![
246 Scalar {
247 bool_value: None,
248 double_value: None,
249 int_value: None,
250 string_value: Some("tester".to_string()),
251 },
252 Scalar {
253 bool_value: None,
254 double_value: None,
255 int_value: None,
256 string_value: Some("test2".to_string()),
257 },
258 ]),
259 nodes: Some(vec![]),
260 relations: Some(vec![]),
261 },
262 Column {
263 scalars: Some(vec![
264 Scalar {
265 bool_value: None,
266 double_value: None,
267 int_value: Some(1985),
268 string_value: None,
269 },
270 Scalar {
271 bool_value: None,
272 double_value: None,
273 int_value: Some(1986),
274 string_value: None,
275 },
276 ]),
277 nodes: Some(vec![]),
278 relations: Some(vec![]),
279 },
280 ],
281 })
282 }
283}