Skip to main content

reifydb_core/value/column/data/
mod.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4pub mod extend;
5pub mod factory;
6pub mod filter;
7pub mod from;
8pub mod get;
9pub mod reorder;
10pub mod slice;
11pub mod take;
12
13use std::fmt;
14
15use reifydb_type::{
16	storage::{Cow, DataBitVec, Storage},
17	util::bitvec::BitVec,
18	value::{
19		Value,
20		constraint::{bytes::MaxBytes, precision::Precision, scale::Scale},
21		container::{
22			any::AnyContainer, blob::BlobContainer, bool::BoolContainer, dictionary::DictionaryContainer,
23			identity_id::IdentityIdContainer, number::NumberContainer, temporal::TemporalContainer,
24			utf8::Utf8Container, uuid::UuidContainer,
25		},
26		date::Date,
27		datetime::DateTime,
28		decimal::Decimal,
29		duration::Duration,
30		int::Int,
31		time::Time,
32		r#type::Type,
33		uint::Uint,
34		uuid::{Uuid4, Uuid7},
35	},
36};
37use serde::{Deserialize, Deserializer, Serialize, Serializer};
38
39pub enum ColumnData<S: Storage = Cow> {
40	Bool(BoolContainer<S>),
41	Float4(NumberContainer<f32, S>),
42	Float8(NumberContainer<f64, S>),
43	Int1(NumberContainer<i8, S>),
44	Int2(NumberContainer<i16, S>),
45	Int4(NumberContainer<i32, S>),
46	Int8(NumberContainer<i64, S>),
47	Int16(NumberContainer<i128, S>),
48	Uint1(NumberContainer<u8, S>),
49	Uint2(NumberContainer<u16, S>),
50	Uint4(NumberContainer<u32, S>),
51	Uint8(NumberContainer<u64, S>),
52	Uint16(NumberContainer<u128, S>),
53	Utf8 {
54		container: Utf8Container<S>,
55		max_bytes: MaxBytes,
56	},
57	Date(TemporalContainer<Date, S>),
58	DateTime(TemporalContainer<DateTime, S>),
59	Time(TemporalContainer<Time, S>),
60	Duration(TemporalContainer<Duration, S>),
61	IdentityId(IdentityIdContainer<S>),
62	Uuid4(UuidContainer<Uuid4, S>),
63	Uuid7(UuidContainer<Uuid7, S>),
64	Blob {
65		container: BlobContainer<S>,
66		max_bytes: MaxBytes,
67	},
68	Int {
69		container: NumberContainer<Int, S>,
70		max_bytes: MaxBytes,
71	},
72	Uint {
73		container: NumberContainer<Uint, S>,
74		max_bytes: MaxBytes,
75	},
76	Decimal {
77		container: NumberContainer<Decimal, S>,
78		precision: Precision,
79		scale: Scale,
80	},
81	// Container for Any type (heterogeneous values)
82	Any(AnyContainer<S>),
83	// Container for DictionaryEntryId values
84	DictionaryId(DictionaryContainer<S>),
85	// Nullable wrapper: inner holds the typed data, bitvec tracks definedness
86	Option {
87		inner: Box<ColumnData<S>>,
88		bitvec: S::BitVec,
89	},
90}
91
92impl<S: Storage> Clone for ColumnData<S> {
93	fn clone(&self) -> Self {
94		match self {
95			ColumnData::Bool(c) => ColumnData::Bool(c.clone()),
96			ColumnData::Float4(c) => ColumnData::Float4(c.clone()),
97			ColumnData::Float8(c) => ColumnData::Float8(c.clone()),
98			ColumnData::Int1(c) => ColumnData::Int1(c.clone()),
99			ColumnData::Int2(c) => ColumnData::Int2(c.clone()),
100			ColumnData::Int4(c) => ColumnData::Int4(c.clone()),
101			ColumnData::Int8(c) => ColumnData::Int8(c.clone()),
102			ColumnData::Int16(c) => ColumnData::Int16(c.clone()),
103			ColumnData::Uint1(c) => ColumnData::Uint1(c.clone()),
104			ColumnData::Uint2(c) => ColumnData::Uint2(c.clone()),
105			ColumnData::Uint4(c) => ColumnData::Uint4(c.clone()),
106			ColumnData::Uint8(c) => ColumnData::Uint8(c.clone()),
107			ColumnData::Uint16(c) => ColumnData::Uint16(c.clone()),
108			ColumnData::Utf8 {
109				container,
110				max_bytes,
111			} => ColumnData::Utf8 {
112				container: container.clone(),
113				max_bytes: *max_bytes,
114			},
115			ColumnData::Date(c) => ColumnData::Date(c.clone()),
116			ColumnData::DateTime(c) => ColumnData::DateTime(c.clone()),
117			ColumnData::Time(c) => ColumnData::Time(c.clone()),
118			ColumnData::Duration(c) => ColumnData::Duration(c.clone()),
119			ColumnData::IdentityId(c) => ColumnData::IdentityId(c.clone()),
120			ColumnData::Uuid4(c) => ColumnData::Uuid4(c.clone()),
121			ColumnData::Uuid7(c) => ColumnData::Uuid7(c.clone()),
122			ColumnData::Blob {
123				container,
124				max_bytes,
125			} => ColumnData::Blob {
126				container: container.clone(),
127				max_bytes: *max_bytes,
128			},
129			ColumnData::Int {
130				container,
131				max_bytes,
132			} => ColumnData::Int {
133				container: container.clone(),
134				max_bytes: *max_bytes,
135			},
136			ColumnData::Uint {
137				container,
138				max_bytes,
139			} => ColumnData::Uint {
140				container: container.clone(),
141				max_bytes: *max_bytes,
142			},
143			ColumnData::Decimal {
144				container,
145				precision,
146				scale,
147			} => ColumnData::Decimal {
148				container: container.clone(),
149				precision: *precision,
150				scale: *scale,
151			},
152			ColumnData::Any(c) => ColumnData::Any(c.clone()),
153			ColumnData::DictionaryId(c) => ColumnData::DictionaryId(c.clone()),
154			ColumnData::Option {
155				inner,
156				bitvec,
157			} => ColumnData::Option {
158				inner: inner.clone(),
159				bitvec: bitvec.clone(),
160			},
161		}
162	}
163}
164
165impl<S: Storage> PartialEq for ColumnData<S> {
166	fn eq(&self, other: &Self) -> bool {
167		match (self, other) {
168			(ColumnData::Bool(a), ColumnData::Bool(b)) => a == b,
169			(ColumnData::Float4(a), ColumnData::Float4(b)) => a == b,
170			(ColumnData::Float8(a), ColumnData::Float8(b)) => a == b,
171			(ColumnData::Int1(a), ColumnData::Int1(b)) => a == b,
172			(ColumnData::Int2(a), ColumnData::Int2(b)) => a == b,
173			(ColumnData::Int4(a), ColumnData::Int4(b)) => a == b,
174			(ColumnData::Int8(a), ColumnData::Int8(b)) => a == b,
175			(ColumnData::Int16(a), ColumnData::Int16(b)) => a == b,
176			(ColumnData::Uint1(a), ColumnData::Uint1(b)) => a == b,
177			(ColumnData::Uint2(a), ColumnData::Uint2(b)) => a == b,
178			(ColumnData::Uint4(a), ColumnData::Uint4(b)) => a == b,
179			(ColumnData::Uint8(a), ColumnData::Uint8(b)) => a == b,
180			(ColumnData::Uint16(a), ColumnData::Uint16(b)) => a == b,
181			(
182				ColumnData::Utf8 {
183					container: a,
184					max_bytes: am,
185				},
186				ColumnData::Utf8 {
187					container: b,
188					max_bytes: bm,
189				},
190			) => a == b && am == bm,
191			(ColumnData::Date(a), ColumnData::Date(b)) => a == b,
192			(ColumnData::DateTime(a), ColumnData::DateTime(b)) => a == b,
193			(ColumnData::Time(a), ColumnData::Time(b)) => a == b,
194			(ColumnData::Duration(a), ColumnData::Duration(b)) => a == b,
195			(ColumnData::IdentityId(a), ColumnData::IdentityId(b)) => a == b,
196			(ColumnData::Uuid4(a), ColumnData::Uuid4(b)) => a == b,
197			(ColumnData::Uuid7(a), ColumnData::Uuid7(b)) => a == b,
198			(
199				ColumnData::Blob {
200					container: a,
201					max_bytes: am,
202				},
203				ColumnData::Blob {
204					container: b,
205					max_bytes: bm,
206				},
207			) => a == b && am == bm,
208			(
209				ColumnData::Int {
210					container: a,
211					max_bytes: am,
212				},
213				ColumnData::Int {
214					container: b,
215					max_bytes: bm,
216				},
217			) => a == b && am == bm,
218			(
219				ColumnData::Uint {
220					container: a,
221					max_bytes: am,
222				},
223				ColumnData::Uint {
224					container: b,
225					max_bytes: bm,
226				},
227			) => a == b && am == bm,
228			(
229				ColumnData::Decimal {
230					container: a,
231					precision: ap,
232					scale: as_,
233				},
234				ColumnData::Decimal {
235					container: b,
236					precision: bp,
237					scale: bs,
238				},
239			) => a == b && ap == bp && as_ == bs,
240			(ColumnData::Any(a), ColumnData::Any(b)) => a == b,
241			(ColumnData::DictionaryId(a), ColumnData::DictionaryId(b)) => a == b,
242			(
243				ColumnData::Option {
244					inner: ai,
245					bitvec: ab,
246				},
247				ColumnData::Option {
248					inner: bi,
249					bitvec: bb,
250				},
251			) => ai == bi && ab == bb,
252			_ => false,
253		}
254	}
255}
256
257impl fmt::Debug for ColumnData<Cow> {
258	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259		match self {
260			ColumnData::Bool(c) => f.debug_tuple("Bool").field(c).finish(),
261			ColumnData::Float4(c) => f.debug_tuple("Float4").field(c).finish(),
262			ColumnData::Float8(c) => f.debug_tuple("Float8").field(c).finish(),
263			ColumnData::Int1(c) => f.debug_tuple("Int1").field(c).finish(),
264			ColumnData::Int2(c) => f.debug_tuple("Int2").field(c).finish(),
265			ColumnData::Int4(c) => f.debug_tuple("Int4").field(c).finish(),
266			ColumnData::Int8(c) => f.debug_tuple("Int8").field(c).finish(),
267			ColumnData::Int16(c) => f.debug_tuple("Int16").field(c).finish(),
268			ColumnData::Uint1(c) => f.debug_tuple("Uint1").field(c).finish(),
269			ColumnData::Uint2(c) => f.debug_tuple("Uint2").field(c).finish(),
270			ColumnData::Uint4(c) => f.debug_tuple("Uint4").field(c).finish(),
271			ColumnData::Uint8(c) => f.debug_tuple("Uint8").field(c).finish(),
272			ColumnData::Uint16(c) => f.debug_tuple("Uint16").field(c).finish(),
273			ColumnData::Utf8 {
274				container,
275				max_bytes,
276			} => f.debug_struct("Utf8").field("container", container).field("max_bytes", max_bytes).finish(),
277			ColumnData::Date(c) => f.debug_tuple("Date").field(c).finish(),
278			ColumnData::DateTime(c) => f.debug_tuple("DateTime").field(c).finish(),
279			ColumnData::Time(c) => f.debug_tuple("Time").field(c).finish(),
280			ColumnData::Duration(c) => f.debug_tuple("Duration").field(c).finish(),
281			ColumnData::IdentityId(c) => f.debug_tuple("IdentityId").field(c).finish(),
282			ColumnData::Uuid4(c) => f.debug_tuple("Uuid4").field(c).finish(),
283			ColumnData::Uuid7(c) => f.debug_tuple("Uuid7").field(c).finish(),
284			ColumnData::Blob {
285				container,
286				max_bytes,
287			} => f.debug_struct("Blob").field("container", container).field("max_bytes", max_bytes).finish(),
288			ColumnData::Int {
289				container,
290				max_bytes,
291			} => f.debug_struct("Int").field("container", container).field("max_bytes", max_bytes).finish(),
292			ColumnData::Uint {
293				container,
294				max_bytes,
295			} => f.debug_struct("Uint").field("container", container).field("max_bytes", max_bytes).finish(),
296			ColumnData::Decimal {
297				container,
298				precision,
299				scale,
300			} => f.debug_struct("Decimal")
301				.field("container", container)
302				.field("precision", precision)
303				.field("scale", scale)
304				.finish(),
305			ColumnData::Any(c) => f.debug_tuple("Any").field(c).finish(),
306			ColumnData::DictionaryId(c) => f.debug_tuple("DictionaryId").field(c).finish(),
307			ColumnData::Option {
308				inner,
309				bitvec,
310			} => f.debug_struct("Option").field("inner", inner).field("bitvec", bitvec).finish(),
311		}
312	}
313}
314
315impl Serialize for ColumnData<Cow> {
316	fn serialize<Ser: Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> {
317		#[derive(Serialize)]
318		enum Helper<'a> {
319			Bool(&'a BoolContainer),
320			Float4(&'a NumberContainer<f32>),
321			Float8(&'a NumberContainer<f64>),
322			Int1(&'a NumberContainer<i8>),
323			Int2(&'a NumberContainer<i16>),
324			Int4(&'a NumberContainer<i32>),
325			Int8(&'a NumberContainer<i64>),
326			Int16(&'a NumberContainer<i128>),
327			Uint1(&'a NumberContainer<u8>),
328			Uint2(&'a NumberContainer<u16>),
329			Uint4(&'a NumberContainer<u32>),
330			Uint8(&'a NumberContainer<u64>),
331			Uint16(&'a NumberContainer<u128>),
332			Utf8 {
333				container: &'a Utf8Container,
334				max_bytes: MaxBytes,
335			},
336			Date(&'a TemporalContainer<Date>),
337			DateTime(&'a TemporalContainer<DateTime>),
338			Time(&'a TemporalContainer<Time>),
339			Duration(&'a TemporalContainer<Duration>),
340			IdentityId(&'a IdentityIdContainer),
341			Uuid4(&'a UuidContainer<Uuid4>),
342			Uuid7(&'a UuidContainer<Uuid7>),
343			Blob {
344				container: &'a BlobContainer,
345				max_bytes: MaxBytes,
346			},
347			Int {
348				container: &'a NumberContainer<Int>,
349				max_bytes: MaxBytes,
350			},
351			Uint {
352				container: &'a NumberContainer<Uint>,
353				max_bytes: MaxBytes,
354			},
355			Decimal {
356				container: &'a NumberContainer<Decimal>,
357				precision: Precision,
358				scale: Scale,
359			},
360			Any(&'a AnyContainer),
361			DictionaryId(&'a DictionaryContainer),
362			Option {
363				inner: &'a Box<ColumnData>,
364				bitvec: &'a BitVec,
365			},
366		}
367		let helper = match self {
368			ColumnData::Bool(c) => Helper::Bool(c),
369			ColumnData::Float4(c) => Helper::Float4(c),
370			ColumnData::Float8(c) => Helper::Float8(c),
371			ColumnData::Int1(c) => Helper::Int1(c),
372			ColumnData::Int2(c) => Helper::Int2(c),
373			ColumnData::Int4(c) => Helper::Int4(c),
374			ColumnData::Int8(c) => Helper::Int8(c),
375			ColumnData::Int16(c) => Helper::Int16(c),
376			ColumnData::Uint1(c) => Helper::Uint1(c),
377			ColumnData::Uint2(c) => Helper::Uint2(c),
378			ColumnData::Uint4(c) => Helper::Uint4(c),
379			ColumnData::Uint8(c) => Helper::Uint8(c),
380			ColumnData::Uint16(c) => Helper::Uint16(c),
381			ColumnData::Utf8 {
382				container,
383				max_bytes,
384			} => Helper::Utf8 {
385				container,
386				max_bytes: *max_bytes,
387			},
388			ColumnData::Date(c) => Helper::Date(c),
389			ColumnData::DateTime(c) => Helper::DateTime(c),
390			ColumnData::Time(c) => Helper::Time(c),
391			ColumnData::Duration(c) => Helper::Duration(c),
392			ColumnData::IdentityId(c) => Helper::IdentityId(c),
393			ColumnData::Uuid4(c) => Helper::Uuid4(c),
394			ColumnData::Uuid7(c) => Helper::Uuid7(c),
395			ColumnData::Blob {
396				container,
397				max_bytes,
398			} => Helper::Blob {
399				container,
400				max_bytes: *max_bytes,
401			},
402			ColumnData::Int {
403				container,
404				max_bytes,
405			} => Helper::Int {
406				container,
407				max_bytes: *max_bytes,
408			},
409			ColumnData::Uint {
410				container,
411				max_bytes,
412			} => Helper::Uint {
413				container,
414				max_bytes: *max_bytes,
415			},
416			ColumnData::Decimal {
417				container,
418				precision,
419				scale,
420			} => Helper::Decimal {
421				container,
422				precision: *precision,
423				scale: *scale,
424			},
425			ColumnData::Any(c) => Helper::Any(c),
426			ColumnData::DictionaryId(c) => Helper::DictionaryId(c),
427			ColumnData::Option {
428				inner,
429				bitvec,
430			} => Helper::Option {
431				inner,
432				bitvec,
433			},
434		};
435		helper.serialize(serializer)
436	}
437}
438
439impl<'de> Deserialize<'de> for ColumnData<Cow> {
440	fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
441		#[derive(Deserialize)]
442		enum Helper {
443			Bool(BoolContainer),
444			Float4(NumberContainer<f32>),
445			Float8(NumberContainer<f64>),
446			Int1(NumberContainer<i8>),
447			Int2(NumberContainer<i16>),
448			Int4(NumberContainer<i32>),
449			Int8(NumberContainer<i64>),
450			Int16(NumberContainer<i128>),
451			Uint1(NumberContainer<u8>),
452			Uint2(NumberContainer<u16>),
453			Uint4(NumberContainer<u32>),
454			Uint8(NumberContainer<u64>),
455			Uint16(NumberContainer<u128>),
456			Utf8 {
457				container: Utf8Container,
458				max_bytes: MaxBytes,
459			},
460			Date(TemporalContainer<Date>),
461			DateTime(TemporalContainer<DateTime>),
462			Time(TemporalContainer<Time>),
463			Duration(TemporalContainer<Duration>),
464			IdentityId(IdentityIdContainer),
465			Uuid4(UuidContainer<Uuid4>),
466			Uuid7(UuidContainer<Uuid7>),
467			Blob {
468				container: BlobContainer,
469				max_bytes: MaxBytes,
470			},
471			Int {
472				container: NumberContainer<Int>,
473				max_bytes: MaxBytes,
474			},
475			Uint {
476				container: NumberContainer<Uint>,
477				max_bytes: MaxBytes,
478			},
479			Decimal {
480				container: NumberContainer<Decimal>,
481				precision: Precision,
482				scale: Scale,
483			},
484			Any(AnyContainer),
485			DictionaryId(DictionaryContainer),
486			Option {
487				inner: Box<ColumnData>,
488				bitvec: BitVec,
489			},
490		}
491		let helper = Helper::deserialize(deserializer)?;
492		Ok(match helper {
493			Helper::Bool(c) => ColumnData::Bool(c),
494			Helper::Float4(c) => ColumnData::Float4(c),
495			Helper::Float8(c) => ColumnData::Float8(c),
496			Helper::Int1(c) => ColumnData::Int1(c),
497			Helper::Int2(c) => ColumnData::Int2(c),
498			Helper::Int4(c) => ColumnData::Int4(c),
499			Helper::Int8(c) => ColumnData::Int8(c),
500			Helper::Int16(c) => ColumnData::Int16(c),
501			Helper::Uint1(c) => ColumnData::Uint1(c),
502			Helper::Uint2(c) => ColumnData::Uint2(c),
503			Helper::Uint4(c) => ColumnData::Uint4(c),
504			Helper::Uint8(c) => ColumnData::Uint8(c),
505			Helper::Uint16(c) => ColumnData::Uint16(c),
506			Helper::Utf8 {
507				container,
508				max_bytes,
509			} => ColumnData::Utf8 {
510				container,
511				max_bytes,
512			},
513			Helper::Date(c) => ColumnData::Date(c),
514			Helper::DateTime(c) => ColumnData::DateTime(c),
515			Helper::Time(c) => ColumnData::Time(c),
516			Helper::Duration(c) => ColumnData::Duration(c),
517			Helper::IdentityId(c) => ColumnData::IdentityId(c),
518			Helper::Uuid4(c) => ColumnData::Uuid4(c),
519			Helper::Uuid7(c) => ColumnData::Uuid7(c),
520			Helper::Blob {
521				container,
522				max_bytes,
523			} => ColumnData::Blob {
524				container,
525				max_bytes,
526			},
527			Helper::Int {
528				container,
529				max_bytes,
530			} => ColumnData::Int {
531				container,
532				max_bytes,
533			},
534			Helper::Uint {
535				container,
536				max_bytes,
537			} => ColumnData::Uint {
538				container,
539				max_bytes,
540			},
541			Helper::Decimal {
542				container,
543				precision,
544				scale,
545			} => ColumnData::Decimal {
546				container,
547				precision,
548				scale,
549			},
550			Helper::Any(c) => ColumnData::Any(c),
551			Helper::DictionaryId(c) => ColumnData::DictionaryId(c),
552			Helper::Option {
553				inner,
554				bitvec,
555			} => ColumnData::Option {
556				inner,
557				bitvec,
558			},
559		})
560	}
561}
562
563/// Extracts the container from every ColumnData variant and evaluates an expression.
564macro_rules! with_container {
565	($self:expr, |$c:ident| $body:expr) => {
566		match $self {
567			ColumnData::Bool($c) => $body,
568			ColumnData::Float4($c) => $body,
569			ColumnData::Float8($c) => $body,
570			ColumnData::Int1($c) => $body,
571			ColumnData::Int2($c) => $body,
572			ColumnData::Int4($c) => $body,
573			ColumnData::Int8($c) => $body,
574			ColumnData::Int16($c) => $body,
575			ColumnData::Uint1($c) => $body,
576			ColumnData::Uint2($c) => $body,
577			ColumnData::Uint4($c) => $body,
578			ColumnData::Uint8($c) => $body,
579			ColumnData::Uint16($c) => $body,
580			ColumnData::Utf8 {
581				container: $c,
582				..
583			} => $body,
584			ColumnData::Date($c) => $body,
585			ColumnData::DateTime($c) => $body,
586			ColumnData::Time($c) => $body,
587			ColumnData::Duration($c) => $body,
588			ColumnData::IdentityId($c) => $body,
589			ColumnData::Uuid4($c) => $body,
590			ColumnData::Uuid7($c) => $body,
591			ColumnData::Blob {
592				container: $c,
593				..
594			} => $body,
595			ColumnData::Int {
596				container: $c,
597				..
598			} => $body,
599			ColumnData::Uint {
600				container: $c,
601				..
602			} => $body,
603			ColumnData::Decimal {
604				container: $c,
605				..
606			} => $body,
607			ColumnData::Any($c) => $body,
608			ColumnData::DictionaryId($c) => $body,
609			ColumnData::Option {
610				..
611			} => {
612				unreachable!(
613					"with_container! must not be called on Option variant directly; handle it explicitly"
614				)
615			}
616		}
617	};
618}
619
620pub(crate) use with_container;
621
622impl<S: Storage> ColumnData<S> {
623	/// Unwrap Option to inner data + bitvec. Non-Option returns self + None.
624	pub fn unwrap_option(&self) -> (&ColumnData<S>, Option<&S::BitVec>) {
625		match self {
626			ColumnData::Option {
627				inner,
628				bitvec,
629			} => (inner.as_ref(), Some(bitvec)),
630			other => (other, None),
631		}
632	}
633
634	/// Owned version: consume self and return inner data + optional bitvec.
635	pub fn into_unwrap_option(self) -> (ColumnData<S>, Option<S::BitVec>) {
636		match self {
637			ColumnData::Option {
638				inner,
639				bitvec,
640			} => (*inner, Some(bitvec)),
641			other => (other, None),
642		}
643	}
644
645	pub fn get_type(&self) -> Type {
646		match self {
647			ColumnData::Bool(_) => Type::Boolean,
648			ColumnData::Float4(_) => Type::Float4,
649			ColumnData::Float8(_) => Type::Float8,
650			ColumnData::Int1(_) => Type::Int1,
651			ColumnData::Int2(_) => Type::Int2,
652			ColumnData::Int4(_) => Type::Int4,
653			ColumnData::Int8(_) => Type::Int8,
654			ColumnData::Int16(_) => Type::Int16,
655			ColumnData::Uint1(_) => Type::Uint1,
656			ColumnData::Uint2(_) => Type::Uint2,
657			ColumnData::Uint4(_) => Type::Uint4,
658			ColumnData::Uint8(_) => Type::Uint8,
659			ColumnData::Uint16(_) => Type::Uint16,
660			ColumnData::Utf8 {
661				..
662			} => Type::Utf8,
663			ColumnData::Date(_) => Type::Date,
664			ColumnData::DateTime(_) => Type::DateTime,
665			ColumnData::Time(_) => Type::Time,
666			ColumnData::Duration(_) => Type::Duration,
667			ColumnData::IdentityId(_) => Type::IdentityId,
668			ColumnData::Uuid4(_) => Type::Uuid4,
669			ColumnData::Uuid7(_) => Type::Uuid7,
670			ColumnData::Blob {
671				..
672			} => Type::Blob,
673			ColumnData::Int {
674				..
675			} => Type::Int,
676			ColumnData::Uint {
677				..
678			} => Type::Uint,
679			ColumnData::Decimal {
680				..
681			} => Type::Decimal,
682			ColumnData::DictionaryId(_) => Type::DictionaryId,
683			ColumnData::Any(_) => Type::Any,
684			ColumnData::Option {
685				inner,
686				..
687			} => Type::Option(Box::new(inner.get_type())),
688		}
689	}
690
691	pub fn is_defined(&self, idx: usize) -> bool {
692		match self {
693			ColumnData::Bool(c) => c.is_defined(idx),
694			ColumnData::Float4(c) => c.is_defined(idx),
695			ColumnData::Float8(c) => c.is_defined(idx),
696			ColumnData::Int1(c) => c.is_defined(idx),
697			ColumnData::Int2(c) => c.is_defined(idx),
698			ColumnData::Int4(c) => c.is_defined(idx),
699			ColumnData::Int8(c) => c.is_defined(idx),
700			ColumnData::Int16(c) => c.is_defined(idx),
701			ColumnData::Uint1(c) => c.is_defined(idx),
702			ColumnData::Uint2(c) => c.is_defined(idx),
703			ColumnData::Uint4(c) => c.is_defined(idx),
704			ColumnData::Uint8(c) => c.is_defined(idx),
705			ColumnData::Uint16(c) => c.is_defined(idx),
706			ColumnData::Utf8 {
707				container: c,
708				..
709			} => c.is_defined(idx),
710			ColumnData::Date(c) => c.is_defined(idx),
711			ColumnData::DateTime(c) => c.is_defined(idx),
712			ColumnData::Time(c) => c.is_defined(idx),
713			ColumnData::Duration(c) => c.is_defined(idx),
714			ColumnData::IdentityId(container) => container.get(idx).is_some(),
715			ColumnData::Uuid4(c) => c.is_defined(idx),
716			ColumnData::Uuid7(c) => c.is_defined(idx),
717			ColumnData::Blob {
718				container: c,
719				..
720			} => c.is_defined(idx),
721			ColumnData::Int {
722				container: c,
723				..
724			} => c.is_defined(idx),
725			ColumnData::Uint {
726				container: c,
727				..
728			} => c.is_defined(idx),
729			ColumnData::Decimal {
730				container: c,
731				..
732			} => c.is_defined(idx),
733			ColumnData::DictionaryId(c) => c.is_defined(idx),
734			ColumnData::Any(c) => c.is_defined(idx),
735			ColumnData::Option {
736				bitvec,
737				..
738			} => idx < DataBitVec::len(bitvec) && DataBitVec::get(bitvec, idx),
739		}
740	}
741
742	pub fn is_bool(&self) -> bool {
743		self.get_type() == Type::Boolean
744	}
745
746	pub fn is_float(&self) -> bool {
747		self.get_type() == Type::Float4 || self.get_type() == Type::Float8
748	}
749
750	pub fn is_utf8(&self) -> bool {
751		self.get_type() == Type::Utf8
752	}
753
754	pub fn is_number(&self) -> bool {
755		matches!(
756			self.get_type(),
757			Type::Float4
758				| Type::Float8 | Type::Int1 | Type::Int2
759				| Type::Int4 | Type::Int8 | Type::Int16
760				| Type::Uint1 | Type::Uint2 | Type::Uint4
761				| Type::Uint8 | Type::Uint16 | Type::Int
762				| Type::Uint | Type::Decimal { .. }
763		)
764	}
765
766	pub fn is_text(&self) -> bool {
767		self.get_type() == Type::Utf8
768	}
769
770	pub fn is_temporal(&self) -> bool {
771		matches!(self.get_type(), Type::Date | Type::DateTime | Type::Time | Type::Duration)
772	}
773
774	pub fn is_uuid(&self) -> bool {
775		matches!(self.get_type(), Type::Uuid4 | Type::Uuid7)
776	}
777}
778
779impl<S: Storage> ColumnData<S> {
780	pub fn none_count(&self) -> usize {
781		match self {
782			ColumnData::Option {
783				bitvec,
784				..
785			} => DataBitVec::count_zeros(bitvec),
786			_ => 0,
787		}
788	}
789}
790
791impl<S: Storage> ColumnData<S> {
792	pub fn len(&self) -> usize {
793		match self {
794			ColumnData::Option {
795				inner,
796				..
797			} => inner.len(),
798			_ => with_container!(self, |c| c.len()),
799		}
800	}
801
802	pub fn capacity(&self) -> usize {
803		match self {
804			ColumnData::Option {
805				inner,
806				..
807			} => inner.capacity(),
808			_ => with_container!(self, |c| c.capacity()),
809		}
810	}
811
812	/// Clear all data, retaining the allocated capacity for reuse.
813	pub fn clear(&mut self) {
814		match self {
815			ColumnData::Option {
816				inner,
817				bitvec,
818			} => {
819				inner.clear();
820				DataBitVec::clear(bitvec);
821			}
822			_ => with_container!(self, |c| c.clear()),
823		}
824	}
825
826	pub fn as_string(&self, index: usize) -> String {
827		match self {
828			ColumnData::Option {
829				inner,
830				bitvec,
831			} => {
832				if index < DataBitVec::len(bitvec) && DataBitVec::get(bitvec, index) {
833					inner.as_string(index)
834				} else {
835					"none".to_string()
836				}
837			}
838			_ => with_container!(self, |c| c.as_string(index)),
839		}
840	}
841}
842
843impl ColumnData {
844	pub fn with_capacity(target: Type, capacity: usize) -> Self {
845		match target {
846			Type::Boolean => Self::bool_with_capacity(capacity),
847			Type::Float4 => Self::float4_with_capacity(capacity),
848			Type::Float8 => Self::float8_with_capacity(capacity),
849			Type::Int1 => Self::int1_with_capacity(capacity),
850			Type::Int2 => Self::int2_with_capacity(capacity),
851			Type::Int4 => Self::int4_with_capacity(capacity),
852			Type::Int8 => Self::int8_with_capacity(capacity),
853			Type::Int16 => Self::int16_with_capacity(capacity),
854			Type::Uint1 => Self::uint1_with_capacity(capacity),
855			Type::Uint2 => Self::uint2_with_capacity(capacity),
856			Type::Uint4 => Self::uint4_with_capacity(capacity),
857			Type::Uint8 => Self::uint8_with_capacity(capacity),
858			Type::Uint16 => Self::uint16_with_capacity(capacity),
859			Type::Utf8 => Self::utf8_with_capacity(capacity),
860			Type::Date => Self::date_with_capacity(capacity),
861			Type::DateTime => Self::datetime_with_capacity(capacity),
862			Type::Time => Self::time_with_capacity(capacity),
863			Type::Duration => Self::duration_with_capacity(capacity),
864			Type::IdentityId => Self::identity_id_with_capacity(capacity),
865			Type::Uuid4 => Self::uuid4_with_capacity(capacity),
866			Type::Uuid7 => Self::uuid7_with_capacity(capacity),
867			Type::Blob => Self::blob_with_capacity(capacity),
868			Type::Int => Self::int_with_capacity(capacity),
869			Type::Uint => Self::uint_with_capacity(capacity),
870			Type::Decimal => Self::decimal_with_capacity(capacity),
871			Type::DictionaryId => Self::dictionary_id_with_capacity(capacity),
872			Type::Option(inner) => ColumnData::Option {
873				inner: Box::new(ColumnData::with_capacity(*inner, capacity)),
874				bitvec: BitVec::with_capacity(capacity),
875			},
876			Type::Any | Type::List(_) => Self::any_with_capacity(capacity),
877		}
878	}
879
880	pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = Value> + 'a> {
881		Box::new((0..self.len()).map(move |i| self.get_value(i)))
882	}
883}