framework_cqrs_lib/cqrs/infra/mappers/
state_view.rs

1use std::cmp::max;
2use std::collections::HashMap;
3
4use serde::Serialize;
5
6use crate::cqrs::core::context::Context;
7use crate::cqrs::core::data::Entity;
8use crate::cqrs::core::repositories::query::Paged;
9use crate::cqrs::models::jsonapi::{CanBeView, CanGetTypee, ManyView, PageView, PaginationView};
10use crate::cqrs::models::views::{DataWrapperView, LinkView};
11use crate::cqrs::models::views::entities::{EntityView, LinksEntityView};
12
13pub trait CanBeManyView<T: Serialize + Clone> {
14    fn to_many_view(
15        &self,
16        ctx: &Context,
17        ontology: String,
18        other_link: HashMap<String, String>,
19    ) -> ManyView<T>;
20}
21
22impl<T: Serialize + Clone> CanBeManyView<T> for Paged<T> {
23    fn to_many_view(&self, ctx: &Context, ontology: String, other_link: HashMap<String, String>) -> ManyView<T> {
24        let external_url = ctx.meta
25            .get("externalUrl")
26            .map(|urlref| urlref.clone())
27            .unwrap_or("unknown".to_string());
28
29        let query_without_prefix = ctx.filters
30            .iter()
31            .map(|(k, v)| {
32                format!("{k}={v}")
33            })
34            .collect::<Vec<String>>()
35            .join("&");
36
37        let query = if query_without_prefix.is_empty() {
38            query_without_prefix
39        } else {
40            format!("?{query_without_prefix}")
41        };
42
43
44        let query_first_without_prefix = ctx.filters
45            .iter()
46            .filter(|(k, _)| **k != "page[number]".to_string() && **k != "page[size]".to_string())
47            .map(|(k, v)| {
48                format!("{k}={v}")
49            })
50            .chain(vec!["page[number]=0".to_string(), format!("page[size]={}", self.meta.page.size)])
51            .collect::<Vec<String>>()
52            .join("&");
53
54        let query_first = if query_first_without_prefix.is_empty() {
55            query_first_without_prefix
56        } else {
57            format!("?{query_first_without_prefix}")
58        };
59
60        let query_prev_without_prefix = ctx.filters
61            .iter()
62            .filter(|(k, _)| **k != "page[number]".to_string() && **k != "page[size]".to_string())
63            .map(|(k, v)| {
64                format!("{k}={v}")
65            })
66            .chain(vec![format!("page[number]={}", max(if self.meta.page.number > 0 { self.meta.page.number - 1 } else { 0 }, 0)), format!("page[size]={}", self.meta.page.size)])
67            .collect::<Vec<String>>()
68            .join("&");
69
70        let query_prev = if query_prev_without_prefix.is_empty() {
71            query_prev_without_prefix
72        } else {
73            format!("?{query_prev_without_prefix}")
74        };
75
76
77        let other_link_sanitize = other_link
78            .into_iter()
79            .map(|(k, v)| (k, format!("{external_url}/{v}")))
80            .collect::<HashMap<String, String>>();
81
82
83        let links = LinkView {
84            links: HashMap::from([
85                ("self".to_string(), format!("{external_url}/{ontology}")),
86                ("last".to_string(), format!("{external_url}/{ontology}{}", query.clone())),
87                ("prev".to_string(), format!("{external_url}/{ontology}{}", query_prev.clone())),
88                ("first".to_string(), format!("{external_url}/{ontology}{query_first}")),
89                ("next".to_string(), format!("{external_url}/{ontology}{}", query.clone())),
90            ])
91                .into_iter().chain(other_link_sanitize)
92                .collect()
93        };
94
95        ManyView {
96            data: self.data.clone(),
97            meta: Some(
98                PaginationView {
99                    total_pages: self.meta.total_pages.clone(),
100                    total_records: self.meta.total_records.clone(),
101                    page: PageView {
102                        number: self.meta.page.number.clone(),
103                        size: self.meta.page.size.clone(),
104                    },
105                }
106            ),
107            links: Some(links),
108        }
109    }
110}
111
112pub fn from_states_to_entity_view<DATA, VIEW>(
113    entity: Entity<DATA, String>,
114    ontology: String,
115    context: &Context,
116) -> EntityView<VIEW>
117where
118    VIEW: Serialize + Clone,
119    DATA: Clone + CanBeView<VIEW> + CanGetTypee,
120{
121    let entity_id = entity.entity_id.as_str();
122
123    let external_url = context.meta
124        .get("externalUrl")
125        .map(|urlref| urlref.clone())
126        .unwrap_or("unknown".to_string());
127
128    let link_event = (
129        "events".to_string(), format!("{external_url}/{ontology}/{entity_id}/events")
130    );
131    let link_self = (
132        "self".to_string(), format!("{external_url}/{ontology}/{entity_id}")
133    );
134
135    EntityView {
136        r#type: entity.data.get_type(),
137        id: entity_id.to_string(),
138        attributes: entity.data.to_view(),
139        links: Some(LinksEntityView {
140            links: HashMap::from([link_event, link_self])
141        }),
142    }
143}
144
145pub fn from_states_to_view<DATA, VIEW>(
146    entity: Entity<DATA, String>,
147    ontology: String,
148    context: &Context,
149) -> DataWrapperView<EntityView<VIEW>>
150where
151    VIEW: Serialize + Clone,
152    DATA: Clone + CanBeView<VIEW> + CanGetTypee,
153{
154    DataWrapperView {
155        data: from_states_to_entity_view(entity, ontology, context)
156    }
157}