icydb_core/db/response/
grouped.rs1use crate::value::OutputValue;
7use candid::CandidType;
8use serde::Deserialize;
9
10#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
19pub struct GroupedRow {
20 group_key: Vec<OutputValue>,
21 aggregate_values: Vec<OutputValue>,
22}
23
24impl GroupedRow {
25 #[must_use]
27 pub fn new<I, J, K, L>(group_key: I, aggregate_values: J) -> Self
28 where
29 I: IntoIterator<Item = K>,
30 J: IntoIterator<Item = L>,
31 K: Into<OutputValue>,
32 L: Into<OutputValue>,
33 {
34 Self {
35 group_key: group_key.into_iter().map(Into::into).collect(),
36 aggregate_values: aggregate_values.into_iter().map(Into::into).collect(),
37 }
38 }
39
40 #[must_use]
42 pub const fn group_key(&self) -> &[OutputValue] {
43 self.group_key.as_slice()
44 }
45
46 #[must_use]
48 pub const fn aggregate_values(&self) -> &[OutputValue] {
49 self.aggregate_values.as_slice()
50 }
51}
52
53#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
55pub struct GroupedQueryOutput {
56 pub entity: String,
58 pub rows: Vec<GroupedRow>,
60 pub row_count: u32,
62 pub next_cursor: Option<String>,
64}
65
66#[cfg(test)]
67mod tests {
68 use candid::CandidType;
69
70 use super::{GroupedQueryOutput, GroupedRow};
71 use crate::value::OutputValue;
72
73 #[derive(CandidType)]
74 struct FrozenGroupedRowWire {
75 group_key: Vec<OutputValue>,
76 aggregate_values: Vec<OutputValue>,
77 }
78
79 #[derive(CandidType)]
80 struct FrozenGroupedQueryOutputWire {
81 entity: String,
82 rows: Vec<FrozenGroupedRowWire>,
83 row_count: u32,
84 next_cursor: Option<String>,
85 }
86
87 #[test]
88 fn grouped_query_output_preserves_its_initial_candid_record_shape() {
89 let current = GroupedQueryOutput {
90 entity: "Example".to_string(),
91 rows: vec![GroupedRow::new(
92 [OutputValue::Nat64(7)],
93 [OutputValue::Nat64(1)],
94 )],
95 row_count: 1,
96 next_cursor: Some("abcd".to_string()),
97 };
98 let frozen = FrozenGroupedQueryOutputWire {
99 entity: current.entity.clone(),
100 rows: vec![FrozenGroupedRowWire {
101 group_key: vec![OutputValue::Nat64(7)],
102 aggregate_values: vec![OutputValue::Nat64(1)],
103 }],
104 row_count: current.row_count,
105 next_cursor: current.next_cursor.clone(),
106 };
107
108 assert_eq!(
109 candid::encode_one(¤t).expect("current grouped output should encode"),
110 candid::encode_one(&frozen).expect("frozen grouped output should encode"),
111 );
112 }
113}