Skip to main content

cratestack_core/
projection.rs

1use 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}