use std::borrow::Cow;
use std::sync::Arc;
use anyhow::Result;
use reblessive::tree::Stk;
use crate::catalog::providers::{DatabaseProvider, NamespaceProvider};
use crate::ctx::FrozenContext;
use crate::dbs::{Iterator, Options, Statement};
use crate::doc::{CursorDoc, NsDbCtx};
use crate::exec::Error as ExecError;
use crate::expr::statements::delete::DeleteStatement;
use crate::idx::planner::{QueryPlanner, RecordStrategy, StatementContext};
use crate::val::Value;
#[instrument(level = "trace", name = "DeleteStatement::compute", skip_all)]
pub(crate) async fn delete_statement_compute(
this: &DeleteStatement,
stk: &mut Stk,
ctx: &FrozenContext,
opt: &Options,
doc: Option<&CursorDoc>,
) -> Result<Value> {
opt.valid_for_db()?;
let mut iterator = Iterator::new();
let stm = Statement::from(this);
let ctx = stm.setup_timeout(stk, ctx, opt, doc).await?;
let mut planner = QueryPlanner::new();
let stm_ctx = StatementContext::new(&ctx, opt, &stm)?;
let txn = ctx.tx();
let ns = txn.expect_ns_by_name(opt.ns()?).await?;
let db = txn.expect_db_by_name(opt.ns()?, opt.db()?).await?;
let doc_ctx = NsDbCtx {
ns: Arc::clone(&ns),
db: Arc::clone(&db),
};
let prepare_ctx: Cow<'_, FrozenContext> = CursorDoc::with_parent_ctx(&ctx, doc);
for w in this.what.iter() {
iterator
.prepare(stk, prepare_ctx.as_ref(), opt, doc, &mut planner, &stm_ctx, &doc_ctx, w)
.await
.map_err(|e| match crate::err::exec_error(&e) {
Some(ExecError::InvalidStatementTarget {
value,
}) => anyhow::Error::new(ExecError::DeleteStatement {
value: value.clone(),
}),
_ => e,
})?;
}
CursorDoc::update_parent(prepare_ctx.as_ref(), None, async |ctx| {
let ctx = stm.setup_query_planner(planner, ctx);
let res = iterator.output(stk, &ctx, opt, &stm, RecordStrategy::KeysAndValues).await?;
ctx.expect_not_timedout().await?;
match res {
Value::Array(mut a) if this.only => match a.len() {
1 => Ok(a.remove(0)),
0 => Ok(Value::None),
_ => Err(anyhow::Error::new(ExecError::SingleOnlyOutput)),
},
v => Ok(v),
}
})
.await
}