use crate::{
db::{
DbSession,
query::{CompiledQuery, ExplainPlan, FilterExpr, PlannedQuery, QueryTracePlan},
response::RowProjectionOutput,
session::macros::impl_session_query_shape_methods,
},
error::Error,
traits::{Entity, SingletonEntity},
types::Id,
};
use icydb_core as core;
pub struct SessionDeleteQuery<'a, E: Entity> {
pub(crate) inner: core::db::FluentDeleteQuery<'a, E>,
}
#[derive(Clone, Debug)]
enum DeleteReturningSelection {
All,
Fields(Vec<String>),
}
impl DeleteReturningSelection {
const fn selected_fields(&self) -> Option<&[String]> {
match self {
Self::All => None,
Self::Fields(fields) => Some(fields.as_slice()),
}
}
}
pub struct SessionDeleteReturningQuery<'a, E: Entity> {
inner: core::db::FluentDeleteQuery<'a, E>,
selection: DeleteReturningSelection,
}
impl<'a, E: Entity> SessionDeleteQuery<'a, E> {
impl_session_query_shape_methods!();
#[must_use]
pub fn max_affected(mut self, limit: u32) -> Self {
self.inner = self.inner.max_affected(limit);
self
}
pub fn plan_hash_hex(&self) -> Result<String, Error> {
Ok(self.inner.plan_hash_hex()?)
}
pub fn trace(&self) -> Result<QueryTracePlan, Error> {
Ok(self.inner.trace()?)
}
pub fn explain(&self) -> Result<ExplainPlan, Error> {
Ok(self.inner.explain()?)
}
pub fn planned(&self) -> Result<PlannedQuery<E>, Error> {
Ok(self.inner.planned()?)
}
pub fn plan(&self) -> Result<CompiledQuery<E>, Error> {
Ok(self.inner.plan()?)
}
#[must_use]
pub fn returning_all(self) -> SessionDeleteReturningQuery<'a, E> {
SessionDeleteReturningQuery {
inner: self.inner,
selection: DeleteReturningSelection::All,
}
}
#[must_use]
pub fn returning<I, S>(self, fields: I) -> SessionDeleteReturningQuery<'a, E>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
SessionDeleteReturningQuery {
inner: self.inner,
selection: DeleteReturningSelection::Fields(
fields
.into_iter()
.map(|field| field.as_ref().to_string())
.collect(),
),
}
}
pub fn execute(&self) -> Result<u32, Error>
where
E: Entity,
{
Ok(self.inner.execute()?)
}
pub fn is_empty(&self) -> Result<bool, Error>
where
E: Entity,
{
Ok(self.execute()? == 0)
}
pub fn count(&self) -> Result<u32, Error>
where
E: Entity,
{
self.execute()
}
pub fn require_one(&self) -> Result<(), Error>
where
E: Entity,
{
Ok(self.inner.require_one()?)
}
pub fn require_some(&self) -> Result<(), Error>
where
E: Entity,
{
Ok(self.inner.require_some()?)
}
}
impl<E: Entity + SingletonEntity> SessionDeleteQuery<'_, E> {
#[must_use]
pub fn singleton(mut self) -> Self
where
E::Key: Default,
{
self.inner = self.inner.singleton();
self
}
}
impl<E: Entity> SessionDeleteReturningQuery<'_, E> {
impl_session_query_shape_methods!();
#[must_use]
pub fn max_affected(mut self, limit: u32) -> Self {
self.inner = self.inner.max_affected(limit);
self
}
pub fn plan_hash_hex(&self) -> Result<String, Error> {
Ok(self.inner.plan_hash_hex()?)
}
pub fn trace(&self) -> Result<QueryTracePlan, Error> {
Ok(self.inner.trace()?)
}
pub fn explain(&self) -> Result<ExplainPlan, Error> {
Ok(self.inner.explain()?)
}
pub fn planned(&self) -> Result<PlannedQuery<E>, Error> {
Ok(self.inner.planned()?)
}
pub fn plan(&self) -> Result<CompiledQuery<E>, Error> {
Ok(self.inner.plan()?)
}
pub fn execute(&self) -> Result<RowProjectionOutput, Error>
where
E: Entity,
{
let deleted = self.inner.execute_rows()?.entities();
DbSession::<E::Canister>::row_projection_output_from_entities::<E>(
E::PATH.to_string(),
deleted,
self.selection.selected_fields(),
|entity, slots| {
self.inner
.project_entity_output_values(entity, slots)
.map_err(Error::from)
},
)
}
pub fn is_empty(&self) -> Result<bool, Error>
where
E: Entity,
{
Ok(self.execute()?.row_count == 0)
}
pub fn count(&self) -> Result<u32, Error>
where
E: Entity,
{
Ok(self.execute()?.row_count)
}
}
impl<E: Entity + SingletonEntity> SessionDeleteReturningQuery<'_, E> {
#[must_use]
pub fn singleton(mut self) -> Self
where
E::Key: Default,
{
self.inner = self.inner.singleton();
self
}
}