reifydb-type 0.4.12

Core type system and value representations for ReifyDB
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 ReifyDB

use serde::{Deserialize, Serialize};

use crate::{
	storage::DataBitVec,
	util::{
		bitvec::BitVec,
		float_format::{format_f32, format_f64},
	},
	value::{
		Value,
		container::{
			any::AnyContainer, blob::BlobContainer, bool::BoolContainer, dictionary::DictionaryContainer,
			identity_id::IdentityIdContainer, number::NumberContainer, temporal::TemporalContainer,
			utf8::Utf8Container, uuid::UuidContainer,
		},
		date::Date,
		datetime::DateTime,
		decimal::Decimal,
		duration::Duration,
		int::Int,
		time::Time,
		r#type::Type,
		uint::Uint,
		uuid::{Uuid4, Uuid7},
	},
};

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum FrameColumnData {
	Bool(BoolContainer),
	Float4(NumberContainer<f32>),
	Float8(NumberContainer<f64>),
	Int1(NumberContainer<i8>),
	Int2(NumberContainer<i16>),
	Int4(NumberContainer<i32>),
	Int8(NumberContainer<i64>),
	Int16(NumberContainer<i128>),
	Uint1(NumberContainer<u8>),
	Uint2(NumberContainer<u16>),
	Uint4(NumberContainer<u32>),
	Uint8(NumberContainer<u64>),
	Uint16(NumberContainer<u128>),
	Utf8(Utf8Container),
	Date(TemporalContainer<Date>),
	DateTime(TemporalContainer<DateTime>),
	Time(TemporalContainer<Time>),
	Duration(TemporalContainer<Duration>),
	IdentityId(IdentityIdContainer),
	Uuid4(UuidContainer<Uuid4>),
	Uuid7(UuidContainer<Uuid7>),
	Blob(BlobContainer),
	Int(NumberContainer<Int>),
	Uint(NumberContainer<Uint>),
	Decimal(NumberContainer<Decimal>),
	Any(AnyContainer),
	DictionaryId(DictionaryContainer),
	// nullable wrapper
	Option {
		inner: Box<FrameColumnData>,
		bitvec: BitVec,
	},
}

impl FrameColumnData {
	pub fn get_type(&self) -> Type {
		match self {
			FrameColumnData::Bool(_) => Type::Boolean,
			FrameColumnData::Float4(_) => Type::Float4,
			FrameColumnData::Float8(_) => Type::Float8,
			FrameColumnData::Int1(_) => Type::Int1,
			FrameColumnData::Int2(_) => Type::Int2,
			FrameColumnData::Int4(_) => Type::Int4,
			FrameColumnData::Int8(_) => Type::Int8,
			FrameColumnData::Int16(_) => Type::Int16,
			FrameColumnData::Uint1(_) => Type::Uint1,
			FrameColumnData::Uint2(_) => Type::Uint2,
			FrameColumnData::Uint4(_) => Type::Uint4,
			FrameColumnData::Uint8(_) => Type::Uint8,
			FrameColumnData::Uint16(_) => Type::Uint16,
			FrameColumnData::Utf8(_) => Type::Utf8,
			FrameColumnData::Date(_) => Type::Date,
			FrameColumnData::DateTime(_) => Type::DateTime,
			FrameColumnData::Time(_) => Type::Time,
			FrameColumnData::Duration(_) => Type::Duration,
			FrameColumnData::IdentityId(_) => Type::IdentityId,
			FrameColumnData::Uuid4(_) => Type::Uuid4,
			FrameColumnData::Uuid7(_) => Type::Uuid7,
			FrameColumnData::Blob(_) => Type::Blob,
			FrameColumnData::Int(_) => Type::Int,
			FrameColumnData::Uint(_) => Type::Uint,
			FrameColumnData::Decimal(_) => Type::Decimal,
			FrameColumnData::Any(_) => Type::Any,
			FrameColumnData::DictionaryId(_) => Type::DictionaryId,
			FrameColumnData::Option {
				inner,
				..
			} => Type::Option(Box::new(inner.get_type())),
		}
	}

