use crate::db::{
executor::ScalarProjectionBoundaryRequest,
query::{
builder::aggregate::ProjectionExplainDescriptor,
plan::{AggregateKind, FieldSlot},
},
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum ProjectionRequest {
Values,
DistinctValues,
CountDistinct,
ValuesWithIds,
TerminalValue { terminal_kind: AggregateKind },
}
impl ProjectionRequest {
const fn boundary_request(self) -> ScalarProjectionBoundaryRequest {
match self {
Self::Values => ScalarProjectionBoundaryRequest::Values,
Self::DistinctValues => ScalarProjectionBoundaryRequest::DistinctValues,
Self::CountDistinct => ScalarProjectionBoundaryRequest::CountDistinct,
Self::ValuesWithIds => ScalarProjectionBoundaryRequest::ValuesWithIds,
Self::TerminalValue { terminal_kind } => {
ScalarProjectionBoundaryRequest::TerminalValue { terminal_kind }
}
}
}
fn terminal_label(self) -> &'static str {
match self {
Self::Values => "values_by",
Self::DistinctValues => "distinct_values_by",
Self::CountDistinct => "count_distinct_by",
Self::ValuesWithIds => "values_by_with_ids",
Self::TerminalValue {
terminal_kind: AggregateKind::First,
} => "first_value_by",
Self::TerminalValue {
terminal_kind: AggregateKind::Last,
} => "last_value_by",
Self::TerminalValue { .. } => {
unreachable!("projection terminal value explain requires FIRST/LAST kind")
}
}
}
const fn output_label(self) -> &'static str {
match self {
Self::Values | Self::DistinctValues => "values",
Self::CountDistinct => "count",
Self::ValuesWithIds => "values_with_ids",
Self::TerminalValue { .. } => "terminal_value",
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct ProjectionStrategy {
target_field: FieldSlot,
request: ProjectionRequest,
}
impl ProjectionStrategy {
#[must_use]
pub(crate) const fn values_by_slot(target_field: FieldSlot) -> Self {
Self {
target_field,
request: ProjectionRequest::Values,
}
}
#[must_use]
pub(crate) const fn distinct_values_by_slot(target_field: FieldSlot) -> Self {
Self {
target_field,
request: ProjectionRequest::DistinctValues,
}
}
#[must_use]
pub(crate) const fn count_distinct_by_slot(target_field: FieldSlot) -> Self {
Self {
target_field,
request: ProjectionRequest::CountDistinct,
}
}
#[must_use]
pub(crate) const fn values_by_with_ids_slot(target_field: FieldSlot) -> Self {
Self {
target_field,
request: ProjectionRequest::ValuesWithIds,
}
}
#[must_use]
pub(crate) const fn first_value_by_slot(target_field: FieldSlot) -> Self {
Self {
target_field,
request: ProjectionRequest::TerminalValue {
terminal_kind: AggregateKind::First,
},
}
}
#[must_use]
pub(crate) const fn last_value_by_slot(target_field: FieldSlot) -> Self {
Self {
target_field,
request: ProjectionRequest::TerminalValue {
terminal_kind: AggregateKind::Last,
},
}
}
#[cfg(test)]
#[must_use]
pub(crate) const fn target_field(&self) -> &FieldSlot {
&self.target_field
}
#[cfg(test)]
#[must_use]
pub(crate) const fn request(&self) -> ProjectionRequest {
self.request
}
#[must_use]
pub(in crate::db) fn into_executor_request(
self,
) -> (
FieldSlot,
ScalarProjectionBoundaryRequest,
ProjectionRequest,
) {
(
self.target_field,
self.request.boundary_request(),
self.request,
)
}
#[must_use]
pub(crate) fn explain_descriptor(&self) -> ProjectionExplainDescriptor<'_> {
ProjectionExplainDescriptor {
terminal: self.request.terminal_label(),
field: self.target_field.field(),
output: self.request.output_label(),
}
}
}