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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use {
	super::Glue,
	crate::{Cast, ExecuteError, Payload, Result},
	serde_json::{json, value::Value as JSONValue},
};

/// ## Select (`SELECT`)
impl Glue {
	/// Only for `SELECT` queries.
	///
	/// Output is one big [String] of [JSON](https://json.org), wrapped in a [Result] in case it fails.
	///
	/// Generally useful for webby interactions.
	pub fn select_as_json(&mut self, query: &str) -> Result<String> {
		// TODO: Make this more efficient and not affect database if not select by converting earlier
		if let Payload::Select { labels, rows } = self.execute(query)? {
			let array = JSONValue::Array(
				rows.into_iter()
					.map(|row| {
						JSONValue::Object(
							row.0
								.into_iter()
								.enumerate()
								.map(|(index, cell)| (labels[index].clone(), cell.into()))
								.collect::<serde_json::map::Map<String, JSONValue>>(),
						)
					})
					.collect(),
			);
			Ok(array.to_string())
		} else {
			Err(ExecuteError::QueryNotSupported.into())
		}
	}

	/// Only for `SELECT` queries.
	///
	/// Output is one big [String] of [JSON](https://json.org), failures will be converted to json of `{error: [error]}`.
	///
	/// Generally useful for webby interactions.
	pub fn select_as_json_with_headers(&mut self, query: &str) -> String {
		// TODO: Make this more efficient and not affect database if not select by converting earlier
		let mut result = || -> Result<_> {
			if let Payload::Select { labels, rows } = self.execute(query)? {
				let array = JSONValue::Array(
					rows.into_iter()
						.map(|row| {
							JSONValue::Object(
								row.0
									.into_iter()
									.enumerate()
									.map(|(index, cell)| (labels[index].clone(), cell.into()))
									.collect::<serde_json::map::Map<String, JSONValue>>(),
							)
						})
						.collect(),
				);
				Ok(json!({
					"labels": JSONValue::from(labels),
					"data": array
				}))
			} else {
				Err(ExecuteError::QueryNotSupported.into())
			}
		};
		match result() {
			Ok(result) => result,
			Err(error) => json!({"error": error.to_string()}),
		}
		.to_string()
	}

	/// Only for `SELECT` queries.
	pub fn select_as_string(&mut self, query: &str) -> Result<Vec<Vec<String>>> {
		// TODO: Make this more efficient and not affect database
		if let Payload::Select { labels, rows } = self.execute(query)? {
			Ok(vec![labels]
				.into_iter()
				.chain(
					rows.into_iter()
						.map(|row| {
							row.0
								.into_iter()
								.map(|value| value.cast())
								.collect::<Result<Vec<String>>>()
						})
						.collect::<Result<Vec<Vec<String>>>>()?,
				)
				.collect())
		} else {
			Err(ExecuteError::QueryNotSupported.into())
		}
	}

	/// Only for `SELECT` queries.
	pub fn select_as_csv(&mut self, query: &str) -> Result<String> {
		// TODO: Don't use `unwrap()`
		if let Payload::Select { labels, rows } = self.execute(query)? {
			{
				let mut writer = csv::Writer::from_writer(vec![]);
				writer.write_record(labels).unwrap();
				for row in rows.into_iter() {
					for field in row.0.into_iter() {
						let string: String = field.cast()?;
						writer.write_field(string).unwrap();
					}
					writer.write_record(None::<&[u8]>).unwrap();
				}
				let bytes = writer.into_inner().unwrap();
				let string = String::from_utf8(bytes).unwrap();
				Some(string)
			}
			.map(Ok)
			.unwrap()
		} else {
			Err(ExecuteError::QueryNotSupported.into())
		}
	}
}