framework_cqrs_lib/cqrs/infra/mappers/
state_view.rs1use 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}