use crate::{
db::{
DbSession, MutationResult, PersistedRow,
query::{
CompiledQuery, ExplainPlan, PlannedQuery, Query, QueryTracePlan,
expr::{FilterExpr, SortExpr},
predicate::Predicate,
},
session::macros::impl_session_query_shape_methods,
sql::SqlQueryRowsOutput,
},
error::Error,
traits::{EntityValue, SingletonEntity},
types::Id,
};
use icydb_core as core;
pub struct SessionDeleteQuery<'a, E: PersistedRow> {
pub(crate) inner: core::db::FluentDeleteQuery<'a, E>,
}
#[derive(Clone, Debug)]
enum DeleteReturningSelection {
All,
Fields(Vec<String>),
}
pub struct SessionDeleteReturningQuery<'a, E: PersistedRow> {
inner: core::db::FluentDeleteQuery<'a, E>,
selection: DeleteReturningSelection,
}
impl<'a, E: PersistedRow> SessionDeleteQuery<'a, E> {
#[must_use]
pub const fn query(&self) -> &Query<E> {
self.inner.query()
}
impl_session_query_shape_methods!();
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<MutationResult<E>, Error>
where
E: EntityValue,
{
Ok(MutationResult::from_count(self.inner.execute()?))
}
pub fn is_empty(&self) -> Result<bool, Error>
where
E: EntityValue,
{
Ok(self.execute()?.is_empty())
}
pub fn count(&self) -> Result<u32, Error>
where
E: EntityValue,
{
Ok(self.execute()?.count())
}
pub fn require_one(&self) -> Result<(), Error>
where
E: EntityValue,
{
Ok(self.inner.require_one()?)
}
pub fn require_some(&self) -> Result<(), Error>
where
E: EntityValue,
{
Ok(self.inner.require_some()?)
}
}
impl<E: PersistedRow + SingletonEntity> SessionDeleteQuery<'_, E> {
#[must_use]
pub fn only(mut self) -> Self
where
E::Key: Default,
{
self.inner = self.inner.only();
self
}
}
impl<E: PersistedRow> SessionDeleteReturningQuery<'_, E> {
#[must_use]
pub const fn query(&self) -> &Query<E> {
self.inner.query()
}
impl_session_query_shape_methods!();
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<SqlQueryRowsOutput, Error>
where
E: EntityValue,
{
let deleted = self.inner.execute_rows()?.entities();
match &self.selection {
DeleteReturningSelection::All => {
DbSession::<E::Canister>::sql_query_rows_output_from_entities::<E>(
E::PATH.to_string(),
deleted,
None,
)
}
DeleteReturningSelection::Fields(fields) => {
DbSession::<E::Canister>::sql_query_rows_output_from_entities::<E>(
E::PATH.to_string(),
deleted,
Some(fields.as_slice()),
)
}
}
}
pub fn is_empty(&self) -> Result<bool, Error>
where
E: EntityValue,
{
Ok(self.execute()?.row_count == 0)
}
pub fn count(&self) -> Result<u32, Error>
where
E: EntityValue,
{
Ok(self.execute()?.row_count)
}
}
impl<E: PersistedRow + SingletonEntity> SessionDeleteReturningQuery<'_, E> {
#[must_use]
pub fn only(mut self) -> Self
where
E::Key: Default,
{
self.inner = self.inner.only();
self
}
}