bnto_core/data/summarize/
mod.rs1mod group;
11mod params;
12mod total;
13
14use serde_json::{Map, Value};
15
16use crate::metadata::{InputCardinality, NodeCategory, NodeMetadata};
17use crate::processor::{
18 BatchFile, BatchInput, FileData, NodeInput, NodeOutput, NodeProcessor, OutputFile,
19};
20use crate::progress::ProgressReporter;
21use crate::{BntoError, ProcessContext};
22
23use params::{SummarizeParams, build_summarize_parameters};
24
25pub struct Summarize;
27
28impl Summarize {
29 pub fn new() -> Self {
30 Self
31 }
32}
33
34impl Default for Summarize {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40impl NodeProcessor for Summarize {
41 fn name(&self) -> &str {
42 "summarize"
43 }
44
45 fn metadata(&self) -> NodeMetadata {
46 NodeMetadata {
47 node_type: "summarize".to_string(),
48 name: "Summarize".to_string(),
49 description: "Summarize items by metadata fields, one item per group with \
50 its count and the totals of numeric fields (sum_<field>). Groups \
51 keep first-seen order; the items summarized don't pass through."
52 .to_string(),
53 category: NodeCategory::Data,
54 accepts: vec![],
55 platforms: vec![
56 "browser".to_string(),
57 "cli".to_string(),
58 "desktop".to_string(),
59 ],
60 parameters: build_summarize_parameters(),
61 input_cardinality: InputCardinality::Batch,
62 requires: vec![],
63 }
64 }
65
66 fn validate(&self, params: &Map<String, Value>) -> Vec<String> {
67 SummarizeParams::read(params).err().into_iter().collect()
68 }
69
70 fn process(
72 &self,
73 input: NodeInput,
74 progress: &ProgressReporter,
75 ctx: &dyn ProcessContext,
76 ) -> Result<NodeOutput, BntoError> {
77 let file = BatchFile {
78 data: input.data,
79 filename: input.filename,
80 mime_type: input.mime_type,
81 metadata: Map::new(),
82 };
83 let batch = BatchInput {
84 files: vec![file],
85 params: input.params,
86 };
87 self.process_batch(batch, progress, ctx)
88 }
89
90 fn process_batch(
91 &self,
92 input: BatchInput,
93 _progress: &ProgressReporter,
94 _ctx: &dyn ProcessContext,
95 ) -> Result<NodeOutput, BntoError> {
96 let params = SummarizeParams::read(&input.params).map_err(BntoError::InvalidInput)?;
97 let groups = group::summarize(&input.files, ¶ms).map_err(BntoError::InvalidInput)?;
98 let mut metadata = Map::new();
99 metadata.insert("groupCount".to_string(), groups.len().into());
100 let files = groups.into_iter().enumerate().map(summary_item).collect();
101 Ok(NodeOutput { files, metadata })
102 }
103}
104
105fn summary_item((i, metadata): (usize, Map<String, Value>)) -> OutputFile {
107 OutputFile {
108 data: FileData::Bytes(Vec::new()),
109 filename: format!("group{i}"),
110 mime_type: "application/octet-stream".to_string(),
111 metadata,
112 }
113}
114
115#[cfg(test)]
116mod tests;