	pub fn is_defined(&self, idx: usize) -> bool {
		match self {
			FrameColumnData::Bool(container) => container.is_defined(idx),
			FrameColumnData::Float4(container) => container.is_defined(idx),
			FrameColumnData::Float8(container) => container.is_defined(idx),
			FrameColumnData::Int1(container) => container.is_defined(idx),
			FrameColumnData::Int2(container) => container.is_defined(idx),
			FrameColumnData::Int4(container) => container.is_defined(idx),
			FrameColumnData::Int8(container) => container.is_defined(idx),
			FrameColumnData::Int16(container) => container.is_defined(idx),
			FrameColumnData::Uint1(container) => container.is_defined(idx),
			FrameColumnData::Uint2(container) => container.is_defined(idx),
			FrameColumnData::Uint4(container) => container.is_defined(idx),
			FrameColumnData::Uint8(container) => container.is_defined(idx),
			FrameColumnData::Uint16(container) => container.is_defined(idx),
			FrameColumnData::Utf8(container) => container.is_defined(idx),
			FrameColumnData::Date(container) => container.is_defined(idx),
			FrameColumnData::DateTime(container) => container.is_defined(idx),
			FrameColumnData::Time(container) => container.is_defined(idx),
			FrameColumnData::Duration(container) => container.is_defined(idx),
			FrameColumnData::IdentityId(container) => container.is_defined(idx),
			FrameColumnData::Uuid4(container) => container.is_defined(idx),
			FrameColumnData::Uuid7(container) => container.is_defined(idx),
			FrameColumnData::Blob(container) => container.is_defined(idx),
			FrameColumnData::Int(container) => container.is_defined(idx),
			FrameColumnData::Uint(container) => container.is_defined(idx),
			FrameColumnData::Decimal(container) => container.is_defined(idx),
			FrameColumnData::Any(container) => container.is_defined(idx),
			FrameColumnData::DictionaryId(container) => container.is_defined(idx),
			FrameColumnData::Option {
				bitvec,
				..
			} => idx < DataBitVec::len(bitvec) && DataBitVec::get(bitvec, idx),
		}
	}

	pub fn is_bool(&self) -> bool {
		self.get_type() == Type::Boolean
	}

	pub fn is_float(&self) -> bool {
		self.get_type() == Type::Float4 || self.get_type() == Type::Float8
	}

	pub fn is_utf8(&self) -> bool {
		self.get_type() == Type::Utf8
	}

	pub fn is_number(&self) -> bool {
		matches!(
			self.get_type(),
			Type::Float4
				| Type::Float8 | Type::Int1 | Type::Int2
				| Type::Int4 | Type::Int8 | Type::Int16
				| Type::Uint1 | Type::Uint2 | Type::Uint4
				| Type::Uint8 | Type::Uint16
		)
	}

	pub fn is_text(&self) -> bool {
		self.get_type() == Type::Utf8
	}

	pub fn is_temporal(&self) -> bool {
		matches!(self.get_type(), Type::Date | Type::DateTime | Type::Time | Type::Duration)
	}

	pub fn is_uuid(&self) -> bool {
		matches!(self.get_type(), Type::Uuid4 | Type::Uuid7)
	}

	pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = Value> + 'a> {
		Box::new((0..self.len()).map(move |i| self.get_value(i)))
	}
}

impl FrameColumnData {
	pub fn len(&self) -> usize {
		match self {
			FrameColumnData::Bool(container) => container.len(),
			FrameColumnData::Float4(container) => container.len(),
			FrameColumnData::Float8(container) => container.len(),
			FrameColumnData::Int1(container) => container.len(),
			FrameColumnData::Int2(container) => container.len(),
			FrameColumnData::Int4(container) => container.len(),
			FrameColumnData::Int8(container) => container.len(),
			FrameColumnData::Int16(container) => container.len(),
			FrameColumnData::Uint1(container) => container.len(),
			FrameColumnData::Uint2(container) => container.len(),
			FrameColumnData::Uint4(container) => container.len(),
			FrameColumnData::Uint8(container) => container.len(),
			FrameColumnData::Uint16(container) => container.len(),
			FrameColumnData::Utf8(container) => container.len(),
			FrameColumnData::Date(container) => container.len(),
			FrameColumnData::DateTime(container) => container.len(),
			FrameColumnData::Time(container) => container.len(),
			FrameColumnData::Duration(container) => container.len(),
			FrameColumnData::IdentityId(container) => container.len(),
			FrameColumnData::Uuid4(container) => container.len(),
			FrameColumnData::Uuid7(container) => container.len(),
			FrameColumnData::Blob(container) => container.len(),
			FrameColumnData::Int(container) => container.len(),
			FrameColumnData::Uint(container) => container.len(),
			FrameColumnData::Decimal(container) => container.len(),
			FrameColumnData::Any(container) => container.len(),
			FrameColumnData::DictionaryId(container) => container.len(),
			FrameColumnData::Option {
				inner,
				..
			} => inner.len(),
		}
	}

