1use std::collections::HashMap;
11
12#[macro_use]
13extern crate serde_derive;
14
15mod conversions;
16mod errors;
17pub mod protocol;
18
19pub use crate::errors::GraphResult;
20pub use errors::GraphError;
21
22pub const CAPID_GRAPHDB: &str = "wascc:graphdb";
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
28pub struct ResultSet {
29 pub columns: Vec<Column>,
33 pub statistics: Statistics,
35}
36
37#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
39pub struct Statistics(pub Vec<String>);
40
41impl ResultSet {
42 pub fn num_columns(&self) -> usize {
44 self.columns.len()
45 }
46
47 pub fn num_rows(&self) -> usize {
49 match self.columns.get(0) {
50 Some(first_column) => first_column.len(),
51 None => 0,
52 }
53 }
54
55 pub fn get_scalar(&self, row_idx: usize, column_idx: usize) -> GraphResult<&Scalar> {
60 match self.columns.get(column_idx) {
61 Some(column) => match column {
62 Column::Scalars(cells) => match cells.get(row_idx) {
63 Some(cell) => Ok(cell),
64 None => client_type_error!(
65 "failed to get scalar: row index out of bounds: the len is {:?} but the index is {:?}", self.columns.len(), column_idx,
66 ),
67 },
68 any => client_type_error!(
69 "failed to get scalar: expected column of scalars, found {:?}",
70 any
71 ),
72 }
73 None => client_type_error!(
74 "failed to get scalar: column index out of bounds: the len is {:?} but the index is {:?}", self.columns.len(), column_idx,
75 ),
76 }
77 }
78
79 pub fn get_node(&self, row_idx: usize, column_idx: usize) -> GraphResult<&Node> {
84 match self.columns.get(column_idx) {
85 Some(column) => match column {
86 Column::Nodes(cells) => match cells.get(row_idx) {
87 Some(cell) => Ok(cell),
88 None => client_type_error!(
89 "failed to get node: row index out of bounds: the len is {:?} but the index is {:?}", self.columns.len(), column_idx,
90 ),
91 },
92 any => client_type_error!(
93 "failed to get node: expected column of nodes, found {:?}",
94 any
95 ),
96 }
97 None => client_type_error!(
98 "failed to get node: column index out of bounds: the len is {:?} but the index is {:?}", self.columns.len(), column_idx,
99 ),
100 }
101 }
102
103 pub fn get_relation(&self, row_idx: usize, column_idx: usize) -> GraphResult<&Relation> {
108 match self.columns.get(column_idx) {
109 Some(column) => match column {
110 Column::Relations(cells) => match cells.get(row_idx) {
111 Some(cell) => Ok(cell),
112 None => client_type_error!(
113 "failed to get relation: row index out of bounds: the len is {:?} but the index is {:?}", self.columns.len(), column_idx,
114 ),
115 },
116 any => client_type_error!(
117 "failed to get relation: expected column of relations, found {:?}",
118 any
119 ),
120 }
121 None => client_type_error!(
122 "failed to get relation: column index out of bounds: the len is {:?} but the index is {:?}", self.columns.len(), column_idx,
123 ),
124 }
125 }
126}
127
128impl FromTable for ResultSet {
129 fn from_table(result_set: &ResultSet) -> GraphResult<Self> {
130 Ok(result_set.clone())
131 }
132}
133
134impl<T: FromRow> FromTable for Vec<T> {
135 fn from_table(result_set: &ResultSet) -> GraphResult<Self> {
136 let num_rows = result_set.num_rows();
137 let mut ret = Self::with_capacity(num_rows);
138
139 for i in 0..num_rows {
140 ret.push(T::from_row(result_set, i)?);
141 }
142
143 Ok(ret)
144 }
145}
146
147pub trait FromTable: Sized {
148 fn from_table(result_set: &ResultSet) -> GraphResult<Self>;
149}
150
151pub trait FromRow: Sized {
153 fn from_row(result_set: &ResultSet, row_idx: usize) -> GraphResult<Self>;
154}
155
156pub trait FromCell: Sized {
158 fn from_cell(result_set: &ResultSet, row_idx: usize, column_idx: usize) -> GraphResult<Self>;
159}
160
161#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
163pub enum Column {
164 Scalars(Vec<Scalar>),
165 Nodes(Vec<Node>),
166 Relations(Vec<Relation>),
167}
168
169impl Column {
170 pub fn len(&self) -> usize {
172 match self {
173 Self::Scalars(cells) => cells.len(),
174 Self::Nodes(cells) => cells.len(),
175 Self::Relations(cells) => cells.len(),
176 }
177 }
178
179 pub fn is_empty(&self) -> bool {
181 self.len() == 0
182 }
183}
184
185#[derive(Serialize, Debug, Deserialize)]
186enum ColumnType {
187 Unknown = 0,
188 Scalar = 1,
189 Node = 2,
190 Relation = 3,
191}
192
193#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
194pub struct Relation {
195 pub type_name: String,
197 pub properties: HashMap<String, Scalar>,
199}
200
201#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
203pub enum Scalar {
204 Nil,
205 Boolean(bool),
206 Integer(i64),
207 Double(f64),
208 String(GraphString), }
210
211#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
213enum ScalarType {
214 Unknown = 0,
215 Nil = 1,
216 String = 2,
217 Integer = 3,
218 Boolean = 4,
219 Double = 5,
220}
221
222#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
224pub struct GraphString(pub Vec<u8>);
225
226impl From<String> for GraphString {
229 fn from(string: String) -> Self {
230 Self(string.into_bytes())
231 }
232}
233
234impl From<Vec<u8>> for GraphString {
235 fn from(bytes: Vec<u8>) -> Self {
236 Self(bytes)
237 }
238}
239
240impl From<GraphString> for Vec<u8> {
241 fn from(redis_string: GraphString) -> Self {
242 redis_string.0
243 }
244}
245
246#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
248pub struct Node {
249 pub labels: Vec<String>,
251 pub properties: HashMap<String, Scalar>,
253}
254
255macro_rules! impl_row_for_tuple {
260 () => ();
261 ($($name:ident,)+) => (
262 #[doc(hidden)]
263 impl<$($name: FromCell),*> FromRow for ($($name,)*) {
264 #[allow(non_snake_case, unused_variables, clippy::eval_order_dependence)]
267 fn from_row(result_set: &ResultSet, row_idx: usize) -> GraphResult<($($name,)*)> {
268 let mut n = 0;
270 $(let $name = (); n += 1;)*
271 if result_set.num_columns() != n {
272 return client_type_error!(
273 "failed to construct tuple: tuple has {:?} entries but result table has {:?} columns",
274 n,
275 result_set.num_columns()
276 );
277 }
278
279 let mut i = 0;
282 Ok(($({let $name = (); $name::from_cell(result_set, row_idx, { i += 1; i - 1 })?},)*))
283 }
284 }
285 impl_row_for_tuple_peel!($($name,)*);
286 )
287}
288
289macro_rules! impl_row_for_tuple_peel {
291 ($name:ident, $($other:ident,)*) => (impl_row_for_tuple!($($other,)*);)
292}
293
294impl_row_for_tuple! { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
296
297impl<T: FromCell> FromRow for T {
299 fn from_row(result_set: &ResultSet, row_idx: usize) -> GraphResult<Self> {
300 T::from_cell(result_set, row_idx, 0)
301 }
302}
303
304impl<T: FromRow> FromTable for T {
305 fn from_table(result_set: &ResultSet) -> GraphResult<Self> {
306 T::from_row(result_set, 0)
307 }
308}
309
310#[cfg(test)]
311mod test {
312 use super::*;
313
314 #[test]
317 fn tuple_extraction_test() {
318 let (name, birth_year): (String, u32) = fake_query("fake query").unwrap();
319 assert_eq!("tester", name);
320 assert_eq!(1985, birth_year);
321 }
322
323 #[test]
324 fn vec_tuple_extraction_test() {
325 let res: Vec<(String, u32)> = fake_vec_query("foo").unwrap();
326 assert_eq!(("tester".to_string(), 1985), res[0]);
327 assert_eq!(("test2".to_string(), 1986), res[1]);
328 }
329
330 fn fake_vec_query<T: FromTable>(_query: &str) -> GraphResult<T> {
331 query_with_statistics2().map(|(value, _)| value)
332 }
333
334 fn fake_query<T: FromTable>(_query: &str) -> GraphResult<T> {
335 query_with_statistics().map(|(value, _)| value)
336 }
337
338 fn query_with_statistics<T: FromTable>() -> GraphResult<(T, Statistics)> {
339 let result_set = get_result_set()?;
340 let value = T::from_table(&result_set)?;
341 Ok((value, result_set.statistics))
342 }
343
344 fn query_with_statistics2<T: FromTable>() -> GraphResult<(T, Statistics)> {
345 let result_set = get_result_set2()?;
346 let value = T::from_table(&result_set)?;
347 Ok((value, result_set.statistics))
348 }
349
350 fn get_result_set() -> GraphResult<ResultSet> {
351 Ok(ResultSet {
352 statistics: Statistics(vec![]),
353 columns: vec![
354 Column::Scalars(vec![Scalar::String(GraphString::from(
355 "tester".to_string(),
356 ))]),
357 Column::Scalars(vec![Scalar::Integer(1985)]),
358 ],
359 })
360 }
361
362 fn get_result_set2() -> GraphResult<ResultSet> {
363 Ok(ResultSet {
364 statistics: Statistics(vec![]),
365 columns: vec![
366 Column::Scalars(vec![
367 Scalar::String(GraphString::from("tester".to_string())),
368 Scalar::String(GraphString::from("test2".to_string())),
369 ]),
370 Column::Scalars(vec![Scalar::Integer(1985), Scalar::Integer(1986)]),
371 ],
372 })
373 }
374}