#![recursion_limit = "256"]
#![cfg(not(target_family = "wasm"))]
mod helpers;
use anyhow::Result;
use helpers::{new_ds, with_enough_stack};
use surrealdb_core::dbs::Session;
use surrealdb_core::syn;
use surrealdb_types::{Error as TypesError, Value};
#[test]
fn ok_graph_traversal_depth() -> Result<()> {
fn graph_traversal(n: usize) -> String {
let mut ret = String::from("REMOVE TABLE IF EXISTS node;\n");
ret.push_str("CREATE node:0;\n");
for i in 1..=n {
let prev = i - 1;
ret.push_str(&format!("CREATE node:{i};\n"));
ret.push_str(&format!("RELATE node:{prev}->edge{i}->node:{i};\n"));
}
ret.push_str("SELECT ");
for i in 1..=n {
ret.push_str(&format!("->edge{i}->node"));
}
ret.push_str(" AS res FROM node:0;\n");
ret
}
for n in 1..=40 {
with_enough_stack(async move {
let mut res = run_queries(&graph_traversal(n)).await;
let tmp = res.next_back().unwrap();
for r in res {
r.unwrap();
}
match tmp {
Ok(res) => {
let val = syn::value(&format!(
"[
{{
res: [node:{n}],
}}
]"
))
.unwrap();
assert_eq!(res, val);
}
Err(res) => {
assert!(n > 10, "Max traversals: {}", n - 1);
panic!("This should not happen: {res:?}");
}
}
Ok(())
})
.unwrap();
}
Ok(())
}
#[test]
fn ok_cast_chain_depth() -> Result<()> {
with_enough_stack(async {
let mut res = run_queries(&cast_chain(10)).await;
assert_eq!(res.len(), 1);
let tmp = res.next().unwrap()?;
let val = Value::from_vec(vec![Value::from_int(5)]);
assert_eq!(tmp, val);
Ok(())
})
}
#[test]
fn excessive_cast_chain_depth() -> Result<()> {
with_enough_stack(async {
let mut res = run_queries(&cast_chain(125)).await;
assert_eq!(res.len(), 1);
let tmp = res.next().unwrap();
let err = tmp.unwrap_err();
assert!(err.is_internal());
assert_eq!(
err.message(),
"Reached excessive computation depth due to functions, subqueries, or computed values"
);
Ok(())
})
}
async fn run_queries(
sql: &str,
) -> impl ExactSizeIterator<Item = std::result::Result<Value, TypesError>> + DoubleEndedIterator + 'static
{
let (_, dbs) = new_ds("test", "test", false).await.expect("Failed to create new datastore");
let ses = Session::owner().with_ns("test").with_db("test");
dbs.execute(sql, &ses, None)
.await
.expect("Failed to execute query")
.into_iter()
.map(|res| res.result)
}
fn cast_chain(n: usize) -> String {
let mut sql = String::from("SELECT * FROM ");
for _ in 0..n {
sql.push_str("<int>");
}
sql.push_str("5;");
sql
}