nodedb_physical/physical_plan/document/
declared_column.rs1use nodedb_types::columnar::{ColumnDef, ColumnType, FloatWidth, IntWidth};
13
14#[derive(
16 Debug,
17 Clone,
18 PartialEq,
19 serde::Serialize,
20 serde::Deserialize,
21 zerompk::ToMessagePack,
22 zerompk::FromMessagePack,
23)]
24pub struct DeclaredColumn {
25 pub name: String,
27 pub column_type: ColumnType,
29 pub int_width: Option<IntWidth>,
31 pub float_width: Option<FloatWidth>,
33}
34
35impl DeclaredColumn {
36 pub fn from_declared(name: &str, declared: &str) -> Option<Self> {
43 let column_type = ColumnType::from_declared_type(declared)?;
44 if !fixes_stored_value(&column_type) {
45 return None;
46 }
47 Some(Self {
48 name: name.to_string(),
49 column_type,
50 int_width: IntWidth::from_declared_type(declared),
51 float_width: FloatWidth::from_declared_type(declared),
52 })
53 }
54
55 pub fn from_column_def(column: &ColumnDef) -> Option<Self> {
60 fixes_stored_value(&column.column_type).then(|| Self {
61 name: column.name.clone(),
62 column_type: column.column_type,
63 int_width: column.int_width,
64 float_width: column.float_width,
65 })
66 }
67}
68
69fn fixes_stored_value(column_type: &ColumnType) -> bool {
72 matches!(
73 column_type,
74 ColumnType::Int64 | ColumnType::Float64 | ColumnType::Decimal(Some(_))
75 )
76}
77
78#[cfg(test)]
79mod tests {
80 use nodedb_types::columnar::DecimalTypmod;
81
82 use super::*;
83
84 #[test]
85 fn numeric_declarations_resolve_with_their_width() {
86 let small = DeclaredColumn::from_declared("n", "SMALLINT NOT NULL").expect("smallint");
87 assert_eq!(small.column_type, ColumnType::Int64);
88 assert_eq!(small.int_width, Some(IntWidth::I16));
89
90 let real = DeclaredColumn::from_declared("r", "REAL").expect("real");
91 assert_eq!(real.column_type, ColumnType::Float64);
92 assert_eq!(real.float_width, Some(FloatWidth::F32));
93
94 let typmod = DecimalTypmod::new(5, 2).expect("valid typmod");
95 let dec = DeclaredColumn::from_declared("d", "DECIMAL(5, 2)").expect("decimal");
96 assert_eq!(dec.column_type, ColumnType::Decimal(Some(typmod)));
97 }
98
99 #[test]
100 fn schema_column_keeps_its_declared_width() {
101 let small = ColumnDef::nullable("n", ColumnType::Int64).with_declared_width("SMALLINT");
102 let declared = DeclaredColumn::from_column_def(&small).expect("integer column");
103 assert_eq!(declared.int_width, Some(IntWidth::I16));
104 assert_eq!(
105 declared,
106 DeclaredColumn::from_declared("n", "SMALLINT").expect("smallint")
107 );
108 assert!(
109 DeclaredColumn::from_column_def(&ColumnDef::nullable("t", ColumnType::String))
110 .is_none()
111 );
112 }
113
114 #[test]
115 fn other_declarations_are_not_retyped() {
116 for declared in [
117 "TEXT",
118 "DECIMAL",
119 "BOOL",
120 "TIMESTAMP",
121 "VECTOR(3)",
122 "unknown",
123 ] {
124 assert!(
125 DeclaredColumn::from_declared("c", declared).is_none(),
126 "{declared}"
127 );
128 }
129 }
130}