cratestack_core/
projection.rs1use crate::{CoolError, Page, SelectionQuery};
2use serde_json::Value as JsonValue;
3
4pub trait ProjectionDecoder {
5 type Output;
6
7 fn selection_query(&self) -> SelectionQuery;
8
9 fn decode_one(&self, value: JsonValue) -> Result<Self::Output, CoolError>;
10
11 fn decode_many(&self, value: JsonValue) -> Result<Vec<Self::Output>, CoolError> {
12 match value {
13 JsonValue::Array(values) => values
14 .into_iter()
15 .map(|value| self.decode_one(value))
16 .collect(),
17 other => Err(CoolError::Internal(format!(
18 "projected list payload must be an array, got {other:?}"
19 ))),
20 }
21 }
22
23 fn decode_page(&self, value: JsonValue) -> Result<Page<Self::Output>, CoolError> {
24 let page = serde_json::from_value::<Page<JsonValue>>(value).map_err(|error| {
25 CoolError::Codec(format!("failed to decode projected page payload: {error}"))
26 })?;
27 let items = page
28 .items
29 .into_iter()
30 .map(|value| self.decode_one(value))
31 .collect::<Result<Vec<_>, _>>()?;
32 Ok(Page::new(items, page.page_info).with_total_count(page.total_count))
33 }
34}
35
36impl ProjectionDecoder for SelectionQuery {
37 type Output = JsonValue;
38
39 fn selection_query(&self) -> SelectionQuery {
40 self.clone()
41 }
42
43 fn decode_one(&self, value: JsonValue) -> Result<Self::Output, CoolError> {
44 Ok(value)
45 }
46}