use crate::client_type_error;
use crate::errors::GraphResult;
use crate::generated::*;
pub const CAPID_GRAPHDB: &str = "wasmcloud:graphdb";
pub fn num_columns(rs: &ResultSet) -> usize {
rs.columns.len()
}
pub fn num_rows(rs: &ResultSet) -> usize {
if let Some(col) = rs.columns.get(0) {
col.scalars.as_ref().unwrap_or(&vec![]).len()
+ col.relations.as_ref().unwrap_or(&vec![]).len()
+ col.nodes.as_ref().unwrap_or(&vec![]).len()
} else {
0
}
}
pub fn get_scalar(rs: &ResultSet, row_idx: usize, column_idx: usize) -> GraphResult<Scalar> {
match rs.columns.get(column_idx) {
Some(column) => match column.scalars.as_ref().unwrap_or(&vec![]).get(row_idx) {
Some(scalar) => Ok(scalar.clone()),
None => client_type_error!(
"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,
),
},
None => client_type_error!(
"failed to get scalar: column index out of bounds: the len is {:?} but the index is {:?}", rs.columns.len(), column_idx,
),
}
}
pub fn get_node(rs: &ResultSet, row_idx: usize, column_idx: usize) -> GraphResult<Node> {
match rs.columns.get(column_idx) {
Some(column) => match column.nodes.as_ref().unwrap_or(&vec![]).get(row_idx) {
Some(node) => Ok(node.clone()),
None => client_type_error!(
"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,
),
},
None => client_type_error!(
"failed to get node: column index out of bounds: the len is {:?} but the index is {:?}", rs.columns.len(), column_idx,
),
}
}
pub fn get_relation(rs: &ResultSet, row_idx: usize, column_idx: usize) -> GraphResult<Relation> {
match rs.columns.get(column_idx) {
Some(column) => match column.relations.as_ref().unwrap_or(&vec![]).get(row_idx) {
Some(relation) => Ok(relation.clone()),
None => client_type_error!(
"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,
),
},
None => client_type_error!(
"failed to get relation: column index out of bounds: the len is {:?} but the index is {:?}", rs.columns.len(), column_idx,
),
}
}
impl FromTable for ResultSet {
fn from_table(result_set: &ResultSet) -> GraphResult<Self> {
Ok(result_set.clone())
}
}
impl<T: FromRow> FromTable for Vec<T> {
fn from_table(result_set: &ResultSet) -> GraphResult<Self> {
let num_rows = num_rows(result_set);
let mut ret = Self::with_capacity(num_rows);
for i in 0..num_rows {
ret.push(T::from_row(result_set, i)?);
}
Ok(ret)
}
}
impl FromTable for () {
fn from_table(result_set: &ResultSet) -> GraphResult<Self> {
Ok(())
}
}
pub trait FromTable: Sized {
fn from_table(result_set: &ResultSet) -> GraphResult<Self>;
}
pub trait FromRow: Sized {
fn from_row(result_set: &ResultSet, row_idx: usize) -> GraphResult<Self>;
}
pub trait FromCell: Sized {
fn from_cell(result_set: &ResultSet, row_idx: usize, column_idx: usize) -> GraphResult<Self>;
}
macro_rules! impl_row_for_tuple {
() => ();
($($name:ident,)+) => (
#[doc(hidden)]
impl<$($name: FromCell),*> FromRow for ($($name,)*) {
#[allow(non_snake_case, unused_variables, clippy::eval_order_dependence)]
fn from_row(result_set: &ResultSet, row_idx: usize) -> GraphResult<($($name,)*)> {
let mut n = 0;
$(let $name = (); n += 1;)*
if num_columns(result_set) != n {
return client_type_error!(
"failed to construct tuple: tuple has {:?} entries but result table has {:?} columns",
n,
num_columns(result_set)
);
}
let mut i = 0;
Ok(($({let $name = (); $name::from_cell(result_set, row_idx, { i += 1; i - 1 })?},)*))
}
}
impl_row_for_tuple_peel!($($name,)*);
)
}
macro_rules! impl_row_for_tuple_peel {
($name:ident, $($other:ident,)*) => (impl_row_for_tuple!($($other,)*);)
}
impl_row_for_tuple! { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
impl<T: FromCell> FromRow for T {
fn from_row(result_set: &ResultSet, row_idx: usize) -> GraphResult<Self> {
T::from_cell(result_set, row_idx, 0)
}
}
impl<T: FromRow> FromTable for T {
fn from_table(result_set: &ResultSet) -> GraphResult<Self> {
T::from_row(result_set, 0)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::generated::*;
#[test]
fn tuple_extraction_test() {
let (name, birth_year): (String, u32) = fake_query("fake query").unwrap();
assert_eq!("tester", name);
assert_eq!(1985, birth_year);
}
#[test]
fn vec_tuple_extraction_test() {
let res: Vec<(String, u32)> = fake_vec_query("foo").unwrap();
assert_eq!(("tester".to_string(), 1985), res[0]);
assert_eq!(("test2".to_string(), 1986), res[1]);
}
fn fake_vec_query<T: FromTable>(_query: &str) -> GraphResult<T> {
query_with_statistics2().map(|(value, _)| value)
}
fn fake_query<T: FromTable>(_query: &str) -> GraphResult<T> {
query_with_statistics().map(|(value, _)| value)
}
fn query_with_statistics<T: FromTable>() -> GraphResult<(T, Vec<String>)> {
let result_set = get_result_set()?;
let value = T::from_table(&result_set)?;
Ok((value, result_set.statistics))
}
fn query_with_statistics2<T: FromTable>() -> GraphResult<(T, Vec<String>)> {
let result_set = get_result_set2()?;
let value = T::from_table(&result_set)?;
Ok((value, result_set.statistics))
}
fn get_result_set() -> GraphResult<ResultSet> {
Ok(ResultSet {
statistics: vec![],
columns: vec![
Column {
scalars: Some(vec![Scalar {
bool_value: None,
double_value: None,
int_value: None,
string_value: Some("tester".to_string()),
}]),
nodes: Some(vec![]),
relations: Some(vec![]),
},
Column {
scalars: Some(vec![Scalar {
bool_value: None,
double_value: None,
int_value: Some(1985),
string_value: None,
}]),
nodes: Some(vec![]),
relations: Some(vec![]),
},
],
})
}
fn get_result_set2() -> GraphResult<ResultSet> {
Ok(ResultSet {
statistics: vec![],
columns: vec![
Column {
scalars: Some(vec![
Scalar {
bool_value: None,
double_value: None,
int_value: None,
string_value: Some("tester".to_string()),
},
Scalar {
bool_value: None,
double_value: None,
int_value: None,
string_value: Some("test2".to_string()),
},
]),
nodes: Some(vec![]),
relations: Some(vec![]),
},
Column {
scalars: Some(vec![
Scalar {
bool_value: None,
double_value: None,
int_value: Some(1985),
string_value: None,
},
Scalar {
bool_value: None,
double_value: None,
int_value: Some(1986),
string_value: None,
},
]),
nodes: Some(vec![]),
relations: Some(vec![]),
},
],
})
}
}