oxigdal_stac/api/
features.rs1use serde::{Deserialize, Serialize};
8
9use super::search::Link;
10
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
13pub struct LandingPage {
14 #[serde(skip_serializing_if = "Option::is_none")]
16 pub title: Option<String>,
17
18 #[serde(skip_serializing_if = "Option::is_none")]
20 pub description: Option<String>,
21
22 #[serde(rename = "stac_version")]
24 pub stac_version: String,
25
26 #[serde(rename = "conformsTo", default, skip_serializing_if = "Vec::is_empty")]
28 pub conforms_to: Vec<String>,
29
30 pub links: Vec<Link>,
32}
33
34impl LandingPage {
35 pub fn new(stac_version: impl Into<String>, links: Vec<Link>) -> Self {
37 Self {
38 title: None,
39 description: None,
40 stac_version: stac_version.into(),
41 conforms_to: Vec::new(),
42 links,
43 }
44 }
45
46 pub fn with_title(mut self, title: impl Into<String>) -> Self {
48 self.title = Some(title.into());
49 self
50 }
51
52 pub fn with_description(mut self, desc: impl Into<String>) -> Self {
54 self.description = Some(desc.into());
55 self
56 }
57
58 pub fn with_conforms_to(mut self, uris: impl IntoIterator<Item = impl Into<String>>) -> Self {
60 self.conforms_to = uris.into_iter().map(Into::into).collect();
61 self
62 }
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
67pub struct CollectionsList {
68 pub collections: Vec<CollectionSummary>,
70 pub links: Vec<Link>,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
76pub struct CollectionSummary {
77 pub id: String,
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub title: Option<String>,
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub description: Option<String>,
85 #[serde(rename = "stac_version")]
87 pub stac_version: String,
88 pub links: Vec<Link>,
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub extent: Option<serde_json::Value>,
93}
94
95impl CollectionSummary {
96 pub fn new(id: impl Into<String>, stac_version: impl Into<String>) -> Self {
98 Self {
99 id: id.into(),
100 title: None,
101 description: None,
102 stac_version: stac_version.into(),
103 links: Vec::new(),
104 extent: None,
105 }
106 }
107
108 pub fn with_title(mut self, title: impl Into<String>) -> Self {
110 self.title = Some(title.into());
111 self
112 }
113
114 pub fn with_description(mut self, desc: impl Into<String>) -> Self {
116 self.description = Some(desc.into());
117 self
118 }
119
120 pub fn add_link(mut self, link: Link) -> Self {
122 self.links.push(link);
123 self
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn test_landing_page_new() {
133 let page = LandingPage::new("1.0.0", vec![]).with_title("My STAC API");
134 assert_eq!(page.title, Some("My STAC API".to_string()));
135 assert_eq!(page.stac_version, "1.0.0");
136 }
137
138 #[test]
139 fn test_landing_page_roundtrip() {
140 let page = LandingPage::new("1.0.0", vec![Link::new("self", "https://example.com")])
141 .with_title("Test API")
142 .with_description("A test STAC API");
143 let json = serde_json::to_string(&page).expect("serialize");
144 let back: LandingPage = serde_json::from_str(&json).expect("deserialize");
145 assert_eq!(page, back);
146 }
147
148 #[test]
149 fn test_collection_summary() {
150 let cs = CollectionSummary::new("sentinel-2-l2a", "1.0.0")
151 .with_title("Sentinel-2 L2A")
152 .add_link(Link::new(
153 "items",
154 "https://example.com/collections/sentinel-2-l2a/items",
155 ));
156 assert_eq!(cs.id, "sentinel-2-l2a");
157 assert_eq!(cs.links.len(), 1);
158 }
159
160 #[test]
161 fn test_collections_list_roundtrip() {
162 let list = CollectionsList {
163 collections: vec![CollectionSummary::new("my-col", "1.0.0")],
164 links: vec![Link::new("self", "https://example.com/collections")],
165 };
166 let json = serde_json::to_string(&list).expect("serialize");
167 let back: CollectionsList = serde_json::from_str(&json).expect("deserialize");
168 assert_eq!(list, back);
169 }
170}