1use rudb_common::{Field, LogicalType};
30
31pub const DUCKDB: &str = "duckdb";
33
34#[must_use]
36pub fn database_fields() -> Vec<Field> {
37 vec![
38 Field::new("database_name", LogicalType::Varchar),
39 Field::new("database_oid", LogicalType::BigInt),
40 Field::new("path", LogicalType::Varchar),
41 Field::new("comment", LogicalType::Varchar),
42 Field::new("tags", tags()),
43 Field::new("internal", LogicalType::Boolean),
44 Field::new("type", LogicalType::Varchar),
45 Field::new("readonly", LogicalType::Boolean),
46 Field::new("encrypted", LogicalType::Boolean),
47 Field::new("cipher", LogicalType::Varchar),
48 Field::new("options", tags()),
49 ]
50}
51
52#[must_use]
58pub fn schema_fields() -> Vec<Field> {
59 vec![
60 Field::new("oid", LogicalType::BigInt),
61 Field::new("database_name", LogicalType::Varchar),
62 Field::new("database_oid", LogicalType::BigInt),
63 Field::new("schema_name", LogicalType::Varchar),
64 Field::new("comment", LogicalType::Varchar),
65 Field::new("tags", tags()),
66 Field::new("internal", LogicalType::Boolean),
67 Field::new("sql", LogicalType::Varchar),
68 Field::new("parent_schema", LogicalType::Varchar),
69 Field::new("parent_schema_oid", LogicalType::BigInt),
70 ]
71}
72
73#[must_use]
75pub fn table_fields() -> Vec<Field> {
76 vec![
77 Field::new("database_name", LogicalType::Varchar),
78 Field::new("database_oid", LogicalType::BigInt),
79 Field::new("schema_name", LogicalType::Varchar),
80 Field::new("schema_oid", LogicalType::BigInt),
81 Field::new("table_name", LogicalType::Varchar),
82 Field::new("table_oid", LogicalType::BigInt),
83 Field::new("comment", LogicalType::Varchar),
84 Field::new("tags", tags()),
85 Field::new("internal", LogicalType::Boolean),
86 Field::new("temporary", LogicalType::Boolean),
87 Field::new("has_primary_key", LogicalType::Boolean),
88 Field::new("estimated_size", LogicalType::BigInt),
89 Field::new("column_count", LogicalType::BigInt),
90 Field::new("index_count", LogicalType::BigInt),
91 Field::new("check_constraint_count", LogicalType::BigInt),
92 Field::new("sql", LogicalType::Varchar),
93 ]
94}
95
96#[must_use]
98pub fn column_fields() -> Vec<Field> {
99 vec![
100 Field::new("database_name", LogicalType::Varchar),
101 Field::new("database_oid", LogicalType::BigInt),
102 Field::new("schema_name", LogicalType::Varchar),
103 Field::new("schema_oid", LogicalType::BigInt),
104 Field::new("table_name", LogicalType::Varchar),
105 Field::new("table_oid", LogicalType::BigInt),
106 Field::new("column_name", LogicalType::Varchar),
107 Field::new("column_index", LogicalType::Integer),
108 Field::new("comment", LogicalType::Varchar),
109 Field::new("internal", LogicalType::Boolean),
110 Field::new("column_default", LogicalType::Varchar),
111 Field::new("is_nullable", LogicalType::Boolean),
112 Field::new("data_type", LogicalType::Varchar),
113 Field::new("data_type_id", LogicalType::BigInt),
114 Field::new("character_maximum_length", LogicalType::Integer),
115 Field::new("numeric_precision", LogicalType::Integer),
116 Field::new("numeric_precision_radix", LogicalType::Integer),
117 Field::new("numeric_scale", LogicalType::Integer),
118 Field::new("tags", tags()),
119 Field::new("is_generated", LogicalType::Boolean),
120 Field::new("generation_expression", LogicalType::Varchar),
121 ]
122}
123
124#[must_use]
131pub fn canonical(ty: &LogicalType) -> String {
132 match ty {
133 LogicalType::Decimal { .. } => "DECIMAL".to_string(),
134 LogicalType::List(_) | LogicalType::Array(_, _) => "LIST".to_string(),
135 LogicalType::Map(_, _) => "MAP".to_string(),
136 LogicalType::Struct(_) => "STRUCT".to_string(),
137 LogicalType::Union(_) => "UNION".to_string(),
138 other => other.to_string(),
139 }
140}
141
142#[must_use]
152pub fn numeric_facts(ty: &LogicalType) -> (Option<i32>, Option<i32>, Option<i32>) {
153 let binary = |bits| (Some(bits), Some(2), Some(0));
154 match ty {
155 LogicalType::TinyInt => binary(8),
156 LogicalType::SmallInt => binary(16),
157 LogicalType::Integer => binary(32),
158 LogicalType::BigInt => binary(64),
159 LogicalType::HugeInt => binary(128),
160 LogicalType::Float => binary(24),
161 LogicalType::Double => binary(53),
162 LogicalType::Decimal { width, scale } => {
163 (Some(i32::from(*width)), Some(10), Some(i32::from(*scale)))
164 }
165 _ => (None, None, None),
166 }
167}
168
169fn tags() -> LogicalType {
171 LogicalType::map(LogicalType::Varchar, LogicalType::Varchar)
172}
173
174#[cfg(test)]
175mod tests {
176 use rudb_common::LogicalType;
177
178 use super::{
179 canonical, column_fields, database_fields, numeric_facts, schema_fields, table_fields,
180 };
181
182 #[test]
183 fn the_four_tables_are_the_shape_the_pin_returns() {
184 assert_eq!(database_fields().len(), 11);
185 assert_eq!(schema_fields().len(), 10);
186 assert_eq!(table_fields().len(), 16);
187 assert_eq!(column_fields().len(), 21);
188 }
189
190 #[test]
192 fn a_numeric_precision_is_bits_everywhere_except_on_a_decimal() {
193 assert_eq!(numeric_facts(&LogicalType::Integer), (Some(32), Some(2), Some(0)));
194 assert_eq!(numeric_facts(&LogicalType::Double), (Some(53), Some(2), Some(0)));
195 assert_eq!(
196 numeric_facts(&LogicalType::Decimal { width: 9, scale: 2 }),
197 (Some(9), Some(10), Some(2))
198 );
199 assert_eq!(numeric_facts(&LogicalType::UBigInt), (None, None, None));
201 assert_eq!(numeric_facts(&LogicalType::Varchar), (None, None, None));
202 }
203
204 #[test]
205 fn a_types_modifiers_are_not_part_of_the_name_the_oid_is_keyed_by() {
206 assert_eq!(canonical(&LogicalType::Decimal { width: 9, scale: 2 }), "DECIMAL");
207 assert_eq!(canonical(&LogicalType::list(LogicalType::Integer)), "LIST");
208 assert_eq!(canonical(&LogicalType::Integer), "INTEGER");
209 assert_eq!(canonical(&LogicalType::TimestampTz), "TIMESTAMP WITH TIME ZONE");
210 }
211
212 #[test]
214 fn a_schemas_own_oid_is_spelled_oid_and_not_schema_oid() {
215 assert_eq!(schema_fields()[0].name, "oid");
216 assert!(schema_fields().iter().all(|field| field.name != "schema_oid"));
217 }
218}