icydb_core/db/response/
rows.rs1use crate::value::{OutputValue, render_output_value_text};
7use candid::CandidType;
8use serde::Deserialize;
9
10#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
12pub struct RowProjectionOutput {
13 pub entity: String,
15 pub columns: Vec<String>,
17 pub rows: Vec<Vec<OutputValue>>,
19 pub row_count: u32,
21}
22
23impl RowProjectionOutput {
24 #[must_use]
26 pub const fn len(&self) -> usize {
27 self.rows.len()
28 }
29
30 #[must_use]
32 pub const fn is_empty(&self) -> bool {
33 self.rows.is_empty()
34 }
35
36 #[must_use]
38 pub fn rendered_rows(&self) -> Vec<Vec<String>> {
39 self.rows
40 .iter()
41 .map(|row| row.iter().map(render_output_value_text).collect())
42 .collect()
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[derive(CandidType)]
51 struct FrozenRowProjectionOutputWire {
52 entity: String,
53 columns: Vec<String>,
54 rows: Vec<Vec<OutputValue>>,
55 row_count: u32,
56 }
57
58 #[test]
59 fn row_projection_output_preserves_the_frozen_candid_record_shape() {
60 let current = RowProjectionOutput {
61 entity: "example".to_string(),
62 columns: vec!["id".to_string()],
63 rows: Vec::new(),
64 row_count: 0,
65 };
66 let frozen = FrozenRowProjectionOutputWire {
67 entity: current.entity.clone(),
68 columns: current.columns.clone(),
69 rows: current.rows.clone(),
70 row_count: current.row_count,
71 };
72
73 assert_eq!(current.len(), 0);
74 assert!(current.is_empty());
75
76 assert_eq!(
77 candid::encode_one(¤t).expect("current row projection should encode"),
78 candid::encode_one(&frozen).expect("frozen row projection should encode"),
79 );
80 }
81}