1use reifydb_type::value::{blob::Blob, r#type::Type};
5
6use crate::encoded::{row::EncodedRow, shape::RowShape};
7
8impl RowShape {
9 pub fn set_blob(&self, row: &mut EncodedRow, index: usize, value: &Blob) {
10 debug_assert_eq!(*self.fields()[index].constraint.get_type().inner_type(), Type::Blob);
11 self.replace_dynamic_data(row, index, value.as_bytes());
12 }
13
14 pub fn get_blob(&self, row: &EncodedRow, index: usize) -> Blob {
15 let field = &self.fields()[index];
16 debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Blob);
17
18 let ref_slice = &row.as_slice()[field.offset as usize..field.offset as usize + 8];
19 let offset = u32::from_le_bytes([ref_slice[0], ref_slice[1], ref_slice[2], ref_slice[3]]) as usize;
20 let length = u32::from_le_bytes([ref_slice[4], ref_slice[5], ref_slice[6], ref_slice[7]]) as usize;
21
22 let dynamic_start = self.dynamic_section_start();
23 let blob_start = dynamic_start + offset;
24 let blob_slice = &row.as_slice()[blob_start..blob_start + length];
25
26 Blob::from_slice(blob_slice)
27 }
28
29 pub fn try_get_blob(&self, row: &EncodedRow, index: usize) -> Option<Blob> {
30 if row.is_defined(index) && self.fields()[index].constraint.get_type() == Type::Blob {
31 Some(self.get_blob(row, index))
32 } else {
33 None
34 }
35 }
36}
37
38#[cfg(test)]
39pub mod tests {
40 use reifydb_type::value::{blob::Blob, r#type::Type};
41
42 use crate::encoded::shape::RowShape;
43
44 #[test]
45 fn test_set_get_blob() {
46 let shape = RowShape::testing(&[Type::Blob]);
47 let mut row = shape.allocate();
48
49 let blob = Blob::from_slice(&[1, 2, 3, 4, 5]);
50 shape.set_blob(&mut row, 0, &blob);
51 assert_eq!(shape.get_blob(&row, 0), blob);
52 }
53
54 #[test]
55 fn test_try_get_blob() {
56 let shape = RowShape::testing(&[Type::Blob]);
57 let mut row = shape.allocate();
58
59 assert_eq!(shape.try_get_blob(&row, 0), None);
60
61 let blob = Blob::from_slice(&[1, 2, 3, 4, 5]);
62 shape.set_blob(&mut row, 0, &blob);
63 assert_eq!(shape.try_get_blob(&row, 0), Some(blob));
64 }
65
66 #[test]
67 fn test_empty() {
68 let shape = RowShape::testing(&[Type::Blob]);
69 let mut row = shape.allocate();
70
71 let empty_blob = Blob::from_slice(&[]);
72 shape.set_blob(&mut row, 0, &empty_blob);
73 assert_eq!(shape.get_blob(&row, 0), empty_blob);
74 assert_eq!(shape.try_get_blob(&row, 0), Some(empty_blob));
75 }
76
77 #[test]
78 fn test_binary_data() {
79 let shape = RowShape::testing(&[Type::Blob]);
80 let mut row = shape.allocate();
81
82 let binary_data = vec![
84 0x00, 0xFF, 0xAA, 0x55, 0xCC, 0x33, 0x00, 0xFF, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
85 ];
86 let blob = Blob::from_slice(&binary_data);
87 shape.set_blob(&mut row, 0, &blob);
88 assert_eq!(shape.get_blob(&row, 0), blob);
89 }
90
91 #[test]
92 fn test_large_data() {
93 let shape = RowShape::testing(&[Type::Blob]);
94 let mut row = shape.allocate();
95
96 let large_data: Vec<u8> = (0..1024).map(|i| (i % 256) as u8).collect();
98 let large_blob = Blob::from_slice(&large_data);
99 shape.set_blob(&mut row, 0, &large_blob);
100 assert_eq!(shape.get_blob(&row, 0), large_blob);
101 }
102
103 #[test]
104 fn test_multiple_fields() {
105 let shape = RowShape::testing(&[Type::Blob, Type::Blob, Type::Blob]);
106 let mut row = shape.allocate();
107
108 let blob1 = Blob::from_slice(&[1, 2, 3]);
109 let blob2 = Blob::from_slice(&[4, 5, 6, 7, 8]);
110 let blob3 = Blob::from_slice(&[9]);
111
112 shape.set_blob(&mut row, 0, &blob1);
113 shape.set_blob(&mut row, 1, &blob2);
114 shape.set_blob(&mut row, 2, &blob3);
115
116 assert_eq!(shape.get_blob(&row, 0), blob1);
117 assert_eq!(shape.get_blob(&row, 1), blob2);
118 assert_eq!(shape.get_blob(&row, 2), blob3);
119 }
120
121 #[test]
122 fn test_mixed_with_static_fields() {
123 let shape = RowShape::testing(&[Type::Boolean, Type::Blob, Type::Int4, Type::Blob]);
124 let mut row = shape.allocate();
125
126 let blob1 = Blob::from_slice(&[0xFF, 0x00, 0xAA]);
127 let blob2 = Blob::from_slice(&[0x11, 0x22, 0x33, 0x44]);
128
129 shape.set_bool(&mut row, 0, true);
130 shape.set_blob(&mut row, 1, &blob1);
131 shape.set_i32(&mut row, 2, -12345);
132 shape.set_blob(&mut row, 3, &blob2);
133
134 assert_eq!(shape.get_bool(&row, 0), true);
135 assert_eq!(shape.get_blob(&row, 1), blob1);
136 assert_eq!(shape.get_i32(&row, 2), -12345);
137 assert_eq!(shape.get_blob(&row, 3), blob2);
138 }
139
140 #[test]
141 fn test_different_sizes() {
142 let shape = RowShape::testing(&[Type::Blob, Type::Blob, Type::Blob]);
143 let mut row = shape.allocate();
144
145 let empty_blob = Blob::from_slice(&[]);
146 let medium_blob = Blob::from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
147 let single_byte_blob = Blob::from_slice(&[42]);
148
149 shape.set_blob(&mut row, 0, &empty_blob);
150 shape.set_blob(&mut row, 1, &medium_blob);
151 shape.set_blob(&mut row, 2, &single_byte_blob);
152
153 assert_eq!(shape.get_blob(&row, 0), empty_blob);
154 assert_eq!(shape.get_blob(&row, 1), medium_blob);
155 assert_eq!(shape.get_blob(&row, 2), single_byte_blob);
156 }
157
158 #[test]
159 fn test_arbitrary_setting_order() {
160 let shape = RowShape::testing(&[Type::Blob, Type::Blob, Type::Blob, Type::Blob]);
161 let mut row = shape.allocate();
162
163 let blob0 = Blob::from_slice(&[10, 20]);
164 let blob1 = Blob::from_slice(&[30, 40, 50]);
165 let blob2 = Blob::from_slice(&[60]);
166 let blob3 = Blob::from_slice(&[70, 80, 90, 100]);
167
168 shape.set_blob(&mut row, 3, &blob3);
170 shape.set_blob(&mut row, 1, &blob1);
171 shape.set_blob(&mut row, 0, &blob0);
172 shape.set_blob(&mut row, 2, &blob2);
173
174 assert_eq!(shape.get_blob(&row, 0), blob0);
175 assert_eq!(shape.get_blob(&row, 1), blob1);
176 assert_eq!(shape.get_blob(&row, 2), blob2);
177 assert_eq!(shape.get_blob(&row, 3), blob3);
178 }
179
180 #[test]
181 fn test_undefined_handling() {
182 let shape = RowShape::testing(&[Type::Blob, Type::Blob, Type::Blob]);
183 let mut row = shape.allocate();
184
185 let blob = Blob::from_slice(&[1, 2, 3, 4]);
186
187 shape.set_blob(&mut row, 0, &blob);
189 shape.set_blob(&mut row, 2, &blob);
190
191 assert_eq!(shape.try_get_blob(&row, 0), Some(blob.clone()));
192 assert_eq!(shape.try_get_blob(&row, 1), None);
193 assert_eq!(shape.try_get_blob(&row, 2), Some(blob.clone()));
194
195 shape.set_none(&mut row, 0);
197 assert_eq!(shape.try_get_blob(&row, 0), None);
198 assert_eq!(shape.try_get_blob(&row, 2), Some(blob));
199 }
200
201 #[test]
202 fn test_all_byte_values() {
203 let shape = RowShape::testing(&[Type::Blob]);
204 let mut row = shape.allocate();
205
206 let all_bytes: Vec<u8> = (0..=255).collect();
208 let full_range_blob = Blob::from_slice(&all_bytes);
209 shape.set_blob(&mut row, 0, &full_range_blob);
210 assert_eq!(shape.get_blob(&row, 0), full_range_blob);
211 }
212
213 #[test]
214 fn test_try_get_blob_wrong_type() {
215 let shape = RowShape::testing(&[Type::Boolean]);
216 let mut row = shape.allocate();
217
218 shape.set_bool(&mut row, 0, true);
219
220 assert_eq!(shape.try_get_blob(&row, 0), None);
221 }
222
223 #[test]
224 fn test_update_blob() {
225 let shape = RowShape::testing(&[Type::Blob]);
226 let mut row = shape.allocate();
227
228 let blob1 = Blob::from_slice(&[1, 2, 3]);
229 shape.set_blob(&mut row, 0, &blob1);
230 assert_eq!(shape.get_blob(&row, 0), blob1);
231
232 let blob2 = Blob::from_slice(&[4, 5, 6, 7, 8]);
234 shape.set_blob(&mut row, 0, &blob2);
235 assert_eq!(shape.get_blob(&row, 0), blob2);
236
237 let blob3 = Blob::from_slice(&[9]);
239 shape.set_blob(&mut row, 0, &blob3);
240 assert_eq!(shape.get_blob(&row, 0), blob3);
241 assert_eq!(row.len(), shape.total_static_size() + 1);
242
243 let empty = Blob::from_slice(&[]);
245 shape.set_blob(&mut row, 0, &empty);
246 assert_eq!(shape.get_blob(&row, 0), empty);
247 assert_eq!(row.len(), shape.total_static_size());
248 }
249
250 #[test]
251 fn test_update_blob_with_other_dynamic_fields() {
252 let shape = RowShape::testing(&[Type::Blob, Type::Utf8, Type::Blob]);
253 let mut row = shape.allocate();
254
255 shape.set_blob(&mut row, 0, &Blob::from_slice(&[1, 2, 3]));
256 shape.set_utf8(&mut row, 1, "hello");
257 shape.set_blob(&mut row, 2, &Blob::from_slice(&[4, 5]));
258
259 shape.set_blob(&mut row, 0, &Blob::from_slice(&[10, 20, 30, 40, 50]));
261
262 assert_eq!(shape.get_blob(&row, 0), Blob::from_slice(&[10, 20, 30, 40, 50]));
263 assert_eq!(shape.get_utf8(&row, 1), "hello");
264 assert_eq!(shape.get_blob(&row, 2), Blob::from_slice(&[4, 5]));
265 }
266}