1use crate::reserved::FIRST_USER_FIELD_ID;
2use llkv_column_map::types::FieldId;
3use llkv_result::{Error, Result};
4use rustc_hash::FxHashMap;
5use std::sync::{Arc, RwLock};
6
7#[derive(Debug, Clone, PartialEq, Eq, Default, bitcode::Encode, bitcode::Decode)]
9pub struct FieldConstraints {
10 pub primary_key: bool,
11 pub unique: bool,
12 pub check_expr: Option<String>,
13}
14
15#[derive(Debug, Clone)]
17pub struct FieldDefinition {
18 pub(super) display_name: String,
19 pub(super) constraints: FieldConstraints,
20}
21
22impl FieldDefinition {
23 pub fn new(display_name: impl Into<String>) -> Self {
24 Self {
25 display_name: display_name.into(),
26 constraints: FieldConstraints::default(),
27 }
28 }
29
30 pub fn with_primary_key(mut self, primary_key: bool) -> Self {
31 self.constraints.primary_key = primary_key;
32 if primary_key {
33 self.constraints.unique = true;
34 }
35 self
36 }
37
38 pub fn with_unique(mut self, unique: bool) -> Self {
39 if unique {
40 self.constraints.unique = true;
41 }
42 self
43 }
44
45 pub fn with_check_expr(mut self, check_expr: Option<String>) -> Self {
46 self.constraints.check_expr = check_expr;
47 self
48 }
49
50 pub fn constraints(&self) -> &FieldConstraints {
51 &self.constraints
52 }
53}
54
55impl From<&str> for FieldDefinition {
56 fn from(value: &str) -> Self {
57 FieldDefinition::new(value)
58 }
59}
60
61impl From<String> for FieldDefinition {
62 fn from(value: String) -> Self {
63 FieldDefinition::new(value)
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
69pub struct FieldInfo {
70 pub field_id: FieldId,
71 pub display_name: String,
72 pub canonical_name: String,
73 pub constraints: FieldConstraints,
74}
75
76#[derive(Debug, Clone)]
77struct FieldMetadata {
78 display_name: String,
79 canonical_name: String,
80 constraints: FieldConstraints,
81}
82
83#[derive(Debug, Clone)]
85pub struct FieldResolver {
86 inner: Arc<RwLock<FieldResolverInner>>,
87}
88
89#[derive(Debug)]
90struct FieldResolverInner {
91 field_name_to_id: FxHashMap<String, FieldId>,
92 field_id_to_meta: FxHashMap<FieldId, FieldMetadata>,
93 next_field_id: FieldId,
94}
95
96impl FieldResolver {
97 pub fn new() -> Self {
98 Self {
99 inner: Arc::new(RwLock::new(FieldResolverInner {
100 field_name_to_id: FxHashMap::default(),
101 field_id_to_meta: FxHashMap::default(),
102 next_field_id: FIRST_USER_FIELD_ID,
103 })),
104 }
105 }
106
107 pub fn register_field(&self, definition: impl Into<FieldDefinition>) -> Result<FieldId> {
108 let FieldDefinition {
109 display_name,
110 constraints,
111 } = definition.into();
112 let canonical_name = display_name.to_ascii_lowercase();
113
114 let mut inner = self.inner.write().map_err(|_| {
115 Error::Internal("Failed to acquire field resolver write lock".to_string())
116 })?;
117
118 if inner.field_name_to_id.contains_key(&canonical_name) {
119 return Err(Error::CatalogError(format!(
120 "Field '{}' already exists in table",
121 display_name
122 )));
123 }
124
125 let field_id = inner.next_field_id;
126 inner.next_field_id = inner
127 .next_field_id
128 .checked_add(1)
129 .ok_or_else(|| Error::Internal("FieldId overflow".to_string()))?;
130
131 inner
132 .field_name_to_id
133 .insert(canonical_name.clone(), field_id);
134 inner.field_id_to_meta.insert(
135 field_id,
136 FieldMetadata {
137 display_name,
138 canonical_name,
139 constraints,
140 },
141 );
142
143 Ok(field_id)
144 }
145
146 pub fn field_id(&self, name: &str) -> Option<FieldId> {
147 let canonical = name.to_ascii_lowercase();
148 let inner = self.inner.read().ok()?;
149 inner.field_name_to_id.get(&canonical).copied()
150 }
151
152 pub fn field_name(&self, id: FieldId) -> Option<String> {
153 let inner = self.inner.read().ok()?;
154 inner
155 .field_id_to_meta
156 .get(&id)
157 .map(|meta| meta.display_name.clone())
158 }
159
160 pub fn field_exists(&self, name: &str) -> bool {
161 self.field_id(name).is_some()
162 }
163
164 pub fn field_count(&self) -> usize {
165 match self.inner.read() {
166 Ok(inner) => inner.field_id_to_meta.len(),
167 Err(_) => 0,
168 }
169 }
170
171 pub fn field_names(&self) -> Vec<String> {
172 match self.inner.read() {
173 Ok(inner) => inner
174 .field_id_to_meta
175 .values()
176 .map(|meta| meta.display_name.clone())
177 .collect(),
178 Err(_) => Vec::new(),
179 }
180 }
181
182 pub fn field_constraints(&self, id: FieldId) -> Option<FieldConstraints> {
183 let inner = self.inner.read().ok()?;
184 inner
185 .field_id_to_meta
186 .get(&id)
187 .map(|meta| meta.constraints.clone())
188 }
189
190 pub fn field_constraints_by_name(&self, name: &str) -> Option<FieldConstraints> {
191 let id = self.field_id(name)?;
192 self.field_constraints(id)
193 }
194
195 pub fn set_field_unique(&self, name: &str, unique: bool) -> Result<()> {
196 let canonical = name.to_ascii_lowercase();
197 let mut inner = self.inner.write().map_err(|_| {
198 Error::Internal("Failed to acquire field resolver write lock".to_string())
199 })?;
200
201 let field_id = *inner.field_name_to_id.get(&canonical).ok_or_else(|| {
202 Error::CatalogError(format!("Field '{}' does not exist in table", name))
203 })?;
204
205 let metadata = inner.field_id_to_meta.get_mut(&field_id).ok_or_else(|| {
206 Error::CatalogError(format!("Field '{}' metadata is missing from catalog", name))
207 })?;
208
209 if unique {
210 metadata.constraints.unique = true;
211 } else if !metadata.constraints.primary_key {
212 metadata.constraints.unique = false;
213 }
214
215 Ok(())
216 }
217
218 pub fn field_info(&self, id: FieldId) -> Option<FieldInfo> {
219 let inner = self.inner.read().ok()?;
220 inner.field_id_to_meta.get(&id).map(|meta| FieldInfo {
221 field_id: id,
222 display_name: meta.display_name.clone(),
223 canonical_name: meta.canonical_name.clone(),
224 constraints: meta.constraints.clone(),
225 })
226 }
227
228 pub fn field_info_by_name(&self, name: &str) -> Option<FieldInfo> {
229 let id = self.field_id(name)?;
230 self.field_info(id)
231 }
232
233 pub fn export_state(&self) -> FieldResolverState {
234 let inner = match self.inner.read() {
235 Ok(inner) => inner,
236 Err(_) => {
237 return FieldResolverState {
238 fields: Vec::new(),
239 next_field_id: FIRST_USER_FIELD_ID,
240 };
241 }
242 };
243
244 let mut fields = Vec::new();
245 for (&field_id, meta) in &inner.field_id_to_meta {
246 fields.push(FieldState {
247 field_id,
248 display_name: meta.display_name.clone(),
249 canonical_name: meta.canonical_name.clone(),
250 constraints: meta.constraints.clone(),
251 });
252 }
253
254 FieldResolverState {
255 fields,
256 next_field_id: inner.next_field_id,
257 }
258 }
259
260 pub fn from_state(state: FieldResolverState) -> Result<Self> {
261 let mut field_name_to_id = FxHashMap::default();
262 let mut field_id_to_meta = FxHashMap::default();
263
264 for field_state in state.fields {
265 let FieldState {
266 field_id,
267 display_name,
268 canonical_name,
269 constraints,
270 } = field_state;
271
272 if field_id_to_meta.contains_key(&field_id) {
273 return Err(Error::CatalogError(format!(
274 "Duplicate field_id {} in field resolver state",
275 field_id
276 )));
277 }
278
279 if field_name_to_id.contains_key(&canonical_name) {
280 return Err(Error::CatalogError(format!(
281 "Duplicate field name '{}' in field resolver state",
282 display_name
283 )));
284 }
285
286 field_name_to_id.insert(canonical_name.clone(), field_id);
287 field_id_to_meta.insert(
288 field_id,
289 FieldMetadata {
290 display_name,
291 canonical_name,
292 constraints,
293 },
294 );
295 }
296
297 Ok(Self {
298 inner: Arc::new(RwLock::new(FieldResolverInner {
299 field_name_to_id,
300 field_id_to_meta,
301 next_field_id: state.next_field_id,
302 })),
303 })
304 }
305}
306
307impl Default for FieldResolver {
308 fn default() -> Self {
309 Self::new()
310 }
311}
312
313#[derive(Debug, Clone, bitcode::Encode, bitcode::Decode)]
315pub struct FieldResolverState {
316 pub fields: Vec<FieldState>,
317 pub next_field_id: FieldId,
318}
319
320#[derive(Debug, Clone, bitcode::Encode, bitcode::Decode)]
322pub struct FieldState {
323 pub field_id: FieldId,
324 pub display_name: String,
325 pub canonical_name: String,
326 pub constraints: FieldConstraints,
327}
328
329#[cfg(test)]
330mod tests {
331 use super::*;
332
333 #[test]
334 fn field_resolver_register_and_lookup() {
335 let resolver = FieldResolver::new();
336 let fid = resolver.register_field("UserName").unwrap();
337 assert_eq!(resolver.field_id("username"), Some(fid));
338 assert_eq!(resolver.field_name(fid), Some("UserName".to_string()));
339 }
340
341 #[test]
342 fn field_resolver_set_unique() {
343 let resolver = FieldResolver::new();
344 resolver
345 .register_field(FieldDefinition::new("id").with_primary_key(true))
346 .unwrap();
347 resolver
348 .register_field(FieldDefinition::new("email"))
349 .unwrap();
350 resolver.set_field_unique("email", true).unwrap();
351 assert!(resolver.field_constraints_by_name("email").unwrap().unique);
352 resolver.set_field_unique("email", false).unwrap();
353 assert!(!resolver.field_constraints_by_name("email").unwrap().unique);
354 }
355
356 #[test]
357 fn field_resolver_export_roundtrip() {
358 let resolver = FieldResolver::new();
359 let fid1 = resolver.register_field("field1").unwrap();
360 let fid2 = resolver.register_field("Field2").unwrap();
361
362 let state = resolver.export_state();
363 let restored = FieldResolver::from_state(state).unwrap();
364
365 assert_eq!(restored.field_id("field1"), Some(fid1));
366 assert_eq!(restored.field_id("field2"), Some(fid2));
367 }
368}