nodedb_types/id/
qualified_collection.rs1use std::fmt;
11
12use serde::{Deserialize, Serialize};
13
14use super::DatabaseId;
15
16#[derive(
24 Debug,
25 Clone,
26 PartialEq,
27 Eq,
28 PartialOrd,
29 Ord,
30 Hash,
31 Serialize,
32 Deserialize,
33 zerompk::ToMessagePack,
34 zerompk::FromMessagePack,
35)]
36pub struct QualifiedCollection(String);
37
38impl QualifiedCollection {
39 pub fn new(database_id: DatabaseId, collection: &str) -> Self {
44 if database_id == DatabaseId::DEFAULT {
45 Self(collection.to_string())
46 } else {
47 Self(format!("{}/{}", database_id.as_u64(), collection))
48 }
49 }
50
51 pub fn from_stored(qualified: String) -> Self {
55 Self(qualified)
56 }
57
58 pub fn as_str(&self) -> &str {
59 &self.0
60 }
61
62 pub fn collection_name(&self, database_id: DatabaseId) -> &str {
65 if database_id == DatabaseId::DEFAULT {
66 return &self.0;
67 }
68 let prefix = format!("{}/", database_id.as_u64());
69 self.0.strip_prefix(prefix.as_str()).unwrap_or(&self.0)
70 }
71}
72
73impl fmt::Display for QualifiedCollection {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 f.write_str(&self.0)
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn default_database_yields_bare_name() {
85 let q = QualifiedCollection::new(DatabaseId::DEFAULT, "users");
86 assert_eq!(q.as_str(), "users");
87 assert_eq!(q.to_string(), "users");
88 }
89
90 #[test]
91 fn non_default_database_yields_prefixed_name() {
92 let q = QualifiedCollection::new(DatabaseId::new(7), "users");
93 assert_eq!(q.as_str(), "7/users");
94 }
95
96 #[test]
97 fn collection_name_inverts_new() {
98 let q = QualifiedCollection::new(DatabaseId::new(7), "users");
99 assert_eq!(q.collection_name(DatabaseId::new(7)), "users");
100 let bare = QualifiedCollection::new(DatabaseId::DEFAULT, "users");
101 assert_eq!(bare.collection_name(DatabaseId::DEFAULT), "users");
102 }
103
104 #[test]
105 fn serde_roundtrips_as_plain_string() {
106 let q = QualifiedCollection::new(DatabaseId::new(7), "users");
107 let json = sonic_rs::to_string(&q).expect("serialize");
108 assert_eq!(json, "\"7/users\"");
109 let decoded: QualifiedCollection = sonic_rs::from_str(&json).expect("deserialize");
110 assert_eq!(q, decoded);
111 }
112
113 #[test]
114 fn zerompk_roundtrips() {
115 let q = QualifiedCollection::new(DatabaseId::new(7), "users");
116 let bytes = zerompk::to_msgpack_vec(&q).expect("msgpack serialization must succeed");
117 let decoded: QualifiedCollection =
118 zerompk::from_msgpack(&bytes).expect("msgpack deserialization must succeed");
119 assert_eq!(q, decoded);
120 }
121
122 #[test]
123 fn equal_inputs_produce_equal_and_same_hash_values() {
124 use std::collections::hash_map::DefaultHasher;
125 use std::hash::{Hash, Hasher};
126
127 let a = QualifiedCollection::new(DatabaseId::new(7), "users");
128 let b = QualifiedCollection::new(DatabaseId::new(7), "users");
129 assert_eq!(a, b);
130
131 let mut ha = DefaultHasher::new();
132 a.hash(&mut ha);
133 let mut hb = DefaultHasher::new();
134 b.hash(&mut hb);
135 assert_eq!(ha.finish(), hb.finish());
136 }
137
138 #[test]
139 fn from_stored_does_not_qualify() {
140 let q = QualifiedCollection::from_stored("7/users".to_string());
141 assert_eq!(q.as_str(), "7/users");
142 }
143}