1use crate::error::{Error, Result};
5
6pub const SEPARATOR: u8 = b'/';
7pub const DATA_PREFIX: &[u8] = b"data";
8pub const INDEX_PREFIX: &[u8] = b"idx";
9pub const WASM_INDEX_PREFIX: &str = "index";
10pub const SUB_PREFIX: &[u8] = b"sub";
11pub const DEDUP_PREFIX: &[u8] = b"dedup";
12pub const META_PREFIX: &[u8] = b"meta";
13
14#[must_use]
15pub fn encode_data_key(entity: &str, id: &str) -> Vec<u8> {
16 let mut key = Vec::with_capacity(DATA_PREFIX.len() + 1 + entity.len() + 1 + id.len());
17 key.extend_from_slice(DATA_PREFIX);
18 key.push(SEPARATOR);
19 key.extend_from_slice(entity.as_bytes());
20 key.push(SEPARATOR);
21 key.extend_from_slice(id.as_bytes());
22 key
23}
24
25pub fn decode_data_key(key: &[u8]) -> Result<(String, String)> {
28 let parts: Vec<&[u8]> = key.split(|&b| b == SEPARATOR).collect();
29
30 if parts.len() != 3 || parts[0] != DATA_PREFIX {
31 return Err(Error::InvalidKey(format!("invalid data key: {key:?}")));
32 }
33
34 let entity = String::from_utf8(parts[1].to_vec())
35 .map_err(|_| Error::InvalidKey("entity not valid UTF-8".into()))?;
36 let id = String::from_utf8(parts[2].to_vec())
37 .map_err(|_| Error::InvalidKey("id not valid UTF-8".into()))?;
38
39 Ok((entity, id))
40}
41
42#[must_use]
43pub fn encode_index_key(entity: &str, field: &str, value: &[u8], id: &str) -> Vec<u8> {
44 let mut key = Vec::with_capacity(
45 INDEX_PREFIX.len() + 1 + entity.len() + 1 + field.len() + 1 + value.len() + 1 + id.len(),
46 );
47 key.extend_from_slice(INDEX_PREFIX);
48 key.push(SEPARATOR);
49 key.extend_from_slice(entity.as_bytes());
50 key.push(SEPARATOR);
51 key.extend_from_slice(field.as_bytes());
52 key.push(SEPARATOR);
53 key.extend_from_slice(value);
54 key.push(SEPARATOR);
55 key.extend_from_slice(id.as_bytes());
56 key
57}
58
59#[must_use]
60pub fn encode_index_prefix(entity: &str, field: &str, value: Option<&[u8]>) -> Vec<u8> {
61 let mut key = Vec::new();
62 key.extend_from_slice(INDEX_PREFIX);
63 key.push(SEPARATOR);
64 key.extend_from_slice(entity.as_bytes());
65 key.push(SEPARATOR);
66 key.extend_from_slice(field.as_bytes());
67
68 if let Some(v) = value {
69 key.push(SEPARATOR);
70 key.extend_from_slice(v);
71 }
72
73 key
74}
75
76#[must_use]
77pub fn encode_subscription_key(sub_id: &str) -> Vec<u8> {
78 let mut key = Vec::with_capacity(SUB_PREFIX.len() + 1 + sub_id.len());
79 key.extend_from_slice(SUB_PREFIX);
80 key.push(SEPARATOR);
81 key.extend_from_slice(sub_id.as_bytes());
82 key
83}
84
85#[must_use]
86pub fn encode_dedup_key(correlation_id: &str) -> Vec<u8> {
87 let mut key = Vec::with_capacity(DEDUP_PREFIX.len() + 1 + correlation_id.len());
88 key.extend_from_slice(DEDUP_PREFIX);
89 key.push(SEPARATOR);
90 key.extend_from_slice(correlation_id.as_bytes());
91 key
92}
93
94#[must_use]
95pub fn encode_meta_key(key_name: &str) -> Vec<u8> {
96 let mut key = Vec::with_capacity(META_PREFIX.len() + 1 + key_name.len());
97 key.extend_from_slice(META_PREFIX);
98 key.push(SEPARATOR);
99 key.extend_from_slice(key_name.as_bytes());
100 key
101}
102
103#[must_use]
104fn encode_i64_sortable(val: i64) -> [u8; 8] {
105 let bits = val.to_be_bytes();
106 let mut out = bits;
107 out[0] ^= 0x80;
108 out
109}
110
111#[must_use]
112fn encode_f64_sortable(val: f64) -> [u8; 8] {
113 let bits = val.to_bits().to_be_bytes();
114 let mut out = bits;
115 if val.is_sign_negative() {
116 for b in &mut out {
117 *b ^= 0xFF;
118 }
119 } else {
120 out[0] ^= 0x80;
121 }
122 out
123}
124
125pub fn encode_value_for_index(value: &serde_json::Value) -> Result<Vec<u8>> {
128 match value {
129 serde_json::Value::Null => Ok(b"null".to_vec()),
130 serde_json::Value::Bool(b) => {
131 if *b {
132 Ok(b"true".to_vec())
133 } else {
134 Ok(b"false".to_vec())
135 }
136 }
137 serde_json::Value::Number(n) => {
138 if let Some(i) = n.as_i64() {
139 Ok(encode_i64_sortable(i).to_vec())
140 } else if let Some(f) = n.as_f64() {
141 Ok(encode_f64_sortable(f).to_vec())
142 } else {
143 Ok(n.to_string().into_bytes())
144 }
145 }
146 serde_json::Value::String(s) => Ok(s.as_bytes().to_vec()),
147 _ => Err(Error::Validation(
148 "cannot index arrays or objects directly".into(),
149 )),
150 }
151}
152
153#[must_use]
154pub fn encode_index_definition_key(entity: &str) -> Vec<u8> {
155 format!("meta/index/{entity}").into_bytes()
156}
157
158#[must_use]
159pub fn encode_schema_key(entity: &str) -> Vec<u8> {
160 format!("meta/schema/{entity}").into_bytes()
161}
162
163#[must_use]
164pub fn encode_constraint_key(constraint_type: &str, entity: &str, name: &str) -> Vec<u8> {
165 format!("meta/constraint/{constraint_type}/{entity}/{name}").into_bytes()
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171
172 #[test]
173 fn test_encode_decode_data_key() {
174 let key = encode_data_key("users", "123");
175 assert_eq!(key, b"data/users/123");
176
177 let (entity, id) = decode_data_key(&key).unwrap();
178 assert_eq!(entity, "users");
179 assert_eq!(id, "123");
180 }
181
182 #[test]
183 fn test_encode_index_key() {
184 let key = encode_index_key("users", "email", b"test@example.com", "123");
185 assert_eq!(key, b"idx/users/email/test@example.com/123");
186 }
187
188 #[test]
189 fn test_encode_value_for_index() {
190 let val = serde_json::json!("hello");
191 let encoded = encode_value_for_index(&val).unwrap();
192 assert_eq!(encoded, b"hello");
193 }
194
195 #[test]
196 fn i64_encoding_preserves_sort_order() {
197 let values: &[i64] = &[i64::MIN, -1000, -1, 0, 1, 1000, i64::MAX];
198 let encoded: Vec<[u8; 8]> = values.iter().map(|v| encode_i64_sortable(*v)).collect();
199 for pair in encoded.windows(2) {
200 assert!(
201 pair[0] < pair[1],
202 "{:?} should sort before {:?}",
203 pair[0],
204 pair[1]
205 );
206 }
207 }
208
209 #[test]
210 fn f64_encoding_preserves_sort_order() {
211 let values: &[f64] = &[
212 f64::NEG_INFINITY,
213 -1e10,
214 -1.0,
215 -0.001,
216 0.0,
217 0.001,
218 1.0,
219 1e10,
220 f64::INFINITY,
221 ];
222 let encoded: Vec<[u8; 8]> = values.iter().map(|v| encode_f64_sortable(*v)).collect();
223 for pair in encoded.windows(2) {
224 assert!(
225 pair[0] < pair[1],
226 "{:?} should sort before {:?}",
227 pair[0],
228 pair[1]
229 );
230 }
231 }
232
233 #[test]
234 fn test_encode_index_definition_key() {
235 let key = encode_index_definition_key("users");
236 assert_eq!(key, b"meta/index/users");
237 }
238
239 #[test]
240 fn negative_integers_sort_before_positive_in_index() {
241 let neg = encode_value_for_index(&serde_json::json!(-5)).unwrap();
242 let zero = encode_value_for_index(&serde_json::json!(0)).unwrap();
243 let pos = encode_value_for_index(&serde_json::json!(5)).unwrap();
244 assert!(neg < zero);
245 assert!(zero < pos);
246 }
247}