-
Notifications
You must be signed in to change notification settings - Fork 2
/
active_version_deserializer.rs
146 lines (126 loc) · 5.53 KB
/
active_version_deserializer.rs
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use apllodb_immutable_schema_engine_domain::{
version::active_version::ActiveVersion, vtable::VTable,
};
use apllodb_shared_components::{
ApllodbError, ApllodbErrorKind, ApllodbResult, AstTranslator, ColumnDataType,
};
use apllodb_sql_parser::{
apllodb_ast::{self, Command, CreateTableCommand, TableElement},
ApllodbAst, ApllodbSqlParser,
};
use serde::{Deserialize, Serialize};
use crate::sqlite::transaction::sqlite_tx::version::dao::{
sqlite_table_name_for_version::SqliteTableNameForVersion, CNAME_NAVI_ROWID,
};
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Serialize, Deserialize)]
pub(super) struct ActiveVersionDeserializer {
create_version_table_sql: String,
}
impl ActiveVersionDeserializer {
pub(super) fn new<S: Into<String>>(create_version_table_sql: S) -> Self {
Self {
create_version_table_sql: create_version_table_sql.into(),
}
}
/// # Failures
///
/// - [UndefinedTable](a.html) when:
/// - Version defined in this CreateTableSqlForVersion is deactivated.
pub(super) fn to_active_version(&self, vtable: &VTable) -> ApllodbResult<ActiveVersion> {
use apllodb_immutable_schema_engine_domain::entity::Entity;
let parser = ApllodbSqlParser::default();
let ast = parser.parse(&self.create_version_table_sql).map_err(|e|
ApllodbError::new(
ApllodbErrorKind::IoError,
format!("SQLite's `{}` table somehow hold string that apllodb-sql-parser cannot parse: {}", super::TNAME, &self.create_version_table_sql),
Some(Box::new(e))
)
)?;
match ast {
ApllodbAst(Command::CreateTableCommandVariant(CreateTableCommand {
table_name,
table_elements,
})) => {
let sqlite_table_name = {
let id = table_name.0;
SqliteTableNameForVersion::from(id.0)
};
let version_number = sqlite_table_name.to_version_number();
let non_pk_column_data_types: Vec<ColumnDataType> = table_elements
.as_vec()
.iter()
.filter_map(|table_element| {
if let TableElement::ColumnDefinitionVariant(cd) = table_element {
if Self::is_control_column(cd) {
None
} else {
Some(cd)
}
} else {
None
}
})
.map(|ast_cd| {
let column_name = AstTranslator::column_name(ast_cd.column_name.clone())?;
let not_null = ast_cd
.column_constraints
.contains(&apllodb_ast::ColumnConstraint::NotNullVariant);
let sql_type = AstTranslator::data_type(ast_cd.data_type.clone());
Ok(ColumnDataType::new(column_name, sql_type, !not_null))
})
.collect::<ApllodbResult<Vec<ColumnDataType>>>()?;
ActiveVersion::new(vtable.id(), &version_number, &non_pk_column_data_types)
}
_ => unreachable!(format!(
"SQLite's `{}` table somehow hold wrong non CREATE TABLE statement: {}",
super::TNAME,
&self.create_version_table_sql
)),
}
}
fn is_control_column(column_definition: &apllodb_ast::ColumnDefinition) -> bool {
let id = &column_definition.column_name.0;
id.0.as_str() == CNAME_NAVI_ROWID
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::ActiveVersionDeserializer;
use crate::sqlite::transaction::sqlite_tx::version::dao::CreateTableSqlForVersionTestWrapper;
use apllodb_immutable_schema_engine_domain::{
entity::Entity, version::active_version::ActiveVersion, vtable::VTable,
};
use apllodb_shared_components::{
ApllodbResult, ColumnConstraints, ColumnDataType, ColumnDefinition, DatabaseName, SqlType,
TableConstraintKind, TableConstraints, TableName,
};
#[test]
fn test_from_into() -> ApllodbResult<()> {
let c1_def = ColumnDefinition::new(
ColumnDataType::factory("c1", SqlType::integer(), false),
ColumnConstraints::new(vec![])?,
);
let testset: Vec<(Vec<ColumnDefinition>, TableConstraints)> = vec![
(
vec![c1_def.clone()],
TableConstraints::new(vec![TableConstraintKind::PrimaryKey {
column_names: vec![c1_def.column_data_type().column_name().clone()],
}])?,
), // TODO more samples
];
for t in testset {
let database_name = DatabaseName::new("db")?;
let table_name = TableName::new("t")?;
let vtable = VTable::create(&database_name, &table_name, &t.1, &t.0)?;
let non_pk_column_data_types: Vec<ColumnDataType> =
t.0.iter().map(|cd| cd.column_data_type().clone()).collect();
let version = ActiveVersion::initial(vtable.id(), &non_pk_column_data_types)?;
let sql = CreateTableSqlForVersionTestWrapper::from(&version);
let sql = sql.as_str();
let deser = ActiveVersionDeserializer::new(sql);
assert_eq!(deser.to_active_version(&vtable)?, version);
}
Ok(())
}
}