#![recursion_limit = "256"]
pub mod query;
pub mod types;
pub use query::executor::core::{OperatorStats, ProfileOutput};
pub use query::executor::procedure::{
ProcedureOutput, ProcedureParam, ProcedureRegistry, ProcedureValueType, RegisteredProcedure,
};
pub use query::executor::{CustomFunctionRegistry, CustomScalarFn, Executor, ResultNormalizer};
pub use query::planner::{CostEstimates, ExplainOutput, IndexUsage, LogicalPlan, QueryPlanner};
pub use types::{
Edge, ExecuteResult, FromValue, Node, Path, QueryCursor, QueryMetrics, QueryResult,
QueryWarning, Row, Value,
};
pub use uni_cypher::ast::{Query as CypherQuery, TimeTravelSpec};
pub fn validate_read_only(query: &CypherQuery) -> Result<(), String> {
use uni_cypher::ast::{Clause, Query, Statement};
fn check_statement(stmt: &Statement) -> Result<(), String> {
for clause in &stmt.clauses {
match clause {
Clause::Create(_)
| Clause::Merge(_)
| Clause::Delete(_)
| Clause::Set(_)
| Clause::Remove(_) => {
return Err(
"Write clauses (CREATE, MERGE, DELETE, SET, REMOVE) are not allowed \
with VERSION AS OF / TIMESTAMP AS OF"
.to_string(),
);
}
_ => {}
}
}
Ok(())
}
fn check_query(q: &Query) -> Result<(), String> {
match q {
Query::Single(stmt) => check_statement(stmt),
Query::Union { left, right, .. } => {
check_query(left)?;
check_query(right)
}
Query::Explain(inner) => check_query(inner),
Query::TimeTravel { query, .. } => check_query(query),
Query::Schema(cmd) => {
use uni_cypher::ast::SchemaCommand;
match cmd.as_ref() {
SchemaCommand::ShowConstraints(_)
| SchemaCommand::ShowIndexes(_)
| SchemaCommand::ShowDatabase
| SchemaCommand::ShowConfig
| SchemaCommand::ShowStatistics => Ok(()),
_ => Err(
"Mutating schema commands are not allowed in read-only context".to_string(),
),
}
}
}
}
check_query(query)
}