Skip to main content

spiral/api/project/
objects.rs

1// Generated by tools/service-contracts/rust.py. Do not edit.
2#![doc = "Generated transport-independent contract objects."]
3
4use std::error::Error as StdError;
5use std::fmt::{self, Display, Formatter};
6
7use serde::{Deserialize, Deserializer, Serialize};
8use serde_json::Value;
9use spiral_contract::error::{ErrorEnvelope, ServiceError};
10use spiral_contract::strict::{DeserializeStrict, Strict};
11use uuid::Uuid;
12
13/// Create using the Organization storage default and optional Volume. A prefix has at most 25
14/// lowercase ASCII letters, digits or hyphens.
15#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16pub struct CreateProjectRequest {
17    /// Contract field description.
18    #[serde(rename = "description")]
19    #[serde(default, skip_serializing_if = "Option::is_none")]
20    pub description: Option<String>,
21    /// Contract field idPrefix.
22    #[serde(rename = "idPrefix")]
23    #[serde(default, skip_serializing_if = "Option::is_none")]
24    pub id_prefix: Option<String>,
25    /// Contract field volumeId.
26    #[serde(rename = "volumeId")]
27    #[serde(default, skip_serializing_if = "Option::is_none")]
28    pub volume_id: Option<String>,
29}
30impl<'de> DeserializeStrict<'de> for CreateProjectRequest {
31    fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
32        #[derive(Deserialize)]
33        #[serde(deny_unknown_fields)]
34        struct __Wire {
35            #[serde(rename = "description")]
36            #[serde(default)]
37            description: Strict<Option<String>>,
38            #[serde(rename = "idPrefix")]
39            #[serde(default)]
40            id_prefix: Strict<Option<String>>,
41            #[serde(rename = "volumeId")]
42            #[serde(default)]
43            volume_id: Strict<Option<String>>,
44        }
45        let wire = __Wire::deserialize(deserializer)?;
46        Ok(Self {
47            description: wire.description.0,
48            id_prefix: wire.id_prefix.0,
49            volume_id: wire.volume_id.0,
50        })
51    }
52}
53
54/// The created Project. Creation also provisions storage, grants and the Catalog.
55#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
56pub struct CreateProjectResponse {
57    /// Contract field project.
58    #[serde(rename = "project")]
59    pub project: Project,
60}
61impl<'de> DeserializeStrict<'de> for CreateProjectResponse {
62    fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
63        #[derive(Deserialize)]
64        #[serde(deny_unknown_fields)]
65        struct __Wire {
66            #[serde(rename = "project")]
67            project: Strict<Project>,
68        }
69        let wire = __Wire::deserialize(deserializer)?;
70        Ok(Self {
71            project: wire.project.0,
72        })
73    }
74}
75
76/// Live continuation request. Page size defaults to 100 and must be 1..=1000. Tokens expire after
77/// one hour and are bound to the credential, operation, filters and page size.
78#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
79pub struct ListProjectsRequest {
80    /// Contract field pageSize.
81    #[serde(rename = "pageSize")]
82    #[serde(default, skip_serializing_if = "Option::is_none")]
83    pub page_size: Option<u32>,
84    /// Contract field pageToken.
85    #[serde(rename = "pageToken")]
86    #[serde(default, skip_serializing_if = "Option::is_none")]
87    pub page_token: Option<String>,
88}
89impl<'de> DeserializeStrict<'de> for ListProjectsRequest {
90    fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
91        #[derive(Deserialize)]
92        #[serde(deny_unknown_fields)]
93        struct __Wire {
94            #[serde(rename = "pageSize")]
95            #[serde(default)]
96            page_size: Strict<Option<u32>>,
97            #[serde(rename = "pageToken")]
98            #[serde(default)]
99            page_token: Strict<Option<String>>,
100        }
101        let wire = __Wire::deserialize(deserializer)?;
102        Ok(Self {
103            page_size: wire.page_size.0,
104            page_token: wire.page_token.0,
105        })
106    }
107}
108
109/// The saved revision and document, or revision zero and no document when absent.
110#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
111pub struct Presentation {
112    /// Contract field revision.
113    #[serde(rename = "revision")]
114    pub revision: i32,
115    /// Contract field value.
116    #[serde(rename = "value")]
117    #[serde(default, skip_serializing_if = "Option::is_none")]
118    pub value: Option<Value>,
119}
120impl<'de> DeserializeStrict<'de> for Presentation {
121    fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
122        #[derive(Deserialize)]
123        #[serde(deny_unknown_fields)]
124        struct __Wire {
125            #[serde(rename = "revision")]
126            revision: Strict<i32>,
127            #[serde(rename = "value")]
128            #[serde(default)]
129            value: Strict<Option<Value>>,
130        }
131        let wire = __Wire::deserialize(deserializer)?;
132        Ok(Self {
133            revision: wire.revision.0,
134            value: wire.value.0,
135        })
136    }
137}
138
139/// A 64-character hexadecimal key for shared presentation state.
140#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
141pub struct PresentationKey {
142    /// Contract field key.
143    #[serde(rename = "key")]
144    pub key: String,
145}
146impl<'de> DeserializeStrict<'de> for PresentationKey {
147    fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
148        #[derive(Deserialize)]
149        #[serde(deny_unknown_fields)]
150        struct __Wire {
151            #[serde(rename = "key")]
152            key: Strict<String>,
153        }
154        let wire = __Wire::deserialize(deserializer)?;
155        Ok(Self { key: wire.key.0 })
156    }
157}
158
159/// Project identity, owning Organization and optional description.
160#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
161pub struct Project {
162    /// Contract field description.
163    #[serde(rename = "description")]
164    #[serde(default, skip_serializing_if = "Option::is_none")]
165    pub description: Option<String>,
166    /// Contract field id.
167    #[serde(rename = "id")]
168    pub id: String,
169    /// Contract field organizationId.
170    #[serde(rename = "organizationId")]
171    pub organization_id: String,
172}
173impl<'de> DeserializeStrict<'de> for Project {
174    fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
175        #[derive(Deserialize)]
176        #[serde(deny_unknown_fields)]
177        struct __Wire {
178            #[serde(rename = "description")]
179            #[serde(default)]
180            description: Strict<Option<String>>,
181            #[serde(rename = "id")]
182            id: Strict<String>,
183            #[serde(rename = "organizationId")]
184            organization_id: Strict<String>,
185        }
186        let wire = __Wire::deserialize(deserializer)?;
187        Ok(Self {
188            description: wire.description.0,
189            id: wire.id.0,
190            organization_id: wire.organization_id.0,
191        })
192    }
193}
194
195/// Accessible Projects in ascending ID order. This is a live listing: changes behind the cursor
196/// require a new traversal.
197#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
198pub struct ProjectPage {
199    /// Contract field items.
200    #[serde(rename = "items")]
201    pub items: Vec<Project>,
202    /// Contract field nextPageToken.
203    #[serde(rename = "nextPageToken")]
204    #[serde(default, skip_serializing_if = "Option::is_none")]
205    pub next_page_token: Option<String>,
206}
207impl<'de> DeserializeStrict<'de> for ProjectPage {
208    fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
209        #[derive(Deserialize)]
210        #[serde(deny_unknown_fields)]
211        struct __Wire {
212            #[serde(rename = "items")]
213            items: Strict<Vec<Project>>,
214            #[serde(rename = "nextPageToken")]
215            #[serde(default)]
216            next_page_token: Strict<Option<String>>,
217        }
218        let wire = __Wire::deserialize(deserializer)?;
219        Ok(Self {
220            items: wire.items.0,
221            next_page_token: wire.next_page_token.0,
222        })
223    }
224}
225
226/// Compare-and-swap one presentation. Revision zero creates it; value must be a JSON object of at
227/// most one MiB.
228#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
229pub struct SavePresentation {
230    /// Contract field key.
231    #[serde(rename = "key")]
232    pub key: String,
233    /// Contract field revision.
234    #[serde(rename = "revision")]
235    pub revision: i32,
236    /// Contract field value.
237    #[serde(rename = "value")]
238    pub value: Value,
239}
240impl<'de> DeserializeStrict<'de> for SavePresentation {
241    fn deserialize_strict<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
242        #[derive(Deserialize)]
243        #[serde(deny_unknown_fields)]
244        struct __Wire {
245            #[serde(rename = "key")]
246            key: Strict<String>,
247            #[serde(rename = "revision")]
248            revision: Strict<i32>,
249            #[serde(rename = "value")]
250            value: Strict<Value>,
251        }
252        let wire = __Wire::deserialize(deserializer)?;
253        Ok(Self {
254            key: wire.key.0,
255            revision: wire.revision.0,
256            value: wire.value.0,
257        })
258    }
259}
260
261/// Typed errors declared by this service contract.
262#[derive(Clone, Debug, PartialEq, Eq)]
263pub enum ProjectError {
264    /// Project:Conflict.
265    Conflict { reason: String },
266    /// Project:InvalidArgument.
267    InvalidArgument { reason: String },
268    /// Project:LimitReached.
269    LimitReached { reason: String },
270    /// Project:NotFound.
271    NotFound { resource: String },
272}
273impl ProjectError {
274    /// HTTP status for this declared error.
275    pub fn status(&self) -> u16 {
276        match self {
277            Self::Conflict { .. } => 409,
278            Self::InvalidArgument { .. } => 400,
279            Self::LimitReached { .. } => 412,
280            Self::NotFound { .. } => 404,
281        }
282    }
283    /// Serialize only contract-declared error parameters.
284    pub fn envelope(&self, instance: String) -> ErrorEnvelope {
285        match self {
286            Self::Conflict { reason } => {
287                let mut envelope = ErrorEnvelope::new("CONFLICT", "Project:Conflict", instance);
288                envelope
289                    .parameters
290                    .insert("reason".into(), reason.to_string());
291                envelope
292            }
293            Self::InvalidArgument { reason } => {
294                let mut envelope =
295                    ErrorEnvelope::new("INVALID_ARGUMENT", "Project:InvalidArgument", instance);
296                envelope
297                    .parameters
298                    .insert("reason".into(), reason.to_string());
299                envelope
300            }
301            Self::LimitReached { reason } => {
302                let mut envelope =
303                    ErrorEnvelope::new("FAILED_PRECONDITION", "Project:LimitReached", instance);
304                envelope
305                    .parameters
306                    .insert("reason".into(), reason.to_string());
307                envelope
308            }
309            Self::NotFound { resource } => {
310                let mut envelope = ErrorEnvelope::new("NOT_FOUND", "Project:NotFound", instance);
311                envelope
312                    .parameters
313                    .insert("resource".into(), resource.to_string());
314                envelope
315            }
316        }
317    }
318    /// Decode a declared error and its typed error parameters.
319    pub fn decode_envelope(envelope: &ErrorEnvelope) -> Option<Self> {
320        if envelope.error_instance_id.len() != 36
321            || Uuid::parse_str(&envelope.error_instance_id).is_err()
322        {
323            return None;
324        }
325        match envelope.error_name.as_str() {
326            "Project:Conflict" => {
327                if envelope.error_code != "CONFLICT" {
328                    return None;
329                }
330                let reason = envelope.parameters.get("reason")?.clone();
331                Some(Self::Conflict { reason })
332            }
333            "Project:InvalidArgument" => {
334                if envelope.error_code != "INVALID_ARGUMENT" {
335                    return None;
336                }
337                let reason = envelope.parameters.get("reason")?.clone();
338                Some(Self::InvalidArgument { reason })
339            }
340            "Project:LimitReached" => {
341                if envelope.error_code != "FAILED_PRECONDITION" {
342                    return None;
343                }
344                let reason = envelope.parameters.get("reason")?.clone();
345                Some(Self::LimitReached { reason })
346            }
347            "Project:NotFound" => {
348                if envelope.error_code != "NOT_FOUND" {
349                    return None;
350                }
351                let resource = envelope.parameters.get("resource")?.clone();
352                Some(Self::NotFound { resource })
353            }
354            _ => None,
355        }
356    }
357}
358impl Display for ProjectError {
359    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
360        match self {
361            Self::Conflict { reason } => write!(formatter, "Project:Conflict (reason: {})", reason),
362            Self::InvalidArgument { reason } => {
363                write!(formatter, "Project:InvalidArgument (reason: {})", reason)
364            }
365            Self::LimitReached { reason } => {
366                write!(formatter, "Project:LimitReached (reason: {})", reason)
367            }
368            Self::NotFound { resource } => {
369                write!(formatter, "Project:NotFound (resource: {})", resource)
370            }
371        }
372    }
373}
374impl StdError for ProjectError {}
375impl ServiceError for ProjectError {
376    fn to_envelope(&self, instance: String) -> ErrorEnvelope {
377        Self::envelope(self, instance)
378    }
379    fn from_envelope(envelope: &ErrorEnvelope) -> Option<Self> {
380        Self::decode_envelope(envelope)
381    }
382}
383#[automatically_derived]
384impl Default for CreateProjectRequest {
385    fn default() -> Self {
386        Self {
387            description: None,
388            id_prefix: None,
389            volume_id: None,
390        }
391    }
392}
393#[automatically_derived]
394impl Default for ListProjectsRequest {
395    fn default() -> Self {
396        Self {
397            page_size: None,
398            page_token: None,
399        }
400    }
401}