use super::super::cache_key::{AggregateCacheKeyInputs, aggregate_cache_key};
use crate::bridge::envelope::{ErrorCode, Response};
use crate::data::executor::core_loop::CoreLoop;
use crate::data::executor::task::ExecutionTask;
use nodedb_physical::physical_plan::{AggregateSpec, GroupKeySpec};
pub(in crate::data::executor) struct AggregateOverDocsParams<'a> {
pub task: &'a ExecutionTask,
pub collection: &'a str,
pub cache_tid: Option<u64>,
pub docs: Vec<(String, Vec<u8>)>,
pub group_by: &'a [GroupKeySpec],
pub aggregates: &'a [AggregateSpec],
pub filters: &'a [u8],
pub having: &'a [u8],
pub limit: usize,
pub sub_group_by: &'a [String],
pub sub_aggregates: &'a [AggregateSpec],
pub sort_keys: &'a [(String, bool)],
}
impl CoreLoop {
pub(in crate::data::executor) fn aggregate_over_docs(
&mut self,
params: AggregateOverDocsParams<'_>,
) -> Response {
let AggregateOverDocsParams {
task,
collection,
cache_tid,
docs,
group_by,
aggregates,
filters,
having,
limit,
sub_group_by,
sub_aggregates,
sort_keys,
} = params;
let (groups, sub_groups) =
match self.accumulate_groups(super::accumulate::AccumulateGroupsParams {
docs: &docs,
group_by,
aggregates,
filters,
sub_group_by,
sub_aggregates,
}) {
Ok(g) => g,
Err(e) => {
return self.response_error(
task,
ErrorCode::Internal {
detail: e.to_string(),
},
);
}
};
match self.finalize_groups(super::finalize::FinalizeGroupsParams {
groups,
sub_groups,
group_by,
aggregates,
having,
limit,
sub_group_by,
sub_aggregates,
sort_keys,
}) {
Ok(payload) => {
if let Some(tid) = cache_tid
&& filters.is_empty()
&& having.is_empty()
{
let cache_key = aggregate_cache_key(AggregateCacheKeyInputs {
database_id: task.request.database_id.as_u64(),
tid,
collection,
group_by,
aggregates,
sub_group_by,
sub_aggregates,
limit,
sort_keys,
});
if self.aggregate_cache.len() < 256 {
self.aggregate_cache.insert(cache_key, payload.clone());
}
}
self.response_with_payload(task, payload)
}
Err(e) => self.response_error(
task,
ErrorCode::Internal {
detail: e.to_string(),
},
),
}
}
}