Skip to main content

gonzalo_core/
key.rs

1//! Stable addressing for records.
2
3use serde::{Deserialize, Serialize};
4use std::fmt;
5
6/// The stable address of a record: `namespace/collection/id`.
7#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
8pub struct RecordKey {
9    pub namespace: String,
10    pub collection: String,
11    pub id: String,
12}
13
14impl RecordKey {
15    pub fn new(
16        namespace: impl Into<String>,
17        collection: impl Into<String>,
18        id: impl Into<String>,
19    ) -> Self {
20        Self {
21            namespace: namespace.into(),
22            collection: collection.into(),
23            id: id.into(),
24        }
25    }
26}
27
28impl fmt::Display for RecordKey {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        write!(f, "{}/{}/{}", self.namespace, self.collection, self.id)
31    }
32}
33
34/// A prefix used to list records. `None` fields match anything.
35#[derive(Clone, Debug, Default, PartialEq, Eq)]
36pub struct KeyPrefix {
37    pub namespace: Option<String>,
38    pub collection: Option<String>,
39}
40
41impl KeyPrefix {
42    pub fn matches(&self, key: &RecordKey) -> bool {
43        self.namespace.as_ref().is_none_or(|n| n == &key.namespace)
44            && self
45                .collection
46                .as_ref()
47                .is_none_or(|c| c == &key.collection)
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn display_is_slash_joined() {
57        let k = RecordKey::new("caliban", "topics", "rust-tips");
58        assert_eq!(k.to_string(), "caliban/topics/rust-tips");
59    }
60
61    #[test]
62    fn prefix_matches_on_set_fields_only() {
63        let k = RecordKey::new("caliban", "topics", "x");
64        assert!(
65            KeyPrefix {
66                namespace: Some("caliban".into()),
67                collection: None
68            }
69            .matches(&k)
70        );
71        assert!(
72            !KeyPrefix {
73                namespace: Some("other".into()),
74                collection: None
75            }
76            .matches(&k)
77        );
78        assert!(KeyPrefix::default().matches(&k));
79    }
80}