#[cfg(feature = "sql")]
use crate::db::query::plan::expr::ProjectionSelection;
use crate::db::{
predicate::Predicate,
query::{
intent::{
IntentError, KeyAccess, KeyAccessKind, KeyAccessState,
state::{GroupedIntent, QueryIntent},
},
plan::{
FieldSlot, GroupAggregateSpec, GroupHavingClause, GroupSpec, GroupedExecutionConfig,
OrderDirection, OrderSpec,
expr::{BinaryOp, Expr},
grouped_having_clause_expr_for_group,
},
},
};
impl<K> QueryIntent<K> {
pub(in crate::db::query::intent) fn append_predicate(&mut self, predicate: Predicate) {
let scalar = self.scalar_mut();
scalar.predicate = match scalar.predicate.take() {
Some(existing) => Some(Predicate::And(vec![existing, predicate])),
None => Some(predicate),
};
}
pub(in crate::db::query::intent) fn push_order_ascending(&mut self, field: &str) {
self.push_order_field(field, OrderDirection::Asc);
}
pub(in crate::db::query::intent) fn push_order_descending(&mut self, field: &str) {
self.push_order_field(field, OrderDirection::Desc);
}
pub(in crate::db::query::intent) fn set_order_spec(&mut self, order: OrderSpec) {
self.scalar_mut().order = Some(order);
}
pub(in crate::db::query::intent) const fn set_distinct(&mut self) {
self.scalar_mut().distinct = true;
}
#[cfg(feature = "sql")]
pub(in crate::db::query::intent) fn set_projection_selection(
&mut self,
projection_selection: ProjectionSelection,
) {
self.scalar_mut().projection_selection = projection_selection;
}
pub(in crate::db::query::intent) fn set_by_id(&mut self, id: K) {
self.set_key_access(KeyAccessKind::Single, KeyAccess::Single(id));
}
pub(in crate::db::query::intent) fn set_by_ids<I>(&mut self, ids: I)
where
I: IntoIterator<Item = K>,
{
self.set_key_access(
KeyAccessKind::Many,
KeyAccess::Many(ids.into_iter().collect()),
);
}
pub(in crate::db::query::intent) fn set_only(&mut self, id: K) {
self.set_key_access(KeyAccessKind::Only, KeyAccess::Single(id));
}
pub(in crate::db::query::intent) fn push_group_field_slot(&mut self, field_slot: FieldSlot) {
let Some(grouped) = self.grouped_mutation_target() else {
return;
};
let group = &mut grouped.group;
if !group
.group_fields
.iter()
.any(|existing| existing.index() == field_slot.index())
{
group.group_fields.push(field_slot);
}
}
pub(in crate::db::query::intent) fn push_group_aggregate(
&mut self,
aggregate: GroupAggregateSpec,
) {
let Some(grouped) = self.grouped_mutation_target() else {
return;
};
grouped.group.aggregates.push(aggregate);
}
pub(in crate::db::query::intent) fn set_grouped_limits(
&mut self,
max_groups: u64,
max_group_bytes: u64,
) {
let Some(grouped) = self.grouped_mutation_target() else {
return;
};
grouped.group.execution =
GroupedExecutionConfig::with_hard_limits(max_groups, max_group_bytes);
}
pub(in crate::db::query::intent) fn push_having_clause(
&mut self,
clause: GroupHavingClause,
) -> Result<(), IntentError> {
if matches!(self, Self::Delete(_)) {
if self.is_grouped() {
self.mark_delete_grouping_requested();
return Ok(());
}
return Err(IntentError::having_requires_group_by());
}
let Some(grouped) = self.grouped_mut() else {
return Err(IntentError::having_requires_group_by());
};
let clause = grouped_having_clause_expr(&grouped.group, &clause)?;
grouped.having_expr = Some(match grouped.having_expr.take() {
Some(existing) => Expr::Binary {
op: BinaryOp::And,
left: Box::new(existing),
right: Box::new(clause),
},
None => clause,
});
Ok(())
}
pub(in crate::db::query::intent) fn push_having_expr(
&mut self,
expr: Expr,
) -> Result<(), IntentError> {
if matches!(self, Self::Delete(_)) {
if self.is_grouped() {
self.mark_delete_grouping_requested();
return Ok(());
}
return Err(IntentError::having_requires_group_by());
}
let Some(grouped) = self.grouped_mut() else {
return Err(IntentError::having_requires_group_by());
};
grouped.having_expr = Some(match grouped.having_expr.take() {
Some(existing) => Expr::Binary {
op: BinaryOp::And,
left: Box::new(existing),
right: Box::new(expr),
},
None => expr,
});
Ok(())
}
fn set_key_access(&mut self, kind: KeyAccessKind, access: KeyAccess<K>) {
let scalar = self.scalar_mut();
if let Some(existing) = &scalar.key_access
&& existing.kind != kind
{
scalar.key_access_conflict = true;
}
scalar.key_access = Some(KeyAccessState { kind, access });
}
fn push_order_field(&mut self, field: &str, direction: OrderDirection) {
let scalar = self.scalar_mut();
scalar.order = Some(match scalar.order.take() {
Some(mut spec) => {
spec.fields.push((field.to_string(), direction));
spec
}
None => OrderSpec {
fields: vec![(field.to_string(), direction)],
},
});
}
fn grouped_mutation_target(&mut self) -> Option<&mut GroupedIntent<K>> {
if matches!(self, Self::Delete(_)) {
self.mark_delete_grouping_requested();
return None;
}
Some(self.ensure_grouped_mut())
}
}
fn grouped_having_clause_expr(
group: &GroupSpec,
clause: &GroupHavingClause,
) -> Result<Expr, IntentError> {
grouped_having_clause_expr_for_group(group, clause)
.ok_or_else(IntentError::having_references_unknown_aggregate)
}