Skip to main content

reifydb_core/encoded/shape/
from.rs

1//  SPDX-License-Identifier: Apache-2.0
2//  Copyright (c) 2025 ReifyDB
3
4use reifydb_type::value::constraint::{Constraint, TypeConstraint};
5
6use crate::{
7	encoded::shape::{RowShape, RowShapeField},
8	interface::catalog::column::Column,
9};
10
11impl From<&Vec<Column>> for RowShape {
12	fn from(value: &Vec<Column>) -> Self {
13		RowShape::from(value.as_slice())
14	}
15}
16impl From<&[Column]> for RowShape {
17	fn from(value: &[Column]) -> Self {
18		let fields = value
19			.iter()
20			.map(|col| {
21				// For dictionary columns, the constraint carries Dictionary info with id_type.
22				// Convert to TypeConstraint::dictionary() so the shape uses DictionaryId as base_type,
23				// matching the shape used to encode the data.
24				let constraint = match col.constraint.constraint() {
25					Some(Constraint::Dictionary(dict_id, id_type)) => {
26						TypeConstraint::dictionary(*dict_id, id_type.clone())
27					}
28					_ => col.constraint.clone(),
29				};
30				RowShapeField::new(col.name.clone(), constraint)
31			})
32			.collect();
33		RowShape::new(fields)
34	}
35}
36
37#[cfg(test)]
38mod tests {
39	mod from_shape {
40		// Tests removed as From<&RowShape> for the old layout type has been removed
41		// RowShape is now the canonical layout descriptor
42	}
43
44	mod from_column {
45		use reifydb_type::value::{constraint::TypeConstraint, r#type::Type};
46
47		use crate::{
48			encoded::shape::{RowShape, RowShapeField},
49			interface::catalog::{
50				column::{Column, ColumnIndex},
51				id::ColumnId,
52			},
53		};
54
55		fn make_column(id: u64, name: &str, ty: Type, index: u8) -> Column {
56			Column {
57				id: ColumnId(id),
58				name: name.to_string(),
59				constraint: TypeConstraint::unconstrained(ty),
60				properties: vec![],
61				index: ColumnIndex(index),
62				auto_increment: false,
63				dictionary_id: None,
64			}
65		}
66
67		#[test]
68		fn test_from_column_single_field() {
69			let columns = vec![make_column(1, "id", Type::Int8, 0)];
70
71			let shape = RowShape::from(columns.as_slice());
72
73			assert_eq!(shape.fields().len(), 1);
74			assert_eq!(shape.fields()[0].name, "id");
75			assert_eq!(shape.fields()[0].constraint.get_type(), Type::Int8);
76		}
77
78		#[test]
79		fn test_from_column_multiple_fields() {
80			let columns = vec![
81				make_column(1, "a", Type::Int1, 0),
82				make_column(2, "b", Type::Int2, 1),
83				make_column(3, "c", Type::Int4, 2),
84			];
85
86			let shape = RowShape::from(columns.as_slice());
87
88			assert_eq!(shape.fields().len(), 3);
89			assert_eq!(shape.fields()[0].name, "a");
90			assert_eq!(shape.fields()[0].constraint.get_type(), Type::Int1);
91			assert_eq!(shape.fields()[1].name, "b");
92			assert_eq!(shape.fields()[1].constraint.get_type(), Type::Int2);
93			assert_eq!(shape.fields()[2].name, "c");
94			assert_eq!(shape.fields()[2].constraint.get_type(), Type::Int4);
95		}
96
97		#[test]
98		fn test_from_column_preserves_field_order() {
99			let columns = vec![
100				make_column(1, "first", Type::Utf8, 0),
101				make_column(2, "second", Type::Int4, 1),
102				make_column(3, "third", Type::Boolean, 2),
103			];
104
105			let shape = RowShape::from(columns.as_slice());
106
107			assert_eq!(shape.fields()[0].name, "first");
108			assert_eq!(shape.fields()[0].constraint.get_type(), Type::Utf8);
109			assert_eq!(shape.fields()[1].name, "second");
110			assert_eq!(shape.fields()[1].constraint.get_type(), Type::Int4);
111			assert_eq!(shape.fields()[2].name, "third");
112			assert_eq!(shape.fields()[2].constraint.get_type(), Type::Boolean);
113		}
114
115		#[test]
116		fn test_from_column_equivalence_with_direct_construction() {
117			let columns = vec![
118				make_column(1, "f0", Type::Uint1, 0),
119				make_column(2, "f1", Type::Uint2, 1),
120				make_column(3, "f2", Type::Uint4, 2),
121				make_column(4, "f3", Type::Uint8, 3),
122				make_column(5, "f4", Type::Uint16, 4),
123			];
124
125			let shape_from_columns = RowShape::from(columns.as_slice());
126			let shape_direct = RowShape::new(vec![
127				RowShapeField::unconstrained("f0", Type::Uint1),
128				RowShapeField::unconstrained("f1", Type::Uint2),
129				RowShapeField::unconstrained("f2", Type::Uint4),
130				RowShapeField::unconstrained("f3", Type::Uint8),
131				RowShapeField::unconstrained("f4", Type::Uint16),
132			]);
133
134			// Full equivalence check
135			assert_eq!(shape_from_columns.fields().len(), shape_direct.fields().len());
136			assert_eq!(shape_from_columns.fingerprint(), shape_direct.fingerprint());
137
138			for (i, (from_columns, direct)) in
139				shape_from_columns.fields().iter().zip(shape_direct.fields().iter()).enumerate()
140			{
141				assert_eq!(from_columns.name, direct.name, "name mismatch at field {}", i);
142				assert_eq!(
143					from_columns.constraint, direct.constraint,
144					"constraint mismatch at field {}",
145					i
146				);
147				assert_eq!(from_columns.offset, direct.offset, "offset mismatch at field {}", i);
148				assert_eq!(from_columns.size, direct.size, "size mismatch at field {}", i);
149				assert_eq!(from_columns.align, direct.align, "align mismatch at field {}", i);
150			}
151		}
152
153		#[test]
154		fn test_from_column_empty() {
155			let columns: Vec<Column> = vec![];
156
157			let shape = RowShape::from(columns.as_slice());
158
159			assert_eq!(shape.fields().len(), 0);
160		}
161
162		#[test]
163		fn test_from_column_nine_fields() {
164			let columns = vec![
165				make_column(1, "f0", Type::Boolean, 0),
166				make_column(2, "f1", Type::Int1, 1),
167				make_column(3, "f2", Type::Int2, 2),
168				make_column(4, "f3", Type::Int4, 3),
169				make_column(5, "f4", Type::Int8, 4),
170				make_column(6, "f5", Type::Uint1, 5),
171				make_column(7, "f6", Type::Uint2, 6),
172				make_column(8, "f7", Type::Uint4, 7),
173				make_column(9, "f8", Type::Uint8, 8),
174			];
175
176			let shape = RowShape::from(columns.as_slice());
177
178			assert_eq!(shape.fields().len(), 9);
179			for (i, field) in shape.fields().iter().enumerate() {
180				assert_eq!(field.name, format!("f{}", i));
181			}
182		}
183	}
184}