surrealdb_core/syn/
mod.rs

1//! Module containing the implementation of the surrealql tokens, lexer, and parser.
2
3use crate::{
4	cnf::{MAX_OBJECT_PARSING_DEPTH, MAX_QUERY_PARSING_DEPTH},
5	dbs::{capabilities::ExperimentalTarget, Capabilities},
6	err::Error,
7	sql::{Block, Datetime, Duration, Idiom, Kind, Query, Range, Subquery, Thing, Value},
8};
9
10pub mod error;
11pub mod lexer;
12pub mod parser;
13pub mod token;
14
15#[cfg(test)]
16pub trait Parse<T> {
17	fn parse(val: &str) -> T;
18}
19
20#[cfg(test)]
21mod test;
22
23use lexer::{compound, Lexer};
24use parser::{Parser, ParserSettings};
25use reblessive::Stack;
26use token::t;
27
28const TARGET: &str = "surrealdb::core::syn";
29
30/// Takes a string and returns if it could be a reserved keyword in certain contexts.
31pub fn could_be_reserved_keyword(s: &str) -> bool {
32	lexer::keywords::could_be_reserved(s)
33}
34
35/// Parses a SurrealQL [`Query`]
36///
37/// During query parsing, the total depth of calls to parse values (including arrays, expressions,
38/// functions, objects, sub-queries), Javascript values, and geometry collections count against
39/// a computation depth limit. If the limit is reached, parsing will return
40/// [`Error::ComputationDepthExceeded`], as opposed to spending more time and potentially
41/// overflowing the call stack.
42///
43/// If you encounter this limit and believe that it should be increased,
44/// please [open an issue](https://github.com/surrealdb/surrealdb/issues)!
45#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
46pub fn parse(input: &str) -> Result<Query, Error> {
47	let capabilities = Capabilities::all();
48	parse_with_capabilities(input, &capabilities)
49}
50
51/// Parses a SurrealQL [`Query`]
52///
53/// During query parsing, the total depth of calls to parse values (including arrays, expressions,
54/// functions, objects, sub-queries), Javascript values, and geometry collections count against
55/// a computation depth limit. If the limit is reached, parsing will return
56/// [`Error::ComputationDepthExceeded`], as opposed to spending more time and potentially
57/// overflowing the call stack.
58///
59/// If you encounter this limit and believe that it should be increased,
60/// please [open an issue](https://github.com/surrealdb/surrealdb/issues)!
61#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
62pub fn parse_with_capabilities(input: &str, capabilities: &Capabilities) -> Result<Query, Error> {
63	trace!(target: TARGET, "Parsing SurrealQL query");
64
65	if input.len() > u32::MAX as usize {
66		return Err(Error::QueryTooLarge);
67	}
68
69	let mut parser = Parser::new_with_settings(
70		input.as_bytes(),
71		ParserSettings {
72			object_recursion_limit: *MAX_OBJECT_PARSING_DEPTH as usize,
73			query_recursion_limit: *MAX_QUERY_PARSING_DEPTH as usize,
74			references_enabled: capabilities
75				.allows_experimental(&ExperimentalTarget::RecordReferences),
76			bearer_access_enabled: capabilities
77				.allows_experimental(&ExperimentalTarget::BearerAccess),
78			define_api_enabled: capabilities.allows_experimental(&ExperimentalTarget::DefineApi),
79			..Default::default()
80		},
81	);
82	let mut stack = Stack::new();
83	stack
84		.enter(|stk| parser.parse_query(stk))
85		.finish()
86		.map_err(|e| e.render_on(input))
87		.map_err(Error::InvalidQuery)
88}
89
90/// Parses a SurrealQL [`Value`].
91#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
92pub fn value(input: &str) -> Result<Value, Error> {
93	let capabilities = Capabilities::all();
94	value_with_capabilities(input, &capabilities)
95}
96
97/// Parses a SurrealQL [`Value`].
98#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
99pub fn value_with_capabilities(input: &str, capabilities: &Capabilities) -> Result<Value, Error> {
100	trace!(target: TARGET, "Parsing SurrealQL value");
101
102	if input.len() > u32::MAX as usize {
103		return Err(Error::QueryTooLarge);
104	}
105
106	let mut parser = Parser::new_with_settings(
107		input.as_bytes(),
108		ParserSettings {
109			object_recursion_limit: *MAX_OBJECT_PARSING_DEPTH as usize,
110			query_recursion_limit: *MAX_QUERY_PARSING_DEPTH as usize,
111			references_enabled: capabilities
112				.allows_experimental(&ExperimentalTarget::RecordReferences),
113			bearer_access_enabled: capabilities
114				.allows_experimental(&ExperimentalTarget::BearerAccess),
115			..Default::default()
116		},
117	);
118	let mut stack = Stack::new();
119	stack
120		.enter(|stk| parser.parse_value_field(stk))
121		.finish()
122		.and_then(|e| parser.assert_finished().map(|_| e))
123		.map_err(|e| e.render_on(input))
124		.map_err(Error::InvalidQuery)
125}
126
127/// Parses JSON into an inert SurrealQL [`Value`]
128#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
129pub fn json(input: &str) -> Result<Value, Error> {
130	trace!(target: TARGET, "Parsing inert JSON value");
131
132	if input.len() > u32::MAX as usize {
133		return Err(Error::QueryTooLarge);
134	}
135
136	let mut parser = Parser::new_with_settings(
137		input.as_bytes(),
138		ParserSettings {
139			object_recursion_limit: *MAX_OBJECT_PARSING_DEPTH as usize,
140			query_recursion_limit: *MAX_QUERY_PARSING_DEPTH as usize,
141			..Default::default()
142		},
143	);
144	let mut stack = Stack::new();
145	stack
146		.enter(|stk| parser.parse_json(stk))
147		.finish()
148		.and_then(|e| parser.assert_finished().map(|_| e))
149		.map_err(|e| e.render_on(input))
150		.map_err(Error::InvalidQuery)
151}
152
153/// Parses a SurrealQL Subquery [`Subquery`]
154#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
155pub fn subquery(input: &str) -> Result<Subquery, Error> {
156	trace!(target: TARGET, "Parsing SurrealQL subquery");
157
158	if input.len() > u32::MAX as usize {
159		return Err(Error::QueryTooLarge);
160	}
161
162	let mut parser = Parser::new_with_settings(
163		input.as_bytes(),
164		ParserSettings {
165			object_recursion_limit: *MAX_OBJECT_PARSING_DEPTH as usize,
166			query_recursion_limit: *MAX_QUERY_PARSING_DEPTH as usize,
167			..Default::default()
168		},
169	);
170	let mut stack = Stack::new();
171	stack
172		.enter(|stk| parser.parse_full_subquery(stk))
173		.finish()
174		.and_then(|e| parser.assert_finished().map(|_| e))
175		.map_err(|e| e.render_on(input))
176		.map_err(Error::InvalidQuery)
177}
178
179/// Parses a SurrealQL [`Idiom`]
180#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
181pub fn idiom(input: &str) -> Result<Idiom, Error> {
182	trace!(target: TARGET, "Parsing SurrealQL idiom");
183
184	if input.len() > u32::MAX as usize {
185		return Err(Error::QueryTooLarge);
186	}
187
188	let mut parser = Parser::new_with_settings(
189		input.as_bytes(),
190		ParserSettings {
191			object_recursion_limit: *MAX_OBJECT_PARSING_DEPTH as usize,
192			query_recursion_limit: *MAX_QUERY_PARSING_DEPTH as usize,
193			..Default::default()
194		},
195	);
196	parser.table_as_field = true;
197	let mut stack = Stack::new();
198	stack
199		.enter(|stk| parser.parse_plain_idiom(stk))
200		.finish()
201		.and_then(|e| parser.assert_finished().map(|_| e))
202		.map_err(|e| e.render_on(input))
203		.map_err(Error::InvalidQuery)
204}
205
206/// Parse a datetime without enclosing delimiters from a string.
207#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
208pub fn datetime(input: &str) -> Result<Datetime, Error> {
209	trace!(target: TARGET, "Parsing SurrealQL datetime");
210
211	if input.len() > u32::MAX as usize {
212		return Err(Error::QueryTooLarge);
213	}
214
215	let mut lexer = Lexer::new(input.as_bytes());
216	let res = compound::datetime_inner(&mut lexer);
217	if let Err(e) = lexer.assert_finished() {
218		return Err(Error::InvalidQuery(e.render_on(input)));
219	}
220	res.map(Datetime).map_err(|e| e.render_on(input)).map_err(Error::InvalidQuery)
221}
222
223/// Parse a duration from a string.
224#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
225pub fn duration(input: &str) -> Result<Duration, Error> {
226	trace!(target: TARGET, "Parsing SurrealQL duration");
227
228	if input.len() > u32::MAX as usize {
229		return Err(Error::QueryTooLarge);
230	}
231
232	let mut parser = Parser::new(input.as_bytes());
233	parser
234		.next_token_value::<Duration>()
235		.and_then(|e| parser.assert_finished().map(|_| e))
236		.map_err(|e| e.render_on(input))
237		.map_err(Error::InvalidQuery)
238}
239
240/// Parse a range.
241#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
242pub fn range(input: &str) -> Result<Range, Error> {
243	trace!(target: TARGET, "Parsing SurrealQL range");
244
245	if input.len() > u32::MAX as usize {
246		return Err(Error::QueryTooLarge);
247	}
248
249	let mut parser = Parser::new(input.as_bytes());
250	let mut stack = Stack::new();
251	stack
252		.enter(|stk| parser.parse_range(stk))
253		.finish()
254		.and_then(|e| parser.assert_finished().map(|_| e))
255		.map_err(|e| e.render_on(input))
256		.map_err(Error::InvalidQuery)
257}
258
259/// Parse a record id.
260#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
261pub fn thing(input: &str) -> Result<Thing, Error> {
262	trace!(target: TARGET, "Parsing SurrealQL thing");
263
264	if input.len() > u32::MAX as usize {
265		return Err(Error::QueryTooLarge);
266	}
267
268	let mut parser = Parser::new_with_settings(
269		input.as_bytes(),
270		ParserSettings {
271			object_recursion_limit: *MAX_OBJECT_PARSING_DEPTH as usize,
272			query_recursion_limit: *MAX_QUERY_PARSING_DEPTH as usize,
273			..Default::default()
274		},
275	);
276	let mut stack = Stack::new();
277	stack
278		.enter(|stk| parser.parse_thing(stk))
279		.finish()
280		.and_then(|e| parser.assert_finished().map(|_| e))
281		.map_err(|e| e.render_on(input))
282		.map_err(Error::InvalidQuery)
283}
284
285/// Parse a record id including ranges.
286#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
287pub fn thing_with_range(input: &str) -> Result<Thing, Error> {
288	trace!(target: TARGET, "Parsing SurrealQL thing");
289
290	if input.len() > u32::MAX as usize {
291		return Err(Error::QueryTooLarge);
292	}
293
294	let mut parser = Parser::new_with_settings(
295		input.as_bytes(),
296		ParserSettings {
297			object_recursion_limit: *MAX_OBJECT_PARSING_DEPTH as usize,
298			query_recursion_limit: *MAX_QUERY_PARSING_DEPTH as usize,
299			..Default::default()
300		},
301	);
302	let mut stack = Stack::new();
303	stack
304		.enter(|stk| parser.parse_thing_with_range(stk))
305		.finish()
306		.and_then(|e| parser.assert_finished().map(|_| e))
307		.map_err(|e| e.render_on(input))
308		.map_err(Error::InvalidQuery)
309}
310
311/// Parse a block, expects the value to be wrapped in `{}`.
312#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
313pub fn block(input: &str) -> Result<Block, Error> {
314	trace!(target: TARGET, "Parsing SurrealQL block");
315
316	if input.len() > u32::MAX as usize {
317		return Err(Error::QueryTooLarge);
318	}
319
320	let mut parser = Parser::new_with_settings(
321		input.as_bytes(),
322		ParserSettings {
323			object_recursion_limit: *MAX_OBJECT_PARSING_DEPTH as usize,
324			query_recursion_limit: *MAX_QUERY_PARSING_DEPTH as usize,
325			..Default::default()
326		},
327	);
328	let mut stack = Stack::new();
329	let token = parser.peek();
330	match token.kind {
331		t!("{") => {
332			let start = parser.pop_peek().span;
333			stack
334				.enter(|stk| parser.parse_block(stk, start))
335				.finish()
336				.and_then(|e| parser.assert_finished().map(|_| e))
337				.map_err(|e| e.render_on(input))
338				.map_err(Error::InvalidQuery)
339		}
340		found => Err(Error::InvalidQuery(
341			error::SyntaxError::new(format_args!("Unexpected token `{found}` expected `{{`"))
342				.with_span(token.span, error::MessageKind::Error)
343				.render_on(input),
344		)),
345	}
346}
347
348/// Parses a SurrealQL [`Value`] and parses values within strings.
349#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
350pub fn value_legacy_strand(input: &str) -> Result<Value, Error> {
351	trace!(target: TARGET, "Parsing SurrealQL value, with legacy strings");
352
353	if input.len() > u32::MAX as usize {
354		return Err(Error::QueryTooLarge);
355	}
356
357	let mut parser = Parser::new_with_settings(
358		input.as_bytes(),
359		ParserSettings {
360			object_recursion_limit: *MAX_OBJECT_PARSING_DEPTH as usize,
361			query_recursion_limit: *MAX_QUERY_PARSING_DEPTH as usize,
362			legacy_strands: true,
363			..Default::default()
364		},
365	);
366	let mut stack = Stack::new();
367	stack
368		.enter(|stk| parser.parse_value_field(stk))
369		.finish()
370		.and_then(|e| parser.assert_finished().map(|_| e))
371		.map_err(|e| e.render_on(input))
372		.map_err(Error::InvalidQuery)
373}
374
375/// Parses JSON into an inert SurrealQL [`Value`] and parses values within strings.
376#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
377pub fn json_legacy_strand(input: &str) -> Result<Value, Error> {
378	trace!(target: TARGET, "Parsing inert JSON value, with legacy strings");
379
380	if input.len() > u32::MAX as usize {
381		return Err(Error::QueryTooLarge);
382	}
383
384	let mut parser = Parser::new_with_settings(
385		input.as_bytes(),
386		ParserSettings {
387			object_recursion_limit: *MAX_OBJECT_PARSING_DEPTH as usize,
388			query_recursion_limit: *MAX_QUERY_PARSING_DEPTH as usize,
389			legacy_strands: true,
390			..Default::default()
391		},
392	);
393	let mut stack = Stack::new();
394	stack
395		.enter(|stk| parser.parse_json(stk))
396		.finish()
397		.and_then(|e| parser.assert_finished().map(|_| e))
398		.map_err(|e| e.render_on(input))
399		.map_err(Error::InvalidQuery)
400}
401
402/// Parse a kind from a string.
403#[instrument(level = "trace", target = "surrealdb::core::syn", fields(length = input.len()))]
404pub fn kind(input: &str) -> Result<Kind, Error> {
405	trace!(target: TARGET, "Parsing SurrealQL duration");
406
407	if input.len() > u32::MAX as usize {
408		return Err(Error::QueryTooLarge);
409	}
410
411	let mut parser = Parser::new(input.as_bytes());
412	let mut stack = Stack::new();
413	stack
414		.enter(|stk| parser.parse_inner_kind(stk))
415		.finish()
416		.and_then(|e| parser.assert_finished().map(|_| e))
417		.map_err(|e| e.render_on(input))
418		.map_err(Error::InvalidQuery)
419}