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}