Skip to main content

reifydb_codec/key/
column.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use reifydb_value::{
5	Result,
6	value::{
7		Value,
8		column_view::{ColumnView, ViewData},
9		constraint::{precision::Precision, scale::Scale},
10		container::{
11			decimal_array::decimal_at,
12			dictionary_array,
13			temporal_array::{dates, datetimes, durations, times},
14			uuid_array::{identity_ids, uuid4s, uuid7s},
15			wide_int_array::wide_at,
16		},
17	},
18};
19
20use crate::{
21	key::{
22		serializer::{KeySerializer, keycode_type_descending},
23		sort::SortOrder,
24	},
25	tag::{TypeTag, ValueKind},
26};
27
28enum Cell {
29	Written,
30	Value(Value),
31}
32
33pub fn extend_column_with_direction(view: &ColumnView, direction: SortOrder, rows: &mut [KeySerializer]) -> Result<()> {
34	let ascending = matches!(direction, SortOrder::Asc);
35	match &view.data {
36		ViewData::Enum {
37			..
38		} => unreachable!("an enum column is keyed by its stored tag, never by its name"),
39		ViewData::Bool(a) => typed(view, rows, ascending, |row, i, _| {
40			row.extend_kind(ValueKind::Boolean).extend_bool(a.value(i));
41			Ok(Cell::Written)
42		}),
43		ViewData::Float4(a) => typed(view, rows, ascending, |row, i, none| {
44			let value = a.value(i);
45			if value.is_nan() {
46				row.extend_raw(none);
47			} else {
48				row.extend_kind(ValueKind::Float4).extend_f32(if value == 0.0 {
49					0.0
50				} else {
51					value
52				});
53			}
54			Ok(Cell::Written)
55		}),
56		ViewData::Float8(a) => typed(view, rows, ascending, |row, i, none| {
57			let value = a.value(i);
58			if value.is_nan() {
59				row.extend_raw(none);
60			} else {
61				row.extend_kind(ValueKind::Float8).extend_f64(if value == 0.0 {
62					0.0
63				} else {
64					value
65				});
66			}
67			Ok(Cell::Written)
68		}),
69		ViewData::Int1(a) => typed(view, rows, ascending, |row, i, _| {
70			row.extend_kind(ValueKind::Int1).extend_i8(a.value(i));
71			Ok(Cell::Written)
72		}),
73		ViewData::Int2(a) => typed(view, rows, ascending, |row, i, _| {
74			row.extend_kind(ValueKind::Int2).extend_i16(a.value(i));
75			Ok(Cell::Written)
76		}),
77		ViewData::Int4(a) => typed(view, rows, ascending, |row, i, _| {
78			row.extend_kind(ValueKind::Int4).extend_i32(a.value(i));
79			Ok(Cell::Written)
80		}),
81		ViewData::Int8(a) => typed(view, rows, ascending, |row, i, _| {
82			row.extend_kind(ValueKind::Int8).extend_i64(a.value(i));
83			Ok(Cell::Written)
84		}),
85		ViewData::Int16(a) => typed(view, rows, ascending, |row, i, _| match wide_at::<i128>(a, i) {
86			Some(value) => {
87				row.extend_kind(ValueKind::Int16).extend_i128(value);
88				Ok(Cell::Written)
89			}
90			None => Ok(Cell::Value(view.get_value(i))),
91		}),
92		ViewData::Uint1(a) => typed(view, rows, ascending, |row, i, _| {
93			row.extend_kind(ValueKind::Uint1).extend_u8(a.value(i));
94			Ok(Cell::Written)
95		}),
96		ViewData::Uint2(a) => typed(view, rows, ascending, |row, i, _| {
97			row.extend_kind(ValueKind::Uint2).extend_u16(a.value(i));
98			Ok(Cell::Written)
99		}),
100		ViewData::Uint4(a) => typed(view, rows, ascending, |row, i, _| {
101			row.extend_kind(ValueKind::Uint4).extend_u32(a.value(i));
102			Ok(Cell::Written)
103		}),
104		ViewData::Uint8(a) => typed(view, rows, ascending, |row, i, _| {
105			row.extend_kind(ValueKind::Uint8).extend_u64(a.value(i));
106			Ok(Cell::Written)
107		}),
108		ViewData::Uint16(a) => typed(view, rows, ascending, |row, i, _| match wide_at::<u128>(a, i) {
109			Some(value) => {
110				row.extend_kind(ValueKind::Uint16).extend_u128(value);
111				Ok(Cell::Written)
112			}
113			None => Ok(Cell::Value(view.get_value(i))),
114		}),
115		ViewData::Utf8 {
116			container,
117			..
118		} => typed(view, rows, ascending, |row, i, _| {
119			row.extend_kind(ValueKind::Utf8).extend_str(container.value(i));
120			Ok(Cell::Written)
121		}),
122		ViewData::Blob {
123			container,
124			..
125		} => typed(view, rows, ascending, |row, i, _| {
126			row.extend_kind(ValueKind::Blob).extend_bytes(container.value(i));
127			Ok(Cell::Written)
128		}),
129		ViewData::Date(a) => {
130			let values = dates(a);
131			typed(view, rows, ascending, |row, i, _| {
132				row.extend_kind(ValueKind::Date).extend_date(&values[i]);
133				Ok(Cell::Written)
134			})
135		}
136		ViewData::DateTime(a) => {
137			let values = datetimes(a);
138			typed(view, rows, ascending, |row, i, _| {
139				row.extend_kind(ValueKind::DateTime).extend_datetime(&values[i]);
140				Ok(Cell::Written)
141			})
142		}
143		ViewData::Time(a) => {
144			let values = times(a);
145			typed(view, rows, ascending, |row, i, _| {
146				row.extend_kind(ValueKind::Time).extend_time(&values[i]);
147				Ok(Cell::Written)
148			})
149		}
150		ViewData::Duration(a) => {
151			let values = durations(a);
152			typed(view, rows, ascending, |row, i, _| {
153				row.extend_kind(ValueKind::Duration).extend_duration(&values[i]);
154				Ok(Cell::Written)
155			})
156		}
157		ViewData::IdentityId(a) => {
158			let values = identity_ids(a);
159			typed(view, rows, ascending, |row, i, _| {
160				row.extend_kind(ValueKind::IdentityId).extend_identity_id(&values[i]);
161				Ok(Cell::Written)
162			})
163		}
164		ViewData::Uuid4(a) => {
165			let values = uuid4s(a);
166			typed(view, rows, ascending, |row, i, _| {
167				row.extend_kind(ValueKind::Uuid4).extend_uuid4(&values[i]);
168				Ok(Cell::Written)
169			})
170		}
171		ViewData::Uuid7(a) => {
172			let values = uuid7s(a);
173			typed(view, rows, ascending, |row, i, _| {
174				row.extend_kind(ValueKind::Uuid7).extend_uuid7(&values[i]);
175				Ok(Cell::Written)
176			})
177		}
178		ViewData::Decimal(d) => typed(view, rows, ascending, |row, i, _| match decimal_at(d, i) {
179			Some(value) => {
180				row.extend_kind(ValueKind::Decimal).extend_decimal(
181					&value,
182					Precision::MAX,
183					Scale::new(value.scale()),
184				)?;
185				Ok(Cell::Written)
186			}
187			None => Ok(Cell::Value(view.get_value(i))),
188		}),
189		ViewData::DictionaryId {
190			container,
191			..
192		} => typed(view, rows, ascending, |row, i, _| match dictionary_array::get(container, i) {
193			Some(id) => {
194				row.try_extend_value(&Value::DictionaryId(id))?;
195				Ok(Cell::Written)
196			}
197			None => Ok(Cell::Value(view.get_value(i))),
198		}),
199		ViewData::Any {
200			..
201		}
202		| ViewData::Digest {
203			..
204		}
205		| ViewData::None {
206			..
207		} => {
208			for (i, row) in rows.iter_mut().enumerate() {
209				extend_cell(row, &view.get_value(i), ascending)?;
210			}
211			Ok(())
212		}
213	}
214}
215
216fn typed(
217	view: &ColumnView,
218	rows: &mut [KeySerializer],
219	ascending: bool,
220	mut write: impl FnMut(&mut KeySerializer, usize, &[u8]) -> Result<Cell>,
221) -> Result<()> {
222	let base = view.base_type();
223	let flip = ascending == keycode_type_descending(&base);
224	let none = [
225		ValueKind::None.byte(),
226		TypeTag::of_type(&base).expect("option nesting in a key none inner exceeds the supported depth").byte(),
227	];
228	for (i, row) in rows.iter_mut().enumerate() {
229		if view.none_at(i) {
230			let start = row.len();
231			row.extend_raw(&none);
232			if flip {
233				row.complement_from(start);
234			}
235			continue;
236		}
237		let start = row.len();
238		match write(row, i, &none)? {
239			Cell::Written => {
240				if flip {
241					row.complement_from(start);
242				}
243			}
244			Cell::Value(value) => extend_cell(row, &value, ascending)?,
245		}
246	}
247	Ok(())
248}
249
250fn extend_cell(row: &mut KeySerializer, value: &Value, ascending: bool) -> Result<()> {
251	let ty = match value {
252		Value::None {
253			inner,
254		} => inner.clone(),
255		present => present.get_type(),
256	};
257	let start = row.len();
258	row.try_extend_value(value)?;
259	if ascending == keycode_type_descending(&ty) {
260		row.complement_from(start);
261	}
262	Ok(())
263}