dameng_helper/table.rs
1use crate::DmDateType;
2use odbc_common::{Print, StyledString, Table, TableTheme, TextStyle};
3use serde::{Deserialize, Serialize};
4use std::collections::BTreeMap;
5use std::str::FromStr;
6use strum::{Display, EnumString};
7
8/// dameng database table item
9#[derive(Debug, Default, Serialize, Deserialize)]
10pub struct DmTableItem {
11 pub name: String,
12 pub table_id: usize,
13 pub col_index: usize,
14 pub r#type: DmDateType,
15 pub length: usize,
16 pub scale: usize,
17 pub nullable: bool,
18 pub default_val: Option<String>,
19 pub table_name: String,
20 pub create_time: String,
21}
22
23impl DmTableItem {
24 fn to_vec(&self) -> Vec<String> {
25 let mut vec = vec![];
26 vec.push(self.name.to_string());
27 vec.push(self.table_id.to_string());
28 vec.push(self.col_index.to_string());
29 vec.push(format!("{:?}", self.r#type));
30 vec.push(self.length.to_string());
31 vec.push(self.scale.to_string());
32 vec.push(self.nullable.to_string());
33 vec.push(self.default_val.clone().unwrap_or_default());
34 vec.push(self.table_name.to_string());
35 vec.push(self.create_time.to_string());
36 vec
37 }
38}
39
40/// table describe
41#[derive(Debug, EnumString, Display, Serialize, Deserialize)]
42pub enum ColNameEnum {
43 #[strum(to_string = "NAME")]
44 Name,
45 #[strum(to_string = "ID")]
46 Id,
47 #[strum(to_string = "COLID")]
48 ColId,
49 #[strum(to_string = "TYPE$")]
50 Type,
51 #[strum(to_string = "LENGTH$")]
52 Length,
53 #[strum(to_string = "SCALE")]
54 Scale,
55 #[strum(to_string = "NULLABLE$")]
56 Nullable,
57 #[strum(to_string = "DEFVAL")]
58 DefaultVal,
59 #[strum(to_string = "TABLE_NAME")]
60 TableName,
61 #[strum(to_string = "CRTDATE")]
62 CreateTime,
63}
64
65/// The table data. Execute sql get table describe
66/// ```bash
67/// > SELECT A.NAME, A.ID, A.COLID, A.TYPE$, A.LENGTH$, A.SCALE, A.NULLABLE$, A.DEFVAL, B.NAME AS TABLE_NAME, B.CRTDATE FROM SYSCOLUMNS AS a LEFT JOIN SYSOBJECTS AS B ON A.id = B.id WHERE B.name IN ('Text_len','T2','test_type') AND B.SCHID IN (SELECT ID FROM SYSOBJECTS WHERE name = 'SYSDBA');
68/// NAME |ID |COLID|TYPE$ |LENGTH$ |SCALE|NULLABLE$|DEFVAL |TABLE_NAME|CRTDATE |
69/// -----------------+----+-----+------------------------------+----------+-----+---------+------------------+----------+-----------------------+
70/// C1 |1155| 0|DATETIME WITH TIME ZONE | 10| 2|Y | |T2 |2022-09-21 09:06:07.633|
71/// C2 |1155| 1|TIMESTAMP | 8| 6|Y | |T2 |2022-09-21 09:06:07.633|
72/// c3 |1155| 2|VARCHAR | 100| 0|Y | |T2 |2022-09-21 09:06:07.633|
73/// c4 |1155| 3|NUMERIC | 0| 0|Y | |T2 |2022-09-21 09:06:07.633|
74/// c5 |1155| 4|TIME WITH TIME ZONE | 7| 0|Y | |T2 |2022-09-21 09:06:07.633|
75/// c6 |1155| 5|TIMESTAMP WITH LOCAL TIME ZONE| 8| 4102|Y | |T2 |2022-09-21 09:06:07.633|
76/// NUMBER |1155| 6|NUMBER | 0| 0|Y | |T2 |2022-09-21 09:06:07.633|
77/// DECIMAL |1155| 7|DECIMAL | 0| 0|Y | |T2 |2022-09-21 09:06:07.633|
78/// BIT |1155| 8|BIT | 1| 0|Y | |T2 |2022-09-21 09:06:07.633|
79/// INTEGER |1155| 9|INTEGER | 4| 0|Y | |T2 |2022-09-21 09:06:07.633|
80/// xxx_PLS_INTEGER |1155| 10|INTEGER | 4| 0|Y | |T2 |2022-09-21 09:06:07.633|
81/// BIGINT |1155| 11|BIGINT | 8| 0|Y | |T2 |2022-09-21 09:06:07.633|
82/// TINYINT |1155| 12|TINYINT | 1| 0|Y | |T2 |2022-09-21 09:06:07.633|
83/// BYTE |1155| 13|BYTE | 1| 0|Y | |T2 |2022-09-21 09:06:07.633|
84/// SMALLINT |1155| 14|SMALLINT | 2| 0|Y | |T2 |2022-09-21 09:06:07.633|
85/// BINARY |1155| 15|BINARY | 1| 0|Y | |T2 |2022-09-21 09:06:07.633|
86/// VARBINARY |1155| 16|VARBINARY | 8188| 0|Y | |T2 |2022-09-21 09:06:07.633|
87/// REAL |1155| 17|REAL | 4| 0|Y | |T2 |2022-09-21 09:06:07.633|
88/// FLOAT |1155| 18|FLOAT | 8| 0|Y | |T2 |2022-09-21 09:06:07.633|
89/// DOUBLE |1155| 19|DOUBLE | 8| 0|Y | |T2 |2022-09-21 09:06:07.633|
90/// DOUBLE_PRECISION |1155| 20|DOUBLE PRECISION | 8| 0|Y | |T2 |2022-09-21 09:06:07.633|
91/// CHAR |1155| 21|CHAR | 1| 0|Y | |T2 |2022-09-21 09:06:07.633|
92/// VARCHAR |1155| 22|VARCHAR | 8188| 0|Y | |T2 |2022-09-21 09:06:07.633|
93/// TEXT |1155| 23|TEXT |2147483647| 0|Y | |T2 |2022-09-21 09:06:07.633|
94/// IMAGE |1155| 24|IMAGE |2147483647| 0|Y | |T2 |2022-09-21 09:06:07.633|
95/// BLOB |1155| 25|BLOB |2147483647| 0|Y | |T2 |2022-09-21 09:06:07.633|
96/// not_null_test |1155| 26|VARCHAR | 100| 0|N |'default_value_hh'|T2 |2022-09-21 09:06:07.633|
97/// not_null_test_len|1155| 27|VARCHAR | 100| 0|N |'default_value_hh'|T2 |2022-09-21 09:06:07.633|
98/// id |1145| 0|INT | 4| 0|Y | |test_type |2022-09-16 09:53:55.521|
99/// id_bigint |1145| 1|BIGINT | 8| 0|Y | |test_type |2022-09-16 09:53:55.521|
100/// id_varchar |1145| 2|VARCHAR | 8188| 0|Y | |test_type |2022-09-16 09:53:55.521|
101/// data_text |1195| 0|TEXT |2147483647| 0|Y | |Text_len |2022-10-08 02:48:41.901|
102/// ```
103///
104#[derive(Debug, Serialize, Deserialize)]
105pub struct DmTableDesc {
106 pub headers: BTreeMap<usize, ColNameEnum>,
107 pub data: BTreeMap<String, Vec<DmTableItem>>,
108}
109
110impl Print for DmTableDesc {
111 fn convert_table(self) -> anyhow::Result<Table> {
112 let headers: Vec<StyledString> = self
113 .headers
114 .iter()
115 .map(|(_, x)| StyledString::new(x.to_string(), TextStyle::default_header()))
116 .collect();
117
118 let items: Vec<DmTableItem> = self.data.into_iter().fold(vec![], |mut vec, (_, mut x)| {
119 vec.append(&mut x);
120 vec
121 });
122 let rows = items
123 .iter()
124 .map(|x| {
125 x.to_vec()
126 .into_iter()
127 .map(|x| StyledString::new(x, TextStyle::basic_left()))
128 .collect()
129 })
130 .collect::<Vec<Vec<StyledString>>>();
131
132 Ok(Table::new(headers, rows, TableTheme::rounded()))
133 }
134}
135
136impl DmTableDesc {
137 pub fn new(headers: Vec<String>, data: Vec<Vec<String>>) -> anyhow::Result<Self> {
138 macro_rules! to_type {
139 ($val:expr,$t:ident) => {
140 $val.parse::<$t>()
141 };
142 }
143
144 let headers = headers
145 .iter()
146 .enumerate()
147 .map(|(index, x)| (index, ColNameEnum::from_str(x).unwrap()))
148 .fold(BTreeMap::default(), |mut m, (index, x)| {
149 m.insert(index, x);
150 m
151 });
152
153 let mut data_map: BTreeMap<String, Vec<DmTableItem>> = Default::default();
154
155 for rows in data {
156 assert_eq!(rows.len(), headers.len());
157 // iterator row item
158 let mut item = DmTableItem::default();
159 for (index, val) in rows.into_iter().enumerate() {
160 match headers.get(&index).unwrap() {
161 ColNameEnum::Name => item.name = val,
162 ColNameEnum::Id => item.table_id = to_type!(val, usize)?,
163 ColNameEnum::ColId => item.col_index = to_type!(val, usize)?,
164 ColNameEnum::Type => item.r#type = to_type!(val, DmDateType)?,
165 ColNameEnum::Length => item.length = to_type!(val, usize)?,
166 ColNameEnum::Scale => item.scale = to_type!(val, usize)?,
167 ColNameEnum::Nullable => match val.to_uppercase().as_ref() {
168 "Y" => item.nullable = true,
169 "N" => item.nullable = false,
170 _ => {}
171 },
172 ColNameEnum::DefaultVal => item.default_val = Some(val),
173 ColNameEnum::TableName => item.table_name = val,
174 ColNameEnum::CreateTime => item.create_time = val,
175 }
176 }
177
178 if let Some(items) = data_map.get_mut(&item.table_name) {
179 items.push(item);
180 } else {
181 data_map.insert(item.table_name.to_owned(), vec![item]);
182 }
183 }
184 Ok(DmTableDesc {
185 headers,
186 data: data_map,
187 })
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194 use crate::tests::mock_table_result;
195
196 #[test]
197 fn test_dameng_table_desc_convert() {
198 let result = mock_table_result();
199 let dm_table_desc = DmTableDesc::new(result.0, result.1).unwrap();
200 let string = format!("\n{}", dm_table_desc.table_string().unwrap());
201 info!("{}", string);
202
203 let expect = r#"
204╭───────────────────┬──────┬───────┬────────────────────────────────┬────────────┬───────┬───────────┬────────────────────┬────────────┬────────────────────────────╮
205│ NAME │ ID │ COLID │ TYPE$ │ LENGTH$ │ SCALE │ NULLABLE$ │ DEFVAL │ TABLE_NAME │ CRTDATE │
206├───────────────────┼──────┼───────┼────────────────────────────────┼────────────┼───────┼───────────┼────────────────────┼────────────┼────────────────────────────┤
207│ C1 │ 1058 │ 0 │ TIMESTAMP_WITH_TIME_ZONE │ 10 │ 6 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
208│ C2 │ 1058 │ 1 │ TIMESTAMP │ 8 │ 6 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
209│ C3 │ 1058 │ 2 │ VARCHAR │ 100 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
210│ C4 │ 1058 │ 3 │ NUMERIC │ 0 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
211│ C5 │ 1058 │ 4 │ TIME_WITH_TIME_ZONE │ 7 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
212│ C6 │ 1058 │ 5 │ TIMESTAMP_WITH_LOCAL_TIME_ZONE │ 8 │ 4102 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
213│ NUMBER │ 1058 │ 6 │ NUMBER │ 0 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
214│ DECIMAL │ 1058 │ 7 │ DECIMAL │ 0 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
215│ BIT │ 1058 │ 8 │ BIT │ 1 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
216│ INTEGER │ 1058 │ 9 │ INTEGER │ 4 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
217│ XXX_PLS_INTEGER │ 1058 │ 10 │ INTEGER │ 4 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
218│ BIGINT │ 1058 │ 11 │ BIGINT │ 8 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
219│ TINYINT │ 1058 │ 12 │ TINYINT │ 1 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
220│ BYTE │ 1058 │ 13 │ BYTE │ 1 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
221│ SMALLINT │ 1058 │ 14 │ SMALLINT │ 2 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
222│ BINARY │ 1058 │ 15 │ BINARY │ 1 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
223│ VARBINARY │ 1058 │ 16 │ VARBINARY │ 8188 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
224│ REAL │ 1058 │ 17 │ REAL │ 4 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
225│ FLOAT │ 1058 │ 18 │ FLOAT │ 8 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
226│ DOUBLE │ 1058 │ 19 │ DOUBLE │ 8 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
227│ DOUBLE_PRECISION │ 1058 │ 20 │ DOUBLE_PRECISION │ 8 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
228│ CHAR │ 1058 │ 21 │ CHAR │ 1 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
229│ VARCHAR │ 1058 │ 22 │ VARCHAR │ 8188 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
230│ TEXT │ 1058 │ 23 │ TEXT │ 2147483647 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
231│ IMAGE │ 1058 │ 24 │ IMAGE │ 2147483647 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
232│ BLOB │ 1058 │ 25 │ BLOB │ 2147483647 │ 0 │ true │ │ T2 │ 2022-10-24 17:28:26.308000 │
233│ NOT_NULL_TEST │ 1058 │ 26 │ VARCHAR │ 100 │ 0 │ false │ 'default_value_hh' │ T2 │ 2022-10-24 17:28:26.308000 │
234│ NOT_NULL_TEST_LEN │ 1058 │ 27 │ VARCHAR │ 100 │ 0 │ false │ 'default_value_hh' │ T2 │ 2022-10-24 17:28:26.308000 │
235│ C1 │ 1058 │ 0 │ TIMESTAMP_WITH_TIME_ZONE │ 10 │ 6 │ true │ │ T3 │ 2022-10-24 17:28:26.308000 │
236│ CASE_SENSITIVE │ 1058 │ 1 │ TIMESTAMP │ 8 │ 6 │ true │ │ T3 │ 2022-10-24 17:28:26.308000 │
237│ C3 │ 1058 │ 2 │ VARCHAR │ 100 │ 0 │ true │ │ T3 │ 2022-10-24 17:28:26.308000 │
238│ C4 │ 1058 │ 3 │ NUMERIC │ 0 │ 0 │ true │ │ T3 │ 2022-10-24 17:28:26.308000 │
239│ NOT_NULL_TEST_LEN │ 1058 │ 4 │ VARCHAR │ 100 │ 0 │ false │ 'default_value_hh' │ T3 │ 2022-10-24 17:28:26.308000 │
240│ ID │ 1058 │ 0 │ INTEGER │ 4 │ 0 │ false │ │ T4 │ 2022-10-24 17:28:26.308000 │
241│ USER_ID │ 1058 │ 1 │ VARCHAR │ 8188 │ 0 │ false │ │ T4 │ 2022-10-24 17:28:26.308000 │
242│ USER_NAME │ 1058 │ 2 │ TEXT │ 2147483647 │ 0 │ false │ │ T4 │ 2022-10-24 17:28:26.308000 │
243│ ROLE │ 1058 │ 3 │ TEXT │ 2147483647 │ 0 │ false │ │ T4 │ 2022-10-24 17:28:26.308000 │
244│ SOURCE │ 1058 │ 4 │ TEXT │ 2147483647 │ 0 │ false │ │ T4 │ 2022-10-24 17:28:26.308000 │
245├───────────────────┼──────┼───────┼────────────────────────────────┼────────────┼───────┼───────────┼────────────────────┼────────────┼────────────────────────────┤
246│ NAME │ ID │ COLID │ TYPE$ │ LENGTH$ │ SCALE │ NULLABLE$ │ DEFVAL │ TABLE_NAME │ CRTDATE │
247╰───────────────────┴──────┴───────┴────────────────────────────────┴────────────┴───────┴───────────┴────────────────────┴────────────┴────────────────────────────╯"#;
248 assert_eq!(string, expect);
249 }
250}