cipherstash_config/column/
config.rsuse std::collections::HashSet;
use super::{index::Index, IndexType, TokenFilter};
use crate::list::ListEntry;
use crate::operator::Operator;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash)]
#[serde(rename_all = "kebab-case")]
pub enum ColumnType {
BigInt,
BigUInt,
Boolean,
Date,
Decimal,
Float,
Int,
SmallInt,
Timestamp,
Utf8Str,
#[serde(rename = "jsonb")]
JsonB,
}
impl std::fmt::Display for ColumnType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
ColumnType::BigInt => "BigInt",
ColumnType::BigUInt => "BigUInt",
ColumnType::Boolean => "Boolean",
ColumnType::Date => "Date",
ColumnType::Decimal => "Decimal",
ColumnType::Float => "Float",
ColumnType::Int => "Int",
ColumnType::SmallInt => "SmallInt",
ColumnType::Timestamp => "Timestamp",
ColumnType::Utf8Str => "Utf8Str",
ColumnType::JsonB => "JSONB",
};
write!(f, "{text}")
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum ColumnMode {
PlaintextDuplicate = 1,
EncryptedDuplicate = 2,
Encrypted = 3,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColumnConfig {
pub name: String,
pub in_place: bool,
pub cast_type: ColumnType,
pub indexes: Vec<Index>,
pub mode: ColumnMode,
}
impl ListEntry for ColumnConfig {}
impl PartialEq for ColumnConfig {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl PartialEq<String> for ColumnConfig {
fn eq(&self, other: &String) -> bool {
self.name == *other
}
}
impl ColumnConfig {
pub fn build(name: impl Into<String>) -> Self {
Self {
name: name.into(),
in_place: false,
cast_type: ColumnType::Utf8Str,
indexes: Default::default(),
mode: ColumnMode::EncryptedDuplicate,
}
}
pub fn casts_as(mut self, field_type: ColumnType) -> Self {
self.cast_type = field_type;
self
}
pub fn add_index(mut self, index: Index) -> Self {
self.indexes.push(index);
self
}
pub fn mode(mut self, mode: ColumnMode) -> Self {
self.mode = mode;
self
}
pub fn supports_operator(&self, op: &Operator) -> bool {
self.index_for_operator(op).is_some()
}
pub fn supported_operations(&self) -> Vec<Operator> {
let hash: HashSet<Operator> = self
.indexes
.iter()
.flat_map(|i| i.index_type.supported_operations(&self.cast_type))
.collect();
hash.into_iter().collect()
}
pub fn index_for_operator(&self, op: &Operator) -> Option<&Index> {
self.indexes
.iter()
.find(|i| i.supports(op, &self.cast_type))
}
pub fn index_for_sort(&self) -> Option<&Index> {
self.indexes.iter().find(|i| i.is_orderable())
}
pub fn sort_indexes_by_type(&mut self) {
self.indexes
.sort_by(|a, b| a.index_type.as_str().cmp(b.index_type.as_str()));
}
pub fn has_unique_index_with_downcase(&self) -> bool {
self.indexes.iter().any(|index| {
if let IndexType::Unique { token_filters } = &index.index_type {
token_filters
.iter()
.any(|filter| matches!(filter, TokenFilter::Downcase))
} else {
false
}
})
}
}