2022-01-13 17:36:41 +00:00
|
|
|
use crate::sql::comment::shouldbespace;
|
2022-06-09 08:18:08 +00:00
|
|
|
use crate::sql::ending::ident as ending;
|
2022-01-16 20:31:50 +00:00
|
|
|
use crate::sql::error::IResult;
|
2023-03-31 18:44:16 +00:00
|
|
|
use crate::sql::fmt::Fmt;
|
2023-03-31 15:42:29 +00:00
|
|
|
use crate::sql::graph::{self, Graph};
|
|
|
|
use crate::sql::ident::{self, Ident};
|
2023-07-15 07:08:26 +00:00
|
|
|
use crate::sql::idiom::{self, Idiom};
|
2022-01-13 17:36:41 +00:00
|
|
|
use crate::sql::number::{number, Number};
|
2023-07-15 07:08:26 +00:00
|
|
|
use crate::sql::param::{self};
|
|
|
|
use crate::sql::strand::{self, no_nul_bytes};
|
2023-03-31 15:42:29 +00:00
|
|
|
use crate::sql::value::{self, Value};
|
2022-01-13 17:36:41 +00:00
|
|
|
use nom::branch::alt;
|
|
|
|
use nom::bytes::complete::tag;
|
|
|
|
use nom::bytes::complete::tag_no_case;
|
2023-08-29 10:50:00 +00:00
|
|
|
use nom::combinator::{self, cut, map, not, peek};
|
|
|
|
use nom::sequence::{preceded, terminated};
|
2023-08-17 18:03:46 +00:00
|
|
|
use revision::revisioned;
|
2022-01-13 17:36:41 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use std::fmt;
|
|
|
|
use std::str;
|
|
|
|
|
2023-08-29 10:50:00 +00:00
|
|
|
use super::comment::mightbespace;
|
2023-09-08 11:28:36 +00:00
|
|
|
use super::common::{closebracket, openbracket};
|
|
|
|
use super::error::{expected, ExplainResultExt};
|
|
|
|
use super::util::expect_delimited;
|
2023-08-29 10:50:00 +00:00
|
|
|
|
2022-10-27 12:23:24 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
2023-08-17 18:03:46 +00:00
|
|
|
#[revisioned(revision = 1)]
|
2022-01-13 17:36:41 +00:00
|
|
|
pub enum Part {
|
|
|
|
All,
|
2023-08-01 07:30:13 +00:00
|
|
|
Flatten,
|
2022-01-13 17:36:41 +00:00
|
|
|
Last,
|
|
|
|
First,
|
|
|
|
Field(Ident),
|
|
|
|
Index(Number),
|
|
|
|
Where(Value),
|
|
|
|
Graph(Graph),
|
2023-03-31 15:42:29 +00:00
|
|
|
Value(Value),
|
2023-07-15 07:08:26 +00:00
|
|
|
Start(Value),
|
2023-05-09 17:48:14 +00:00
|
|
|
Method(#[serde(with = "no_nul_bytes")] String, Vec<Value>),
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 08:07:18 +00:00
|
|
|
impl From<i32> for Part {
|
|
|
|
fn from(v: i32) -> Self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Index(v.into())
|
2022-04-07 08:07:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-22 21:16:13 +00:00
|
|
|
impl From<isize> for Part {
|
|
|
|
fn from(v: isize) -> Self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Index(v.into())
|
2022-01-22 21:16:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<usize> for Part {
|
|
|
|
fn from(v: usize) -> Self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Index(v.into())
|
2022-01-22 21:16:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-31 15:42:29 +00:00
|
|
|
impl From<String> for Part {
|
|
|
|
fn from(v: String) -> Self {
|
|
|
|
Self::Field(v.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
impl From<Number> for Part {
|
|
|
|
fn from(v: Number) -> Self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Index(v)
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Ident> for Part {
|
|
|
|
fn from(v: Ident) -> Self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Field(v)
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Graph> for Part {
|
|
|
|
fn from(v: Graph) -> Self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Self::Graph(v)
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<&str> for Part {
|
|
|
|
fn from(v: &str) -> Self {
|
2022-01-22 21:16:13 +00:00
|
|
|
match v.parse::<isize>() {
|
2022-10-04 21:51:18 +00:00
|
|
|
Ok(v) => Self::from(v),
|
|
|
|
_ => Self::from(v.to_owned()),
|
2022-01-22 21:16:13 +00:00
|
|
|
}
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-04 08:55:05 +00:00
|
|
|
impl Part {
|
2023-05-09 22:17:29 +00:00
|
|
|
/// Check if we require a writeable transaction
|
|
|
|
pub(crate) fn writeable(&self) -> bool {
|
|
|
|
match self {
|
2023-07-15 07:08:26 +00:00
|
|
|
Part::Start(v) => v.writeable(),
|
2023-05-09 22:17:29 +00:00
|
|
|
Part::Where(v) => v.writeable(),
|
|
|
|
Part::Value(v) => v.writeable(),
|
|
|
|
Part::Method(_, v) => v.iter().any(Value::writeable),
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
2022-10-19 09:55:19 +00:00
|
|
|
/// Returns a yield if an alias is specified
|
2022-06-04 08:55:05 +00:00
|
|
|
pub(crate) fn alias(&self) -> Option<&Idiom> {
|
|
|
|
match self {
|
|
|
|
Part::Graph(v) => v.alias.as_ref(),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
impl fmt::Display for Part {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
2022-10-04 21:51:18 +00:00
|
|
|
Part::All => f.write_str("[*]"),
|
|
|
|
Part::Last => f.write_str("[$]"),
|
|
|
|
Part::First => f.write_str("[0]"),
|
2023-07-15 07:08:26 +00:00
|
|
|
Part::Start(v) => write!(f, "{v}"),
|
2023-02-03 11:47:07 +00:00
|
|
|
Part::Field(v) => write!(f, ".{v}"),
|
2023-08-01 07:30:13 +00:00
|
|
|
Part::Flatten => f.write_str("…"),
|
2023-02-03 11:47:07 +00:00
|
|
|
Part::Index(v) => write!(f, "[{v}]"),
|
|
|
|
Part::Where(v) => write!(f, "[WHERE {v}]"),
|
|
|
|
Part::Graph(v) => write!(f, "{v}"),
|
2023-07-15 07:08:26 +00:00
|
|
|
Part::Value(v) => write!(f, "[{v}]"),
|
2023-03-31 18:44:16 +00:00
|
|
|
Part::Method(v, a) => write!(f, ".{v}({})", Fmt::comma_separated(a)),
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-22 19:05:58 +00:00
|
|
|
// ------------------------------
|
|
|
|
|
|
|
|
pub trait Next<'a> {
|
|
|
|
fn next(&'a self) -> &[Part];
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Next<'a> for &'a [Part] {
|
|
|
|
fn next(&'a self) -> &'a [Part] {
|
|
|
|
match self.len() {
|
|
|
|
0 => &[],
|
|
|
|
_ => &self[1..],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
pub fn part(i: &str) -> IResult<&str, Part> {
|
2023-08-29 10:50:00 +00:00
|
|
|
alt((
|
|
|
|
flatten,
|
|
|
|
preceded(tag("."), cut(dot_part)),
|
2023-09-08 11:28:36 +00:00
|
|
|
expect_delimited(openbracket, cut(bracketed_part), closebracket),
|
2023-08-29 10:50:00 +00:00
|
|
|
graph,
|
|
|
|
))(i)
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:00 +00:00
|
|
|
pub fn graph(i: &str) -> IResult<&str, Part> {
|
|
|
|
map(graph::graph, Part::Graph)(i)
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:00 +00:00
|
|
|
pub fn flatten(i: &str) -> IResult<&str, Part> {
|
|
|
|
combinator::value(Part::Flatten, alt((tag("..."), tag("…"))))(i)
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:00 +00:00
|
|
|
pub fn local_part(i: &str) -> IResult<&str, Part> {
|
|
|
|
// Cant cut dot part since it might be part of the flatten at the end.
|
2023-09-08 11:28:36 +00:00
|
|
|
alt((
|
|
|
|
preceded(tag("."), dot_part),
|
|
|
|
expect_delimited(openbracket, cut(local_bracketed_part), closebracket),
|
|
|
|
// TODO explain
|
|
|
|
))(i)
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:00 +00:00
|
|
|
pub fn basic_part(i: &str) -> IResult<&str, Part> {
|
2023-09-08 11:28:36 +00:00
|
|
|
alt((
|
|
|
|
preceded(
|
|
|
|
tag("."),
|
|
|
|
cut(|i| dot_part(i).explain("flattening is not allowed with a basic idiom", tag(".."))),
|
|
|
|
),
|
|
|
|
|s| {
|
|
|
|
let (i, _) = openbracket(s)?;
|
|
|
|
let (i, v) = expected(
|
|
|
|
"$, * or a number",
|
|
|
|
cut(terminated(basic_bracketed_part, closebracket)),
|
|
|
|
)(i)
|
|
|
|
.explain("basic idioms don't allow computed values", bracketed_value)
|
|
|
|
.explain("basic idioms don't allow where selectors", bracketed_where)?;
|
|
|
|
Ok((i, v))
|
|
|
|
},
|
|
|
|
))(i)
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:00 +00:00
|
|
|
fn dot_part(i: &str) -> IResult<&str, Part> {
|
|
|
|
alt((
|
|
|
|
combinator::value(Part::All, tag("*")),
|
|
|
|
map(terminated(ident::ident, ending), Part::Field),
|
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn basic_bracketed_part(i: &str) -> IResult<&str, Part> {
|
|
|
|
alt((
|
2023-09-08 11:28:36 +00:00
|
|
|
combinator::value(Part::All, tag("*")),
|
|
|
|
combinator::value(Part::Last, tag("$")),
|
|
|
|
map(number, Part::Index),
|
2023-08-29 10:50:00 +00:00
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn local_bracketed_part(i: &str) -> IResult<&str, Part> {
|
2023-09-08 11:28:36 +00:00
|
|
|
alt((combinator::value(Part::All, tag("*")), map(number, Part::Index)))(i)
|
|
|
|
.explain("using `[$]` in a local idiom is not allowed", tag("$"))
|
2023-08-01 07:30:13 +00:00
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:00 +00:00
|
|
|
fn bracketed_part(i: &str) -> IResult<&str, Part> {
|
|
|
|
alt((
|
2023-09-08 11:28:36 +00:00
|
|
|
combinator::value(Part::All, tag("*")),
|
|
|
|
combinator::value(Part::Last, terminated(tag("$"), peek(closebracket))),
|
|
|
|
map(number, Part::Index),
|
2023-08-29 10:50:00 +00:00
|
|
|
bracketed_where,
|
|
|
|
bracketed_value,
|
|
|
|
))(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn first(i: &str) -> IResult<&str, Part> {
|
|
|
|
let (i, _) = peek(not(number))(i)?;
|
2023-03-31 15:42:29 +00:00
|
|
|
let (i, v) = ident::ident(i)?;
|
2022-06-09 08:18:08 +00:00
|
|
|
let (i, _) = ending(i)?;
|
2022-01-13 17:36:41 +00:00
|
|
|
Ok((i, Part::Field(v)))
|
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:00 +00:00
|
|
|
pub fn bracketed_where(i: &str) -> IResult<&str, Part> {
|
|
|
|
let (i, _) = alt((
|
|
|
|
terminated(tag("?"), mightbespace),
|
|
|
|
terminated(tag_no_case("WHERE"), shouldbespace),
|
|
|
|
))(i)?;
|
|
|
|
|
2023-03-31 15:42:29 +00:00
|
|
|
let (i, v) = value::value(i)?;
|
2022-01-13 17:36:41 +00:00
|
|
|
Ok((i, Part::Where(v)))
|
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:00 +00:00
|
|
|
pub fn bracketed_value(i: &str) -> IResult<&str, Part> {
|
2023-07-15 07:08:26 +00:00
|
|
|
let (i, v) = alt((
|
|
|
|
map(strand::strand, Value::Strand),
|
|
|
|
map(param::param, Value::Param),
|
|
|
|
map(idiom::basic, Value::Idiom),
|
|
|
|
))(i)?;
|
2023-03-31 15:42:29 +00:00
|
|
|
Ok((i, Part::Value(v)))
|
2022-06-09 08:18:08 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
2023-08-29 10:50:00 +00:00
|
|
|
use param::Param;
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
use super::*;
|
|
|
|
use crate::sql::expression::Expression;
|
|
|
|
use crate::sql::test::Parse;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn part_all() {
|
|
|
|
let sql = "[*]";
|
|
|
|
let res = part(sql);
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("[*]", format!("{}", out));
|
|
|
|
assert_eq!(out, Part::All);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn part_last() {
|
|
|
|
let sql = "[$]";
|
|
|
|
let res = part(sql);
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("[$]", format!("{}", out));
|
|
|
|
assert_eq!(out, Part::Last);
|
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:00 +00:00
|
|
|
#[test]
|
|
|
|
fn part_param() {
|
|
|
|
let sql = "[$param]";
|
|
|
|
let res = part(sql);
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("[$param]", format!("{}", out));
|
|
|
|
assert_eq!(out, Part::Value(Value::Param(Param::from("param"))));
|
|
|
|
}
|
|
|
|
|
2023-08-01 07:30:13 +00:00
|
|
|
#[test]
|
|
|
|
fn part_flatten() {
|
|
|
|
let sql = "...";
|
|
|
|
let res = part(sql);
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("…", format!("{}", out));
|
|
|
|
assert_eq!(out, Part::Flatten);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn part_flatten_ellipsis() {
|
|
|
|
let sql = "…";
|
|
|
|
let res = part(sql);
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("…", format!("{}", out));
|
|
|
|
assert_eq!(out, Part::Flatten);
|
|
|
|
}
|
|
|
|
|
2022-01-13 17:36:41 +00:00
|
|
|
#[test]
|
|
|
|
fn part_number() {
|
|
|
|
let sql = "[0]";
|
|
|
|
let res = part(sql);
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("[0]", format!("{}", out));
|
2023-04-25 10:13:04 +00:00
|
|
|
assert_eq!(out, Part::Index(Number::from(0)));
|
2022-01-13 17:36:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn part_expression_question() {
|
2023-08-29 10:50:00 +00:00
|
|
|
let sql = "[?test = true]";
|
2022-01-13 17:36:41 +00:00
|
|
|
let res = part(sql);
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("[WHERE test = true]", format!("{}", out));
|
|
|
|
assert_eq!(out, Part::Where(Value::from(Expression::parse("test = true"))));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn part_expression_condition() {
|
|
|
|
let sql = "[WHERE test = true]";
|
|
|
|
let res = part(sql);
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
assert_eq!("[WHERE test = true]", format!("{}", out));
|
|
|
|
assert_eq!(out, Part::Where(Value::from(Expression::parse("test = true"))));
|
|
|
|
}
|
|
|
|
}
|