use crate::{
db::{
DbSession, PersistedRow, Query,
query::{
api::ResponseCardinalityExt,
builder::{
AvgBySlotTerminal, AvgDistinctBySlotTerminal, CountDistinctBySlotTerminal,
CountRowsTerminal, DistinctValuesBySlotTerminal, ExistsRowsTerminal,
FirstIdTerminal, FirstValueBySlotTerminal, LastIdTerminal, LastValueBySlotTerminal,
MaxIdBySlotTerminal, MaxIdTerminal, MedianIdBySlotTerminal, MinIdBySlotTerminal,
MinIdTerminal, MinMaxIdBySlotTerminal, NthIdBySlotTerminal, SumBySlotTerminal,
SumDistinctBySlotTerminal, ValueProjectionExpr, ValuesBySlotTerminal,
ValuesBySlotWithIdsTerminal,
},
explain::{ExplainAggregateTerminalPlan, ExplainExecutionNodeDescriptor},
fluent::load::{FluentLoadQuery, LoadQueryResult},
intent::QueryError,
},
response::EntityResponse,
},
traits::EntityValue,
types::{Decimal, Id},
value::{OutputValue, Value},
};
type MinMaxByIds<E> = Option<(Id<E>, Id<E>)>;
trait TerminalStrategyDriver<E: PersistedRow + EntityValue> {
type Output;
type ExplainOutput;
fn execute(
self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::Output, QueryError>;
fn explain(
&self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::ExplainOutput, QueryError>;
}
macro_rules! impl_aggregate_terminal_driver {
($terminal:ty, $output:ty, $execute:ident) => {
impl<E> TerminalStrategyDriver<E> for $terminal
where
E: PersistedRow + EntityValue,
{
type Output = $output;
type ExplainOutput = ExplainAggregateTerminalPlan;
fn execute(
self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::Output, QueryError> {
session.$execute(query, self)
}
fn explain(
&self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::ExplainOutput, QueryError> {
session.explain_query_prepared_aggregate_terminal_with_visible_indexes(query, self)
}
}
};
}
macro_rules! impl_projection_terminal_driver {
($terminal:ty, $output:ty, $execute:ident) => {
impl<E> TerminalStrategyDriver<E> for $terminal
where
E: PersistedRow + EntityValue,
{
type Output = $output;
type ExplainOutput = ExplainExecutionNodeDescriptor;
fn execute(
self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::Output, QueryError> {
session.$execute(query, self)
}
fn explain(
&self,
session: &DbSession<E::Canister>,
query: &Query<E>,
) -> Result<Self::ExplainOutput, QueryError> {
session.explain_query_prepared_projection_terminal_with_visible_indexes(query, self)
}
}
};
}
impl_aggregate_terminal_driver!(CountRowsTerminal, u32, execute_fluent_count_rows_terminal);
impl_aggregate_terminal_driver!(
ExistsRowsTerminal,
bool,
execute_fluent_exists_rows_terminal
);
impl_aggregate_terminal_driver!(MinIdTerminal, Option<Id<E>>, execute_fluent_min_id_terminal);
impl_aggregate_terminal_driver!(MaxIdTerminal, Option<Id<E>>, execute_fluent_max_id_terminal);
impl_aggregate_terminal_driver!(
MinIdBySlotTerminal,
Option<Id<E>>,
execute_fluent_min_id_by_slot
);
impl_aggregate_terminal_driver!(
MaxIdBySlotTerminal,
Option<Id<E>>,
execute_fluent_max_id_by_slot
);
impl_aggregate_terminal_driver!(
SumBySlotTerminal,
Option<Decimal>,
execute_fluent_sum_by_slot
);
impl_aggregate_terminal_driver!(
SumDistinctBySlotTerminal,
Option<Decimal>,
execute_fluent_sum_distinct_by_slot
);
impl_aggregate_terminal_driver!(
AvgBySlotTerminal,
Option<Decimal>,
execute_fluent_avg_by_slot
);
impl_aggregate_terminal_driver!(
AvgDistinctBySlotTerminal,
Option<Decimal>,
execute_fluent_avg_distinct_by_slot
);
impl_aggregate_terminal_driver!(
FirstIdTerminal,
Option<Id<E>>,
execute_fluent_first_id_terminal
);
impl_aggregate_terminal_driver!(
LastIdTerminal,
Option<Id<E>>,
execute_fluent_last_id_terminal
);
impl_aggregate_terminal_driver!(
NthIdBySlotTerminal,
Option<Id<E>>,
execute_fluent_nth_id_by_slot
);
impl_aggregate_terminal_driver!(
MedianIdBySlotTerminal,
Option<Id<E>>,
execute_fluent_median_id_by_slot
);
impl_aggregate_terminal_driver!(
MinMaxIdBySlotTerminal,
MinMaxByIds<E>,
execute_fluent_min_max_id_by_slot
);
impl_projection_terminal_driver!(
ValuesBySlotTerminal,
Vec<Value>,
execute_fluent_values_by_slot
);
impl_projection_terminal_driver!(
DistinctValuesBySlotTerminal,
Vec<Value>,
execute_fluent_distinct_values_by_slot
);
impl_projection_terminal_driver!(
CountDistinctBySlotTerminal,
u32,
execute_fluent_count_distinct_by_slot
);
impl_projection_terminal_driver!(
ValuesBySlotWithIdsTerminal,
Vec<(Id<E>, Value)>,
execute_fluent_values_by_with_ids_slot
);
impl_projection_terminal_driver!(
FirstValueBySlotTerminal,
Option<Value>,
execute_fluent_first_value_by_slot
);
impl_projection_terminal_driver!(
LastValueBySlotTerminal,
Option<Value>,
execute_fluent_last_value_by_slot
);
fn output(value: Value) -> OutputValue {
OutputValue::from(value)
}
fn output_values(values: Vec<Value>) -> Vec<OutputValue> {
values.into_iter().map(output).collect()
}
fn output_values_with_ids<E: PersistedRow>(
values: Vec<(Id<E>, Value)>,
) -> Vec<(Id<E>, OutputValue)> {
values
.into_iter()
.map(|(id, value)| (id, output(value)))
.collect()
}
impl<E> FluentLoadQuery<'_, E>
where
E: PersistedRow,
{
pub fn execute(&self) -> Result<LoadQueryResult<E>, QueryError>
where
E: EntityValue,
{
self.with_non_paged(DbSession::execute_query_result)
}
fn with_non_paged<T>(
&self,
map: impl FnOnce(&DbSession<E::Canister>, &Query<E>) -> Result<T, QueryError>,
) -> Result<T, QueryError>
where
E: EntityValue,
{
self.ensure_non_paged_mode_ready()?;
map(self.session, self.query())
}
fn explain_execution_descriptor(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.with_non_paged(DbSession::explain_query_execution_with_visible_indexes)
}
fn render_execution_descriptor(
&self,
render: impl FnOnce(ExplainExecutionNodeDescriptor) -> String,
) -> Result<String, QueryError>
where
E: EntityValue,
{
let descriptor = self.explain_execution_descriptor()?;
Ok(render(descriptor))
}
fn execute_terminal<S>(&self, strategy: S) -> Result<S::Output, QueryError>
where
E: EntityValue,
S: TerminalStrategyDriver<E>,
{
self.with_non_paged(|session, query| strategy.execute(session, query))
}
fn explain_terminal<S>(&self, strategy: &S) -> Result<S::ExplainOutput, QueryError>
where
E: EntityValue,
S: TerminalStrategyDriver<E>,
{
self.with_non_paged(|session, query| strategy.explain(session, query))
}
fn project_terminal_items<P, T, U>(
projection: &P,
values: impl IntoIterator<Item = T>,
mut map: impl FnMut(&P, T) -> Result<U, QueryError>,
) -> Result<Vec<U>, QueryError>
where
P: ValueProjectionExpr,
{
values
.into_iter()
.map(|value| map(projection, value))
.collect()
}
pub fn is_empty(&self) -> Result<bool, QueryError>
where
E: EntityValue,
{
self.not_exists()
}
pub fn not_exists(&self) -> Result<bool, QueryError>
where
E: EntityValue,
{
Ok(!self.exists()?)
}
pub fn exists(&self) -> Result<bool, QueryError>
where
E: EntityValue,
{
self.execute_terminal(ExistsRowsTerminal::new())
}
pub fn explain_exists(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_terminal(&ExistsRowsTerminal::new())
}
pub fn explain_not_exists(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_exists()
}
pub fn explain_execution(&self) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
self.explain_execution_descriptor()
}
pub fn explain_execution_text(&self) -> Result<String, QueryError>
where
E: EntityValue,
{
self.render_execution_descriptor(|descriptor| descriptor.render_text_tree())
}
pub fn explain_execution_json(&self) -> Result<String, QueryError>
where
E: EntityValue,
{
self.render_execution_descriptor(|descriptor| descriptor.render_json_canonical())
}
pub fn explain_execution_verbose(&self) -> Result<String, QueryError>
where
E: EntityValue,
{
self.with_non_paged(DbSession::explain_query_execution_verbose_with_visible_indexes)
}
pub fn count(&self) -> Result<u32, QueryError>
where
E: EntityValue,
{
self.execute_terminal(CountRowsTerminal::new())
}
pub fn bytes(&self) -> Result<u64, QueryError>
where
E: EntityValue,
{
self.with_non_paged(DbSession::execute_fluent_bytes)
}
pub fn bytes_by(&self, field: impl AsRef<str>) -> Result<u64, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.with_non_paged(|session, query| {
session.execute_fluent_bytes_by_slot(query, target_slot)
})
}
pub fn explain_bytes_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.with_non_paged(|session, query| {
session.explain_query_bytes_by_with_visible_indexes(query, target_slot.field())
})
}
pub fn min(&self) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.execute_terminal(MinIdTerminal::new())
}
pub fn explain_min(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_terminal(&MinIdTerminal::new())
}
pub fn min_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(MinIdBySlotTerminal::new(target_slot))
}
pub fn max(&self) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.execute_terminal(MaxIdTerminal::new())
}
pub fn explain_max(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_terminal(&MaxIdTerminal::new())
}
pub fn max_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(MaxIdBySlotTerminal::new(target_slot))
}
pub fn nth_by(&self, field: impl AsRef<str>, nth: usize) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(NthIdBySlotTerminal::new(target_slot, nth))
}
pub fn sum_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(SumBySlotTerminal::new(target_slot))
}
pub fn explain_sum_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.explain_terminal(&SumBySlotTerminal::new(target_slot))
}
pub fn sum_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(SumDistinctBySlotTerminal::new(target_slot))
}
pub fn explain_sum_distinct_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.explain_terminal(&SumDistinctBySlotTerminal::new(target_slot))
}
pub fn avg_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(AvgBySlotTerminal::new(target_slot))
}
pub fn explain_avg_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.explain_terminal(&AvgBySlotTerminal::new(target_slot))
}
pub fn avg_distinct_by(&self, field: impl AsRef<str>) -> Result<Option<Decimal>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(AvgDistinctBySlotTerminal::new(target_slot))
}
pub fn explain_avg_distinct_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.explain_terminal(&AvgDistinctBySlotTerminal::new(target_slot))
}
pub fn median_by(&self, field: impl AsRef<str>) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(MedianIdBySlotTerminal::new(target_slot))
}
pub fn count_distinct_by(&self, field: impl AsRef<str>) -> Result<u32, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(CountDistinctBySlotTerminal::new(target_slot))
}
pub fn explain_count_distinct_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.explain_terminal(&CountDistinctBySlotTerminal::new(target_slot))
}
pub fn min_max_by(&self, field: impl AsRef<str>) -> Result<MinMaxByIds<E>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(MinMaxIdBySlotTerminal::new(target_slot))
}
pub fn values_by(&self, field: impl AsRef<str>) -> Result<Vec<OutputValue>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(ValuesBySlotTerminal::new(target_slot))
.map(output_values)
}
pub fn project_values<P>(&self, projection: &P) -> Result<Vec<OutputValue>, QueryError>
where
E: EntityValue,
P: ValueProjectionExpr,
{
let target_slot = self.resolve_non_paged_slot(projection.field())?;
let values = self.execute_terminal(ValuesBySlotTerminal::new(target_slot))?;
Self::project_terminal_items(projection, values, |projection, value| {
projection.apply_value(value)
})
.map(output_values)
}
pub fn explain_project_values<P>(
&self,
projection: &P,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
P: ValueProjectionExpr,
{
let target_slot = self.resolve_non_paged_slot(projection.field())?;
self.explain_terminal(&ValuesBySlotTerminal::new(target_slot))
}
pub fn explain_values_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.explain_terminal(&ValuesBySlotTerminal::new(target_slot))
}
pub fn take(&self, take_count: u32) -> Result<EntityResponse<E>, QueryError>
where
E: EntityValue,
{
self.with_non_paged(|session, query| session.execute_fluent_take(query, take_count))
}
pub fn top_k_by(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<EntityResponse<E>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.with_non_paged(|session, query| {
session.execute_fluent_top_k_rows_by_slot(query, target_slot, take_count)
})
}
pub fn bottom_k_by(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<EntityResponse<E>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.with_non_paged(|session, query| {
session.execute_fluent_bottom_k_rows_by_slot(query, target_slot, take_count)
})
}
pub fn top_k_by_values(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<OutputValue>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.with_non_paged(|session, query| {
session
.execute_fluent_top_k_values_by_slot(query, target_slot, take_count)
.map(output_values)
})
}
pub fn bottom_k_by_values(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<OutputValue>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.with_non_paged(|session, query| {
session
.execute_fluent_bottom_k_values_by_slot(query, target_slot, take_count)
.map(output_values)
})
}
pub fn top_k_by_with_ids(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.with_non_paged(|session, query| {
session
.execute_fluent_top_k_values_with_ids_by_slot(query, target_slot, take_count)
.map(output_values_with_ids)
})
}
pub fn bottom_k_by_with_ids(
&self,
field: impl AsRef<str>,
take_count: u32,
) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.with_non_paged(|session, query| {
session
.execute_fluent_bottom_k_values_with_ids_by_slot(query, target_slot, take_count)
.map(output_values_with_ids)
})
}
pub fn distinct_values_by(&self, field: impl AsRef<str>) -> Result<Vec<OutputValue>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(DistinctValuesBySlotTerminal::new(target_slot))
.map(output_values)
}
pub fn explain_distinct_values_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.explain_terminal(&DistinctValuesBySlotTerminal::new(target_slot))
}
pub fn values_by_with_ids(
&self,
field: impl AsRef<str>,
) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(ValuesBySlotWithIdsTerminal::new(target_slot))
.map(output_values_with_ids)
}
pub fn project_values_with_ids<P>(
&self,
projection: &P,
) -> Result<Vec<(Id<E>, OutputValue)>, QueryError>
where
E: EntityValue,
P: ValueProjectionExpr,
{
let target_slot = self.resolve_non_paged_slot(projection.field())?;
let values = self.execute_terminal(ValuesBySlotWithIdsTerminal::new(target_slot))?;
Self::project_terminal_items(projection, values, |projection, (id, value)| {
Ok((id, projection.apply_value(value)?))
})
.map(output_values_with_ids)
}
pub fn explain_values_by_with_ids(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.explain_terminal(&ValuesBySlotWithIdsTerminal::new(target_slot))
}
pub fn first_value_by(&self, field: impl AsRef<str>) -> Result<Option<OutputValue>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(FirstValueBySlotTerminal::new(target_slot))
.map(|value| value.map(output))
}
pub fn project_first_value<P>(&self, projection: &P) -> Result<Option<OutputValue>, QueryError>
where
E: EntityValue,
P: ValueProjectionExpr,
{
let target_slot = self.resolve_non_paged_slot(projection.field())?;
let value = self.execute_terminal(FirstValueBySlotTerminal::new(target_slot))?;
let mut projected =
Self::project_terminal_items(projection, value, |projection, value| {
projection.apply_value(value)
})?;
Ok(projected.pop().map(output))
}
pub fn explain_first_value_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.explain_terminal(&FirstValueBySlotTerminal::new(target_slot))
}
pub fn last_value_by(&self, field: impl AsRef<str>) -> Result<Option<OutputValue>, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.execute_terminal(LastValueBySlotTerminal::new(target_slot))
.map(|value| value.map(output))
}
pub fn project_last_value<P>(&self, projection: &P) -> Result<Option<OutputValue>, QueryError>
where
E: EntityValue,
P: ValueProjectionExpr,
{
let target_slot = self.resolve_non_paged_slot(projection.field())?;
let value = self.execute_terminal(LastValueBySlotTerminal::new(target_slot))?;
let mut projected =
Self::project_terminal_items(projection, value, |projection, value| {
projection.apply_value(value)
})?;
Ok(projected.pop().map(output))
}
pub fn explain_last_value_by(
&self,
field: impl AsRef<str>,
) -> Result<ExplainExecutionNodeDescriptor, QueryError>
where
E: EntityValue,
{
let target_slot = self.resolve_non_paged_slot(field)?;
self.explain_terminal(&LastValueBySlotTerminal::new(target_slot))
}
pub fn first(&self) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.execute_terminal(FirstIdTerminal::new())
}
pub fn explain_first(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_terminal(&FirstIdTerminal::new())
}
pub fn last(&self) -> Result<Option<Id<E>>, QueryError>
where
E: EntityValue,
{
self.execute_terminal(LastIdTerminal::new())
}
pub fn explain_last(&self) -> Result<ExplainAggregateTerminalPlan, QueryError>
where
E: EntityValue,
{
self.explain_terminal(&LastIdTerminal::new())
}
pub fn require_one(&self) -> Result<(), QueryError>
where
E: EntityValue,
{
self.execute()?.into_rows()?.require_one()?;
Ok(())
}
pub fn require_some(&self) -> Result<(), QueryError>
where
E: EntityValue,
{
self.execute()?.into_rows()?.require_some()?;
Ok(())
}
}