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 /// Executes a GQL query with visibility at the specified epoch.
43 ///
44 /// This enables time-travel queries: the query sees the database
45 /// as it existed at the given epoch.
46 ///
47 /// # Errors
48 ///
49 /// Returns an error if parsing or execution fails.
50 #[cfg(feature = "gql")]
51 pub fn execute_at_epoch(
52 &self,
53 query: &str,
54 epoch: grafeo_common::types::EpochId,
55 ) -> Result<QueryResult> {
56 self.with_session(|s| s.execute_at_epoch(query, epoch))
57 }
58
59 /// Executes a query with parameters and returns the result.
60 ///
61 /// # Errors
62 ///
63 /// Returns an error if the query fails.
64 pub fn execute_with_params(
65 &self,
66 query: &str,
67 params: std::collections::HashMap<String, grafeo_common::types::Value>,
68 ) -> Result<QueryResult> {
69 self.with_session(|s| s.execute_with_params(query, params))
70 }
71
72 /// Executes a Cypher query and returns the result.
73 ///
74 /// # Errors
75 ///
76 /// Returns an error if the query fails.
77 #[cfg(feature = "cypher")]
78 pub fn execute_cypher(&self, query: &str) -> Result<QueryResult> {
79 self.with_session(|s| s.execute_cypher(query))
80 }
81
82 /// Executes a Cypher query with parameters and returns the result.
83 ///
84 /// # Errors
85 ///
86 /// Returns an error if the query fails.
87 #[cfg(feature = "cypher")]
88 pub fn execute_cypher_with_params(
89 &self,
90 query: &str,
91 params: std::collections::HashMap<String, grafeo_common::types::Value>,
92 ) -> Result<QueryResult> {
93 self.with_session(|s| s.execute_language(query, "cypher", Some(params)))
94 }
95
96 /// Executes a Gremlin query and returns the result.
97 ///
98 /// # Errors
99 ///
100 /// Returns an error if the query fails.
101 #[cfg(feature = "gremlin")]
102 pub fn execute_gremlin(&self, query: &str) -> Result<QueryResult> {
103 self.with_session(|s| s.execute_gremlin(query))
104 }
105
106 /// Executes a Gremlin query with parameters and returns the result.
107 ///
108 /// # Errors
109 ///
110 /// Returns an error if the query fails.
111 #[cfg(feature = "gremlin")]
112 pub fn execute_gremlin_with_params(
113 &self,
114 query: &str,
115 params: std::collections::HashMap<String, grafeo_common::types::Value>,
116 ) -> Result<QueryResult> {
117 self.with_session(|s| s.execute_gremlin_with_params(query, params))
118 }
119
120 /// Executes a GraphQL query and returns the result.
121 ///
122 /// # Errors
123 ///
124 /// Returns an error if the query fails.
125 #[cfg(feature = "graphql")]
126 pub fn execute_graphql(&self, query: &str) -> Result<QueryResult> {
127 self.with_session(|s| s.execute_graphql(query))
128 }
129
130 /// Executes a GraphQL query with parameters and returns the result.
131 ///
132 /// # Errors
133 ///
134 /// Returns an error if the query fails.
135 #[cfg(feature = "graphql")]
136 pub fn execute_graphql_with_params(
137 &self,
138 query: &str,
139 params: std::collections::HashMap<String, grafeo_common::types::Value>,
140 ) -> Result<QueryResult> {
141 self.with_session(|s| s.execute_graphql_with_params(query, params))
142 }
143
144 /// Executes a SQL/PGQ query (SQL:2023 GRAPH_TABLE) and returns the result.
145 ///
146 /// # Errors
147 ///
148 /// Returns an error if the query fails.
149 #[cfg(feature = "sql-pgq")]
150 pub fn execute_sql(&self, query: &str) -> Result<QueryResult> {
151 self.with_session(|s| s.execute_sql(query))
152 }
153
154 /// Executes a SQL/PGQ query with parameters and returns the result.
155 ///
156 /// # Errors
157 ///
158 /// Returns an error if the query fails.
159 #[cfg(feature = "sql-pgq")]
160 pub fn execute_sql_with_params(
161 &self,
162 query: &str,
163 params: std::collections::HashMap<String, grafeo_common::types::Value>,
164 ) -> Result<QueryResult> {
165 self.with_session(|s| s.execute_sql_with_params(query, params))
166 }
167
168 /// Executes a query in the specified language by name.
169 ///
170 /// Supported language names: `"gql"`, `"cypher"`, `"gremlin"`, `"graphql"`,
171 /// `"sparql"`, `"sql"`. Each requires the corresponding feature flag.
172 ///
173 /// # Errors
174 ///
175 /// Returns an error if the language is unknown/disabled, or if the query
176 /// fails.
177 pub fn execute_language(
178 &self,
179 query: &str,
180 language: &str,
181 params: Option<std::collections::HashMap<String, grafeo_common::types::Value>>,
182 ) -> Result<QueryResult> {
183 self.with_session(|s| s.execute_language(query, language, params))
184 }
185
186 /// Executes a query and returns a single scalar value.
187 ///
188 /// # Errors
189 ///
190 /// Returns an error if the query fails or doesn't return exactly one row.
191 pub fn query_scalar<T: FromValue>(&self, query: &str) -> Result<T> {
192 let result = self.execute(query)?;
193 result.scalar()
194 }
195}