1use crate::sql::{fmt::Fmt, strand::no_nul_bytes, Graph, Ident, Idiom, Number, Value};
2use revision::revisioned;
3use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::fmt::Write;
6use std::str;
7
8use super::fmt::{is_pretty, pretty_indent};
9
10#[revisioned(revision = 2)]
11#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
12#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
13#[non_exhaustive]
14pub enum Part {
15 All,
16 Flatten,
17 Last,
18 First,
19 Field(Ident),
20 Index(Number),
21 Where(Value),
22 Graph(Graph),
23 Value(Value),
24 Start(Value),
25 Method(#[serde(with = "no_nul_bytes")] String, Vec<Value>),
26 #[revision(start = 2)]
27 Destructure(Vec<DestructurePart>),
28 Optional,
29}
30
31impl From<i32> for Part {
32 fn from(v: i32) -> Self {
33 Self::Index(v.into())
34 }
35}
36
37impl From<isize> for Part {
38 fn from(v: isize) -> Self {
39 Self::Index(v.into())
40 }
41}
42
43impl From<usize> for Part {
44 fn from(v: usize) -> Self {
45 Self::Index(v.into())
46 }
47}
48
49impl From<String> for Part {
50 fn from(v: String) -> Self {
51 Self::Field(v.into())
52 }
53}
54
55impl From<Number> for Part {
56 fn from(v: Number) -> Self {
57 Self::Index(v)
58 }
59}
60
61impl From<Ident> for Part {
62 fn from(v: Ident) -> Self {
63 Self::Field(v)
64 }
65}
66
67impl From<Graph> for Part {
68 fn from(v: Graph) -> Self {
69 Self::Graph(v)
70 }
71}
72
73impl From<&str> for Part {
74 fn from(v: &str) -> Self {
75 match v.parse::<isize>() {
76 Ok(v) => Self::from(v),
77 _ => Self::from(v.to_owned()),
78 }
79 }
80}
81
82impl Part {
83 pub(crate) fn writeable(&self) -> bool {
85 match self {
86 Part::Start(v) => v.writeable(),
87 Part::Where(v) => v.writeable(),
88 Part::Value(v) => v.writeable(),
89 Part::Method(_, v) => v.iter().any(Value::writeable),
90 _ => false,
91 }
92 }
93 pub(crate) fn alias(&self) -> Option<&Idiom> {
95 match self {
96 Part::Graph(v) => v.alias.as_ref(),
97 _ => None,
98 }
99 }
100}
101
102impl fmt::Display for Part {
103 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104 match self {
105 Part::All => f.write_str("[*]"),
106 Part::Last => f.write_str("[$]"),
107 Part::First => f.write_str("[0]"),
108 Part::Start(v) => write!(f, "{v}"),
109 Part::Field(v) => write!(f, ".{v}"),
110 Part::Flatten => f.write_str("…"),
111 Part::Index(v) => write!(f, "[{v}]"),
112 Part::Where(v) => write!(f, "[WHERE {v}]"),
113 Part::Graph(v) => write!(f, "{v}"),
114 Part::Value(v) => write!(f, "[{v}]"),
115 Part::Method(v, a) => write!(f, ".{v}({})", Fmt::comma_separated(a)),
116 Part::Destructure(v) => {
117 f.write_str(".{")?;
118 if !is_pretty() {
119 f.write_char(' ')?;
120 }
121 if !v.is_empty() {
122 let indent = pretty_indent();
123 write!(f, "{}", Fmt::pretty_comma_separated(v))?;
124 drop(indent);
125 }
126 if is_pretty() {
127 f.write_char('}')
128 } else {
129 f.write_str(" }")
130 }
131 }
132 Part::Optional => write!(f, "?"),
133 }
134 }
135}
136
137pub trait Next<'a> {
140 fn next(&'a self) -> &[Part];
141}
142
143impl<'a> Next<'a> for &'a [Part] {
144 fn next(&'a self) -> &'a [Part] {
145 match self.len() {
146 0 => &[],
147 _ => &self[1..],
148 }
149 }
150}
151
152pub trait NextMethod<'a> {
155 fn next_method(&'a self) -> &[Part];
156}
157
158impl<'a> NextMethod<'a> for &'a [Part] {
159 fn next_method(&'a self) -> &'a [Part] {
160 match self.iter().position(|p| matches!(p, Part::Method(_, _))) {
161 None => &[],
162 Some(i) => &self[i..],
163 }
164 }
165}
166
167impl<'a> NextMethod<'a> for &'a Idiom {
168 fn next_method(&'a self) -> &'a [Part] {
169 match self.iter().position(|p| matches!(p, Part::Method(_, _))) {
170 None => &[],
171 Some(i) => &self[i..],
172 }
173 }
174}
175
176#[revisioned(revision = 1)]
179#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
180#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
181#[non_exhaustive]
182pub enum DestructurePart {
183 All(Ident),
184 Field(Ident),
185 Aliased(Ident, Idiom),
186 Destructure(Ident, Vec<DestructurePart>),
187}
188
189impl DestructurePart {
190 pub fn field(&self) -> &Ident {
191 match self {
192 DestructurePart::All(v) => v,
193 DestructurePart::Field(v) => v,
194 DestructurePart::Aliased(v, _) => v,
195 DestructurePart::Destructure(v, _) => v,
196 }
197 }
198
199 pub fn path(&self) -> Vec<Part> {
200 match self {
201 DestructurePart::All(v) => vec![Part::Field(v.clone()), Part::All],
202 DestructurePart::Field(v) => vec![Part::Field(v.clone())],
203 DestructurePart::Aliased(_, v) => v.0.clone(),
204 DestructurePart::Destructure(f, d) => {
205 vec![Part::Field(f.clone()), Part::Destructure(d.clone())]
206 }
207 }
208 }
209}
210
211impl fmt::Display for DestructurePart {
212 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
213 match self {
214 DestructurePart::All(fd) => write!(f, "{fd}.*"),
215 DestructurePart::Field(fd) => write!(f, "{fd}"),
216 DestructurePart::Aliased(fd, v) => write!(f, "{fd}: {v}"),
217 DestructurePart::Destructure(fd, d) => {
218 write!(f, "{fd}{}", Part::Destructure(d.clone()))
219 }
220 }
221 }
222}