	pub fn is_empty(&self) -> bool {
		self.len() == 0
	}

	pub fn as_string(&self, index: usize) -> String {
		match self {
			FrameColumnData::Bool(container) => container.as_string(index),
			FrameColumnData::Float4(container) => {
				if let Some(&v) = container.get(index) {
					format_f32(v)
				} else {
					"none".to_string()
				}
			}
			FrameColumnData::Float8(container) => {
				if let Some(&v) = container.get(index) {
					format_f64(v)
				} else {
					"none".to_string()
				}
			}
			FrameColumnData::Int1(container) => container.as_string(index),
			FrameColumnData::Int2(container) => container.as_string(index),
			FrameColumnData::Int4(container) => container.as_string(index),
			FrameColumnData::Int8(container) => container.as_string(index),
			FrameColumnData::Int16(container) => container.as_string(index),
			FrameColumnData::Uint1(container) => container.as_string(index),
			FrameColumnData::Uint2(container) => container.as_string(index),
			FrameColumnData::Uint4(container) => container.as_string(index),
			FrameColumnData::Uint8(container) => container.as_string(index),
			FrameColumnData::Uint16(container) => container.as_string(index),
			FrameColumnData::Utf8(container) => container.as_string(index),
			FrameColumnData::Date(container) => container.as_string(index),
			FrameColumnData::DateTime(container) => container.as_string(index),
			FrameColumnData::Time(container) => container.as_string(index),
			FrameColumnData::Duration(container) => container.as_string(index),
			FrameColumnData::IdentityId(container) => container.as_string(index),
			FrameColumnData::Uuid4(container) => container.as_string(index),
			FrameColumnData::Uuid7(container) => container.as_string(index),
			FrameColumnData::Blob(container) => container.as_string(index),
			FrameColumnData::Int(container) => container.as_string(index),
			FrameColumnData::Uint(container) => container.as_string(index),
			FrameColumnData::Decimal(container) => container.as_string(index),
			FrameColumnData::Any(container) => container.as_string(index),
			FrameColumnData::DictionaryId(container) => container.as_string(index),
			FrameColumnData::Option {
				inner,
				bitvec,
			} => {
				if DataBitVec::get(bitvec, index) {
					inner.as_string(index)
				} else {
					"none".to_string()
				}
			}
		}
	}
}

impl FrameColumnData {
	pub fn get_value(&self, index: usize) -> Value {
		match self {
			FrameColumnData::Bool(container) => container.get_value(index),
			FrameColumnData::Float4(container) => container.get_value(index),
			FrameColumnData::Float8(container) => container.get_value(index),
			FrameColumnData::Int1(container) => container.get_value(index),
			FrameColumnData::Int2(container) => container.get_value(index),
			FrameColumnData::Int4(container) => container.get_value(index),
			FrameColumnData::Int8(container) => container.get_value(index),
			FrameColumnData::Int16(container) => container.get_value(index),
			FrameColumnData::Uint1(container) => container.get_value(index),
			FrameColumnData::Uint2(container) => container.get_value(index),
			FrameColumnData::Uint4(container) => container.get_value(index),
			FrameColumnData::Uint8(container) => container.get_value(index),
			FrameColumnData::Uint16(container) => container.get_value(index),
			FrameColumnData::Utf8(container) => container.get_value(index),
			FrameColumnData::Date(container) => container.get_value(index),
			FrameColumnData::DateTime(container) => container.get_value(index),
			FrameColumnData::Time(container) => container.get_value(index),
			FrameColumnData::Duration(container) => container.get_value(index),
			FrameColumnData::IdentityId(container) => container.get_value(index),
			FrameColumnData::Uuid4(container) => container.get_value(index),
			FrameColumnData::Uuid7(container) => container.get_value(index),
			FrameColumnData::Blob(container) => container.get_value(index),
			FrameColumnData::Int(container) => container.get_value(index),
			FrameColumnData::Uint(container) => container.get_value(index),
			FrameColumnData::Decimal(container) => container.get_value(index),
			FrameColumnData::Any(container) => container.get_value(index),
			FrameColumnData::DictionaryId(container) => container.get_value(index),
			FrameColumnData::Option {
				inner,
				bitvec,
			} => {
				if DataBitVec::get(bitvec, index) {
					inner.get_value(index)
				} else {
					Value::none_of(inner.get_type())
				}
			}
		}
	}
}