Skip to main content

origin_domain/
ids.rs

1//! Typed identifiers.
2//!
3//! Every id is a distinct type so that an `AccountId` can never be passed where a
4//! `JobId` is expected. All of them serialise as plain strings.
5
6use serde::{Deserialize, Serialize};
7use std::fmt;
8
9macro_rules! string_id {
10    ($(#[$meta:meta])* $name:ident) => {
11        $(#[$meta])*
12        // No `#[serde(transparent)]`: for a single-field tuple struct, serde_json
13        // already serialises as the bare inner value, and ts-rs cannot parse the
14        // attribute (it treats a one-field tuple struct as transparent on its own).
15        #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
16        #[cfg_attr(feature = "ts", derive(ts_rs::TS))]
17        pub struct $name(String);
18
19        impl $name {
20            /// A fresh random id.
21            pub fn generate() -> Self {
22                Self(uuid::Uuid::new_v4().to_string())
23            }
24
25            pub fn new(value: impl Into<String>) -> Self {
26                Self(value.into())
27            }
28
29            pub fn as_str(&self) -> &str {
30                &self.0
31            }
32
33            pub fn into_string(self) -> String {
34                self.0
35            }
36        }
37
38        impl fmt::Display for $name {
39            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40                f.write_str(&self.0)
41            }
42        }
43
44        impl From<String> for $name {
45            fn from(value: String) -> Self {
46                Self(value)
47            }
48        }
49
50        impl From<&str> for $name {
51            fn from(value: &str) -> Self {
52                Self(value.to_owned())
53            }
54        }
55    };
56}
57
58string_id!(
59    /// Identifies one configured account of one connector.
60    AccountId
61);
62string_id!(
63    /// Identifies a connector, e.g. `github`, `google-analytics`, `cloudflare`.
64    ConnectorId
65);
66string_id!(
67    /// Identifies an alert instance.
68    AlertId
69);
70string_id!(
71    /// Identifies a background job run.
72    JobId
73);
74string_id!(
75    /// Identifies one synchronisation run, used as a logging correlation id.
76    SyncId
77);
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn ids_serialise_as_plain_strings() {
85        let id = AccountId::new("acc-1");
86        assert_eq!(id.as_str(), "acc-1");
87        assert_eq!(id.to_string(), "acc-1");
88    }
89
90    #[test]
91    fn generated_ids_are_unique() {
92        assert_ne!(JobId::generate(), JobId::generate());
93    }
94}