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
use crate::DatabaseError;
use {
crate::{
Cast, Column, DBBase, Plane, Result, Row, Schema, SheetDatabase, SheetDatabaseError, Value,
},
async_trait::async_trait,
std::convert::TryFrom,
umya_spreadsheet::{Cell, Worksheet},
};
#[async_trait(?Send)]
impl DBBase for SheetDatabase {
async fn fetch_schema(&self, sheet_name: &str) -> Result<Option<Schema>> {
if let Ok(sheet) = self.book.get_sheet_by_name(sheet_name) {
schema_from_sheet(sheet).map(Some)
} else {
Ok(None)
}
}
async fn scan_schemas(&self) -> Result<Vec<Schema>> {
self.book
.get_sheet_collection()
.iter()
.map(schema_from_sheet)
.collect()
}
async fn scan_data(&self, sheet_name: &str) -> Result<Plane> {
let sheet = self
.book
.get_sheet_by_name(sheet_name)
.map_err(|_| SheetDatabaseError::FailedToGetSheet)?;
let Schema { column_defs, .. } = schema_from_sheet(sheet)?;
let row_count = sheet.get_highest_row();
let col_count = sheet.get_highest_column();
let rows = vec![vec![None; col_count as usize]; (row_count as usize) - 1];
let rows = sheet
.get_collection_to_hashmap()
.iter()
.filter(|((row, _col), _)| row != &1)
.fold(rows, |mut rows, ((row_num, col_num), cell)| {
rows[(row_num - 2) as usize][(col_num - 1) as usize] = Some(cell.clone());
rows
});
rows.into_iter()
.enumerate()
.map(|(pk, row)| {
(
Value::U64((pk + 2) as u64),
Row(row
.into_iter()
.zip(&column_defs)
.map(|(cell, Column { data_type, .. })| {
Value::Str(
cell.map(|cell| cell.get_value().to_string())
.unwrap_or_default(),
)
.cast_valuetype(data_type)
.unwrap_or(Value::Null)
})
.collect()),
)
})
.map(Ok)
.collect::<Result<Vec<(Value, Row)>>>()
}
}
impl TryFrom<Cell> for Value {
type Error = crate::Error;
fn try_from(cell: Cell) -> Result<Self> {
Ok(match cell.get_data_type() {
"s" => Value::Str(cell.get_value().to_string()),
"b" => Value::Bool(Value::Str(cell.get_value().to_string()).cast()?),
"n" => Value::F64(Value::Str(cell.get_value().to_string()).cast()?),
"" => Value::Null,
_ => return Err(DatabaseError::Unimplemented.into()),
})
}
}
fn schema_from_sheet(sheet: &Worksheet) -> Result<Schema> {
let mut column_defs: Vec<(_, Column)> = sheet
.get_comments()
.iter()
.filter_map(|comment| {
let coordinate = comment.get_coordinate();
if coordinate.get_row_num() == &1 {
let col = coordinate.get_col_num();
let text = comment.get_text().get_text();
let column_def: Column = serde_yaml::from_str(&text).unwrap_or_default();
Some(Ok((col, column_def)))
} else {
None
}
})
.collect::<Result<Vec<_>>>()?;
column_defs.sort_by(|(col_a, _), (col_b, _)| col_a.cmp(col_b));
let column_defs = column_defs
.into_iter()
.map(|(_, column_def)| column_def)
.collect();
Ok(Schema {
table_name: sheet.get_name().to_string(),
column_defs,
indexes: vec![],
})
}