reifydb_catalog/store/column/
get.rs1use reifydb_core::{
5 Error,
6 interface::{ColumnsKey, DictionaryId, QueryTransaction},
7};
8use reifydb_type::{Constraint, Type, TypeConstraint, internal};
9
10use crate::store::column::layout::column::LAYOUT;
11
12fn decode_constraint(bytes: &[u8]) -> Option<Constraint> {
14 if bytes.is_empty() {
15 return None;
16 }
17
18 match bytes[0] {
19 0 => None, 1 if bytes.len() >= 5 => {
21 let max_bytes = u32::from_le_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
23 Some(Constraint::MaxBytes(max_bytes.into()))
24 }
25 2 if bytes.len() >= 3 => {
26 let precision = bytes[1];
28 let scale = bytes[2];
29 Some(Constraint::PrecisionScale(precision.into(), scale.into()))
30 }
31 _ => None, }
33}
34
35use crate::{
36 CatalogStore,
37 store::column::{
38 ColumnDef, ColumnId, ColumnIndex,
39 layout::column::{AUTO_INCREMENT, CONSTRAINT, DICTIONARY_ID, ID, INDEX, NAME, VALUE},
40 },
41};
42
43impl CatalogStore {
44 pub async fn get_column(rx: &mut impl QueryTransaction, column: ColumnId) -> crate::Result<ColumnDef> {
45 let multi = rx.get(&ColumnsKey::encoded(column)).await?.ok_or_else(|| {
46 Error(internal!(
47 "Table column with ID {:?} not found in catalog. This indicates a critical catalog inconsistency.",
48 column
49 ))
50 })?;
51
52 let row = multi.values;
53
54 let id = ColumnId(LAYOUT.get_u64(&row, ID));
55 let name = LAYOUT.get_utf8(&row, NAME).to_string();
56 let base_type = Type::from_u8(LAYOUT.get_u8(&row, VALUE));
57 let index = ColumnIndex(LAYOUT.get_u8(&row, INDEX));
58 let auto_increment = LAYOUT.get_bool(&row, AUTO_INCREMENT);
59
60 let constraint_bytes = LAYOUT.get_blob(&row, CONSTRAINT);
62 let constraint = match decode_constraint(constraint_bytes.as_bytes()) {
63 Some(c) => TypeConstraint::with_constraint(base_type, c),
64 None => TypeConstraint::unconstrained(base_type),
65 };
66
67 let dict_id_raw = LAYOUT.get_u64(&row, DICTIONARY_ID);
69 let dictionary_id = if dict_id_raw == 0 {
70 None
71 } else {
72 Some(DictionaryId(dict_id_raw))
73 };
74
75 let policies = Self::list_column_policies(rx, id).await?;
76
77 Ok(ColumnDef {
78 id,
79 name,
80 constraint,
81 index,
82 policies,
83 auto_increment,
84 dictionary_id,
85 })
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use reifydb_core::interface::ColumnId;
92 use reifydb_engine::test_utils::create_test_command_transaction;
93 use reifydb_type::{Type, TypeConstraint};
94
95 use crate::{CatalogStore, test_utils::create_test_column};
96
97 #[tokio::test]
98 async fn test_ok() {
99 let mut txn = create_test_command_transaction().await;
100 create_test_column(&mut txn, "col_1", TypeConstraint::unconstrained(Type::Int1), vec![]).await;
101 create_test_column(&mut txn, "col_2", TypeConstraint::unconstrained(Type::Int2), vec![]).await;
102 create_test_column(&mut txn, "col_3", TypeConstraint::unconstrained(Type::Int4), vec![]).await;
103
104 let result = CatalogStore::get_column(&mut txn, ColumnId(8194)).await.unwrap();
105
106 assert_eq!(result.id, ColumnId(8194));
107 assert_eq!(result.name, "col_2");
108 assert_eq!(result.constraint.get_type(), Type::Int2);
109 assert_eq!(result.auto_increment, false);
110 }
111
112 #[tokio::test]
113 async fn test_not_found() {
114 let mut txn = create_test_command_transaction().await;
115 create_test_column(&mut txn, "col_1", TypeConstraint::unconstrained(Type::Int1), vec![]).await;
116 create_test_column(&mut txn, "col_2", TypeConstraint::unconstrained(Type::Int2), vec![]).await;
117 create_test_column(&mut txn, "col_3", TypeConstraint::unconstrained(Type::Int4), vec![]).await;
118
119 let err = CatalogStore::get_column(&mut txn, ColumnId(4)).await.unwrap_err();
120 assert_eq!(err.code, "INTERNAL_ERROR");
121 assert!(err.message.contains("ColumnId(4)"));
122 assert!(err.message.contains("not found in catalog"));
123 }
124}