use crate::sql::{fmt::Fmt, strand::no_nul_bytes, Graph, Ident, Idiom, Number, Value}; use revision::revisioned; use serde::{Deserialize, Serialize}; use std::fmt; use std::str; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] #[revisioned(revision = 1)] pub enum Part { All, Flatten, Last, First, Field(Ident), Index(Number), Where(Value), Graph(Graph), Value(Value), Start(Value), Method(#[serde(with = "no_nul_bytes")] String, Vec), } impl From for Part { fn from(v: i32) -> Self { Self::Index(v.into()) } } impl From for Part { fn from(v: isize) -> Self { Self::Index(v.into()) } } impl From for Part { fn from(v: usize) -> Self { Self::Index(v.into()) } } impl From for Part { fn from(v: String) -> Self { Self::Field(v.into()) } } impl From for Part { fn from(v: Number) -> Self { Self::Index(v) } } impl From for Part { fn from(v: Ident) -> Self { Self::Field(v) } } impl From for Part { fn from(v: Graph) -> Self { Self::Graph(v) } } impl From<&str> for Part { fn from(v: &str) -> Self { match v.parse::() { Ok(v) => Self::from(v), _ => Self::from(v.to_owned()), } } } impl Part { /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { match self { Part::Start(v) => v.writeable(), Part::Where(v) => v.writeable(), Part::Value(v) => v.writeable(), Part::Method(_, v) => v.iter().any(Value::writeable), _ => false, } } /// Returns a yield if an alias is specified pub(crate) fn alias(&self) -> Option<&Idiom> { match self { Part::Graph(v) => v.alias.as_ref(), _ => None, } } } impl fmt::Display for Part { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Part::All => f.write_str("[*]"), Part::Last => f.write_str("[$]"), Part::First => f.write_str("[0]"), Part::Start(v) => write!(f, "{v}"), Part::Field(v) => write!(f, ".{v}"), Part::Flatten => f.write_str("…"), Part::Index(v) => write!(f, "[{v}]"), Part::Where(v) => write!(f, "[WHERE {v}]"), Part::Graph(v) => write!(f, "{v}"), Part::Value(v) => write!(f, "[{v}]"), Part::Method(v, a) => write!(f, ".{v}({})", Fmt::comma_separated(a)), } } } // ------------------------------ 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..], } } }