2020-06-29 15:36:01 +00:00
|
|
|
use crate::err::Error;
|
2023-01-08 17:11:35 +00:00
|
|
|
use crate::sql::error::Error::{Field, Group, Order, Parser, Split};
|
2022-09-27 21:35:30 +00:00
|
|
|
use crate::sql::error::IResult;
|
2020-06-29 15:36:01 +00:00
|
|
|
use crate::sql::query::{query, Query};
|
2022-06-20 11:26:43 +00:00
|
|
|
use crate::sql::thing::Thing;
|
|
|
|
use crate::sql::value::Value;
|
2020-06-29 15:36:01 +00:00
|
|
|
use nom::Err;
|
|
|
|
use std::str;
|
|
|
|
|
2022-12-07 19:30:29 +00:00
|
|
|
/// Parses a SurrealQL [`Query`]
|
2020-06-29 15:36:01 +00:00
|
|
|
pub fn parse(input: &str) -> Result<Query, Error> {
|
2022-09-27 21:35:30 +00:00
|
|
|
parse_impl(input, query)
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
2022-12-07 19:30:29 +00:00
|
|
|
/// Parses a SurrealQL [`Thing`]
|
2022-06-20 11:26:43 +00:00
|
|
|
pub fn thing(input: &str) -> Result<Thing, Error> {
|
2022-09-27 21:35:30 +00:00
|
|
|
parse_impl(input, super::thing::thing)
|
2022-06-20 11:26:43 +00:00
|
|
|
}
|
|
|
|
|
2022-12-07 19:30:29 +00:00
|
|
|
/// Parses a SurrealQL [`Value`]
|
2022-02-22 14:16:50 +00:00
|
|
|
pub fn json(input: &str) -> Result<Value, Error> {
|
2022-09-27 21:35:30 +00:00
|
|
|
parse_impl(input, super::value::json)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_impl<O>(input: &str, parser: impl Fn(&str) -> IResult<&str, O>) -> Result<O, Error> {
|
2022-10-16 14:20:41 +00:00
|
|
|
// Check the length of the input
|
2022-02-22 14:16:50 +00:00
|
|
|
match input.trim().len() {
|
2022-10-16 14:20:41 +00:00
|
|
|
// The input query was empty
|
2022-03-06 10:58:59 +00:00
|
|
|
0 => Err(Error::QueryEmpty),
|
2022-10-16 14:20:41 +00:00
|
|
|
// Continue parsing the query
|
2022-09-27 21:35:30 +00:00
|
|
|
_ => match parser(input) {
|
2022-10-16 14:20:41 +00:00
|
|
|
// The query was parsed successfully
|
2022-10-16 21:25:48 +00:00
|
|
|
Ok((v, parsed)) if v.is_empty() => Ok(parsed),
|
2022-10-16 14:20:41 +00:00
|
|
|
// There was unparsed SQL remaining
|
|
|
|
Ok((_, _)) => Err(Error::QueryRemaining),
|
|
|
|
// There was an error when parsing the query
|
2023-01-08 17:11:35 +00:00
|
|
|
Err(Err::Error(e)) | Err(Err::Failure(e)) => Err(match e {
|
2022-10-16 14:20:41 +00:00
|
|
|
// There was a parsing error
|
2023-01-08 17:11:35 +00:00
|
|
|
Parser(e) => {
|
2022-10-16 14:20:41 +00:00
|
|
|
// Locate the parser position
|
2022-03-04 16:01:32 +00:00
|
|
|
let (s, l, c) = locate(input, e);
|
2022-10-16 14:20:41 +00:00
|
|
|
// Return the parser error
|
2023-01-08 17:11:35 +00:00
|
|
|
Error::InvalidQuery {
|
2022-02-22 14:16:50 +00:00
|
|
|
line: l,
|
|
|
|
char: c,
|
|
|
|
sql: s.to_string(),
|
2023-01-08 17:11:35 +00:00
|
|
|
}
|
2022-03-04 16:01:32 +00:00
|
|
|
}
|
2023-01-08 17:11:35 +00:00
|
|
|
// There was a SPLIT ON error
|
|
|
|
Field(e, f) => Error::InvalidField {
|
|
|
|
line: locate(input, e).1,
|
|
|
|
field: f,
|
|
|
|
},
|
|
|
|
// There was a SPLIT ON error
|
|
|
|
Split(e, f) => Error::InvalidSplit {
|
|
|
|
line: locate(input, e).1,
|
|
|
|
field: f,
|
|
|
|
},
|
|
|
|
// There was a ORDER BY error
|
|
|
|
Order(e, f) => Error::InvalidOrder {
|
|
|
|
line: locate(input, e).1,
|
|
|
|
field: f,
|
|
|
|
},
|
|
|
|
// There was a GROUP BY error
|
|
|
|
Group(e, f) => Error::InvalidGroup {
|
|
|
|
line: locate(input, e).1,
|
|
|
|
field: f,
|
|
|
|
},
|
|
|
|
}),
|
2022-02-22 14:16:50 +00:00
|
|
|
_ => unreachable!(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-15 09:51:57 +00:00
|
|
|
fn truncate(s: &str, l: usize) -> &str {
|
2022-10-04 21:51:18 +00:00
|
|
|
// TODO: use s.floor_char_boundary once https://github.com/rust-lang/rust/issues/93743 lands
|
2022-01-15 09:51:57 +00:00
|
|
|
match s.char_indices().nth(l) {
|
|
|
|
None => s,
|
|
|
|
Some((i, _)) => &s[..i],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn locate<'a>(input: &str, tried: &'a str) -> (&'a str, usize, usize) {
|
|
|
|
let index = input.len() - tried.len();
|
2022-03-04 16:01:32 +00:00
|
|
|
let tried = truncate(tried, 100);
|
2022-10-04 21:51:18 +00:00
|
|
|
let lines = input.split('\n').map(|l| l.len()).enumerate();
|
2022-01-15 09:51:57 +00:00
|
|
|
let (mut total, mut chars) = (0, 0);
|
|
|
|
for (line, size) in lines {
|
|
|
|
total += size + 1;
|
|
|
|
if index < total {
|
|
|
|
let line_num = line + 1;
|
|
|
|
let char_num = index - chars;
|
|
|
|
return (tried, line_num, char_num);
|
|
|
|
}
|
|
|
|
chars += size + 1;
|
|
|
|
}
|
2022-03-04 16:01:32 +00:00
|
|
|
(tried, 0, 0)
|
2022-01-15 09:51:57 +00:00
|
|
|
}
|
|
|
|
|
2020-06-29 15:36:01 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn no_ending() {
|
|
|
|
let sql = "SELECT * FROM test";
|
|
|
|
let res = parse(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_query_string() {
|
|
|
|
let sql = "SELECT * FROM test;";
|
|
|
|
let res = parse(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn trim_query_string() {
|
|
|
|
let sql = " SELECT * FROM test ; ";
|
|
|
|
let res = parse(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_complex_rubbish() {
|
|
|
|
let sql = " SELECT * FROM test ; /* shouldbespace */ ;;; ";
|
|
|
|
let res = parse(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_complex_failure() {
|
|
|
|
let sql = " SELECT * FROM { }} ";
|
|
|
|
let res = parse(sql);
|
|
|
|
assert!(res.is_err());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parser_try() {
|
|
|
|
let sql = "
|
|
|
|
SELECT
|
|
|
|
*,
|
|
|
|
tags[$].value,
|
|
|
|
3s as duration,
|
|
|
|
1.345 AS number,
|
|
|
|
test AS `some thing`,
|
|
|
|
'2012-04-23T18:25:43.511Z' AS utctime,
|
|
|
|
'2012-04-23T18:25:43.511-08:00' AS pacifictime,
|
2021-03-29 15:43:37 +00:00
|
|
|
{ key: (3 + 1 + 2), other: 9 * 7, 'some thing': { otherkey: 'text', } } AS object
|
2020-06-29 15:36:01 +00:00
|
|
|
FROM $param, test, temp, test:thingy, |test:10|, |test:1..10|
|
|
|
|
WHERE IF true THEN 'YAY' ELSE 'OOPS' END
|
2022-01-13 17:36:41 +00:00
|
|
|
AND (0.1341, 0.5719) INSIDE { type: 'Polygon', coordinates: [[[0.1341, 0.5719], [0.1341, 0.5719]]] }
|
2020-06-29 15:36:01 +00:00
|
|
|
AND (3 + 3 * 4)=6
|
|
|
|
AND 3 + 3 * 4 = 6
|
|
|
|
AND ages CONTAINS 18
|
|
|
|
AND if IS true
|
|
|
|
SPLIT test.things
|
2022-10-17 02:26:32 +00:00
|
|
|
VERSION '2019-01-01T08:00:00Z'
|
2020-06-29 15:36:01 +00:00
|
|
|
TIMEOUT 2w;
|
|
|
|
|
|
|
|
CREATE person SET name = 'Tobie', age += 18;
|
|
|
|
";
|
|
|
|
let res = parse(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let tmp = res.unwrap();
|
2021-03-29 15:43:37 +00:00
|
|
|
|
2022-05-21 00:35:59 +00:00
|
|
|
let enc: Vec<u8> = Vec::from(&tmp);
|
|
|
|
let dec: Query = Query::from(enc);
|
2021-03-29 15:43:37 +00:00
|
|
|
assert_eq!(tmp, dec);
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
}
|