1use reifydb_core::{
5 common::CommitVersion,
6 encoded::shape::{RowShape, RowShapeField},
7 interface::{
8 catalog::{flow::FlowNodeId, id::TableId, shape::ShapeId},
9 change::{Change, ChangeOrigin, Diff, Diffs},
10 },
11 row::Row,
12 value::column::columns::Columns,
13};
14use reifydb_type::value::{Value, datetime::DateTime, row_number::RowNumber, r#type::Type};
15
16pub struct TestRowBuilder {
17 row_number: RowNumber,
18 values: Vec<Value>,
19 shape: Option<RowShape>,
20}
21
22impl TestRowBuilder {
23 pub fn new(row_number: impl Into<RowNumber>) -> Self {
24 Self {
25 row_number: row_number.into(),
26 values: Vec::new(),
27 shape: None,
28 }
29 }
30
31 pub fn with_values(mut self, values: Vec<Value>) -> Self {
32 self.values = values;
33 self
34 }
35
36 pub fn add_value(mut self, value: Value) -> Self {
37 self.values.push(value);
38 self
39 }
40
41 pub fn with_shape(mut self, shape: RowShape) -> Self {
42 self.shape = Some(shape);
43 self
44 }
45
46 pub fn build(self) -> Row {
47 let shape = if let Some(shape) = self.shape {
48 shape
49 } else {
50 let fields: Vec<RowShapeField> = self
51 .values
52 .iter()
53 .enumerate()
54 .map(|(i, v)| RowShapeField::unconstrained(format!("field{}", i), v.get_type()))
55 .collect();
56 RowShape::new(fields)
57 };
58
59 let mut encoded = shape.allocate();
60 shape.set_values(&mut encoded, &self.values);
61
62 Row {
63 number: self.row_number,
64 encoded,
65 shape,
66 }
67 }
68}
69
70pub struct TestChangeBuilder {
71 origin: ChangeOrigin,
72 diffs: Diffs,
73 version: CommitVersion,
74 changed_at: DateTime,
75}
76
77impl Default for TestChangeBuilder {
78 fn default() -> Self {
79 Self::new()
80 }
81}
82
83impl TestChangeBuilder {
84 pub fn new() -> Self {
85 Self {
86 origin: ChangeOrigin::Shape(ShapeId::Table(TableId(1))),
87 diffs: Diffs::new(),
88 version: CommitVersion(1),
89 changed_at: DateTime::default(),
90 }
91 }
92
93 pub fn changed_by_shape(mut self, shape: ShapeId) -> Self {
94 self.origin = ChangeOrigin::Shape(shape);
95 self
96 }
97
98 pub fn changed_by_node(mut self, node: FlowNodeId) -> Self {
99 self.origin = ChangeOrigin::Flow(node);
100 self
101 }
102
103 pub fn with_version(mut self, version: CommitVersion) -> Self {
104 self.version = version;
105 self
106 }
107
108 pub fn with_changed_at(mut self, changed_at: DateTime) -> Self {
109 self.changed_at = changed_at;
110 self
111 }
112
113 pub fn insert(mut self, row: Row) -> Self {
114 self.diffs.push(Diff::insert(Columns::from_row(&row)));
115 self
116 }
117
118 pub fn insert_row(self, row_number: impl Into<RowNumber>, values: Vec<Value>) -> Self {
119 let row = TestRowBuilder::new(row_number).with_values(values).build();
120 self.insert(row)
121 }
122
123 pub fn update(mut self, pre: Row, post: Row) -> Self {
124 self.diffs.push(Diff::update(Columns::from_row(&pre), Columns::from_row(&post)));
125 self
126 }
127
128 pub fn update_row(
129 self,
130 row_number: impl Into<RowNumber>,
131 pre_values: Vec<Value>,
132 post_values: Vec<Value>,
133 ) -> Self {
134 let row_number = row_number.into();
135 let pre = TestRowBuilder::new(row_number).with_values(pre_values).build();
136 let post = TestRowBuilder::new(row_number).with_values(post_values).build();
137 self.update(pre, post)
138 }
139
140 pub fn remove(mut self, row: Row) -> Self {
141 self.diffs.push(Diff::remove(Columns::from_row(&row)));
142 self
143 }
144
145 pub fn remove_row(self, row_number: impl Into<RowNumber>, values: Vec<Value>) -> Self {
146 let row = TestRowBuilder::new(row_number).with_values(values).build();
147 self.remove(row)
148 }
149
150 pub fn build(self) -> Change {
151 Change {
152 origin: self.origin,
153 diffs: self.diffs,
154 version: self.version,
155 changed_at: self.changed_at,
156 }
157 }
158}
159
160pub struct TestLayoutBuilder {
161 fields: Vec<RowShapeField>,
162}
163
164impl Default for TestLayoutBuilder {
165 fn default() -> Self {
166 Self::new()
167 }
168}
169
170impl TestLayoutBuilder {
171 pub fn new() -> Self {
172 Self {
173 fields: Vec::new(),
174 }
175 }
176
177 pub fn add_type(mut self, ty: Type) -> Self {
178 let field_name = format!("field{}", self.fields.len());
179 self.fields.push(RowShapeField::unconstrained(field_name, ty));
180 self
181 }
182
183 pub fn add_field(mut self, name: impl Into<String>, ty: Type) -> Self {
184 self.fields.push(RowShapeField::unconstrained(name, ty));
185 self
186 }
187
188 pub fn build(self) -> RowShape {
189 RowShape::new(self.fields)
190 }
191
192 pub fn build_named(self) -> RowShape {
193 self.build()
194 }
195}
196
197pub mod helpers {
198 use reifydb_core::{encoded::shape::RowShape, interface::change::Change, row::Row};
199 use reifydb_type::value::{row_number::RowNumber, r#type::Type};
200
201 use super::*;
202
203 pub fn counter_layout() -> RowShape {
204 TestLayoutBuilder::new().add_type(Type::Int8).build()
205 }
206
207 pub fn key_value_layout() -> RowShape {
208 TestLayoutBuilder::new().add_type(Type::Utf8).add_type(Type::Int8).build()
209 }
210
211 pub fn named_key_value_layout() -> RowShape {
212 TestLayoutBuilder::new().add_field("key", Type::Utf8).add_field("value", Type::Int8).build_named()
213 }
214
215 pub fn int_row(row_number: impl Into<RowNumber>, value: i8) -> Row {
216 TestRowBuilder::new(row_number).with_values(vec![Value::Int8(value as i64)]).build()
217 }
218
219 pub fn key_value_row(row_number: impl Into<RowNumber>, key: &str, value: i8) -> Row {
220 TestRowBuilder::new(row_number)
221 .with_values(vec![Value::Utf8(key.into()), Value::Int8(value as i64)])
222 .build()
223 }
224
225 pub fn empty_change() -> Change {
226 TestChangeBuilder::new().build()
227 }
228
229 pub fn insert_change(row: Row) -> Change {
230 TestChangeBuilder::new().insert(row).build()
231 }
232
233 pub fn batch_insert_change(rows: Vec<Row>) -> Change {
234 let mut builder = TestChangeBuilder::new();
235 for row in rows {
236 builder = builder.insert(row);
237 }
238 builder.build()
239 }
240}
241
242#[cfg(test)]
243pub mod tests {
244 use reifydb_core::{
245 common::CommitVersion,
246 interface::{catalog::shape::ShapeId, change::ChangeOrigin},
247 };
248 use reifydb_type::value::{row_number::RowNumber, r#type::Type};
249
250 use super::{helpers::*, *};
251
252 #[test]
253 fn test_row_builder() {
254 let row = TestRowBuilder::new(42)
255 .add_value(Value::Int8(10i64))
256 .add_value(Value::Utf8("test".into()))
257 .build();
258
259 assert_eq!(row.number, RowNumber(42));
260 assert_eq!(row.shape.field_count(), 2);
261 }
262
263 #[test]
264 fn test_flow_change_builder() {
265 let change = TestChangeBuilder::new()
266 .changed_by_shape(ShapeId::table(100))
267 .with_version(CommitVersion(5))
268 .insert_row(1, vec![Value::Int8(42i64)])
269 .update_row(2, vec![Value::Int8(10i64)], vec![Value::Int8(20i64)])
270 .remove_row(3, vec![Value::Int8(30i64)])
271 .build();
272
273 assert_eq!(change.version, CommitVersion(5));
274 assert_eq!(change.diffs.len(), 3);
275
276 match &change.origin {
277 ChangeOrigin::Shape(shape) => {
278 assert_eq!(*shape, ShapeId::table(100));
279 }
280 _ => panic!("Expected external origin"),
281 }
282 }
283
284 #[test]
285 fn test_layout_builder() {
286 let unnamed = TestLayoutBuilder::new().add_type(Type::Int8).add_type(Type::Utf8).build();
287
288 assert_eq!(unnamed.field_count(), 2);
289
290 let named = TestLayoutBuilder::new()
291 .add_field("count", Type::Int8)
292 .add_field("name", Type::Utf8)
293 .build_named();
294
295 assert_eq!(named.field_count(), 2);
296 assert_eq!(named.get_field_name(0).unwrap(), "count");
297 assert_eq!(named.get_field_name(1).unwrap(), "name");
298 }
299
300 #[test]
301 fn test_helpers() {
302 let row = int_row(1, 42);
303 assert_eq!(row.number, RowNumber(1));
304
305 let kv_row = key_value_row(2, "test", 100);
306 assert_eq!(kv_row.number, RowNumber(2));
307
308 let change = insert_change(row.clone());
309 assert_eq!(change.diffs.len(), 1);
310
311 let batch = batch_insert_change(vec![row.clone(), kv_row.clone()]);
312 assert_eq!(batch.diffs.len(), 2);
313 }
314}