1use std::ptr;
5
6use reifydb_value::{
7 reifydb_assertions,
8 value::{identity::IdentityId, uuid::Uuid7, value_type::ValueType},
9};
10use uuid::Uuid;
11
12use crate::encoded::{row::EncodedRow, shape::RowShape};
13
14impl RowShape {
15 pub fn set_identity_id(&self, row: &mut EncodedRow, index: usize, value: IdentityId) {
16 let field = &self.fields()[index];
17 reifydb_assertions! {
18 assert!(
19 row.len() >= self.total_static_size(),
20 "row/shape size mismatch: row.len()={} < total_static_size()={}",
21 row.len(),
22 self.total_static_size()
23 );
24 assert_eq!(*field.constraint.get_type().inner_type(), ValueType::IdentityId);
25 }
26 row.set_valid(index, true);
27 unsafe {
28 ptr::write_unaligned(
29 row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut [u8; 16],
30 *value.as_bytes(),
31 );
32 }
33 }
34
35 pub fn get_identity_id(&self, row: &EncodedRow, index: usize) -> IdentityId {
36 let field = &self.fields()[index];
37 reifydb_assertions! {
38 assert!(
39 row.len() >= self.total_static_size(),
40 "row/shape size mismatch: row.len()={} < total_static_size()={}",
41 row.len(),
42 self.total_static_size()
43 );
44 assert_eq!(*field.constraint.get_type().inner_type(), ValueType::IdentityId);
45 }
46 unsafe {
47 let bytes: [u8; 16] =
48 ptr::read_unaligned(row.as_ptr().add(field.offset as usize) as *const [u8; 16]);
49 let uuid = Uuid::from_bytes(bytes);
50 let uuid7 = Uuid7::from(uuid);
51 IdentityId::from(uuid7)
52 }
53 }
54
55 pub fn try_get_identity_id(&self, row: &EncodedRow, index: usize) -> Option<IdentityId> {
56 if row.is_defined(index) && self.fields()[index].constraint.get_type() == ValueType::IdentityId {
57 Some(self.get_identity_id(row, index))
58 } else {
59 None
60 }
61 }
62}
63
64#[cfg(test)]
65pub mod tests {
66 use reifydb_runtime::context::{
67 clock::{Clock, MockClock},
68 rng::Rng,
69 };
70 use reifydb_value::value::{identity::IdentityId, value_type::ValueType};
71
72 use crate::encoded::shape::RowShape;
73
74 fn test_clock_and_rng() -> (MockClock, Clock, Rng) {
75 let mock = MockClock::from_millis(1000);
76 let clock = Clock::Mock(mock.clone());
77 let rng = Rng::seeded(42);
78 (mock, clock, rng)
79 }
80
81 #[test]
82 fn test_set_get_identity_id() {
83 let (_mock, clock, rng) = test_clock_and_rng();
84 let shape = RowShape::testing(&[ValueType::IdentityId]);
85 let mut row = shape.allocate();
86
87 let id = IdentityId::generate(&clock, &rng);
88 shape.set_identity_id(&mut row, 0, id.clone());
89 assert_eq!(shape.get_identity_id(&row, 0), id);
90 }
91
92 #[test]
93 fn test_try_get_identity_id() {
94 let (_mock, clock, rng) = test_clock_and_rng();
95 let shape = RowShape::testing(&[ValueType::IdentityId]);
96 let mut row = shape.allocate();
97
98 assert_eq!(shape.try_get_identity_id(&row, 0), None);
99
100 let id = IdentityId::generate(&clock, &rng);
101 shape.set_identity_id(&mut row, 0, id.clone());
102 assert_eq!(shape.try_get_identity_id(&row, 0), Some(id));
103 }
104
105 #[test]
106 fn test_multiple_generations() {
107 let (mock, clock, rng) = test_clock_and_rng();
108 let shape = RowShape::testing(&[ValueType::IdentityId]);
109
110 let mut ids = Vec::new();
112 for _ in 0..10 {
113 let mut row = shape.allocate();
114 let id = IdentityId::generate(&clock, &rng);
115 shape.set_identity_id(&mut row, 0, id.clone());
116 let retrieved = shape.get_identity_id(&row, 0);
117 assert_eq!(retrieved, id);
118 ids.push(id);
119 mock.advance_millis(1);
120 }
121
122 for i in 0..ids.len() {
124 for j in (i + 1)..ids.len() {
125 assert_ne!(ids[i], ids[j], "Identity IDs should be unique");
126 }
127 }
128 }
129
130 #[test]
131 fn test_uuid7_properties() {
132 let (_mock, clock, rng) = test_clock_and_rng();
133 let shape = RowShape::testing(&[ValueType::IdentityId]);
134 let mut row = shape.allocate();
135
136 let id = IdentityId::generate(&clock, &rng);
137 shape.set_identity_id(&mut row, 0, id.clone());
138 let retrieved = shape.get_identity_id(&row, 0);
139
140 assert_eq!(retrieved.get_version_num(), 7);
142 assert_eq!(id.get_version_num(), 7);
143 }
144
145 #[test]
146 fn test_timestamp_ordering() {
147 let (mock, clock, rng) = test_clock_and_rng();
148 let shape = RowShape::testing(&[ValueType::IdentityId]);
149
150 let mut ids = Vec::new();
153 for _ in 0..5 {
154 let mut row = shape.allocate();
155 let id = IdentityId::generate(&clock, &rng);
156 shape.set_identity_id(&mut row, 0, id.clone());
157 let retrieved = shape.get_identity_id(&row, 0);
158 assert_eq!(retrieved, id);
159 ids.push(id);
160
161 mock.advance_millis(1);
163 }
164
165 for i in 1..ids.len() {
167 assert!(ids[i].as_bytes() >= ids[i - 1].as_bytes(), "Identity IDs should be timestamp-ordered");
168 }
169 }
170
171 #[test]
172 fn test_mixed_with_other_types() {
173 let (mock, clock, rng) = test_clock_and_rng();
174 let shape = RowShape::testing(&[
175 ValueType::IdentityId,
176 ValueType::Boolean,
177 ValueType::IdentityId,
178 ValueType::Int4,
179 ]);
180 let mut row = shape.allocate();
181
182 let id1 = IdentityId::generate(&clock, &rng);
183 mock.advance_millis(1);
184 let id2 = IdentityId::generate(&clock, &rng);
185
186 shape.set_identity_id(&mut row, 0, id1.clone());
187 shape.set_bool(&mut row, 1, true);
188 shape.set_identity_id(&mut row, 2, id2.clone());
189 shape.set_i32(&mut row, 3, 42);
190
191 assert_eq!(shape.get_identity_id(&row, 0), id1);
192 assert_eq!(shape.get_bool(&row, 1), true);
193 assert_eq!(shape.get_identity_id(&row, 2), id2);
194 assert_eq!(shape.get_i32(&row, 3), 42);
195 }
196
197 #[test]
198 fn test_undefined_handling() {
199 let (_mock, clock, rng) = test_clock_and_rng();
200 let shape = RowShape::testing(&[ValueType::IdentityId, ValueType::IdentityId]);
201 let mut row = shape.allocate();
202
203 let id = IdentityId::generate(&clock, &rng);
204 shape.set_identity_id(&mut row, 0, id.clone());
205
206 assert_eq!(shape.try_get_identity_id(&row, 0), Some(id));
207 assert_eq!(shape.try_get_identity_id(&row, 1), None);
208
209 shape.set_none(&mut row, 0);
210 assert_eq!(shape.try_get_identity_id(&row, 0), None);
211 }
212
213 #[test]
214 fn test_persistence() {
215 let (_mock, clock, rng) = test_clock_and_rng();
216 let shape = RowShape::testing(&[ValueType::IdentityId]);
217 let mut row = shape.allocate();
218
219 let id = IdentityId::generate(&clock, &rng);
220 let id_string = id.to_string();
221
222 shape.set_identity_id(&mut row, 0, id.clone());
223 let retrieved = shape.get_identity_id(&row, 0);
224
225 assert_eq!(retrieved, id);
226 assert_eq!(retrieved.to_string(), id_string);
227 assert_eq!(retrieved.as_bytes(), id.as_bytes());
228 }
229
230 #[test]
231 fn test_clone_consistency() {
232 let (_mock, clock, rng) = test_clock_and_rng();
233 let shape = RowShape::testing(&[ValueType::IdentityId]);
234 let mut row = shape.allocate();
235
236 let original_id = IdentityId::generate(&clock, &rng);
237 shape.set_identity_id(&mut row, 0, original_id.clone());
238
239 let retrieved_id = shape.get_identity_id(&row, 0);
240 assert_eq!(retrieved_id, original_id);
241
242 assert_eq!(retrieved_id.as_bytes(), original_id.as_bytes());
245 }
246
247 #[test]
248 fn test_multiple_fields() {
249 let (mock, clock, rng) = test_clock_and_rng();
250 let shape = RowShape::testing(&[ValueType::IdentityId, ValueType::IdentityId, ValueType::IdentityId]);
251 let mut row = shape.allocate();
252
253 let id1 = IdentityId::generate(&clock, &rng);
254 mock.advance_millis(1);
255 let id2 = IdentityId::generate(&clock, &rng);
256 mock.advance_millis(1);
257 let id3 = IdentityId::generate(&clock, &rng);
258
259 shape.set_identity_id(&mut row, 0, id1.clone());
260 shape.set_identity_id(&mut row, 1, id2.clone());
261 shape.set_identity_id(&mut row, 2, id3.clone());
262
263 assert_eq!(shape.get_identity_id(&row, 0), id1);
264 assert_eq!(shape.get_identity_id(&row, 1), id2);
265 assert_eq!(shape.get_identity_id(&row, 2), id3);
266
267 assert_ne!(id1, id2);
269 assert_ne!(id1, id3);
270 assert_ne!(id2, id3);
271 }
272
273 #[test]
274 fn test_format_consistency() {
275 let (_mock, clock, rng) = test_clock_and_rng();
276 let shape = RowShape::testing(&[ValueType::IdentityId]);
277 let mut row = shape.allocate();
278
279 let id = IdentityId::generate(&clock, &rng);
280 let original_string = id.to_string();
281
282 shape.set_identity_id(&mut row, 0, id.clone());
283 let retrieved = shape.get_identity_id(&row, 0);
284 let retrieved_string = retrieved.to_string();
285
286 assert_eq!(original_string, retrieved_string);
287
288 assert_eq!(original_string.len(), 36);
291 assert_eq!(original_string.matches('-').count(), 4);
292 }
293
294 #[test]
295 fn test_byte_level_storage() {
296 let (_mock, clock, rng) = test_clock_and_rng();
297 let shape = RowShape::testing(&[ValueType::IdentityId]);
298 let mut row = shape.allocate();
299
300 let id = IdentityId::generate(&clock, &rng);
301 let original_bytes = *id.as_bytes();
302
303 shape.set_identity_id(&mut row, 0, id.clone());
304 let retrieved = shape.get_identity_id(&row, 0);
305 let retrieved_bytes = *retrieved.as_bytes();
306
307 assert_eq!(original_bytes, retrieved_bytes);
308
309 assert_eq!(original_bytes.len(), 16);
311 assert_eq!(retrieved_bytes.len(), 16);
312 }
313
314 #[test]
315 fn test_time_based_properties() {
316 let (mock, clock, rng) = test_clock_and_rng();
317 let shape = RowShape::testing(&[ValueType::IdentityId]);
318
319 let id1 = IdentityId::generate(&clock, &rng);
321 mock.advance_millis(2);
322 let id2 = IdentityId::generate(&clock, &rng);
323
324 let mut row1 = shape.allocate();
325 let mut row2 = shape.allocate();
326
327 shape.set_identity_id(&mut row1, 0, id1.clone());
328 shape.set_identity_id(&mut row2, 0, id2.clone());
329
330 let retrieved1 = shape.get_identity_id(&row1, 0);
331 let retrieved2 = shape.get_identity_id(&row2, 0);
332
333 assert!(retrieved2.as_bytes() > retrieved1.as_bytes());
336 }
337
338 #[test]
339 fn test_as_primary_key() {
340 let (_mock, clock, rng) = test_clock_and_rng();
341 let shape = RowShape::testing(&[
342 ValueType::IdentityId, ValueType::Utf8, ValueType::Int4, ]);
346 let mut row = shape.allocate();
347
348 let primary_key = IdentityId::generate(&clock, &rng);
350 shape.set_identity_id(&mut row, 0, primary_key.clone());
351 shape.set_utf8(&mut row, 1, "John Doe");
352 shape.set_i32(&mut row, 2, 30);
353
354 assert_eq!(shape.get_identity_id(&row, 0), primary_key);
355 assert_eq!(shape.get_utf8(&row, 1), "John Doe");
356 assert_eq!(shape.get_i32(&row, 2), 30);
357
358 assert_eq!(primary_key.get_version_num(), 7);
360 }
361
362 #[test]
363 fn test_try_get_identity_id_wrong_type() {
364 let shape = RowShape::testing(&[ValueType::Boolean]);
365 let mut row = shape.allocate();
366
367 shape.set_bool(&mut row, 0, true);
368
369 assert_eq!(shape.try_get_identity_id(&row, 0), None);
370 }
371}