1use std::sync::Arc;
2
3use reblessive::tree::Stk;
4
5use super::IgnoreError;
6use crate::ctx::{Context, MutableContext};
7use crate::dbs::{Options, Statement};
8use crate::doc::Document;
9use crate::doc::Permitted::*;
10use crate::doc::compute::DocKind;
11use crate::expr::output::Output;
12use crate::expr::permission::Permission;
13use crate::expr::{FlowResultExt as _, Operation};
14use crate::iam::Action;
15use crate::val::Value;
16
17impl Document {
18 pub(super) async fn pluck(
23 &mut self,
24 stk: &mut Stk,
25 ctx: &Context,
26 opt: &Options,
27 stm: &Statement<'_>,
28 ) -> Result<Value, IgnoreError> {
29 self.check_permissions_view(stk, ctx, opt, stm).await?;
31 let mut out = match stm.output() {
33 Some(v) => match v {
34 Output::None => Err(IgnoreError::Ignore),
35 Output::Null => Ok(Value::Null),
36 Output::Diff => {
37 let (initial, current) = if self.reduced(stk, ctx, opt, Both).await? {
39 self.computed_fields(stk, ctx, opt, DocKind::InitialReduced).await?;
41 self.computed_fields(stk, ctx, opt, DocKind::CurrentReduced).await?;
42 (&mut self.initial_reduced, &mut self.current_reduced)
43 } else {
44 self.computed_fields(stk, ctx, opt, DocKind::Initial).await?;
46 self.computed_fields(stk, ctx, opt, DocKind::Current).await?;
47 (&mut self.initial, &mut self.current)
48 };
49 let ops = initial.doc.as_ref().diff(current.doc.as_ref());
51 Ok(Operation::operations_to_value(ops))
52 }
53 Output::After => {
54 if self.reduced(stk, ctx, opt, Current).await? {
56 self.computed_fields(stk, ctx, opt, DocKind::CurrentReduced).await?;
57 Ok(self.current_reduced.doc.as_ref().to_owned())
58 } else {
59 self.computed_fields(stk, ctx, opt, DocKind::Current).await?;
60 Ok(self.current.doc.as_ref().to_owned())
61 }
62 }
63 Output::Before => {
64 if self.reduced(stk, ctx, opt, Initial).await? {
66 self.computed_fields(stk, ctx, opt, DocKind::InitialReduced).await?;
67 Ok(self.initial_reduced.doc.as_ref().to_owned())
68 } else {
69 self.computed_fields(stk, ctx, opt, DocKind::Initial).await?;
70 Ok(self.initial.doc.as_ref().to_owned())
71 }
72 }
73 Output::Fields(v) => {
74 let (initial, current) = if self.reduced(stk, ctx, opt, Both).await? {
76 self.computed_fields(stk, ctx, opt, DocKind::InitialReduced).await?;
77 self.computed_fields(stk, ctx, opt, DocKind::CurrentReduced).await?;
78 (&mut self.initial_reduced, &mut self.current_reduced)
79 } else {
80 self.computed_fields(stk, ctx, opt, DocKind::Initial).await?;
81 self.computed_fields(stk, ctx, opt, DocKind::Current).await?;
82 (&mut self.initial, &mut self.current)
83 };
84 let mut ctx = MutableContext::new(ctx);
86 ctx.add_value("after", current.doc.as_arc());
87 ctx.add_value("before", initial.doc.as_arc());
88 let ctx = ctx.freeze();
89 v.compute(stk, &ctx, opt, Some(current), false).await.map_err(IgnoreError::from)
91 }
92 },
93 None => match stm {
94 Statement::Live(_) => Err(IgnoreError::Error(anyhow::anyhow!(
95 ".lives() uses .lq_pluck(), not .pluck()"
96 ))),
97 Statement::Select(s) => {
98 let current = if self.reduced(stk, ctx, opt, Current).await? {
100 self.computed_fields(stk, ctx, opt, DocKind::CurrentReduced).await?;
101 &self.current_reduced
102 } else {
103 self.computed_fields(stk, ctx, opt, DocKind::Current).await?;
104 &self.current
105 };
106 s.expr
108 .compute(stk, ctx, opt, Some(current), s.group.is_some())
109 .await
110 .map_err(IgnoreError::from)
111 }
112 Statement::Create(_)
113 | Statement::Upsert(_)
114 | Statement::Update(_)
115 | Statement::Relate(_)
116 | Statement::Insert(_) => {
117 if self.reduced(stk, ctx, opt, Current).await? {
119 self.computed_fields(stk, ctx, opt, DocKind::CurrentReduced).await?;
120 Ok(self.current_reduced.doc.as_ref().to_owned())
121 } else {
122 self.computed_fields(stk, ctx, opt, DocKind::Current).await?;
123 Ok(self.current.doc.as_ref().to_owned())
124 }
125 }
126 _ => Err(IgnoreError::Ignore),
127 },
128 }?;
129 if self.id.is_some() {
131 if opt.check_perms(Action::View)? {
133 for fd in self.fd(ctx, opt).await?.iter() {
135 for k in out.each(&fd.name).iter() {
137 match &fd.permissions.select {
139 Permission::Full => (),
140 Permission::None => out.del(stk, ctx, opt, k).await?,
141 Permission::Specific(e) => {
142 let opt = &opt.new_with_perms(false);
144 let val = Arc::new(self.current.doc.as_ref().pick(k));
146 let mut ctx = MutableContext::new(ctx);
148 ctx.add_value("value", val);
149 let ctx = ctx.freeze();
150 if !stk
152 .run(|stk| e.compute(stk, &ctx, opt, Some(&self.current)))
153 .await
154 .catch_return()?
155 .is_truthy()
156 {
157 out.cut(k);
158 }
159 }
160 }
161 }
162 }
163 }
164 }
165 if let Some(v) = stm.omit() {
167 for v in v.iter() {
168 out.del(stk, ctx, opt, v).await?;
169 }
170 }
171 Ok(out)
173 }
174}