cipherstash_config/column/
config.rs1use std::collections::HashSet;
2
3use super::{index::Index, IndexType, TokenFilter};
4use crate::list::ListEntry;
5use crate::operator::Operator;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash)]
10#[serde(rename_all = "kebab-case")]
11pub enum ColumnType {
12 BigInt,
13 BigUInt,
14 Boolean,
15 Date,
16 Decimal,
17 Float,
18 Int,
19 SmallInt,
20 Timestamp,
21 Utf8Str,
22 #[serde(rename = "jsonb")]
23 JsonB,
24 }
26
27impl std::fmt::Display for ColumnType {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 let text = match self {
30 ColumnType::BigInt => "BigInt",
31 ColumnType::BigUInt => "BigUInt",
32 ColumnType::Boolean => "Boolean",
33 ColumnType::Date => "Date",
34 ColumnType::Decimal => "Decimal",
35 ColumnType::Float => "Float",
36 ColumnType::Int => "Int",
37 ColumnType::SmallInt => "SmallInt",
38 ColumnType::Timestamp => "Timestamp",
39 ColumnType::Utf8Str => "Utf8Str",
40 ColumnType::JsonB => "JSONB",
41 };
42
43 write!(f, "{text}")
44 }
45}
46
47#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
48#[serde(rename_all = "kebab-case")]
49pub enum ColumnMode {
50 PlaintextDuplicate = 1,
53 EncryptedDuplicate = 2,
56 Encrypted = 3,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct ColumnConfig {
63 pub name: String,
64 pub in_place: bool,
65 pub cast_type: ColumnType,
66 pub indexes: Vec<Index>,
67 pub mode: ColumnMode,
68}
69
70impl ListEntry for ColumnConfig {}
71
72impl PartialEq for ColumnConfig {
74 fn eq(&self, other: &Self) -> bool {
75 self.name == other.name
76 }
77}
78
79impl PartialEq<String> for ColumnConfig {
81 fn eq(&self, other: &String) -> bool {
82 self.name == *other
83 }
84}
85
86impl ColumnConfig {
87 pub fn build(name: impl Into<String>) -> Self {
93 Self {
94 name: name.into(),
95 in_place: false,
96 cast_type: ColumnType::Utf8Str,
97 indexes: Default::default(),
98 mode: ColumnMode::EncryptedDuplicate,
99 }
100 }
101
102 pub fn casts_as(mut self, field_type: ColumnType) -> Self {
105 self.cast_type = field_type;
106 self
107 }
108
109 pub fn add_index(mut self, index: Index) -> Self {
112 self.indexes.push(index);
115 self
116 }
117
118 pub fn mode(mut self, mode: ColumnMode) -> Self {
119 self.mode = mode;
120 self
121 }
122
123 pub fn supports_operator(&self, op: &Operator) -> bool {
124 self.index_for_operator(op).is_some()
125 }
126
127 pub fn supported_operations(&self) -> Vec<Operator> {
128 let hash: HashSet<Operator> = self
129 .indexes
130 .iter()
131 .flat_map(|i| i.index_type.supported_operations(&self.cast_type))
132 .collect();
133
134 hash.into_iter().collect()
135 }
136
137 pub fn index_for_operator(&self, op: &Operator) -> Option<&Index> {
138 self.indexes
139 .iter()
140 .find(|i| i.supports(op, &self.cast_type))
141 }
142
143 pub fn index_for_sort(&self) -> Option<&Index> {
144 self.indexes.iter().find(|i| i.is_orderable())
145 }
146
147 pub fn sort_indexes_by_type(&mut self) {
149 self.indexes
150 .sort_by(|a, b| a.index_type.as_str().cmp(b.index_type.as_str()));
151 }
152
153 pub fn has_unique_index_with_downcase(&self) -> bool {
154 self.indexes.iter().any(|index| {
155 if let IndexType::Unique { token_filters } = &index.index_type {
156 token_filters
157 .iter()
158 .any(|filter| matches!(filter, TokenFilter::Downcase))
159 } else {
160 false
161 }
162 })
163 }
164
165 pub fn into_match_index(self) -> Option<Index> {
166 self.indexes.into_iter().find(|i| i.is_match())
167 }
168
169 pub fn into_ore_index(self) -> Option<Index> {
170 self.indexes.into_iter().find(|i| i.is_ore())
171 }
172
173 pub fn into_unique_index(self) -> Option<Index> {
174 self.indexes.into_iter().find(|i| i.is_unique())
175 }
176
177 pub fn into_ste_vec_index(self) -> Option<Index> {
178 self.indexes.into_iter().find(|i| i.is_ste_vec())
179 }
180}