Skip to main content

uqa_storage/
value_index_key.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Physical B-tree namespaces distinguish column accelerators from named SQL indexes.
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
10pub enum ValueIndexKey {
11    Column(String),
12    Index(String),
13}
14
15impl ValueIndexKey {
16    #[must_use]
17    pub fn name(&self) -> &str {
18        match self {
19            Self::Column(name) | Self::Index(name) => name,
20        }
21    }
22}
23
24impl From<&str> for ValueIndexKey {
25    fn from(name: &str) -> Self {
26        Self::Column(name.into())
27    }
28}
29
30impl From<String> for ValueIndexKey {
31    fn from(name: String) -> Self {
32        Self::Column(name)
33    }
34}
35
36impl std::fmt::Display for ValueIndexKey {
37    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38        match self {
39            Self::Column(name) => write!(formatter, "column {name}"),
40            Self::Index(name) => write!(formatter, "index {name}"),
41        }
42    }
43}
44
45impl rusqlite::ToSql for ValueIndexKey {
46    fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
47        use rusqlite::types::{ToSqlOutput, ValueRef};
48        // SQLite's TEXT and BLOB key domains are disjoint, even for identical bytes. Legacy column keys retain their original TEXT representation.
49        Ok(ToSqlOutput::Borrowed(match self {
50            Self::Column(name) => ValueRef::Text(name.as_bytes()),
51            Self::Index(name) => ValueRef::Blob(name.as_bytes()),
52        }))
53    }
54}
55
56impl rusqlite::types::FromSql for ValueIndexKey {
57    fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
58        use rusqlite::types::{FromSqlError, ValueRef};
59        match value {
60            ValueRef::Text(bytes) => Ok(Self::Column(
61                std::str::from_utf8(bytes)
62                    .map_err(|error| FromSqlError::Other(Box::new(error)))?
63                    .into(),
64            )),
65            ValueRef::Blob(bytes) => Ok(Self::Index(
66                std::str::from_utf8(bytes)
67                    .map_err(|error| FromSqlError::Other(Box::new(error)))?
68                    .into(),
69            )),
70            _ => Err(FromSqlError::InvalidType),
71        }
72    }
73}