Skip to main content

icydb_core/db/response/
grouped.rs

1//! Module: response::grouped
2//! Responsibility: grouped paged response payload contracts.
3//! Does not own: grouped execution evaluation, route policy, or cursor token protocol.
4//! Boundary: grouped DTOs returned by session/query execution APIs.
5
6use crate::{
7    db::{
8        diagnostics::{ExecutionMetrics, ExecutionTrace},
9        executor::RuntimeGroupedRow,
10    },
11    value::OutputValue,
12};
13
14///
15/// GroupedRow
16///
17/// One grouped public output row: ordered grouping key values plus ordered
18/// aggregate outputs. Group and aggregate vectors preserve query declaration
19/// order at the outward API boundary.
20///
21
22#[derive(Clone, Debug, Eq, PartialEq)]
23pub struct GroupedRow {
24    group_key: Vec<OutputValue>,
25    aggregate_values: Vec<OutputValue>,
26}
27
28impl GroupedRow {
29    /// Construct one grouped output row payload.
30    #[must_use]
31    pub fn new<I, J, K, L>(group_key: I, aggregate_values: J) -> Self
32    where
33        I: IntoIterator<Item = K>,
34        J: IntoIterator<Item = L>,
35        K: Into<OutputValue>,
36        L: Into<OutputValue>,
37    {
38        Self {
39            group_key: group_key.into_iter().map(Into::into).collect(),
40            aggregate_values: aggregate_values.into_iter().map(Into::into).collect(),
41        }
42    }
43
44    /// Materialize one grouped output row from the runtime grouped carrier.
45    #[must_use]
46    pub(in crate::db) fn from_runtime_row(row: RuntimeGroupedRow) -> Self {
47        let (group_key, aggregate_values) = row.into_parts();
48
49        Self::new(group_key, aggregate_values)
50    }
51
52    /// Borrow grouped key values.
53    #[must_use]
54    pub const fn group_key(&self) -> &[OutputValue] {
55        self.group_key.as_slice()
56    }
57
58    /// Borrow aggregate output values.
59    #[must_use]
60    pub const fn aggregate_values(&self) -> &[OutputValue] {
61        self.aggregate_values.as_slice()
62    }
63}
64
65///
66/// PagedGroupedExecution
67///
68/// Cursor-paged grouped execution payload with optional continuation cursor bytes.
69///
70
71#[derive(Clone, Debug)]
72pub struct PagedGroupedExecution {
73    rows: Vec<GroupedRow>,
74    continuation_cursor: Option<Vec<u8>>,
75}
76
77impl PagedGroupedExecution {
78    /// Construct one grouped paged execution payload.
79    #[must_use]
80    pub const fn new(rows: Vec<GroupedRow>, continuation_cursor: Option<Vec<u8>>) -> Self {
81        Self {
82            rows,
83            continuation_cursor,
84        }
85    }
86
87    /// Borrow grouped rows.
88    #[must_use]
89    pub const fn rows(&self) -> &[GroupedRow] {
90        self.rows.as_slice()
91    }
92
93    /// Borrow optional continuation cursor bytes.
94    #[must_use]
95    pub fn continuation_cursor(&self) -> Option<&[u8]> {
96        self.continuation_cursor.as_deref()
97    }
98
99    /// Consume into grouped rows and continuation cursor bytes.
100    #[must_use]
101    pub fn into_parts(self) -> (Vec<GroupedRow>, Option<Vec<u8>>) {
102        (self.rows, self.continuation_cursor)
103    }
104}
105
106///
107/// PagedGroupedExecutionWithTrace
108///
109/// Cursor-paged grouped execution payload plus optional route/execution trace.
110///
111
112#[derive(Clone, Debug)]
113pub struct PagedGroupedExecutionWithTrace {
114    rows: Vec<GroupedRow>,
115    continuation_cursor: Option<Vec<u8>>,
116    execution_trace: Option<ExecutionTrace>,
117}
118
119impl PagedGroupedExecutionWithTrace {
120    /// Construct one traced grouped paged execution payload.
121    #[must_use]
122    pub const fn new(
123        rows: Vec<GroupedRow>,
124        continuation_cursor: Option<Vec<u8>>,
125        execution_trace: Option<ExecutionTrace>,
126    ) -> Self {
127        Self {
128            rows,
129            continuation_cursor,
130            execution_trace,
131        }
132    }
133
134    /// Borrow grouped rows.
135    #[must_use]
136    pub const fn rows(&self) -> &[GroupedRow] {
137        self.rows.as_slice()
138    }
139
140    /// Borrow optional continuation cursor bytes.
141    #[must_use]
142    pub fn continuation_cursor(&self) -> Option<&[u8]> {
143        self.continuation_cursor.as_deref()
144    }
145
146    /// Borrow optional execution trace details.
147    #[must_use]
148    pub const fn execution_trace(&self) -> Option<&ExecutionTrace> {
149        self.execution_trace.as_ref()
150    }
151
152    /// Borrow compact execution metrics derived from the optional execution trace.
153    #[must_use]
154    pub fn execution_metrics(&self) -> Option<ExecutionMetrics> {
155        self.execution_trace.as_ref().map(ExecutionTrace::metrics)
156    }
157
158    /// Consume payload and drop trace details.
159    #[must_use]
160    pub fn into_execution(self) -> PagedGroupedExecution {
161        PagedGroupedExecution {
162            rows: self.rows,
163            continuation_cursor: self.continuation_cursor,
164        }
165    }
166
167    /// Consume into grouped rows, continuation cursor bytes, and optional trace.
168    #[must_use]
169    pub fn into_parts(self) -> (Vec<GroupedRow>, Option<Vec<u8>>, Option<ExecutionTrace>) {
170        (self.rows, self.continuation_cursor, self.execution_trace)
171    }
172}