1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use crate::{DatabaseInner, ExecuteError, Payload, Row, Schema, Value};
use crate::{Glue, Result};
use sqlparser::ast::ObjectName;

impl Glue {
	pub async fn explain(&self, object: &ObjectName) -> Result<Payload> {
		let mut name_vec = object.0.clone();
		let (store_name, opt_table_name) = match name_vec.len() {
			2 => (
				Some(name_vec.remove(0).value),
				Some(name_vec.remove(0).value),
			),
			1 => {
				let name = name_vec.remove(0).value;
				if name == "ALL" {
					let databases: Vec<Row> = self
						.get_database_list()
						.into_iter()
						.map(|name| Row(vec![name.clone().into()]))
						.collect();
					return Ok(Payload::Select {
						labels: vec![String::from("database")],
						rows: databases,
					});
				}
				if name == "ALL_TABLE" {
					let mut tables = vec![];
					for db_name in self.get_database_list().into_iter() {
						tables.extend(
							self.get_database(&Some(db_name.clone()))?
								.get_tables()
								.await?
								.iter()
								.map(|table| Row(vec![db_name.clone().into(), table.clone()])),
						);
					}
					return Ok(Payload::Select {
						labels: vec![String::from("database"), String::from("table")],
						rows: tables,
					});
				} else if self.get_database_list().contains(&&name) {
					(Some(name), None)
				} else {
					(None, Some(name))
				}
			}
			_ => return Err(ExecuteError::ObjectNotRecognised.into()),
		};

		let database = self.get_database(&store_name)?;
		if let Some(table_name) = opt_table_name {
			let Schema { column_defs, .. } = database
				.fetch_schema(&table_name)
				.await?
				.ok_or(ExecuteError::ObjectNotRecognised)?;
			let columns = column_defs
				.iter()
				.map(|column| {
					(
						column.name.clone().into(),
						column.data_type.to_string().into(),
					)
				})
				.map(|(name, data_type)| Row(vec![name, data_type]))
				.collect();
			Ok(Payload::Select {
				labels: vec![String::from("column"), String::from("data_type")],
				rows: columns,
			})
		} else {
			Ok(Payload::Select {
				labels: vec![String::from("table")],
				rows: database
					.get_tables()
					.await?
					.into_iter()
					.map(|table| Row(vec![table]))
					.collect(),
			})
		}
	}
}
impl DatabaseInner {
	async fn get_tables(&self) -> Result<Vec<Value>> {
		Ok(self
			.scan_schemas()
			.await?
			.into_iter()
			.map(|Schema { table_name, .. }| table_name.into())
			.collect())
	}
}