cognite/dto/
identity.rs

1use std::collections::HashMap;
2
3use serde::{ser::SerializeSeq, Deserialize, Serialize};
4
5use crate::{
6    models::instances::InstanceId, ApiErrorDetail, FromErrorDetail, IntegerStringOrObject,
7};
8
9#[derive(Serialize, Deserialize, Debug, Hash, PartialEq, Eq, Clone)]
10#[serde(untagged, rename_all_fields = "camelCase")]
11/// An Identity represents a CDF resource either by internal ID or external ID.
12pub enum Identity {
13    /// Identity by CDF internal ID.
14    Id {
15        /// Numerical internal ID.
16        id: i64,
17    },
18    /// Identity by CDF external ID.
19    ExternalId {
20        /// External ID, unique for the given resource.
21        external_id: String,
22    },
23}
24
25impl Identity {
26    /// Create an identity using a CDF internal ID.
27    pub fn id(id: i64) -> Self {
28        Identity::Id { id }
29    }
30
31    /// Create an identity using a CDF external ID.
32    pub fn external_id(external_id: impl Into<String>) -> Self {
33        Identity::ExternalId {
34            external_id: external_id.into(),
35        }
36    }
37
38    /// Consume self and return Some if this is an external ID.
39    pub fn into_external_id(self) -> Option<String> {
40        match self {
41            Identity::ExternalId { external_id } => Some(external_id),
42            _ => None,
43        }
44    }
45
46    /// Consume self and return Some if this is an internal ID.
47    pub fn into_id(self) -> Option<i64> {
48        match self {
49            Identity::Id { id } => Some(id),
50            _ => None,
51        }
52    }
53
54    /// Get self as external ID.
55    pub fn as_external_id(&self) -> Option<&String> {
56        match self {
57            Identity::ExternalId { external_id } => Some(external_id),
58            _ => None,
59        }
60    }
61
62    /// Get self as internal ID.
63    pub fn as_id(&self) -> Option<i64> {
64        match self {
65            Identity::Id { id } => Some(*id),
66            _ => None,
67        }
68    }
69}
70
71impl Default for Identity {
72    fn default() -> Self {
73        Identity::Id { id: 0 }
74    }
75}
76
77impl From<i64> for Identity {
78    fn from(id: i64) -> Self {
79        Identity::Id { id }
80    }
81}
82
83impl From<&String> for Identity {
84    fn from(value: &String) -> Self {
85        Self::from(value.clone())
86    }
87}
88
89impl From<String> for Identity {
90    fn from(external_id: String) -> Self {
91        Identity::ExternalId { external_id }
92    }
93}
94
95impl From<&str> for Identity {
96    fn from(external_id: &str) -> Self {
97        Identity::ExternalId {
98            external_id: external_id.to_owned(),
99        }
100    }
101}
102
103impl FromErrorDetail for Identity {
104    fn from_detail(detail: &HashMap<String, Box<IntegerStringOrObject>>) -> Option<Self> {
105        ApiErrorDetail::get_integer(detail, "id")
106            .map(|id| Identity::Id { id })
107            .or_else(|| {
108                ApiErrorDetail::get_string(detail, "externalId").map(|id| Identity::ExternalId {
109                    external_id: id.to_owned(),
110                })
111            })
112    }
113}
114
115#[derive(Serialize, Deserialize, Debug, Clone)]
116#[serde(rename_all = "camelCase")]
117/// Wrapper around a cognite internal ID.
118pub struct CogniteId {
119    /// Internal ID.
120    id: i64,
121}
122
123impl FromErrorDetail for CogniteId {
124    fn from_detail(detail: &HashMap<String, Box<IntegerStringOrObject>>) -> Option<Self> {
125        ApiErrorDetail::get_integer(detail, "id").map(|id| CogniteId { id })
126    }
127}
128
129#[derive(Serialize, Deserialize, Debug, Clone, Default)]
130#[serde(rename_all = "camelCase")]
131/// Wrapper around a cognite external ID.
132pub struct CogniteExternalId {
133    /// External ID.
134    pub external_id: String,
135}
136
137impl FromErrorDetail for CogniteExternalId {
138    fn from_detail(detail: &HashMap<String, Box<IntegerStringOrObject>>) -> Option<Self> {
139        ApiErrorDetail::get_string(detail, "externalId").map(|external_id| CogniteExternalId {
140            external_id: external_id.to_owned(),
141        })
142    }
143}
144
145/// Trait indicating that a type can be compared to an identity.
146pub trait EqIdentity {
147    /// Return true if the identity given by `id` points to self.
148    fn eq(&self, id: &Identity) -> bool;
149}
150
151impl From<String> for CogniteExternalId {
152    fn from(external_id: String) -> Self {
153        CogniteExternalId { external_id }
154    }
155}
156
157impl From<i64> for CogniteId {
158    fn from(id: i64) -> Self {
159        CogniteId { id }
160    }
161}
162
163#[derive(Debug, Deserialize, Serialize, Clone, Hash, Eq, PartialEq)]
164#[serde(rename_all_fields = "camelCase")]
165#[serde(untagged)]
166/// Identity or instance ID.
167pub enum IdentityOrInstance {
168    /// Identity, external ID or internal ID.
169    Identity(Identity),
170    /// Instance ID, refering to a node in data modeling.
171    InstanceId {
172        /// Instance id.
173        instance_id: InstanceId,
174    },
175}
176
177impl IdentityOrInstance {
178    /// Create a new IdentityOrInstance using an internal ID.
179    pub fn id(id: i64) -> Self {
180        Self::Identity(Identity::id(id))
181    }
182
183    /// Create a new IdentityOrInstance using an external ID.
184    pub fn external_id(external_id: impl Into<String>) -> Self {
185        Self::Identity(Identity::external_id(external_id))
186    }
187
188    /// Create a new IdentityOrInstance using an instance ID.
189    pub fn instance_id(instance_id: impl Into<InstanceId>) -> Self {
190        Self::InstanceId {
191            instance_id: instance_id.into(),
192        }
193    }
194
195    /// Get self as internal ID.
196    pub fn as_id(&self) -> Option<i64> {
197        match self {
198            Self::Identity(i) => i.as_id(),
199            _ => None,
200        }
201    }
202
203    /// Get self as external ID.
204    pub fn as_external_id(&self) -> Option<&String> {
205        match self {
206            Self::Identity(i) => i.as_external_id(),
207            _ => None,
208        }
209    }
210
211    /// Get self as identity.
212    pub fn as_identity(&self) -> Option<&Identity> {
213        match self {
214            Self::Identity(i) => Some(i),
215            _ => None,
216        }
217    }
218
219    /// Get self as instance id.
220    pub fn as_instance_id(&self) -> Option<&InstanceId> {
221        match self {
222            Self::InstanceId { instance_id: i } => Some(i),
223            _ => None,
224        }
225    }
226}
227
228// Default impl is not super meaningful, but is useful in some cases
229impl Default for IdentityOrInstance {
230    fn default() -> Self {
231        Self::Identity(Default::default())
232    }
233}
234
235impl From<&str> for IdentityOrInstance {
236    fn from(value: &str) -> Self {
237        Self::Identity(Identity::from(value))
238    }
239}
240
241impl From<&String> for IdentityOrInstance {
242    fn from(value: &String) -> Self {
243        Self::Identity(Identity::from(value))
244    }
245}
246
247impl From<String> for IdentityOrInstance {
248    fn from(value: String) -> Self {
249        Self::Identity(Identity::from(value))
250    }
251}
252
253impl From<i64> for IdentityOrInstance {
254    fn from(value: i64) -> Self {
255        Self::Identity(Identity::from(value))
256    }
257}
258
259impl From<Identity> for IdentityOrInstance {
260    fn from(value: Identity) -> Self {
261        Self::Identity(value)
262    }
263}
264
265impl From<InstanceId> for IdentityOrInstance {
266    fn from(value: InstanceId) -> Self {
267        Self::InstanceId { instance_id: value }
268    }
269}
270
271impl PartialEq<i64> for IdentityOrInstance {
272    fn eq(&self, other: &i64) -> bool {
273        self.as_id().as_ref() == Some(other)
274    }
275}
276
277impl PartialEq<str> for IdentityOrInstance {
278    fn eq(&self, other: &str) -> bool {
279        self.as_external_id().map(|a| a.as_str()) == Some(other)
280    }
281}
282
283impl PartialEq<InstanceId> for IdentityOrInstance {
284    fn eq(&self, other: &InstanceId) -> bool {
285        self.as_instance_id() == Some(other)
286    }
287}
288
289impl PartialEq<Identity> for IdentityOrInstance {
290    fn eq(&self, other: &Identity) -> bool {
291        self.as_identity() == Some(other)
292    }
293}
294
295impl FromErrorDetail for IdentityOrInstance {
296    fn from_detail(detail: &HashMap<String, Box<IntegerStringOrObject>>) -> Option<Self> {
297        if let Some(object) = ApiErrorDetail::get_object(detail, "instanceId") {
298            match (
299                ApiErrorDetail::get_string(object, "space"),
300                ApiErrorDetail::get_string(object, "externalId"),
301            ) {
302                (Some(space), Some(external_id)) => Some(Self::InstanceId {
303                    instance_id: InstanceId {
304                        space: space.to_owned(),
305                        external_id: external_id.to_owned(),
306                    },
307                }),
308                _ => None,
309            }
310        } else {
311            Identity::from_detail(detail).map(Self::Identity)
312        }
313    }
314}
315
316/// Serializable wrapper around a list of identities.
317/// This implements serialize for individual strings or integers.
318/// as well as lists of these. This is useful for the many endpoints that
319/// accept lists of identities.
320pub struct IdentityList<R>(R);
321
322impl<R> From<R> for IdentityList<R> {
323    fn from(value: R) -> Self {
324        IdentityList(value)
325    }
326}
327
328/// Serializable wrapper around a list of identity or instance IDs.
329/// This implements serialize for individual strings, integers or instance IDs,
330/// as well as lists of these.
331/// This is useful for the many endpoints that accept lists of identities.
332pub struct IdentityOrInstanceList<R>(R);
333
334impl<T> Serialize for IdentityOrInstanceList<T>
335where
336    IdentityList<T>: Serialize,
337    T: Copy,
338{
339    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
340    where
341        S: serde::Serializer,
342    {
343        IdentityList(self.0).serialize(serializer)
344    }
345}
346
347impl<R> From<R> for IdentityOrInstanceList<R> {
348    fn from(value: R) -> Self {
349        IdentityOrInstanceList(value)
350    }
351}
352
353macro_rules! identity_list_ser_directly {
354    ($r:ident, $t:ty) => {
355        impl Serialize for $r<$t> {
356            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
357            where
358                S: serde::Serializer,
359            {
360                self.0.serialize(serializer)
361            }
362        }
363    };
364    ($r:ident, $t:ty, $n:ident) => {
365        impl<const $n: usize> Serialize for $r<$t> {
366            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
367            where
368                S: serde::Serializer,
369            {
370                self.0.serialize(serializer)
371            }
372        }
373    };
374}
375
376identity_list_ser_directly!(IdentityList, &Vec<Identity>);
377identity_list_ser_directly!(IdentityOrInstanceList, &Vec<IdentityOrInstance>);
378identity_list_ser_directly!(IdentityList, &Vec<CogniteExternalId>);
379identity_list_ser_directly!(IdentityList, &Vec<CogniteId>);
380identity_list_ser_directly!(IdentityList, &Vec<&Identity>);
381identity_list_ser_directly!(IdentityOrInstanceList, &Vec<&IdentityOrInstance>);
382identity_list_ser_directly!(IdentityList, &Vec<&CogniteExternalId>);
383identity_list_ser_directly!(IdentityList, &Vec<&CogniteId>);
384identity_list_ser_directly!(IdentityList, &[Identity]);
385identity_list_ser_directly!(IdentityOrInstanceList, &[IdentityOrInstance]);
386identity_list_ser_directly!(IdentityList, &[CogniteExternalId]);
387identity_list_ser_directly!(IdentityList, &[CogniteId]);
388identity_list_ser_directly!(IdentityList, &[&Identity]);
389identity_list_ser_directly!(IdentityOrInstanceList, &[&IdentityOrInstance]);
390identity_list_ser_directly!(IdentityList, &[&CogniteExternalId]);
391identity_list_ser_directly!(IdentityList, &[&CogniteId]);
392identity_list_ser_directly!(IdentityList, &[Identity; N], N);
393identity_list_ser_directly!(IdentityOrInstanceList, &[IdentityOrInstance; N], N);
394identity_list_ser_directly!(IdentityList, &[CogniteExternalId; N], N);
395identity_list_ser_directly!(IdentityList, &[CogniteId; N], N);
396identity_list_ser_directly!(IdentityList, &[&Identity; N], N);
397identity_list_ser_directly!(IdentityOrInstanceList, &[&IdentityOrInstance; N], N);
398identity_list_ser_directly!(IdentityList, &[&CogniteExternalId; N], N);
399identity_list_ser_directly!(IdentityList, &[&CogniteId; N], N);
400
401#[derive(Serialize)]
402#[serde(rename_all = "camelCase")]
403struct ExternalIdRef<'a, T> {
404    external_id: &'a T,
405}
406
407macro_rules! identity_list_ser_external_id {
408    ($t:ty) => {
409        impl Serialize for IdentityList<$t> {
410            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
411            where
412                S: serde::Serializer,
413            {
414                let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
415                for id in self.0.iter() {
416                    seq.serialize_element(&ExternalIdRef { external_id: id })?;
417                }
418                seq.end()
419            }
420        }
421    };
422
423    ($t:ty, $n:ident) => {
424        impl<const $n: usize> Serialize for IdentityList<$t> {
425            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
426            where
427                S: serde::Serializer,
428            {
429                let mut seq = serializer.serialize_seq(Some($n))?;
430                for id in self.0.iter() {
431                    seq.serialize_element(&ExternalIdRef { external_id: id })?;
432                }
433                seq.end()
434            }
435        }
436    };
437}
438identity_list_ser_external_id!(&Vec<String>);
439identity_list_ser_external_id!(&[String]);
440identity_list_ser_external_id!(&[String; N], N);
441identity_list_ser_external_id!(&Vec<&String>);
442identity_list_ser_external_id!(&[&String]);
443identity_list_ser_external_id!(&[&String; N], N);
444identity_list_ser_external_id!(&Vec<&str>);
445identity_list_ser_external_id!(&[&str]);
446identity_list_ser_external_id!(&[&str; N], N);
447
448macro_rules! identity_list_ser_id {
449    ($t:ty) => {
450        impl Serialize for IdentityList<$t> {
451            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
452            where
453                S: serde::Serializer,
454            {
455                let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
456                for id in self.0.iter() {
457                    seq.serialize_element(&CogniteId { id: *id })?;
458                }
459                seq.end()
460            }
461        }
462    };
463
464    ($t:ty, $n:ident) => {
465        impl<const N: usize> Serialize for IdentityList<$t> {
466            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
467            where
468                S: serde::Serializer,
469            {
470                let mut seq = serializer.serialize_seq(Some(N))?;
471                for id in self.0.iter() {
472                    seq.serialize_element(&CogniteId { id: *id })?;
473                }
474                seq.end()
475            }
476        }
477    };
478}
479
480identity_list_ser_id!(&Vec<i64>);
481identity_list_ser_id!(&[i64]);
482identity_list_ser_id!(&[i64; N], N);
483
484#[derive(Serialize)]
485#[serde(rename_all = "camelCase")]
486struct InstanceIdRef<'a> {
487    instance_id: &'a InstanceId,
488}
489
490macro_rules! identity_list_ser_instance_id {
491    ($t:ty) => {
492        impl Serialize for IdentityOrInstanceList<$t> {
493            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
494            where
495                S: serde::Serializer,
496            {
497                let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
498                for id in self.0.iter() {
499                    seq.serialize_element(&InstanceIdRef { instance_id: id })?;
500                }
501                seq.end()
502            }
503        }
504    };
505
506    ($t:ty, $n:ident) => {
507        impl<const N: usize> Serialize for IdentityOrInstanceList<$t> {
508            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
509            where
510                S: serde::Serializer,
511            {
512                let mut seq = serializer.serialize_seq(Some(N))?;
513                for id in self.0.iter() {
514                    seq.serialize_element(&InstanceIdRef { instance_id: id })?;
515                }
516                seq.end()
517            }
518        }
519    };
520}
521
522identity_list_ser_instance_id!(&Vec<InstanceId>);
523identity_list_ser_instance_id!(&[InstanceId]);
524identity_list_ser_instance_id!(&[InstanceId; N], N);
525identity_list_ser_instance_id!(&Vec<&InstanceId>);
526identity_list_ser_instance_id!(&[&InstanceId]);
527identity_list_ser_instance_id!(&[&InstanceId; N], N);
528
529macro_rules! identity_list_ser_single {
530    ($r:ident, $t:ty) => {
531        impl Serialize for $r<$t> {
532            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
533            where
534                S: serde::Serializer,
535            {
536                Serialize::serialize(&$r(&[self.0]), serializer)
537            }
538        }
539    };
540}
541
542identity_list_ser_single!(IdentityList, i64);
543identity_list_ser_single!(IdentityList, &str);
544identity_list_ser_single!(IdentityList, &String);
545identity_list_ser_single!(IdentityOrInstanceList, &InstanceId);
546identity_list_ser_single!(IdentityList, &Identity);
547identity_list_ser_single!(IdentityOrInstanceList, &IdentityOrInstance);
548identity_list_ser_single!(IdentityList, &CogniteExternalId);
549identity_list_ser_single!(IdentityList, &CogniteId);