use crate::db::query::plan::expr::ProjectionSelection;
use crate::db::query::{
intent::{
IntentError,
state::{GroupedIntent, NormalizedFilter, QueryIntent},
},
plan::{
GroupAggregateSpec, GroupFieldSet, GroupedExecutionConfig, OrderSpec,
expr::{BinaryOp, Expr, normalize_bool_expr},
},
};
use crate::db::{QueryError, predicate::Predicate, query::preparation::PreparationWork};
impl QueryIntent {
pub(in crate::db::query::intent) fn append_filter_expr(
&mut self,
expr: Expr,
work: &PreparationWork<'_>,
) -> Result<(), QueryError> {
self.append_normalized_filter(NormalizedFilter::from_normalized_expr(expr), work)
}
pub(in crate::db::query::intent) fn append_predicate(&mut self, predicate: Predicate) {
let scalar = self.scalar_mut();
match scalar.filter.as_mut() {
Some(existing) => existing.append_predicate(predicate),
None => scalar.filter = Some(NormalizedFilter::from_normalized_predicate(predicate)),
}
}
pub(in crate::db::query::intent) fn append_filter_with_predicate_subset(
&mut self,
expr: Expr,
predicate: Predicate,
work: &PreparationWork<'_>,
) -> Result<(), QueryError> {
self.append_normalized_filter(
NormalizedFilter::from_normalized_expr_and_predicate_subset(expr, predicate),
work,
)
}
fn append_normalized_filter(
&mut self,
filter: NormalizedFilter,
work: &PreparationWork<'_>,
) -> Result<(), QueryError> {
let scalar = self.scalar_mut();
match scalar.filter.as_mut() {
Some(existing) => existing.append(filter, work)?,
None => scalar.filter = Some(filter),
}
Ok(())
}
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;
}
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_group_fields(&mut self, fields: GroupFieldSet) {
let Some(grouped) = self.grouped_mutation_target() else {
return;
};
grouped.group.group_fields = fields;
}
pub(in crate::db::query::intent) fn set_group_aggregates(
&mut self,
aggregates: Vec<GroupAggregateSpec>,
) {
let Some(grouped) = self.grouped_mutation_target() else {
return;
};
grouped.group.aggregates = aggregates;
}
pub(in crate::db::query::intent) fn set_grouped_execution_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_expr_preserving_shape(
&mut self,
expr: Expr,
work: &PreparationWork<'_>,
) -> Result<(), QueryError> {
if matches!(self, Self::Delete(_)) {
if self.is_grouped() {
self.mark_delete_grouping_requested();
return Ok(());
}
return Err(QueryError::intent(IntentError::having_requires_group_by()));
}
let Some(grouped) = self.grouped_mut() else {
return Err(QueryError::intent(IntentError::having_requires_group_by()));
};
let combined = match grouped.having_expr.take() {
Some(existing) => Expr::Binary {
op: BinaryOp::And,
left: Box::new(existing),
right: Box::new(expr),
},
None => expr,
};
let canonical = normalize_bool_expr(combined, work)?;
grouped.having_expr = Some(canonical);
Ok(())
}
fn grouped_mutation_target(&mut self) -> Option<&mut GroupedIntent> {
if matches!(self, Self::Delete(_)) {
self.mark_delete_grouping_requested();
return None;
}
self.ensure_grouped_mut()
}
}