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