reifydb-core 0.9.1

Core database interfaces and data structures for ReifyDB
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2026 ReifyDB

use reifydb_codec::key::{deserializer::KeyDeserializer, encoded::EncodedKey, serializer::KeySerializer};
use smallvec::{SmallVec, smallvec};

use super::KeyTag;
use crate::{
	interface::catalog::id::ProcedureId,
	key::{
		any::{Field, KeyFields, Width},
		bound::TaggedKeyBoundRange,
	},
};

#[derive(Debug, Clone, PartialEq, Hash)]
pub struct ProcedureKey {
	pub procedure: ProcedureId,
}

impl ProcedureKey {
	pub const TAG: KeyTag = KeyTag::Procedure;

	pub fn encode(&self) -> EncodedKey {
		let mut serializer = KeySerializer::with_capacity(9);
		serializer.extend_u8(Self::TAG as u8).extend_u64(self.procedure);
		serializer.to_encoded_key()
	}

	pub fn decode(key: &EncodedKey) -> Option<Self> {
		let mut de = KeyDeserializer::from_bytes(key.as_slice());

		let kind: KeyTag = de.read_u8().ok()?.try_into().ok()?;
		if kind != Self::TAG {
			return None;
		}

		let procedure = de.read_u64().ok()?;

		Some(Self {
			procedure: ProcedureId::from_raw(procedure),
		})
	}
}

impl ProcedureKey {
	pub fn new(procedure: impl Into<ProcedureId>) -> Self {
		Self {
			procedure: procedure.into(),
		}
	}

	pub fn encoded(procedure: impl Into<ProcedureId>) -> EncodedKey {
		Self::new(procedure).encode()
	}

	pub fn full_scan() -> TaggedKeyBoundRange {
		TaggedKeyBoundRange::kind(Self::TAG)
	}
}

#[cfg(test)]
pub mod procedure_key_tests {
	use super::ProcedureKey;
	use crate::interface::catalog::id::ProcedureId;

	#[test]
	fn test_encode_decode() {
		let key = ProcedureKey {
			procedure: ProcedureId::from_raw(0xABCD),
		};
		let encoded = key.encode();
		let key = ProcedureKey::decode(&encoded).unwrap();
		assert_eq!(key.procedure, 0xABCD);
	}
}

#[derive(Debug, Clone, PartialEq, Hash)]
pub struct ProcedureParamKey {
	pub procedure: ProcedureId,
	pub param_index: u16,
}

impl ProcedureParamKey {
	pub const TAG: KeyTag = KeyTag::ProcedureParam;

	pub fn encode(&self) -> EncodedKey {
		let mut serializer = KeySerializer::with_capacity(11);
		serializer.extend_u8(Self::TAG as u8).extend_u64(self.procedure).extend_u16(self.param_index);
		serializer.to_encoded_key()
	}

	pub fn decode(key: &EncodedKey) -> Option<Self> {
		let mut de = KeyDeserializer::from_bytes(key.as_slice());

		let kind: KeyTag = de.read_u8().ok()?.try_into().ok()?;
		if kind != Self::TAG {
			return None;
		}

		let procedure = de.read_u64().ok()?;
		let param_index = de.read_u16().ok()?;

		Some(Self {
			procedure: ProcedureId::from_raw(procedure),
			param_index,
		})
	}
}

impl ProcedureParamKey {
	pub fn new(procedure: impl Into<ProcedureId>, param_index: u16) -> Self {
		Self {
			procedure: procedure.into(),
			param_index,
		}
	}

	pub fn encoded(procedure: impl Into<ProcedureId>, param_index: u16) -> EncodedKey {
		Self::new(procedure, param_index).encode()
	}

	pub fn full_scan(procedure: ProcedureId) -> TaggedKeyBoundRange {
		TaggedKeyBoundRange::prefix(Self::TAG, [Field::UDesc(Width::U64, *procedure as u128)])
	}
}

#[cfg(test)]
pub mod procedure_param_key_tests {
	use super::ProcedureParamKey;
	use crate::interface::catalog::id::ProcedureId;

	#[test]
	fn test_encode_decode() {
		let key = ProcedureParamKey {
			procedure: ProcedureId::from_raw(0xCAFE),
			param_index: 7,
		};
		let encoded = key.encode();
		let key = ProcedureParamKey::decode(&encoded).unwrap();
		assert_eq!(key.procedure, 0xCAFE);
		assert_eq!(key.param_index, 7);
	}
}

impl KeyFields for ProcedureKey {
	fn fields(&self) -> SmallVec<[Field<'_>; 6]> {
		smallvec![Field::UDesc(Width::U64, *self.procedure as u128)]
	}
}

impl KeyFields for ProcedureParamKey {
	fn fields(&self) -> SmallVec<[Field<'_>; 6]> {
		smallvec![
			Field::UDesc(Width::U64, *self.procedure as u128),
			Field::UDesc(Width::U16, self.param_index as u128)
		]
	}
}