1use reifydb_codec::encoded::{
5 row::EncodedRow,
6 shape::{RowShape, RowShapeField},
7};
8use reifydb_value::value::{
9 constraint::{Constraint, TypeConstraint},
10 duration::Duration,
11 row_number::RowNumber,
12};
13use serde::{Deserialize, Serialize};
14
15use crate::interface::catalog::column::Column;
16
17#[derive(Debug, Clone)]
18pub struct Row {
19 pub number: RowNumber,
20 pub encoded: EncodedRow,
21 pub shape: RowShape,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25pub struct Ttl {
26 pub duration: Duration,
27
28 pub cleanup_mode: TtlCleanupMode,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
32pub struct RowSettings {
33 pub ttl: Option<Ttl>,
34
35 pub persistent: bool,
36}
37
38impl RowSettings {
39 pub fn is_persistent(&self) -> bool {
40 self.persistent
41 }
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45pub struct OperatorSettings {
46 pub ttl: Option<Ttl>,
47
48 pub join: Option<JoinTtl>,
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
52pub enum TtlCleanupMode {
53 Delete,
54
55 Drop,
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
59pub struct JoinTtl {
60 pub left: Option<Ttl>,
61
62 pub right: Option<Ttl>,
63}
64
65pub fn row_shape_from_columns(value: &[Column]) -> RowShape {
66 {
67 let fields = value
68 .iter()
69 .map(|col| {
70 let constraint = match col.constraint.constraint() {
71 Some(Constraint::Dictionary(dict_id, id_type)) => {
72 TypeConstraint::dictionary(*dict_id, id_type.clone())
73 }
74 _ => col.constraint.clone(),
75 };
76 RowShapeField::new(col.name.clone(), constraint)
77 })
78 .collect();
79 RowShape::new(fields)
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 mod from_shape {
86 }
89
90 mod from_column {
91 use reifydb_codec::encoded::shape::{RowShape, RowShapeField};
92 use reifydb_value::value::{constraint::TypeConstraint, value_type::ValueType};
93
94 use crate::{
95 interface::catalog::{
96 column::{Column, ColumnIndex},
97 id::ColumnId,
98 },
99 row::row_shape_from_columns,
100 };
101
102 fn make_column(id: u64, name: &str, ty: ValueType, index: u8) -> Column {
103 Column {
104 id: ColumnId(id),
105 name: name.to_string(),
106 constraint: TypeConstraint::unconstrained(ty),
107 properties: vec![],
108 index: ColumnIndex(index),
109 auto_increment: false,
110 dictionary_id: None,
111 }
112 }
113
114 #[test]
115 fn test_from_column_single_field() {
116 let columns = vec![make_column(1, "id", ValueType::Int8, 0)];
117
118 let shape = row_shape_from_columns(columns.as_slice());
119
120 assert_eq!(shape.fields().len(), 1);
121 assert_eq!(shape.fields()[0].name, "id");
122 assert_eq!(shape.fields()[0].constraint.get_type(), ValueType::Int8);
123 }
124
125 #[test]
126 fn test_from_column_multiple_fields() {
127 let columns = vec![
128 make_column(1, "a", ValueType::Int1, 0),
129 make_column(2, "b", ValueType::Int2, 1),
130 make_column(3, "c", ValueType::Int4, 2),
131 ];
132
133 let shape = row_shape_from_columns(columns.as_slice());
134
135 assert_eq!(shape.fields().len(), 3);
136 assert_eq!(shape.fields()[0].name, "a");
137 assert_eq!(shape.fields()[0].constraint.get_type(), ValueType::Int1);
138 assert_eq!(shape.fields()[1].name, "b");
139 assert_eq!(shape.fields()[1].constraint.get_type(), ValueType::Int2);
140 assert_eq!(shape.fields()[2].name, "c");
141 assert_eq!(shape.fields()[2].constraint.get_type(), ValueType::Int4);
142 }
143
144 #[test]
145 fn test_from_column_preserves_field_order() {
146 let columns = vec![
147 make_column(1, "first", ValueType::Utf8, 0),
148 make_column(2, "second", ValueType::Int4, 1),
149 make_column(3, "third", ValueType::Boolean, 2),
150 ];
151
152 let shape = row_shape_from_columns(columns.as_slice());
153
154 assert_eq!(shape.fields()[0].name, "first");
155 assert_eq!(shape.fields()[0].constraint.get_type(), ValueType::Utf8);
156 assert_eq!(shape.fields()[1].name, "second");
157 assert_eq!(shape.fields()[1].constraint.get_type(), ValueType::Int4);
158 assert_eq!(shape.fields()[2].name, "third");
159 assert_eq!(shape.fields()[2].constraint.get_type(), ValueType::Boolean);
160 }
161
162 #[test]
163 fn test_from_column_equivalence_with_direct_construction() {
164 let columns = vec![
165 make_column(1, "f0", ValueType::Uint1, 0),
166 make_column(2, "f1", ValueType::Uint2, 1),
167 make_column(3, "f2", ValueType::Uint4, 2),
168 make_column(4, "f3", ValueType::Uint8, 3),
169 make_column(5, "f4", ValueType::Uint16, 4),
170 ];
171
172 let shape_from_columns = row_shape_from_columns(columns.as_slice());
173 let shape_direct = RowShape::new(vec![
174 RowShapeField::unconstrained("f0", ValueType::Uint1),
175 RowShapeField::unconstrained("f1", ValueType::Uint2),
176 RowShapeField::unconstrained("f2", ValueType::Uint4),
177 RowShapeField::unconstrained("f3", ValueType::Uint8),
178 RowShapeField::unconstrained("f4", ValueType::Uint16),
179 ]);
180
181 assert_eq!(shape_from_columns.fields().len(), shape_direct.fields().len());
183 assert_eq!(shape_from_columns.fingerprint(), shape_direct.fingerprint());
184
185 for (i, (from_columns, direct)) in
186 shape_from_columns.fields().iter().zip(shape_direct.fields().iter()).enumerate()
187 {
188 assert_eq!(from_columns.name, direct.name, "name mismatch at field {}", i);
189 assert_eq!(
190 from_columns.constraint, direct.constraint,
191 "constraint mismatch at field {}",
192 i
193 );
194 assert_eq!(from_columns.offset, direct.offset, "offset mismatch at field {}", i);
195 assert_eq!(from_columns.size, direct.size, "size mismatch at field {}", i);
196 assert_eq!(from_columns.align, direct.align, "align mismatch at field {}", i);
197 }
198 }
199
200 #[test]
201 fn test_from_column_empty() {
202 let columns: Vec<Column> = vec![];
203
204 let shape = row_shape_from_columns(columns.as_slice());
205
206 assert_eq!(shape.fields().len(), 0);
207 }
208
209 #[test]
210 fn test_from_column_nine_fields() {
211 let columns = vec![
212 make_column(1, "f0", ValueType::Boolean, 0),
213 make_column(2, "f1", ValueType::Int1, 1),
214 make_column(3, "f2", ValueType::Int2, 2),
215 make_column(4, "f3", ValueType::Int4, 3),
216 make_column(5, "f4", ValueType::Int8, 4),
217 make_column(6, "f5", ValueType::Uint1, 5),
218 make_column(7, "f6", ValueType::Uint2, 6),
219 make_column(8, "f7", ValueType::Uint4, 7),
220 make_column(9, "f8", ValueType::Uint8, 8),
221 ];
222
223 let shape = row_shape_from_columns(columns.as_slice());
224
225 assert_eq!(shape.fields().len(), 9);
226 for (i, field) in shape.fields().iter().enumerate() {
227 assert_eq!(field.name, format!("f{}", i));
228 }
229 }
230 }
231}