Skip to main content

yugendb_core/
key.rs

1//! Namespace, collection name, and key validation.
2
3use std::fmt::{Display, Formatter};
4
5use crate::{Result, YugenDbError};
6
7const DEFAULT_NAME: &str = "default";
8
9fn validate_component(kind: &str, value: &str) -> Result<()> {
10    if value.is_empty() {
11        return Err(match kind {
12            "namespace" => YugenDbError::invalid_namespace("namespace must not be empty"),
13            "collection" => YugenDbError::invalid_collection("collection name must not be empty"),
14            "key" => YugenDbError::invalid_key("key must not be empty"),
15            _ => YugenDbError::internal_error("unknown key component kind"),
16        });
17    }
18
19    if value.chars().any(char::is_control) {
20        return Err(match kind {
21            "namespace" => {
22                YugenDbError::invalid_namespace("namespace must not contain control characters")
23            }
24            "collection" => YugenDbError::invalid_collection(
25                "collection name must not contain control characters",
26            ),
27            "key" => YugenDbError::invalid_key("key must not contain control characters"),
28            _ => YugenDbError::internal_error("unknown key component kind"),
29        });
30    }
31
32    Ok(())
33}
34
35/// Logical storage partition above collections.
36#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub struct Namespace(String);
38
39impl Namespace {
40    /// Creates a validated namespace.
41    pub fn new(value: impl Into<String>) -> Result<Self> {
42        let value = value.into();
43        validate_component("namespace", &value)?;
44        Ok(Self(value))
45    }
46
47    /// Returns the default namespace.
48    #[must_use]
49    pub fn default_namespace() -> Self {
50        Self(DEFAULT_NAME.to_owned())
51    }
52
53    /// Returns the namespace as a string slice.
54    #[must_use]
55    pub fn as_str(&self) -> &str {
56        &self.0
57    }
58}
59
60impl Default for Namespace {
61    fn default() -> Self {
62        Self::default_namespace()
63    }
64}
65
66impl TryFrom<String> for Namespace {
67    type Error = YugenDbError;
68
69    fn try_from(value: String) -> Result<Self> {
70        Self::new(value)
71    }
72}
73
74impl TryFrom<&str> for Namespace {
75    type Error = YugenDbError;
76
77    fn try_from(value: &str) -> Result<Self> {
78        Self::new(value)
79    }
80}
81
82impl AsRef<str> for Namespace {
83    fn as_ref(&self) -> &str {
84        self.as_str()
85    }
86}
87
88impl Display for Namespace {
89    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
90        formatter.write_str(self.as_str())
91    }
92}
93
94/// Logical collection name inside a namespace.
95#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
96pub struct CollectionName(String);
97
98impl CollectionName {
99    /// Creates a validated collection name.
100    pub fn new(value: impl Into<String>) -> Result<Self> {
101        let value = value.into();
102        validate_component("collection", &value)?;
103        Ok(Self(value))
104    }
105
106    /// Returns the default collection name.
107    #[must_use]
108    pub fn default_collection() -> Self {
109        Self(DEFAULT_NAME.to_owned())
110    }
111
112    /// Returns the collection name as a string slice.
113    #[must_use]
114    pub fn as_str(&self) -> &str {
115        &self.0
116    }
117}
118
119impl Default for CollectionName {
120    fn default() -> Self {
121        Self::default_collection()
122    }
123}
124
125impl TryFrom<String> for CollectionName {
126    type Error = YugenDbError;
127
128    fn try_from(value: String) -> Result<Self> {
129        Self::new(value)
130    }
131}
132
133impl TryFrom<&str> for CollectionName {
134    type Error = YugenDbError;
135
136    fn try_from(value: &str) -> Result<Self> {
137        Self::new(value)
138    }
139}
140
141impl AsRef<str> for CollectionName {
142    fn as_ref(&self) -> &str {
143        self.as_str()
144    }
145}
146
147impl Display for CollectionName {
148    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
149        formatter.write_str(self.as_str())
150    }
151}
152
153/// Stable key inside a namespace and collection.
154#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
155pub struct Key(String);
156
157impl Key {
158    /// Creates a validated key.
159    pub fn new(value: impl Into<String>) -> Result<Self> {
160        let value = value.into();
161        validate_component("key", &value)?;
162        Ok(Self(value))
163    }
164
165    /// Returns the key as a string slice.
166    #[must_use]
167    pub fn as_str(&self) -> &str {
168        &self.0
169    }
170}
171
172impl TryFrom<String> for Key {
173    type Error = YugenDbError;
174
175    fn try_from(value: String) -> Result<Self> {
176        Self::new(value)
177    }
178}
179
180impl TryFrom<&str> for Key {
181    type Error = YugenDbError;
182
183    fn try_from(value: &str) -> Result<Self> {
184        Self::new(value)
185    }
186}
187
188impl AsRef<str> for Key {
189    fn as_ref(&self) -> &str {
190        self.as_str()
191    }
192}
193
194impl Display for Key {
195    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
196        formatter.write_str(self.as_str())
197    }
198}