2022-05-14 12:35:08 +00:00
|
|
|
use crate::ctx::Context;
|
2022-01-13 17:36:41 +00:00
|
|
|
use crate::dbs::Options;
|
2022-02-15 01:00:30 +00:00
|
|
|
use crate::dbs::Transaction;
|
2021-03-29 15:43:37 +00:00
|
|
|
use crate::err::Error;
|
2020-06-29 15:36:01 +00:00
|
|
|
use crate::sql::common::commas;
|
2022-01-16 20:31:50 +00:00
|
|
|
use crate::sql::error::IResult;
|
2022-03-23 11:51:36 +00:00
|
|
|
use crate::sql::part::{all, field, first, graph, index, last, part, Part};
|
2022-01-13 17:36:41 +00:00
|
|
|
use crate::sql::value::Value;
|
|
|
|
use nom::branch::alt;
|
|
|
|
use nom::multi::many0;
|
2021-03-29 15:43:37 +00:00
|
|
|
use nom::multi::separated_list1;
|
2020-06-29 15:36:01 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use std::fmt;
|
2022-02-22 19:05:58 +00:00
|
|
|
use std::ops::Deref;
|
2020-06-29 15:36:01 +00:00
|
|
|
use std::str;
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
|
|
|
|
pub struct Idioms(pub Vec<Idiom>);
|
2020-06-29 15:36:01 +00:00
|
|
|
|
2022-04-09 09:09:01 +00:00
|
|
|
impl Deref for Idioms {
|
|
|
|
type Target = Vec<Idiom>;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-29 15:36:01 +00:00
|
|
|
impl fmt::Display for Idioms {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.0.iter().map(|ref v| format!("{}", v)).collect::<Vec<_>>().join(", "))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
pub fn locals(i: &str) -> IResult<&str, Idioms> {
|
|
|
|
let (i, v) = separated_list1(commas, local)(i)?;
|
2020-06-29 15:36:01 +00:00
|
|
|
Ok((i, Idioms(v)))
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:43:37 +00:00
|
|
|
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
|
2022-05-05 11:26:46 +00:00
|
|
|
pub struct Idiom(pub Vec<Part>);
|
2020-06-29 15:36:01 +00:00
|
|
|
|
2022-02-22 19:05:58 +00:00
|
|
|
impl Deref for Idiom {
|
|
|
|
type Target = [Part];
|
|
|
|
fn deref(&self) -> &Self::Target {
|
2022-05-05 11:26:46 +00:00
|
|
|
self.0.as_slice()
|
2022-02-22 19:05:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
impl From<Vec<Part>> for Idiom {
|
|
|
|
fn from(v: Vec<Part>) -> Self {
|
2022-05-05 11:26:46 +00:00
|
|
|
Idiom(v)
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
impl Idiom {
|
2022-05-05 11:26:46 +00:00
|
|
|
///
|
2022-05-04 10:34:17 +00:00
|
|
|
pub fn push(mut self, n: Part) -> Idiom {
|
2022-05-05 11:26:46 +00:00
|
|
|
self.0.push(n);
|
2022-04-07 14:33:57 +00:00
|
|
|
self
|
2022-01-22 21:16:13 +00:00
|
|
|
}
|
2022-05-05 11:26:46 +00:00
|
|
|
///
|
2022-01-31 23:11:06 +00:00
|
|
|
pub fn to_path(&self) -> String {
|
|
|
|
format!("/{}", self).replace(']', "").replace(&['.', '['][..], "/")
|
|
|
|
}
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
2022-01-14 08:12:56 +00:00
|
|
|
impl Idiom {
|
2022-05-01 22:25:53 +00:00
|
|
|
pub(crate) async fn compute(
|
2022-01-14 08:12:56 +00:00
|
|
|
&self,
|
2022-05-14 12:35:08 +00:00
|
|
|
ctx: &Context<'_>,
|
2022-02-06 21:06:52 +00:00
|
|
|
opt: &Options,
|
2022-02-15 03:33:16 +00:00
|
|
|
txn: &Transaction,
|
2022-01-14 08:12:56 +00:00
|
|
|
doc: Option<&Value>,
|
|
|
|
) -> Result<Value, Error> {
|
|
|
|
match doc {
|
|
|
|
// There is a current document
|
2022-02-15 01:00:30 +00:00
|
|
|
Some(v) => v.get(ctx, opt, txn, self).await?.compute(ctx, opt, txn, doc).await,
|
2022-01-14 08:12:56 +00:00
|
|
|
// There isn't any document
|
|
|
|
None => Ok(Value::None),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-29 15:36:01 +00:00
|
|
|
impl fmt::Display for Idiom {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2022-01-13 17:36:41 +00:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"{}",
|
2022-05-05 11:26:46 +00:00
|
|
|
self.0
|
2022-01-13 17:36:41 +00:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, p)| match (i, p) {
|
|
|
|
(0, Part::Field(v)) => format!("{}", v),
|
|
|
|
_ => format!("{}", p),
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("")
|
|
|
|
)
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-23 11:51:36 +00:00
|
|
|
// Used in a DEFINE FIELD and DEFINE INDEX clauses
|
2022-01-13 17:36:41 +00:00
|
|
|
pub fn local(i: &str) -> IResult<&str, Idiom> {
|
|
|
|
let (i, p) = first(i)?;
|
|
|
|
let (i, mut v) = many0(alt((all, index, field)))(i)?;
|
|
|
|
v.insert(0, p);
|
2020-06-29 15:36:01 +00:00
|
|
|
Ok((i, Idiom::from(v)))
|
|
|
|
}
|
|
|
|
|
2022-03-23 11:51:36 +00:00
|
|
|
// Used in a SPLIT, ORDER, and GROUP clauses
|
|
|
|
pub fn basic(i: &str) -> IResult<&str, Idiom> {
|
|
|
|
let (i, p) = first(i)?;
|
|
|
|
let (i, mut v) = many0(alt((all, last, index, field)))(i)?;
|
|
|
|
v.insert(0, p);
|
|
|
|
Ok((i, Idiom::from(v)))
|
|
|
|
}
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
// Used in a $param definition
|
|
|
|
pub fn param(i: &str) -> IResult<&str, Idiom> {
|
|
|
|
let (i, p) = first(i)?;
|
|
|
|
let (i, mut v) = many0(part)(i)?;
|
|
|
|
v.insert(0, p);
|
|
|
|
Ok((i, Idiom::from(v)))
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
pub fn idiom(i: &str) -> IResult<&str, Idiom> {
|
|
|
|
let (i, p) = alt((first, graph))(i)?;
|
|
|
|
let (i, mut v) = many0(part)(i)?;
|
|
|
|
v.insert(0, p);
|
|
|
|
Ok((i, Idiom::from(v)))
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
|
|
|
use super::*;
|
2022-01-13 17:36:41 +00:00
|
|
|
use crate::sql::expression::Expression;
|
|
|
|
use crate::sql::test::Parse;
|
2020-06-29 15:36:01 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn idiom_normal() {
|
|
|
|
let sql = "test";
|
|
|
|
let res = idiom(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("test", format!("{}", out));
|
2022-05-05 11:26:46 +00:00
|
|
|
assert_eq!(out, Idiom(vec![Part::from("test")]));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn idiom_quoted_backtick() {
|
|
|
|
let sql = "`test`";
|
|
|
|
let res = idiom(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("test", format!("{}", out));
|
2022-05-05 11:26:46 +00:00
|
|
|
assert_eq!(out, Idiom(vec![Part::from("test")]));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn idiom_quoted_brackets() {
|
|
|
|
let sql = "⟨test⟩";
|
|
|
|
let res = idiom(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("test", format!("{}", out));
|
2022-05-05 11:26:46 +00:00
|
|
|
assert_eq!(out, Idiom(vec![Part::from("test")]));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn idiom_nested() {
|
|
|
|
let sql = "test.temp";
|
|
|
|
let res = idiom(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("test.temp", format!("{}", out));
|
2022-05-05 11:26:46 +00:00
|
|
|
assert_eq!(out, Idiom(vec![Part::from("test"), Part::from("temp"),]));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn idiom_nested_quoted() {
|
|
|
|
let sql = "test.`some key`";
|
|
|
|
let res = idiom(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("test.`some key`", format!("{}", out));
|
2022-05-05 11:26:46 +00:00
|
|
|
assert_eq!(out, Idiom(vec![Part::from("test"), Part::from("some key"),]));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn idiom_nested_array_all() {
|
|
|
|
let sql = "test.temp[*]";
|
|
|
|
let res = idiom(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("test.temp[*]", format!("{}", out));
|
2022-05-05 11:26:46 +00:00
|
|
|
assert_eq!(out, Idiom(vec![Part::from("test"), Part::from("temp"), Part::All,]));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn idiom_nested_array_last() {
|
|
|
|
let sql = "test.temp[$]";
|
|
|
|
let res = idiom(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("test.temp[$]", format!("{}", out));
|
2022-05-05 11:26:46 +00:00
|
|
|
assert_eq!(out, Idiom(vec![Part::from("test"), Part::from("temp"), Part::Last,]));
|
2020-06-29 15:36:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn idiom_nested_array_value() {
|
|
|
|
let sql = "test.temp[*].text";
|
|
|
|
let res = idiom(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("test.temp[*].text", format!("{}", out));
|
|
|
|
assert_eq!(
|
|
|
|
out,
|
2022-05-05 11:26:46 +00:00
|
|
|
Idiom(vec![Part::from("test"), Part::from("temp"), Part::All, Part::from("text")])
|
2020-06-29 15:36:01 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn idiom_nested_array_question() {
|
|
|
|
let sql = "test.temp[? test = true].text";
|
|
|
|
let res = idiom(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("test.temp[WHERE test = true].text", format!("{}", out));
|
|
|
|
assert_eq!(
|
|
|
|
out,
|
2022-05-05 11:26:46 +00:00
|
|
|
Idiom(vec![
|
|
|
|
Part::from("test"),
|
|
|
|
Part::from("temp"),
|
|
|
|
Part::from(Value::from(Expression::parse("test = true"))),
|
|
|
|
Part::from("text")
|
|
|
|
])
|
2020-06-29 15:36:01 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn idiom_nested_array_condition() {
|
|
|
|
let sql = "test.temp[WHERE test = true].text";
|
|
|
|
let res = idiom(sql);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("test.temp[WHERE test = true].text", format!("{}", out));
|
|
|
|
assert_eq!(
|
|
|
|
out,
|
2022-05-05 11:26:46 +00:00
|
|
|
Idiom(vec![
|
|
|
|
Part::from("test"),
|
|
|
|
Part::from("temp"),
|
|
|
|
Part::from(Value::from(Expression::parse("test = true"))),
|
|
|
|
Part::from("text")
|
|
|
|
])
|
2020-06-29 15:36:01 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|