1use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10fn deserialize_null_as_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
18where
19 D: serde::Deserializer<'de>,
20 T: serde::Deserialize<'de> + Default,
21{
22 Ok(Option::<T>::deserialize(deserializer)?.unwrap_or_default())
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct SearchResponse {
28 #[serde(default, deserialize_with = "deserialize_null_as_default")]
30 pub results: Vec<SearchHit>,
31 #[serde(default, skip_serializing_if = "Option::is_none")]
33 pub after: Option<String>,
34 #[serde(default, skip_serializing_if = "Option::is_none")]
36 pub sort: Option<String>,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct SearchHit {
45 #[serde(default, skip_serializing_if = "Option::is_none")]
47 pub identifier: Option<String>,
48 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub slug: Option<String>,
51 #[serde(default, skip_serializing_if = "Option::is_none")]
53 pub title: Option<String>,
54 #[serde(default, skip_serializing_if = "Option::is_none")]
56 pub description: Option<String>,
57 #[serde(default, skip_serializing_if = "Option::is_none")]
59 pub publisher: Option<String>,
60 #[serde(default, skip_serializing_if = "Option::is_none")]
62 pub organization: Option<Organization>,
63 #[serde(default, deserialize_with = "deserialize_null_as_default")]
65 pub keyword: Vec<String>,
66 #[serde(default, deserialize_with = "deserialize_null_as_default")]
68 pub theme: Vec<String>,
69 #[serde(default, skip_serializing_if = "Option::is_none")]
71 pub has_spatial: Option<bool>,
72 #[serde(default, skip_serializing_if = "Option::is_none")]
74 pub popularity: Option<i64>,
75 #[serde(default, skip_serializing_if = "Option::is_none")]
77 pub last_harvested_date: Option<String>,
78 #[serde(default, deserialize_with = "deserialize_null_as_default")]
80 pub distribution_titles: Vec<String>,
81 #[serde(default, skip_serializing_if = "Option::is_none")]
83 pub harvest_record: Option<String>,
84 #[serde(default, skip_serializing_if = "Option::is_none")]
86 pub harvest_record_raw: Option<String>,
87 #[serde(default, skip_serializing_if = "Option::is_none")]
89 pub spatial_centroid: Option<Value>,
90 #[serde(default, skip_serializing_if = "Option::is_none")]
92 pub spatial_shape: Option<Value>,
93 #[serde(default, skip_serializing_if = "Option::is_none")]
95 pub dcat: Option<Dataset>,
96 #[serde(default, rename = "_score", skip_serializing_if = "Option::is_none")]
98 pub score: Option<f64>,
99 #[serde(default, rename = "_sort", skip_serializing_if = "Option::is_none")]
101 pub sort_key: Option<Value>,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct Dataset {
109 #[serde(default, rename = "@type", skip_serializing_if = "Option::is_none")]
111 pub type_hint: Option<String>,
112 #[serde(default, skip_serializing_if = "Option::is_none")]
113 pub title: Option<String>,
114 #[serde(default, skip_serializing_if = "Option::is_none")]
115 pub description: Option<String>,
116 #[serde(default, skip_serializing_if = "Option::is_none")]
118 pub identifier: Option<String>,
119 #[serde(
121 default,
122 skip_serializing_if = "Option::is_none",
123 rename = "accessLevel"
124 )]
125 pub access_level: Option<String>,
126 #[serde(default, skip_serializing_if = "Option::is_none")]
128 pub modified: Option<String>,
129 #[serde(default, skip_serializing_if = "Option::is_none")]
131 pub issued: Option<String>,
132 #[serde(default, skip_serializing_if = "Option::is_none")]
133 pub publisher: Option<Publisher>,
134 #[serde(
135 default,
136 skip_serializing_if = "Option::is_none",
137 rename = "contactPoint"
138 )]
139 pub contact_point: Option<ContactPoint>,
140 #[serde(default, deserialize_with = "deserialize_null_as_default")]
141 pub keyword: Vec<String>,
142 #[serde(default, deserialize_with = "deserialize_null_as_default")]
143 pub theme: Vec<String>,
144 #[serde(default, deserialize_with = "deserialize_null_as_default")]
146 pub distribution: Vec<Distribution>,
147 #[serde(
149 default,
150 skip_serializing_if = "Option::is_none",
151 rename = "landingPage"
152 )]
153 pub landing_page: Option<String>,
154 #[serde(default, skip_serializing_if = "Option::is_none")]
155 pub license: Option<String>,
156 #[serde(default, skip_serializing_if = "Option::is_none")]
157 pub rights: Option<String>,
158 #[serde(default, skip_serializing_if = "Option::is_none")]
159 pub spatial: Option<String>,
160 #[serde(default, skip_serializing_if = "Option::is_none")]
161 pub temporal: Option<String>,
162 #[serde(
163 default,
164 skip_serializing_if = "Option::is_none",
165 rename = "accrualPeriodicity"
166 )]
167 pub accrual_periodicity: Option<String>,
168 #[serde(default, deserialize_with = "deserialize_null_as_default")]
169 pub language: Vec<String>,
170 #[serde(
171 default,
172 skip_serializing_if = "Option::is_none",
173 rename = "bureauCode"
174 )]
175 pub bureau_code: Option<Value>,
176 #[serde(
177 default,
178 skip_serializing_if = "Option::is_none",
179 rename = "programCode"
180 )]
181 pub program_code: Option<Value>,
182 #[serde(
184 default,
185 skip_serializing_if = "Option::is_none",
186 rename = "describedBy"
187 )]
188 pub described_by: Option<String>,
189 #[serde(
190 default,
191 skip_serializing_if = "Option::is_none",
192 rename = "describedByType"
193 )]
194 pub described_by_type: Option<String>,
195 #[serde(default, deserialize_with = "deserialize_null_as_default")]
196 pub references: Vec<String>,
197 #[serde(
198 default,
199 skip_serializing_if = "Option::is_none",
200 rename = "dataQuality"
201 )]
202 pub data_quality: Option<bool>,
203 #[serde(
204 default,
205 skip_serializing_if = "Option::is_none",
206 rename = "systemOfRecords"
207 )]
208 pub system_of_records: Option<String>,
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize)]
213pub struct Distribution {
214 #[serde(default, rename = "@type", skip_serializing_if = "Option::is_none")]
215 pub type_hint: Option<String>,
216 #[serde(default, skip_serializing_if = "Option::is_none")]
217 pub title: Option<String>,
218 #[serde(default, skip_serializing_if = "Option::is_none")]
219 pub description: Option<String>,
220 #[serde(
222 default,
223 skip_serializing_if = "Option::is_none",
224 rename = "downloadURL"
225 )]
226 pub download_url: Option<String>,
227 #[serde(default, skip_serializing_if = "Option::is_none", rename = "accessURL")]
229 pub access_url: Option<String>,
230 #[serde(default, skip_serializing_if = "Option::is_none", rename = "mediaType")]
232 pub media_type: Option<String>,
233 #[serde(default, skip_serializing_if = "Option::is_none")]
235 pub format: Option<String>,
236 #[serde(default, skip_serializing_if = "Option::is_none")]
237 pub license: Option<String>,
238 #[serde(
239 default,
240 skip_serializing_if = "Option::is_none",
241 rename = "describedBy"
242 )]
243 pub described_by: Option<String>,
244 #[serde(
245 default,
246 skip_serializing_if = "Option::is_none",
247 rename = "describedByType"
248 )]
249 pub described_by_type: Option<String>,
250}
251
252#[derive(Debug, Clone, Serialize, Deserialize)]
254pub struct Publisher {
255 #[serde(default, rename = "@type", skip_serializing_if = "Option::is_none")]
256 pub type_hint: Option<String>,
257 #[serde(default, skip_serializing_if = "Option::is_none")]
258 pub name: Option<String>,
259 #[serde(
261 default,
262 skip_serializing_if = "Option::is_none",
263 rename = "subOrganizationOf"
264 )]
265 pub sub_organization_of: Option<Box<Publisher>>,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct ContactPoint {
271 #[serde(default, rename = "@type", skip_serializing_if = "Option::is_none")]
272 pub type_hint: Option<String>,
273 #[serde(default, skip_serializing_if = "Option::is_none")]
275 pub fn_: Option<String>,
276 #[serde(default, skip_serializing_if = "Option::is_none", rename = "hasEmail")]
278 pub has_email: Option<String>,
279}
280
281impl ContactPoint {
283 pub fn with_name(name: impl Into<String>) -> Self {
285 Self {
286 type_hint: None,
287 fn_: Some(name.into()),
288 has_email: None,
289 }
290 }
291}
292
293#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct OrganizationsResponse {
296 #[serde(default, deserialize_with = "deserialize_null_as_default")]
297 pub organizations: Vec<Organization>,
298 #[serde(default)]
299 pub total: i64,
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize)]
304pub struct Organization {
305 #[serde(default, skip_serializing_if = "Option::is_none")]
306 pub id: Option<String>,
307 #[serde(default, skip_serializing_if = "Option::is_none")]
308 pub name: Option<String>,
309 #[serde(default, skip_serializing_if = "Option::is_none")]
310 pub slug: Option<String>,
311 #[serde(default, skip_serializing_if = "Option::is_none")]
312 pub description: Option<String>,
313 #[serde(default, skip_serializing_if = "Option::is_none")]
314 pub logo: Option<String>,
315 #[serde(default, skip_serializing_if = "Option::is_none")]
316 pub organization_type: Option<String>,
317 #[serde(default, skip_serializing_if = "Option::is_none")]
318 pub dataset_count: Option<i64>,
319 #[serde(default, skip_serializing_if = "Option::is_none")]
320 pub source_count: Option<i64>,
321 #[serde(default, deserialize_with = "deserialize_null_as_default")]
322 pub aliases: Vec<String>,
323}
324
325#[derive(Debug, Clone, Serialize, Deserialize)]
327pub struct KeywordsResponse {
328 #[serde(default, deserialize_with = "deserialize_null_as_default")]
329 pub keywords: Vec<KeywordCount>,
330 #[serde(default)]
331 pub total: i64,
332 #[serde(default)]
333 pub size: i64,
334 #[serde(default)]
335 pub min_count: i64,
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize)]
340pub struct KeywordCount {
341 pub keyword: String,
342 pub count: i64,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct LocationsResponse {
348 #[serde(default, deserialize_with = "deserialize_null_as_default")]
349 pub locations: Vec<Location>,
350 #[serde(default)]
351 pub total: i64,
352 #[serde(default)]
353 pub size: i64,
354}
355
356#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct Location {
359 pub id: String,
360 pub display_name: String,
361}
362
363#[derive(Debug, Clone, Serialize, Deserialize)]
366pub struct HarvestRecord {
367 #[serde(default, skip_serializing_if = "Option::is_none")]
368 pub id: Option<String>,
369 #[serde(default, skip_serializing_if = "Option::is_none")]
370 pub ckan_id: Option<String>,
371 #[serde(default, skip_serializing_if = "Option::is_none")]
372 pub identifier: Option<String>,
373 #[serde(default, skip_serializing_if = "Option::is_none")]
374 pub parent_identifier: Option<String>,
375 #[serde(default, skip_serializing_if = "Option::is_none")]
376 pub harvest_job_id: Option<String>,
377 #[serde(default, skip_serializing_if = "Option::is_none")]
378 pub harvest_source_id: Option<String>,
379 #[serde(default, skip_serializing_if = "Option::is_none")]
380 pub action: Option<String>,
381 #[serde(default, skip_serializing_if = "Option::is_none")]
382 pub status: Option<String>,
383 #[serde(default, skip_serializing_if = "Option::is_none")]
384 pub date_created: Option<String>,
385 #[serde(default, skip_serializing_if = "Option::is_none")]
386 pub date_finished: Option<String>,
387 #[serde(default, skip_serializing_if = "Option::is_none")]
388 pub source_hash: Option<String>,
389 #[serde(default, skip_serializing_if = "Option::is_none")]
391 pub source_raw: Option<Value>,
392 #[serde(default, skip_serializing_if = "Option::is_none")]
394 pub source_transform: Option<Value>,
395}