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