surrealdb-sql 1.1.0

Full type definitions for the SurrealQL query language
Documentation
use super::{
	common::{commas, val_char},
	error::expected,
	IResult,
};
use crate::{Ident, Param, Table, Tables};
use nom::{
	branch::alt,
	bytes::complete::{escaped_transform, is_not, tag, take_while1},
	character::complete::char,
	combinator::{cut, recognize, value},
	multi::separated_list1,
	sequence::delimited,
};

pub mod algorithm;
pub mod datetime;
pub mod duration;
pub mod filter;
pub mod language;
pub mod number;
pub mod range;
pub mod regex;
pub mod scoring;
pub mod strand;
pub mod tokenizer;
pub mod uuid;

pub use self::algorithm::algorithm;
pub use self::datetime::{datetime, datetime_all_raw};
pub use self::duration::duration;
pub use self::filter::filters;
pub use self::number::number;
pub use self::range::range;
pub use self::regex::regex;
pub use self::scoring::scoring;
pub use self::strand::strand;
pub use self::uuid::uuid;

const BRACKET_L: char = '';
const BRACKET_R: char = '';
const BRACKET_END_NUL: &str = "\0";

pub fn ident(i: &str) -> IResult<&str, Ident> {
	let (i, v) = expected("an identifier", ident_raw)(i)?;
	Ok((i, Ident::from(v)))
}

pub fn ident_path(i: &str) -> IResult<&str, Ident> {
	let (i, v) = recognize(separated_list1(tag("::"), take_while1(val_char)))(i)?;
	Ok((i, Ident::from(v)))
}

pub fn ident_raw(i: &str) -> IResult<&str, String> {
	let (i, v) = alt((ident_default, ident_backtick, ident_brackets))(i)?;
	Ok((i, v))
}

fn ident_default(i: &str) -> IResult<&str, String> {
	let (i, v) = take_while1(val_char)(i)?;
	Ok((i, String::from(v)))
}

fn ident_backtick(i: &str) -> IResult<&str, String> {
	let (i, _) = char('`')(i)?;
	let (i, v) = escaped_transform(
		is_not("`\\\0"),
		'\\',
		alt((
			value('\u{5c}', char('\\')),
			value('\u{60}', char('`')),
			value('\u{2f}', char('/')),
			value('\u{08}', char('b')),
			value('\u{0c}', char('f')),
			value('\u{0a}', char('n')),
			value('\u{0d}', char('r')),
			value('\u{09}', char('t')),
		)),
	)(i)?;
	let (i, _) = char('`')(i)?;
	Ok((i, v))
}

fn ident_brackets(i: &str) -> IResult<&str, String> {
	let (i, v) = delimited(char(BRACKET_L), is_not(BRACKET_END_NUL), char(BRACKET_R))(i)?;
	Ok((i, String::from(v)))
}

pub fn param(i: &str) -> IResult<&str, Param> {
	let (i, _) = char('$')(i)?;
	cut(|i| {
		let (i, v) = ident(i)?;
		Ok((i, Param::from(v)))
	})(i)
}

pub fn table(i: &str) -> IResult<&str, Table> {
	let (i, v) = expected("a table name", ident_raw)(i)?;
	Ok((i, Table(v)))
}

pub fn tables(i: &str) -> IResult<&str, Tables> {
	let (i, v) = separated_list1(commas, table)(i)?;
	Ok((i, Tables(v)))
}

#[cfg(test)]
mod tests {

	use super::*;
	use crate::syn::test::Parse;

	#[test]
	fn ident_normal() {
		let sql = "test";
		let res = ident(sql);
		let out = res.unwrap().1;
		assert_eq!("test", format!("{}", out));
		assert_eq!(out, Ident::from("test"));
	}

	#[test]
	fn ident_quoted_backtick() {
		let sql = "`test`";
		let res = ident(sql);
		let out = res.unwrap().1;
		assert_eq!("test", format!("{}", out));
		assert_eq!(out, Ident::from("test"));
	}

	#[test]
	fn ident_quoted_brackets() {
		let sql = "⟨test⟩";
		let res = ident(sql);
		let out = res.unwrap().1;
		assert_eq!("test", format!("{}", out));
		assert_eq!(out, Ident::from("test"));
	}

	#[test]
	fn param_normal() {
		let sql = "$test";
		let res = param(sql);
		let out = res.unwrap().1;
		assert_eq!("$test", format!("{}", out));
		assert_eq!(out, Param::parse("$test"));
	}

	#[test]
	fn param_longer() {
		let sql = "$test_and_deliver";
		let res = param(sql);
		let out = res.unwrap().1;
		assert_eq!("$test_and_deliver", format!("{}", out));
		assert_eq!(out, Param::parse("$test_and_deliver"));
	}

	#[test]
	fn table_normal() {
		let sql = "test";
		let res = table(sql);
		let out = res.unwrap().1;
		assert_eq!("test", format!("{}", out));
		assert_eq!(out, Table(String::from("test")));
	}

	#[test]
	fn table_quoted_backtick() {
		let sql = "`test`";
		let res = table(sql);
		let out = res.unwrap().1;
		assert_eq!("test", format!("{}", out));
		assert_eq!(out, Table(String::from("test")));
	}

	#[test]
	fn table_quoted_brackets() {
		let sql = "⟨test⟩";
		let res = table(sql);
		let out = res.unwrap().1;
		assert_eq!("test", format!("{}", out));
		assert_eq!(out, Table(String::from("test")));
	}
}