Skip to main content

shopify_client/common/
gid.rs

1use std::fmt;
2
3pub const GID_PREFIX: &str = "gid://shopify/";
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct Gid<'a> {
7    kind: &'a str,
8    id: &'a str,
9}
10
11impl<'a> Gid<'a> {
12    pub const ORDER: &'static str = "Order";
13
14    pub fn of(kind: &'a str, id: &'a str) -> Self {
15        Self {
16            kind,
17            id: Self::id_of(id),
18        }
19    }
20
21    pub fn id_of(value: &str) -> &str {
22        match value.strip_prefix(GID_PREFIX) {
23            Some(rest) => rest
24                .split('?')
25                .next()
26                .unwrap_or(rest)
27                .rsplit('/')
28                .next()
29                .unwrap_or(rest),
30            None => value,
31        }
32    }
33
34    pub fn kind(&self) -> &'a str {
35        self.kind
36    }
37
38    pub fn id(&self) -> &'a str {
39        self.id
40    }
41}
42
43impl fmt::Display for Gid<'_> {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        write!(f, "{GID_PREFIX}{}/{}", self.kind, self.id)
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn renders_a_gid_from_a_bare_id() {
55        assert_eq!(
56            Gid::of(Gid::ORDER, "1001").to_string(),
57            "gid://shopify/Order/1001"
58        );
59    }
60
61    #[test]
62    fn building_from_a_gid_is_idempotent() {
63        let once = Gid::of(Gid::ORDER, "1001").to_string();
64        assert_eq!(Gid::of(Gid::ORDER, &once).to_string(), once);
65    }
66
67    #[test]
68    fn id_of_strips_the_prefix_and_the_type() {
69        assert_eq!(Gid::id_of("gid://shopify/Order/1001"), "1001");
70        assert_eq!(Gid::id_of("gid://shopify/ProductVariant/11"), "11");
71    }
72
73    #[test]
74    fn id_of_drops_query_parameters() {
75        assert_eq!(
76            Gid::id_of("gid://shopify/Order/1001?namespace=custom"),
77            "1001"
78        );
79    }
80
81    #[test]
82    fn id_of_leaves_a_value_that_is_not_a_gid_alone() {
83        assert_eq!(Gid::id_of("1001"), "1001");
84        assert_eq!(Gid::id_of(""), "");
85        assert_eq!(Gid::id_of("shopify/Order/1001"), "shopify/Order/1001");
86    }
87
88    #[test]
89    fn parts_are_readable_back() {
90        let gid = Gid::of(Gid::ORDER, "gid://shopify/Order/1001");
91        assert_eq!(gid.kind(), "Order");
92        assert_eq!(gid.id(), "1001");
93    }
94}