surql_parser/upstream/syn/
mod.rs1use crate::compat::Capabilities;
4use crate::compat::capabilities::ExperimentalTarget;
5use crate::compat::err::Error;
6use crate::compat::types::{PublicDatetime, PublicDuration, PublicRecordId, PublicValue};
7use crate::config::{MAX_OBJECT_PARSING_DEPTH, MAX_QUERY_PARSING_DEPTH};
8use crate::upstream::sql::kind::KindLiteral;
9use crate::upstream::sql::{Ast, Block, Expr, Function, Idiom, Kind};
10use std::collections::HashSet;
11pub mod error;
12pub mod lexer;
13pub mod parser;
14pub mod token;
15#[cfg(test)]
16pub trait Parse<T> {
17 fn parse(val: &str) -> T;
18}
19use anyhow::{Result, bail, ensure};
20use lexer::Lexer;
21pub use parser::ParserSettings;
22use parser::{ParseResult, Parser};
23use reblessive::{Stack, Stk};
24use token::t;
25const TARGET: &str = "surrealdb::core::syn";
26pub fn could_be_reserved_keyword(s: &str) -> bool {
29 lexer::keywords::could_be_reserved(s)
30}
31pub fn parse_with<F, R>(input: &[u8], f: F) -> Result<R>
32where
33 F: AsyncFnOnce(&mut Parser<'_>, &mut Stk) -> ParseResult<R>,
34{
35 parse_with_settings(input, settings_from_capabilities(&Capabilities::all()), f)
36}
37pub fn parse_with_settings<F, R>(input: &[u8], settings: ParserSettings, f: F) -> Result<R>
38where
39 F: for<'a> AsyncFnOnce(&'a mut Parser<'a>, &'a mut Stk) -> ParseResult<R>,
40{
41 ensure!(input.len() <= u32::MAX as usize, Error::QueryTooLarge);
42 let mut parser = Parser::new_with_settings(input, settings);
43 let mut stack = Stack::new();
44 stack
45 .enter(|stk| f(&mut parser, stk))
46 .finish()
47 .map_err(|e| e.render_on_bytes(input))
48 .map_err(Error::InvalidQuery)
49 .map_err(anyhow::Error::new)
50}
51pub fn settings_from_capabilities(cap: &Capabilities) -> ParserSettings {
54 ParserSettings {
55 object_recursion_limit: MAX_OBJECT_PARSING_DEPTH as usize,
56 query_recursion_limit: MAX_QUERY_PARSING_DEPTH as usize,
57 files_enabled: cap.allows_experimental(&ExperimentalTarget::Files),
58 surrealism_enabled: cap.allows_experimental(&ExperimentalTarget::Surrealism),
59 ..Default::default()
60 }
61}
62pub fn parse(input: &str) -> Result<Ast> {
73 let capabilities = Capabilities::all();
74 parse_with_capabilities(input, &capabilities)
75}
76pub fn parse_with_capabilities(input: &str, capabilities: &Capabilities) -> Result<Ast> {
87 trace!(target : TARGET, "Parsing SurrealQL query");
88 parse_with_settings(
89 input.as_bytes(),
90 settings_from_capabilities(capabilities),
91 async |parser, stk| parser.parse_query(stk).await,
92 )
93}
94#[allow(dead_code)]
96pub fn expr(input: &str) -> Result<Expr> {
97 let capabilities = Capabilities::all();
98 expr_with_capabilities(input, &capabilities)
99}
100#[allow(dead_code)]
102pub fn expr_with_capabilities(input: &str, capabilities: &Capabilities) -> Result<Expr> {
103 trace!(target : TARGET, "Parsing SurrealQL value");
104 parse_with_settings(
105 input.as_bytes(),
106 settings_from_capabilities(capabilities),
107 async |parser, stk| parser.parse_expr_field(stk).await,
108 )
109}
110pub fn function(input: &str) -> Result<Function> {
112 let capabilities = Capabilities::all();
113 function_with_capabilities(input, &capabilities)
114}
115pub fn function_with_capabilities(input: &str, capabilities: &Capabilities) -> Result<Function> {
117 trace!(target : TARGET, "Parsing SurrealQL function name");
118 parse_with_settings(
119 input.as_bytes(),
120 settings_from_capabilities(capabilities),
121 async |parser, _stk| parser.parse_function_name().await,
122 )
123}
124pub fn json(input: &str) -> Result<PublicValue> {
126 trace!(target : TARGET, "Parsing inert JSON value");
127 parse_with(input.as_bytes(), async |parser, stk| {
128 parser.parse_json(stk).await
129 })
130}
131pub fn idiom(input: &str) -> Result<Idiom> {
133 trace!(target : TARGET, "Parsing SurrealQL idiom");
134 parse_with(input.as_bytes(), async |parser, stk| {
135 parser.parse_plain_idiom(stk).await
136 })
137}
138pub fn datetime(input: &str) -> Result<PublicDatetime> {
140 trace!(target : TARGET, "Parsing SurrealQL datetime");
141 ensure!(input.len() <= u32::MAX as usize, Error::QueryTooLarge);
142 match Lexer::lex_datetime(input) {
143 Ok(x) => Ok(x),
144 Err(e) => bail!(Error::InvalidQuery(e.render_on(input))),
145 }
146}
147pub fn duration(input: &str) -> Result<PublicDuration> {
149 trace!(target : TARGET, "Parsing SurrealQL duration");
150 ensure!(input.len() <= u32::MAX as usize, Error::QueryTooLarge);
151 let mut parser = Parser::new(input.as_bytes());
152 parser
153 .next_token_value::<PublicDuration>()
154 .and_then(|e| parser.assert_finished().map(|_| e))
155 .map_err(|e| e.render_on(input))
156 .map_err(Error::InvalidQuery)
157 .map_err(anyhow::Error::new)
158}
159pub fn record_id(input: &str) -> Result<PublicRecordId> {
161 trace!(target : TARGET, "Parsing SurrealQL record id");
162 parse_with(input.as_bytes(), async |parser, stk| {
163 parser.parse_value_record_id(stk).await
164 })
165}
166pub fn table(input: &str) -> Result<crate::compat::val::TableName> {
168 trace!(target : TARGET, "Parsing SurrealQL table name");
169 parse_with(input.as_bytes(), async |parser, _stk| {
170 let ident = parser.parse_ident()?;
171 Ok(crate::compat::val::TableName::new(ident))
172 })
173}
174pub fn block(input: &str) -> Result<Block> {
176 trace!(target : TARGET, "Parsing SurrealQL block");
177 parse_with_settings(
178 input.as_bytes(),
179 ParserSettings {
180 legacy_strands: false,
181 flexible_record_id: true,
182 files_enabled: true,
183 surrealism_enabled: true,
184 ..Default::default()
185 },
186 async |parser, stk| {
187 let token = parser.peek();
188 match token.kind {
189 t!("{") => {
190 let start = parser.pop_peek().span;
191 parser.parse_block(stk, start).await
192 }
193 found => Err(error::SyntaxError::new(format_args!(
194 "Unexpected token `{found}` expected `{{`"
195 ))
196 .with_span(token.span, error::MessageKind::Error)),
197 }
198 },
199 )
200}
201#[allow(dead_code)]
203pub fn expr_legacy_strand(input: &str) -> Result<Expr> {
204 trace!(target : TARGET, "Parsing SurrealQL value, with legacy strings");
205 let settings = ParserSettings {
206 object_recursion_limit: MAX_OBJECT_PARSING_DEPTH as usize,
207 query_recursion_limit: MAX_QUERY_PARSING_DEPTH as usize,
208 legacy_strands: true,
209 ..Default::default()
210 };
211 parse_with_settings(input.as_bytes(), settings, async |parser, stk| {
212 parser.parse_expr_field(stk).await
213 })
214}
215pub fn value(input: &str) -> Result<PublicValue> {
217 trace!(target : TARGET, "Parsing SurrealQL value, with legacy strings");
218 let settings = ParserSettings {
219 object_recursion_limit: MAX_OBJECT_PARSING_DEPTH as usize,
220 query_recursion_limit: MAX_QUERY_PARSING_DEPTH as usize,
221 ..Default::default()
222 };
223 parse_with_settings(input.as_bytes(), settings, async |parser, stk| {
224 parser.parse_value(stk).await
225 })
226}
227pub fn value_legacy_strand(input: &str) -> Result<PublicValue> {
229 trace!(target : TARGET, "Parsing SurrealQL value, with legacy strings");
230 let settings = ParserSettings {
231 object_recursion_limit: MAX_OBJECT_PARSING_DEPTH as usize,
232 query_recursion_limit: MAX_QUERY_PARSING_DEPTH as usize,
233 legacy_strands: true,
234 ..Default::default()
235 };
236 parse_with_settings(input.as_bytes(), settings, async |parser, stk| {
237 parser.parse_value(stk).await
238 })
239}
240pub fn json_legacy_strand(input: &str) -> Result<PublicValue> {
243 trace!(target : TARGET, "Parsing inert JSON value, with legacy strings");
244 let settings = ParserSettings {
245 object_recursion_limit: MAX_OBJECT_PARSING_DEPTH as usize,
246 query_recursion_limit: MAX_QUERY_PARSING_DEPTH as usize,
247 legacy_strands: true,
248 ..Default::default()
249 };
250 parse_with_settings(input.as_bytes(), settings, async |parser, stk| {
251 parser.parse_json(stk).await
252 })
253}
254pub fn kind(input: &str) -> Result<Kind> {
256 trace!(target : TARGET, "Parsing SurrealQL duration");
257 parse_with(input.as_bytes(), async |parser, stk| {
258 parser.parse_inner_kind(stk).await
259 })
260}
261#[doc(hidden)]
272pub fn extract_tables_from_kind(sql: &str) -> Result<Vec<String>> {
273 let kind = kind(sql)?;
274 let mut found_tables = HashSet::new();
275 extract_tables_from_kind_impl(&kind, &mut found_tables);
276 let mut tables_sorted: Vec<String> = found_tables.into_iter().collect();
277 tables_sorted.sort();
278 Ok(tables_sorted)
279}
280fn extract_tables_from_kind_impl(kind: &Kind, tables: &mut HashSet<String>) {
281 match kind {
282 Kind::Any
283 | Kind::None
284 | Kind::Null
285 | Kind::Bool
286 | Kind::Bytes
287 | Kind::Datetime
288 | Kind::Decimal
289 | Kind::Duration
290 | Kind::Float
291 | Kind::Int
292 | Kind::Number
293 | Kind::Object
294 | Kind::String
295 | Kind::Uuid
296 | Kind::Regex
297 | Kind::Geometry(_) => {}
298 Kind::Table(ts) => {
299 for table in ts {
300 tables.insert(table.clone());
301 }
302 }
303 Kind::Record(ts) => {
304 for table in ts {
305 tables.insert(table.clone());
306 }
307 }
308 Kind::Either(kinds) => {
309 for kind in kinds {
310 extract_tables_from_kind_impl(kind, tables);
311 }
312 }
313 Kind::Set(kind, _) => {
314 extract_tables_from_kind_impl(kind, tables);
315 }
316 Kind::Array(kind, _) => {
317 extract_tables_from_kind_impl(kind, tables);
318 }
319 Kind::Function(_, _) => {}
320 Kind::Range => {}
321 Kind::Literal(literal) => match literal {
322 KindLiteral::Array(kinds) => {
323 for kind in kinds {
324 extract_tables_from_kind_impl(kind, tables);
325 }
326 }
327 KindLiteral::Object(kinds) => {
328 for kind in kinds.values() {
329 extract_tables_from_kind_impl(kind, tables);
330 }
331 }
332 _ => {}
333 },
334 Kind::File(_) => {}
335 }
336}