1use crate::{err::Error, Subquery};
2use crate::{Datetime, Duration, Idiom, Query, Range, Thing, Value};
3use nom::{Err, Finish};
4
5pub mod literal;
6mod part;
7mod stmt;
8
9mod block;
10pub(crate) mod builtin;
11mod comment;
12mod common;
13mod depth;
14mod ending;
15mod error;
16mod expression;
17mod function;
18mod idiom;
19mod kind;
20mod omit;
21mod operator;
22mod special;
23mod subquery;
24mod thing;
25mod value;
26
27pub use error::{IResult, ParseError};
28
29#[cfg(test)]
30pub(crate) mod test;
31
32fn query(i: &str) -> IResult<&str, Query> {
33 let (i, v) = stmt::statements(i)?;
34 if !i.is_empty() {
35 return Err(Err::Failure(ParseError::ExplainedExpected {
36 tried: i,
37 expected: "query to end",
38 explained: "perhaps missing a semicolon on the previous statement?",
39 }));
40 }
41 Ok((i, Query(v)))
42}
43
44#[instrument(level = "debug", name = "parser", skip_all, fields(length = input.len()))]
55pub fn parse(input: &str) -> Result<Query, Error> {
56 parse_impl(input, query)
57}
58
59#[instrument(level = "debug", name = "parser", skip_all, fields(length = input.len()))]
61pub fn value(input: &str) -> Result<Value, Error> {
62 parse_impl(input, value::value)
63}
64
65#[instrument(level = "debug", name = "parser", skip_all, fields(length = input.len()))]
67pub fn json(input: &str) -> Result<Value, Error> {
68 parse_impl(input, value::json)
69}
70#[instrument(level = "debug", name = "parser", skip_all, fields(length = input.len()))]
72pub fn subquery(input: &str) -> Result<Subquery, Error> {
73 parse_impl(input, subquery::subquery)
74}
75
76#[instrument(level = "debug", name = "parser", skip_all, fields(length = input.len()))]
78pub fn idiom(input: &str) -> Result<Idiom, Error> {
79 parse_impl(input, idiom::plain)
80}
81
82pub fn datetime(input: &str) -> Result<Datetime, Error> {
83 parse_impl(input, literal::datetime)
84}
85
86pub fn datetime_raw(input: &str) -> Result<Datetime, Error> {
87 parse_impl(input, literal::datetime_all_raw)
88}
89
90pub fn duration(input: &str) -> Result<Duration, Error> {
91 parse_impl(input, literal::duration)
92}
93
94pub fn path_like(input: &str) -> Result<Value, Error> {
95 parse_impl(input, value::path_like)
96}
97
98pub fn range(input: &str) -> Result<Range, Error> {
99 parse_impl(input, literal::range)
100}
101
102pub fn thing(input: &str) -> Result<Thing, Error> {
104 parse_impl(input, thing::thing)
105}
106
107pub fn thing_raw(input: &str) -> Result<Thing, Error> {
108 parse_impl(input, thing::thing_raw)
109}
110
111fn parse_impl<O>(input: &str, parser: impl Fn(&str) -> IResult<&str, O>) -> Result<O, Error> {
112 depth::reset();
114
115 match input.trim().len() {
117 0 => Err(Error::QueryEmpty),
119 _ => match parser(input).finish() {
121 Ok((v, parsed)) if v.is_empty() => Ok(parsed),
123 Ok((_, _)) => Err(Error::QueryRemaining),
125 Err(e) => Err(Error::InvalidQuery(e.render_on(input))),
127 },
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use serde::Serialize;
135 use std::{
136 collections::HashMap,
137 time::{Duration, Instant},
138 };
139
140 #[test]
141 fn no_ending() {
142 let sql = "SELECT * FROM test";
143 parse(sql).unwrap();
144 }
145
146 #[test]
147 fn parse_query_string() {
148 let sql = "SELECT * FROM test;";
149 parse(sql).unwrap();
150 }
151
152 #[test]
153 fn trim_query_string() {
154 let sql = " SELECT * FROM test ; ";
155 parse(sql).unwrap();
156 }
157
158 #[test]
159 fn parse_complex_rubbish() {
160 let sql = " SELECT * FROM test ; /* shouldbespace */ ;;; ";
161 parse(sql).unwrap();
162 }
163
164 #[test]
165 fn parse_complex_failure() {
166 let sql = " SELECT * FROM { }} ";
167 parse(sql).unwrap_err();
168 }
169
170 #[test]
171 fn parse_ok_recursion() {
172 let sql = "SELECT * FROM ((SELECT * FROM (5))) * 5;";
173 parse(sql).unwrap();
174 }
175
176 #[test]
177 fn parse_ok_recursion_deeper() {
178 let sql = "SELECT * FROM (((( SELECT * FROM ((5)) + ((5)) + ((5)) )))) * ((( function() {return 5;} )));";
179 let start = Instant::now();
180 parse(sql).unwrap();
181 let elapsed = start.elapsed();
182 assert!(
183 elapsed < Duration::from_millis(2000),
184 "took {}ms, previously took ~1000ms in debug",
185 elapsed.as_millis()
186 )
187 }
188
189 #[test]
190 fn parse_recursion_cast() {
191 for n in [10, 100, 500] {
192 recursive("SELECT * FROM ", "<int>", "5", "", n, n > 50);
193 }
194 }
195
196 #[test]
197 fn parse_recursion_geometry() {
198 for n in [1, 50, 100] {
199 recursive(
200 "SELECT * FROM ",
201 r#"{type: "GeometryCollection",geometries: ["#,
202 r#"{type: "MultiPoint",coordinates: [[10.0, 11.2],[10.5, 11.9]]}"#,
203 "]}",
204 n,
205 n > 25,
206 );
207 }
208 }
209
210 #[test]
211 fn parse_recursion_javascript() {
212 for n in [10, 1000] {
213 recursive("SELECT * FROM ", "function() {", "return 5;", "}", n, n > 500);
214 }
215 }
216
217 #[test]
218 fn parse_recursion_mixed() {
219 for n in [3, 15, 75] {
220 recursive("", "SELECT * FROM ((((", "5 * 5", ")))) * 5", n, n > 5);
221 }
222 }
223
224 #[test]
225 fn parse_recursion_select() {
226 for n in [5, 10, 100] {
227 recursive("SELECT * FROM ", "(SELECT * FROM ", "5", ")", n, n > 15);
228 }
229 }
230
231 #[test]
232 fn parse_recursion_value_subquery() {
233 for p in 1..=4 {
234 recursive("SELECT * FROM ", "(", "5", ")", 10usize.pow(p), p > 1);
235 }
236 }
237
238 #[test]
239 fn parse_recursion_if_subquery() {
240 for p in 1..=3 {
241 recursive("SELECT * FROM ", "IF true THEN ", "5", " ELSE 4 END", 6usize.pow(p), p > 1);
242 }
243 }
244
245 #[test]
246 fn parser_try() {
247 let sql = "
248 SELECT
249 *,
250 tags[$].value,
251 3s as duration,
252 1.345 AS number,
253 test AS `some thing`,
254 '2012-04-23T18:25:43.511Z' AS utctime,
255 '2012-04-23T18:25:43.511-08:00' AS pacifictime,
256 { key: (3 + 1 + 2), other: 9 * 7, 'some thing': { otherkey: 'text', } } AS object
257 FROM $param, test, temp, test:thingy, |test:10|, |test:1..10|
258 WHERE IF true THEN 'YAY' ELSE 'OOPS' END
259 AND (0.1341, 0.5719) INSIDE { type: 'Polygon', coordinates: [[[0.1341, 0.5719], [0.1341, 0.5719]]] }
260 AND (3 + 3 * 4)=6
261 AND 3 + 3 * 4 = 6
262 AND ages CONTAINS 18
263 AND if IS true
264 SPLIT test.things
265 VERSION '2019-01-01T08:00:00Z'
266 TIMEOUT 2w;
267 CREATE person SET name = 'Tobie', age += 18;
268 ";
269 let tmp = parse(sql).unwrap();
270
271 let enc: Vec<u8> = Vec::from(&tmp);
272 let dec: Query = Query::from(enc);
273 assert_eq!(tmp, dec);
274 }
275
276 #[test]
277 fn parser_full() {
278 let sql = std::fs::read("test.surql").unwrap();
279 let sql = std::str::from_utf8(&sql).unwrap();
280 let res = parse(sql);
281 let tmp = res.unwrap();
282
283 let enc: Vec<u8> = Vec::from(&tmp);
284 let dec: Query = Query::from(enc);
285 assert_eq!(tmp, dec);
286 }
287
288 #[test]
289 #[cfg_attr(debug_assertions, ignore)]
290 fn json_benchmark() {
291 #[derive(Clone, Serialize)]
295 struct Data {
296 boolean: bool,
297 integer: i32,
298 decimal: f32,
299 string: String,
300 inner: Option<Box<Self>>,
301 inners: Vec<Self>,
302 inner_map: HashMap<String, Self>,
303 }
304
305 let inner = Data {
306 boolean: true,
307 integer: -1,
308 decimal: 0.5,
309 string: "foo".to_owned(),
310 inner: None,
311 inners: Vec::new(),
312 inner_map: HashMap::new(),
313 };
314 let inners = vec![inner.clone(); 10];
315
316 let data = Data {
317 boolean: false,
318 integer: 42,
319 decimal: 9000.0,
320 string: "SurrealDB".to_owned(),
321 inner_map: inners.iter().enumerate().map(|(i, d)| (i.to_string(), d.clone())).collect(),
322 inners,
323 inner: Some(Box::new(inner)),
324 };
325
326 let json = serde_json::to_string(&data).unwrap();
327 let json_pretty = serde_json::to_string_pretty(&data).unwrap();
328
329 let benchmark = |de: fn(&str) -> Value| {
330 let time = Instant::now();
331 const ITERATIONS: u32 = 32;
332 for _ in 0..ITERATIONS {
333 std::hint::black_box(de(std::hint::black_box(&json)));
334 std::hint::black_box(de(std::hint::black_box(&json_pretty)));
335 }
336 time.elapsed().as_secs_f32() / (2 * ITERATIONS) as f32
337 };
338
339 println!("crate::json took {:.10}s/iter", benchmark(|s| crate::json(s).unwrap()));
340 }
341
342 fn recursive(
345 prefix: &str,
346 recursive_start: &str,
347 base: &str,
348 recursive_end: &str,
349 n: usize,
350 excessive: bool,
351 ) {
352 let mut sql = String::from(prefix);
353 for _ in 0..n {
354 sql.push_str(recursive_start);
355 }
356 sql.push_str(base);
357 for _ in 0..n {
358 sql.push_str(recursive_end);
359 }
360 let start = Instant::now();
361 let res = query(&sql).finish();
362 let elapsed = start.elapsed();
363 if excessive {
364 assert!(
365 matches!(res, Err(ParseError::ExcessiveDepth(_))),
366 "expected computation depth exceeded, got {:?}",
367 res
368 );
369 } else {
370 res.unwrap();
371 }
372 let cutoff = if excessive {
374 500
375 } else {
376 1000
377 };
378 assert!(
379 elapsed < Duration::from_millis(cutoff),
380 "took {}ms, previously much faster to parse {n} in debug mode",
381 elapsed.as_millis()
382 )
383 }
384
385 #[test]
386 fn single_query() {
387 let sql = "CREATE test";
388 let res = query(sql);
389 assert!(res.is_ok());
390 let out = res.unwrap().1;
391 assert_eq!("CREATE test;", format!("{}", out))
392 }
393
394 #[test]
395 fn multiple_query() {
396 let sql = "CREATE test; CREATE temp;";
397 let res = query(sql);
398 assert!(res.is_ok());
399 let out = res.unwrap().1;
400 assert_eq!("CREATE test;\nCREATE temp;", format!("{}", out))
401 }
402
403 #[test]
404 fn multiple_query_semicolons() {
405 let sql = "CREATE test;;;CREATE temp;;;";
406 let res = query(sql);
407 assert!(res.is_ok());
408 let out = res.unwrap().1;
409 assert_eq!("CREATE test;\nCREATE temp;", format!("{}", out))
410 }
411
412 #[test]
413 fn multiple_query_semicolons_comments() {
414 let sql = "CREATE test;;;CREATE temp;;;/* some comment */";
415 let res = query(sql);
416 assert!(res.is_ok());
417 let out = res.unwrap().1;
418 assert_eq!("CREATE test;\nCREATE temp;", format!("{}", out))
419 }
420
421 #[test]
422 fn multiple_query_semicolons_multi_comments() {
423 let sql = "CREATE test;;;CREATE temp;;;/* some comment */;;;/* other comment */";
424 let res = query(sql);
425 assert!(res.is_ok());
426 let out = res.unwrap().1;
427 assert_eq!("CREATE test;\nCREATE temp;", format!("{}", out))
428 }
429}