Skip to main content

uni_query/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2024-2026 Dragonscale Team
3
4//! Query execution layer for the Uni graph database.
5//!
6//! This crate provides OpenCypher query parsing, logical planning, and
7//! execution against Uni's object-store-backed property graph.
8//!
9//! # Modules
10//!
11//! - [`query`] — planner, executor, DataFusion integration, pushdown logic
12//! - [`types`] — public value types (`Value`, `Node`, `Edge`, `Path`, etc.)
13//!
14//! # Quick Start
15//!
16//! ```rust,ignore
17//! let executor = Executor::new(storage);
18//! let planner = QueryPlanner::new(schema);
19//! let plan = planner.plan(cypher_ast)?;
20//! let result = executor.execute_plan(plan, &params).await?;
21//! ```
22
23#![recursion_limit = "256"]
24
25pub mod query;
26pub mod types;
27
28pub use query::executor::core::{OperatorStats, ProfileOutput};
29pub use query::executor::procedure::{
30    ProcedureOutput, ProcedureParam, ProcedureRegistry, ProcedureValueType, RegisteredProcedure,
31};
32pub use query::executor::{Executor, ResultNormalizer};
33pub use query::planner::{CostEstimates, ExplainOutput, IndexUsage, LogicalPlan, QueryPlanner};
34pub use types::{
35    Edge, ExecuteResult, FromValue, Node, Path, QueryCursor, QueryResult, QueryWarning, Row, Value,
36};
37pub use uni_cypher::ast::{Query as CypherQuery, TimeTravelSpec};
38
39/// Validate that a query AST contains only read clauses.
40///
41/// Rejects any query that contains CREATE, MERGE, DELETE, SET, REMOVE,
42/// schema commands, or transaction commands.
43///
44/// # Errors
45///
46/// Returns `Err(message)` describing the first write clause found. Used to
47/// enforce read-only access for time-travel queries (`VERSION AS OF` /
48/// `TIMESTAMP AS OF`).
49pub fn validate_read_only(query: &CypherQuery) -> Result<(), String> {
50    use uni_cypher::ast::{Clause, Query, Statement};
51
52    fn check_statement(stmt: &Statement) -> Result<(), String> {
53        for clause in &stmt.clauses {
54            match clause {
55                Clause::Create(_)
56                | Clause::Merge(_)
57                | Clause::Delete(_)
58                | Clause::Set(_)
59                | Clause::Remove(_) => {
60                    return Err(
61                        "Write clauses (CREATE, MERGE, DELETE, SET, REMOVE) are not allowed \
62                         with VERSION AS OF / TIMESTAMP AS OF"
63                            .to_string(),
64                    );
65                }
66                _ => {}
67            }
68        }
69        Ok(())
70    }
71
72    fn check_query(q: &Query) -> Result<(), String> {
73        match q {
74            Query::Single(stmt) => check_statement(stmt),
75            Query::Union { left, right, .. } => {
76                check_query(left)?;
77                check_query(right)
78            }
79            Query::Explain(inner) => check_query(inner),
80            Query::TimeTravel { query, .. } => check_query(query),
81            Query::Schema(_) | Query::Transaction(_) => {
82                Err("Schema and transaction commands are not allowed \
83                 with VERSION AS OF / TIMESTAMP AS OF"
84                    .to_string())
85            }
86        }
87    }
88
89    check_query(query)
90}