1use crate::ctx::Context;
2use crate::dbs::{Options, Transaction};
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::syn;
6use crate::{fmt::Fmt, Idiom, Part, Value};
7use revision::revisioned;
8use serde::{Deserialize, Serialize};
9use std::borrow::Cow;
10use std::fmt::{self, Display, Formatter, Write};
11use std::ops::Deref;
12
13#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
14#[revisioned(revision = 1)]
15pub struct Fields(pub Vec<Field>, pub bool);
16
17impl Fields {
18 pub fn all() -> Self {
19 Self(vec![Field::All], false)
20 }
21 pub fn is_all(&self) -> bool {
23 self.0.iter().any(|v| matches!(v, Field::All))
24 }
25 pub fn other(&self) -> impl Iterator<Item = &Field> {
27 self.0.iter().filter(|v| !matches!(v, Field::All))
28 }
29 pub fn single(&self) -> Option<&Field> {
31 match (self.0.len(), self.1) {
32 (1, true) => match self.0.first() {
33 Some(Field::All) => None,
34 Some(v) => Some(v),
35 _ => None,
36 },
37 _ => None,
38 }
39 }
40}
41
42impl Deref for Fields {
43 type Target = Vec<Field>;
44 fn deref(&self) -> &Self::Target {
45 &self.0
46 }
47}
48
49impl IntoIterator for Fields {
50 type Item = Field;
51 type IntoIter = std::vec::IntoIter<Self::Item>;
52 fn into_iter(self) -> Self::IntoIter {
53 self.0.into_iter()
54 }
55}
56
57impl Display for Fields {
58 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
59 match self.single() {
60 Some(v) => write!(f, "VALUE {}", &v),
61 None => Display::fmt(&Fmt::comma_separated(&self.0), f),
62 }
63 }
64}
65
66impl Fields {
67 pub(crate) async fn compute(
69 &self,
70 ctx: &Context<'_>,
71 opt: &Options,
72 txn: &Transaction,
73 doc: Option<&CursorDoc<'_>>,
74 group: bool,
75 ) -> Result<Value, Error> {
76 if let Some(doc) = doc {
77 self.compute_value(ctx, opt, txn, doc, group).await
78 } else {
79 let doc = (&Value::None).into();
80 self.compute_value(ctx, opt, txn, &doc, group).await
81 }
82 }
83
84 async fn compute_value(
85 &self,
86 ctx: &Context<'_>,
87 opt: &Options,
88 txn: &Transaction,
89 doc: &CursorDoc<'_>,
90 group: bool,
91 ) -> Result<Value, Error> {
92 let opt = &opt.new_with_futures(true);
94 let mut out = match self.is_all() {
96 true => doc.doc.compute(ctx, opt, txn, Some(doc)).await?,
97 false => Value::base(),
98 };
99 for v in self.other() {
100 match v {
101 Field::All => (),
102 Field::Single {
103 expr,
104 alias,
105 } => {
106 let name = alias
107 .as_ref()
108 .map(Cow::Borrowed)
109 .unwrap_or_else(|| Cow::Owned(expr.to_idiom()));
110 match expr {
111 Value::Function(f) if group && f.is_aggregate() => {
113 let x = match f.args().len() {
114 0 => f.compute(ctx, opt, txn, Some(doc)).await?,
116 _ => f.args()[0].compute(ctx, opt, txn, Some(doc)).await?,
118 };
119 match self.single().is_some() {
121 false => out.set(ctx, opt, txn, name.as_ref(), x).await?,
122 true => out = x,
123 }
124 }
125 Value::Idiom(v) if v.is_multi_yield() => {
127 let mut res: Vec<(&[Part], Value)> = Vec::new();
129 for v in v.split_inclusive(Idiom::split_multi_yield) {
131 let x = match res.last() {
133 Some((_, r)) => r,
134 None => doc.doc.as_ref(),
135 };
136 let x = x
138 .get(ctx, opt, txn, Some(doc), v)
139 .await?
140 .compute(ctx, opt, txn, Some(doc))
141 .await?
142 .flatten();
143 res.push((v, x));
145 }
146 for (p, x) in res {
148 match p.last().unwrap().alias() {
149 Some(a) => {
151 if let Some(i) = alias {
152 out.set(ctx, opt, txn, i, x.clone()).await?;
153 }
154 out.set(ctx, opt, txn, a, x).await?;
155 }
156 None => {
158 out.set(ctx, opt, txn, alias.as_ref().unwrap_or(v), x)
159 .await?
160 }
161 }
162 }
163 }
164 Value::Function(f) if f.name() == Some("type::fields") => {
166 let expr = expr.compute(ctx, opt, txn, Some(doc)).await?;
168 match self.single().is_some() {
170 false => {
171 let args = match f.args().first().unwrap() {
173 Value::Param(v) => {
174 v.compute(ctx, opt, txn, Some(doc)).await?
175 }
176 v => v.to_owned(),
177 };
178 let expr: Vec<Value> = expr.try_into()?;
180 let args: Vec<Value> = args.try_into()?;
182 for (name, expr) in args.into_iter().zip(expr) {
184 let name = syn::idiom(&name.to_raw_string())?;
186 out.set(ctx, opt, txn, name.as_ref(), expr).await?
188 }
189 }
190 true => out = expr,
191 }
192 }
193 Value::Function(f) if f.name() == Some("type::field") => {
195 let expr = expr.compute(ctx, opt, txn, Some(doc)).await?;
197 match self.single().is_some() {
199 false => {
200 let name = match f.args().first().unwrap() {
202 Value::Param(v) => {
203 v.compute(ctx, opt, txn, Some(doc)).await?
204 }
205 v => v.to_owned(),
206 };
207 let name = if let Some(x) = alias.as_ref().map(Cow::Borrowed) {
210 x
211 } else {
212 Cow::Owned(syn::idiom(&name.to_raw_string())?)
213 };
214 out.set(ctx, opt, txn, name.as_ref(), expr).await?
216 }
217 true => out = expr,
218 }
219 }
220 _ => {
222 let expr = expr.compute(ctx, opt, txn, Some(doc)).await?;
223 match self.single().is_some() {
225 false => out.set(ctx, opt, txn, name.as_ref(), expr).await?,
226 true => out = expr,
227 }
228 }
229 }
230 }
231 }
232 }
233 Ok(out)
234 }
235}
236
237#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
238#[revisioned(revision = 1)]
239pub enum Field {
240 #[default]
242 All,
243 Single {
245 expr: Value,
246 alias: Option<Idiom>,
248 },
249}
250
251impl Display for Field {
252 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
253 match self {
254 Self::All => f.write_char('*'),
255 Self::Single {
256 expr,
257 alias,
258 } => {
259 Display::fmt(expr, f)?;
260 if let Some(alias) = alias {
261 f.write_str(" AS ")?;
262 Display::fmt(alias, f)
263 } else {
264 Ok(())
265 }
266 }
267 }
268 }
269}