grafeo_engine/database/query.rs
1//! Query execution methods for GrafeoDB.
2
3use grafeo_common::utils::error::Result;
4
5use super::{FromValue, QueryResult};
6
7impl super::GrafeoDB {
8 /// Executes a closure with a one-shot session, syncing graph context back
9 /// to the database afterward. This ensures `USE GRAPH`, `SESSION SET GRAPH`,
10 /// and `SESSION RESET` persist across one-shot `execute()` calls.
11 fn with_session<F>(&self, func: F) -> Result<QueryResult>
12 where
13 F: FnOnce(&crate::session::Session) -> Result<QueryResult>,
14 {
15 let session = self.session();
16 let result = func(&session);
17 // Sync graph and schema state back, even on error (the session command may
18 // have succeeded before a subsequent query failed in the same session).
19 *self.current_graph.write() = session.current_graph();
20 *self.current_schema.write() = session.current_schema();
21 result
22 }
23
24 /// Runs a query directly on the database.
25 ///
26 /// A convenience method that creates a temporary session behind the
27 /// scenes. If you're running multiple queries, grab a
28 /// [`session()`](Self::session) instead to avoid the overhead.
29 ///
30 /// Graph context commands (`USE GRAPH`, `SESSION SET GRAPH`, `SESSION RESET`)
31 /// persist across calls: running `execute("USE GRAPH analytics")` followed
32 /// by `execute("MATCH (n) RETURN n")` routes the second query to the
33 /// analytics graph.
34 ///
35 /// # Errors
36 ///
37 /// Returns an error if parsing or execution fails.
38 pub fn execute(&self, query: &str) -> Result<QueryResult> {
39 self.with_session(|s| s.execute(query))
40 }
41
42 /// Runs a read-only GQL query and returns a lazy result stream.
43 ///
44 /// The stream pulls chunks from the operator pipeline on demand, so
45 /// memory usage is bounded regardless of result-set size. Rejects
46 /// mutations, EXPLAIN/PROFILE, schema/session commands, and queries
47 /// whose planner emits a push-based pipeline (ORDER BY, aggregate,
48 /// DISTINCT, etc.). Use [`execute`](Self::execute) for those.
49 ///
50 /// # Stability: Experimental
51 ///
52 /// New in 0.5.40. Signature may change before being promoted to Beta.
53 ///
54 /// # Errors
55 ///
56 /// Returns an error if parsing or planning fails, or if the query is a
57 /// kind that cannot be streamed.
58 #[cfg(all(feature = "gql", feature = "lpg"))]
59 pub fn execute_streaming(
60 &self,
61 query: &str,
62 ) -> Result<crate::query::executor::stream::OwnedResultStream> {
63 use crate::query::executor::stream::OwnedResultStream;
64 let session = self.session();
65 let (source, columns, deadline) = session.build_streaming_plan(query)?;
66 // Sync graph/schema state back (parser may have changed the session's
67 // view, although streaming rejects session commands so this is a
68 // defensive no-op today).
69 *self.current_graph.write() = session.current_graph();
70 *self.current_schema.write() = session.current_schema();
71 Ok(OwnedResultStream::new(source, columns, deadline))
72 }
73
74 /// Executes a GQL query with visibility at the specified epoch.
75 ///
76 /// This enables time-travel queries: the query sees the database
77 /// as it existed at the given epoch.
78 ///
79 /// # Errors
80 ///
81 /// Returns an error if parsing or execution fails.
82 #[cfg(feature = "gql")]
83 pub fn execute_at_epoch(
84 &self,
85 query: &str,
86 epoch: grafeo_common::types::EpochId,
87 ) -> Result<QueryResult> {
88 self.with_session(|s| s.execute_at_epoch(query, epoch))
89 }
90
91 /// Executes a query with parameters and returns the result.
92 ///
93 /// # Errors
94 ///
95 /// Returns an error if the query fails.
96 pub fn execute_with_params(
97 &self,
98 query: &str,
99 params: std::collections::HashMap<String, grafeo_common::types::Value>,
100 ) -> Result<QueryResult> {
101 self.with_session(|s| s.execute_with_params(query, params))
102 }
103
104 /// Executes a Cypher query and returns the result.
105 ///
106 /// # Errors
107 ///
108 /// Returns an error if the query fails.
109 #[cfg(feature = "cypher")]
110 pub fn execute_cypher(&self, query: &str) -> Result<QueryResult> {
111 self.with_session(|s| s.execute_cypher(query))
112 }
113
114 /// Executes a Cypher query with parameters and returns the result.
115 ///
116 /// # Errors
117 ///
118 /// Returns an error if the query fails.
119 #[cfg(feature = "cypher")]
120 pub fn execute_cypher_with_params(
121 &self,
122 query: &str,
123 params: std::collections::HashMap<String, grafeo_common::types::Value>,
124 ) -> Result<QueryResult> {
125 self.with_session(|s| s.execute_language(query, "cypher", Some(params)))
126 }
127
128 /// Executes a Gremlin query and returns the result.
129 ///
130 /// # Errors
131 ///
132 /// Returns an error if the query fails.
133 #[cfg(feature = "gremlin")]
134 pub fn execute_gremlin(&self, query: &str) -> Result<QueryResult> {
135 self.with_session(|s| s.execute_gremlin(query))
136 }
137
138 /// Executes a Gremlin query with parameters and returns the result.
139 ///
140 /// # Errors
141 ///
142 /// Returns an error if the query fails.
143 #[cfg(feature = "gremlin")]
144 pub fn execute_gremlin_with_params(
145 &self,
146 query: &str,
147 params: std::collections::HashMap<String, grafeo_common::types::Value>,
148 ) -> Result<QueryResult> {
149 self.with_session(|s| s.execute_gremlin_with_params(query, params))
150 }
151
152 /// Executes a GraphQL query and returns the result.
153 ///
154 /// # Errors
155 ///
156 /// Returns an error if the query fails.
157 #[cfg(feature = "graphql")]
158 pub fn execute_graphql(&self, query: &str) -> Result<QueryResult> {
159 self.with_session(|s| s.execute_graphql(query))
160 }
161
162 /// Executes a GraphQL query with parameters and returns the result.
163 ///
164 /// # Errors
165 ///
166 /// Returns an error if the query fails.
167 #[cfg(feature = "graphql")]
168 pub fn execute_graphql_with_params(
169 &self,
170 query: &str,
171 params: std::collections::HashMap<String, grafeo_common::types::Value>,
172 ) -> Result<QueryResult> {
173 self.with_session(|s| s.execute_graphql_with_params(query, params))
174 }
175
176 /// Executes a SQL/PGQ query (SQL:2023 GRAPH_TABLE) and returns the result.
177 ///
178 /// # Errors
179 ///
180 /// Returns an error if the query fails.
181 #[cfg(feature = "sql-pgq")]
182 pub fn execute_sql(&self, query: &str) -> Result<QueryResult> {
183 self.with_session(|s| s.execute_sql(query))
184 }
185
186 /// Executes a SQL/PGQ query with parameters and returns the result.
187 ///
188 /// # Errors
189 ///
190 /// Returns an error if the query fails.
191 #[cfg(feature = "sql-pgq")]
192 pub fn execute_sql_with_params(
193 &self,
194 query: &str,
195 params: std::collections::HashMap<String, grafeo_common::types::Value>,
196 ) -> Result<QueryResult> {
197 self.with_session(|s| s.execute_sql_with_params(query, params))
198 }
199
200 /// Executes a query in the specified language by name.
201 ///
202 /// Supported language names: `"gql"`, `"cypher"`, `"gremlin"`, `"graphql"`,
203 /// `"sparql"`, `"sql"`. Each requires the corresponding feature flag.
204 ///
205 /// # Errors
206 ///
207 /// Returns an error if the language is unknown/disabled, or if the query
208 /// fails.
209 pub fn execute_language(
210 &self,
211 query: &str,
212 language: &str,
213 params: Option<std::collections::HashMap<String, grafeo_common::types::Value>>,
214 ) -> Result<QueryResult> {
215 self.with_session(|s| s.execute_language(query, language, params))
216 }
217
218 /// Executes a query and returns a single scalar value.
219 ///
220 /// # Errors
221 ///
222 /// Returns an error if the query fails or doesn't return exactly one row.
223 pub fn query_scalar<T: FromValue>(&self, query: &str) -> Result<T> {
224 let result = self.execute(query)?;
225 result.scalar()
226 }
227}