graphs renamed to web
This commit is contained in:
163
web/src/pages/add_table/state.rs
Normal file
163
web/src/pages/add_table/state.rs
Normal file
@@ -0,0 +1,163 @@
|
||||
use crate::definitions::table_definition::{
|
||||
ColumnDefinition, MoneyRounding, PostTableDefinitionRequest, TableLink,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Default, serde::Deserialize)]
|
||||
pub(crate) struct CreateTableForm {
|
||||
#[serde(default)]
|
||||
pub profile_name: String,
|
||||
#[serde(default)]
|
||||
pub table_name: String,
|
||||
#[serde(default)]
|
||||
pub columns: String,
|
||||
#[serde(default)]
|
||||
pub indexed_columns: String,
|
||||
#[serde(default)]
|
||||
pub required_links: String,
|
||||
#[serde(default)]
|
||||
pub optional_links: String,
|
||||
#[serde(default)]
|
||||
pub base_currency: String,
|
||||
#[serde(default)]
|
||||
pub row_display_columns: String,
|
||||
}
|
||||
|
||||
pub(crate) struct AddTablePageState {
|
||||
pub profiles: Vec<String>,
|
||||
pub form: CreateTableForm,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
impl CreateTableForm {
|
||||
pub(crate) fn into_request(self) -> Result<PostTableDefinitionRequest, String> {
|
||||
let profile_name = self.profile_name.trim().to_string();
|
||||
let table_name = self.table_name.trim().to_string();
|
||||
if profile_name.is_empty() {
|
||||
return Err("Select a profile.".to_string());
|
||||
}
|
||||
if table_name.is_empty() {
|
||||
return Err("Enter a table name.".to_string());
|
||||
}
|
||||
|
||||
let indexed_columns = comma_separated(&self.indexed_columns);
|
||||
let mut columns = Vec::new();
|
||||
let mut inline_indexes = Vec::new();
|
||||
for (index, line) in self.columns.lines().enumerate() {
|
||||
let line = line.trim();
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let mut parts = line.splitn(3, ':');
|
||||
let name = parts.next().unwrap_or_default().trim();
|
||||
let field_type = parts.next().unwrap_or_default().trim();
|
||||
let flags = parts.next().unwrap_or_default();
|
||||
if name.is_empty() || field_type.is_empty() {
|
||||
return Err(format!(
|
||||
"Column line {} must use `name: type`.",
|
||||
index + 1
|
||||
));
|
||||
}
|
||||
let flags = flags
|
||||
.split(',')
|
||||
.map(str::trim)
|
||||
.filter(|flag| !flag.is_empty())
|
||||
.collect::<Vec<_>>();
|
||||
if flags.contains(&"indexed") {
|
||||
inline_indexes.push(name.to_string());
|
||||
}
|
||||
let rounding = if flags.contains(&"half-up") {
|
||||
MoneyRounding::HalfUp
|
||||
} else {
|
||||
MoneyRounding::None
|
||||
};
|
||||
columns.push(ColumnDefinition {
|
||||
name: name.to_string(),
|
||||
field_type: field_type.to_string(),
|
||||
rounding: rounding.into(),
|
||||
quantity_ledger: flags.contains(&"quantity-ledger"),
|
||||
});
|
||||
}
|
||||
if columns.is_empty() {
|
||||
return Err("Add at least one column.".to_string());
|
||||
}
|
||||
|
||||
let mut indexes = indexed_columns;
|
||||
for name in inline_indexes {
|
||||
if !indexes.contains(&name) {
|
||||
indexes.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
let mut links = comma_separated(&self.required_links)
|
||||
.into_iter()
|
||||
.map(|linked_table_name| TableLink {
|
||||
linked_table_name,
|
||||
required: true,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
links.extend(
|
||||
comma_separated(&self.optional_links)
|
||||
.into_iter()
|
||||
.map(|linked_table_name| TableLink {
|
||||
linked_table_name,
|
||||
required: false,
|
||||
}),
|
||||
);
|
||||
|
||||
let has_money = columns.iter().any(|column| {
|
||||
column.field_type.eq_ignore_ascii_case("money")
|
||||
|| column.field_type.eq_ignore_ascii_case("accounting")
|
||||
});
|
||||
let base_currency = self.base_currency.trim().to_ascii_uppercase();
|
||||
if has_money && base_currency.is_empty() {
|
||||
return Err("A base currency is required when a MONEY column is used.".to_string());
|
||||
}
|
||||
|
||||
Ok(PostTableDefinitionRequest {
|
||||
accounting_currency: String::new(),
|
||||
table_name,
|
||||
links,
|
||||
columns,
|
||||
indexes,
|
||||
profile_name,
|
||||
base_currency: if has_money { base_currency } else { String::new() },
|
||||
row_display_columns: comma_separated(&self.row_display_columns),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn comma_separated(value: &str) -> Vec<String> {
|
||||
value
|
||||
.split(',')
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(str::to_string)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parses_columns_indexes_links_and_money_options() {
|
||||
let request = CreateTableForm {
|
||||
profile_name: "accounting".into(),
|
||||
table_name: "invoice".into(),
|
||||
columns: "number: text:indexed\namount: money:half-up,quantity-ledger".into(),
|
||||
required_links: "customer".into(),
|
||||
base_currency: "eur".into(),
|
||||
row_display_columns: "number, amount".into(),
|
||||
..Default::default()
|
||||
}
|
||||
.into_request()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(request.indexes, vec!["number"]);
|
||||
assert_eq!(request.links[0].linked_table_name, "customer");
|
||||
assert!(request.links[0].required);
|
||||
assert_eq!(request.base_currency, "EUR");
|
||||
assert_eq!(request.row_display_columns, vec!["number", "amount"]);
|
||||
assert!(request.columns[1].quantity_ledger);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user