mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: number sort (#2570)
* chore: remove sign * fix: sort number * chore: update patch * ci: fix dart test * chore: fmt
This commit is contained in:
@ -13,9 +13,6 @@ pub struct NumberTypeOptionPB {
|
||||
#[pb(index = 3)]
|
||||
pub symbol: String,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub sign_positive: bool,
|
||||
|
||||
#[pb(index = 5)]
|
||||
pub name: String,
|
||||
}
|
||||
@ -26,7 +23,6 @@ impl From<NumberTypeOption> for NumberTypeOptionPB {
|
||||
format: data.format.into(),
|
||||
scale: data.scale,
|
||||
symbol: data.symbol,
|
||||
sign_positive: data.sign_positive,
|
||||
name: data.name,
|
||||
}
|
||||
}
|
||||
@ -38,7 +34,6 @@ impl From<NumberTypeOptionPB> for NumberTypeOption {
|
||||
format: data.format.into(),
|
||||
scale: data.scale,
|
||||
symbol: data.symbol,
|
||||
sign_positive: data.sign_positive,
|
||||
name: data.name,
|
||||
}
|
||||
}
|
||||
|
@ -347,7 +347,7 @@ pub(crate) async fn get_cell_handler(
|
||||
data_result_ok(cell)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
pub(crate) async fn update_cell_handler(
|
||||
data: AFPluginData<CellChangesetPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
|
@ -58,7 +58,7 @@ pub trait CellDataChangeset: TypeOption {
|
||||
/// FieldType::SingleSelect => SelectOptionChangeset
|
||||
///
|
||||
/// cell_rev: It will be None if the cell does not contain any data.
|
||||
pub fn apply_cell_data_changeset<C: ToCellChangeset>(
|
||||
pub fn apply_cell_changeset<C: ToCellChangeset>(
|
||||
changeset: C,
|
||||
cell: Option<Cell>,
|
||||
field: &Field,
|
||||
@ -194,11 +194,11 @@ pub fn stringify_cell_data(
|
||||
}
|
||||
|
||||
pub fn insert_text_cell(s: String, field: &Field) -> Cell {
|
||||
apply_cell_data_changeset(s, None, field, None).unwrap()
|
||||
apply_cell_changeset(s, None, field, None).unwrap()
|
||||
}
|
||||
|
||||
pub fn insert_number_cell(num: i64, field: &Field) -> Cell {
|
||||
apply_cell_data_changeset(num.to_string(), None, field, None).unwrap()
|
||||
apply_cell_changeset(num.to_string(), None, field, None).unwrap()
|
||||
}
|
||||
|
||||
pub fn insert_url_cell(url: String, field: &Field) -> Cell {
|
||||
@ -212,7 +212,7 @@ pub fn insert_url_cell(url: String, field: &Field) -> Cell {
|
||||
_ => url,
|
||||
};
|
||||
|
||||
apply_cell_data_changeset(url, None, field, None).unwrap()
|
||||
apply_cell_changeset(url, None, field, None).unwrap()
|
||||
}
|
||||
|
||||
pub fn insert_checkbox_cell(is_check: bool, field: &Field) -> Cell {
|
||||
@ -221,7 +221,7 @@ pub fn insert_checkbox_cell(is_check: bool, field: &Field) -> Cell {
|
||||
} else {
|
||||
UNCHECK.to_string()
|
||||
};
|
||||
apply_cell_data_changeset(s, None, field, None).unwrap()
|
||||
apply_cell_changeset(s, None, field, None).unwrap()
|
||||
}
|
||||
|
||||
pub fn insert_date_cell(timestamp: i64, field: &Field) -> Cell {
|
||||
@ -232,19 +232,19 @@ pub fn insert_date_cell(timestamp: i64, field: &Field) -> Cell {
|
||||
timezone_id: None,
|
||||
})
|
||||
.unwrap();
|
||||
apply_cell_data_changeset(cell_data, None, field, None).unwrap()
|
||||
apply_cell_changeset(cell_data, None, field, None).unwrap()
|
||||
}
|
||||
|
||||
pub fn insert_select_option_cell(option_ids: Vec<String>, field: &Field) -> Cell {
|
||||
let changeset =
|
||||
SelectOptionCellChangeset::from_insert_options(option_ids).to_cell_changeset_str();
|
||||
apply_cell_data_changeset(changeset, None, field, None).unwrap()
|
||||
apply_cell_changeset(changeset, None, field, None).unwrap()
|
||||
}
|
||||
|
||||
pub fn delete_select_option_cell(option_ids: Vec<String>, field: &Field) -> Cell {
|
||||
let changeset =
|
||||
SelectOptionCellChangeset::from_delete_options(option_ids).to_cell_changeset_str();
|
||||
apply_cell_data_changeset(changeset, None, field, None).unwrap()
|
||||
apply_cell_changeset(changeset, None, field, None).unwrap()
|
||||
}
|
||||
|
||||
/// Deserialize the String into cell specific data type.
|
||||
|
@ -6,7 +6,7 @@ use bytes::Bytes;
|
||||
use collab_database::database::{gen_row_id, timestamp, Database as InnerDatabase};
|
||||
use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::{Cell, Cells, Row, RowCell, RowId};
|
||||
use collab_database::views::{DatabaseLayout, DatabaseView, LayoutSetting, RowOrder};
|
||||
use collab_database::views::{DatabaseLayout, DatabaseView, LayoutSetting};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
|
||||
@ -23,14 +23,11 @@ use crate::entities::{
|
||||
};
|
||||
use crate::notification::{send_notification, DatabaseNotification};
|
||||
use crate::services::cell::{
|
||||
apply_cell_data_changeset, get_type_cell_protobuf, AnyTypeCache, CellBuilder, CellCache,
|
||||
apply_cell_changeset, get_type_cell_protobuf, AnyTypeCache, CellBuilder, CellCache,
|
||||
ToCellChangeset,
|
||||
};
|
||||
use crate::services::database::util::database_view_setting_pb_from_view;
|
||||
use crate::services::database::{DatabaseRowEvent, InsertedRow, UpdatedRow};
|
||||
use crate::services::database_view::{
|
||||
DatabaseViewChanged, DatabaseViewData, DatabaseViews, RowEventSender,
|
||||
};
|
||||
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewData, DatabaseViews};
|
||||
use crate::services::field::{
|
||||
default_type_option_data_for_type, default_type_option_data_from_type,
|
||||
select_type_option_from_field, transform_type_option, type_option_data_from_pb_or_default,
|
||||
@ -46,7 +43,6 @@ pub struct DatabaseEditor {
|
||||
database: MutexDatabase,
|
||||
pub cell_cache: CellCache,
|
||||
database_views: Arc<DatabaseViews>,
|
||||
row_event_tx: RowEventSender,
|
||||
}
|
||||
|
||||
impl DatabaseEditor {
|
||||
@ -55,27 +51,18 @@ impl DatabaseEditor {
|
||||
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
||||
) -> FlowyResult<Self> {
|
||||
let cell_cache = AnyTypeCache::<u64>::new();
|
||||
let (row_event_tx, row_event_rx) = broadcast::channel(100);
|
||||
let database_view_data = Arc::new(DatabaseViewDataImpl {
|
||||
database: database.clone(),
|
||||
task_scheduler: task_scheduler.clone(),
|
||||
cell_cache: cell_cache.clone(),
|
||||
});
|
||||
|
||||
let database_views = Arc::new(
|
||||
DatabaseViews::new(
|
||||
database.clone(),
|
||||
cell_cache.clone(),
|
||||
database_view_data,
|
||||
row_event_rx,
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
let database_views =
|
||||
Arc::new(DatabaseViews::new(database.clone(), cell_cache.clone(), database_view_data).await?);
|
||||
Ok(Self {
|
||||
database,
|
||||
cell_cache,
|
||||
database_views,
|
||||
row_event_tx,
|
||||
})
|
||||
}
|
||||
|
||||
@ -295,7 +282,14 @@ impl DatabaseEditor {
|
||||
// self.database.lock().views.update_view(view_id, |view| {
|
||||
// view.move_row_order(from as u32, to as u32);
|
||||
// });
|
||||
// self.row_event_tx.send(DatabaseRowEvent::Move { from: _from, to: _to})
|
||||
// let changeset = RowsChangesetPB::from_move(
|
||||
// view_id.to_string(),
|
||||
// vec![from.into_inner()],
|
||||
// vec![to.into()],
|
||||
// );
|
||||
// send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
// .payload(changeset)
|
||||
// .send();
|
||||
}
|
||||
|
||||
pub async fn create_row(&self, params: CreateRowParams) -> FlowyResult<Option<Row>> {
|
||||
@ -319,14 +313,6 @@ impl DatabaseEditor {
|
||||
);
|
||||
|
||||
if let Some((index, row_order)) = result {
|
||||
let _ = self
|
||||
.row_event_tx
|
||||
.send(DatabaseRowEvent::InsertRow(InsertedRow {
|
||||
row: row_order.clone(),
|
||||
index: Some(index as i32),
|
||||
is_new: true,
|
||||
}));
|
||||
|
||||
let row = self.database.lock().get_row(&row_order.id);
|
||||
if let Some(row) = row {
|
||||
for view in self.database_views.editors().await {
|
||||
@ -423,10 +409,6 @@ impl DatabaseEditor {
|
||||
let row = self.database.lock().remove_row(row_id);
|
||||
if let Some(row) = row {
|
||||
tracing::trace!("Did delete row:{:?}", row);
|
||||
let _ = self
|
||||
.row_event_tx
|
||||
.send(DatabaseRowEvent::DeleteRow(row.id.clone()));
|
||||
|
||||
for view in self.database_views.editors().await {
|
||||
view.v_did_delete_row(&row).await;
|
||||
}
|
||||
@ -481,15 +463,18 @@ impl DatabaseEditor {
|
||||
}?;
|
||||
(
|
||||
field,
|
||||
database.get_cell(field_id, &row_id).map(|cell| cell.cell),
|
||||
database
|
||||
.get_cell(field_id, &row_id)
|
||||
.map(|row_cell| row_cell.cell),
|
||||
)
|
||||
};
|
||||
let cell_changeset = cell_changeset.to_cell_changeset_str();
|
||||
let new_cell =
|
||||
apply_cell_data_changeset(cell_changeset, cell, &field, Some(self.cell_cache.clone()))?;
|
||||
apply_cell_changeset(cell_changeset, cell, &field, Some(self.cell_cache.clone()))?;
|
||||
self.update_cell(view_id, row_id, field_id, new_cell).await
|
||||
}
|
||||
|
||||
/// Update a cell in the database.
|
||||
/// This will notify all views that the cell has been updated.
|
||||
pub async fn update_cell(
|
||||
&self,
|
||||
view_id: &str,
|
||||
@ -497,6 +482,7 @@ impl DatabaseEditor {
|
||||
field_id: &str,
|
||||
new_cell: Cell,
|
||||
) -> FlowyResult<()> {
|
||||
// Get the old row before updating the cell. It would be better to get the old cell
|
||||
let old_row = { self.database.lock().get_row(&row_id) };
|
||||
self.database.lock().update_row(&row_id, |row_update| {
|
||||
row_update.update_cells(|cell_update| {
|
||||
@ -506,14 +492,8 @@ impl DatabaseEditor {
|
||||
|
||||
let option_row = self.database.lock().get_row(&row_id);
|
||||
if let Some(new_row) = option_row {
|
||||
let _ = self
|
||||
.row_event_tx
|
||||
.send(DatabaseRowEvent::UpdateRow(UpdatedRow {
|
||||
row: RowOrder::from(&new_row),
|
||||
field_ids: vec![field_id.to_string()],
|
||||
}));
|
||||
for view in self.database_views.editors().await {
|
||||
view.v_did_update_row(&old_row, &new_row).await;
|
||||
view.v_did_update_row(&old_row, &new_row, field_id).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use std::sync::Arc;
|
||||
use collab_database::database::{gen_database_filter_id, gen_database_sort_id};
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{Cells, Row, RowCell, RowId};
|
||||
use collab_database::views::{DatabaseLayout, DatabaseView, LayoutSetting};
|
||||
use collab_database::views::{DatabaseLayout, DatabaseView, LayoutSetting, RowOrder};
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
@ -20,7 +20,7 @@ use crate::entities::{
|
||||
};
|
||||
use crate::notification::{send_notification, DatabaseNotification};
|
||||
use crate::services::cell::CellCache;
|
||||
use crate::services::database::{database_view_setting_pb_from_view, DatabaseRowEvent};
|
||||
use crate::services::database::{database_view_setting_pb_from_view, DatabaseRowEvent, UpdatedRow};
|
||||
use crate::services::database_view::view_filter::make_filter_controller;
|
||||
use crate::services::database_view::view_group::{
|
||||
get_cell_for_row, get_cells_for_field, new_group_controller, new_group_controller_with_field,
|
||||
@ -55,6 +55,7 @@ pub trait DatabaseViewData: Send + Sync + 'static {
|
||||
/// Returns the `index` and `RowRevision` with row_id
|
||||
fn get_row(&self, view_id: &str, row_id: &RowId) -> Fut<Option<(usize, Arc<Row>)>>;
|
||||
|
||||
/// Returns all the rows in the view
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<Row>>>;
|
||||
|
||||
fn get_cells_for_field(&self, view_id: &str, field_id: &str) -> Fut<Vec<Arc<RowCell>>>;
|
||||
@ -180,7 +181,12 @@ impl DatabaseViewEditor {
|
||||
pub async fn v_did_create_row(&self, row: &Row, group_id: &Option<String>, index: usize) {
|
||||
// Send the group notification if the current view has groups
|
||||
match group_id.as_ref() {
|
||||
None => {},
|
||||
None => {
|
||||
let changeset = RowsChangesetPB::from_insert(self.view_id.clone(), vec![row.into()]);
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changeset)
|
||||
.send();
|
||||
},
|
||||
Some(group_id) => {
|
||||
self
|
||||
.group_controller
|
||||
@ -213,9 +219,17 @@ impl DatabaseViewEditor {
|
||||
notify_did_update_group_rows(changeset).await;
|
||||
}
|
||||
}
|
||||
let changeset =
|
||||
RowsChangesetPB::from_delete(self.view_id.clone(), vec![row.id.clone().into_inner()]);
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changeset)
|
||||
.send();
|
||||
}
|
||||
|
||||
pub async fn v_did_update_row(&self, old_row: &Option<Row>, row: &Row) {
|
||||
/// Notify the view that the row has been updated. If the view has groups,
|
||||
/// send the group notification with [GroupRowsNotificationPB]. Otherwise,
|
||||
/// send the view notification with [RowsChangesetPB]
|
||||
pub async fn v_did_update_row(&self, old_row: &Option<Row>, row: &Row, field_id: &str) {
|
||||
let result = self
|
||||
.mut_group_controller(|group_controller, field| {
|
||||
Ok(group_controller.did_update_group_row(old_row, row, &field))
|
||||
@ -244,20 +258,35 @@ impl DatabaseViewEditor {
|
||||
for changeset in result.row_changesets {
|
||||
notify_did_update_group_rows(changeset).await;
|
||||
}
|
||||
} else {
|
||||
let update_row = UpdatedRow {
|
||||
row: RowOrder::from(row),
|
||||
field_ids: vec![field_id.to_string()],
|
||||
};
|
||||
let changeset = RowsChangesetPB::from_update(self.view_id.clone(), vec![update_row.into()]);
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changeset)
|
||||
.send();
|
||||
}
|
||||
|
||||
let filter_controller = self.filter_controller.clone();
|
||||
let sort_controller = self.sort_controller.clone();
|
||||
// Each row update will trigger a filter and sort operation. We don't want
|
||||
// to block the main thread, so we spawn a new task to do the work.
|
||||
let row_id = row.id.clone();
|
||||
let weak_filter_controller = Arc::downgrade(&self.filter_controller);
|
||||
let weak_sort_controller = Arc::downgrade(&self.sort_controller);
|
||||
tokio::spawn(async move {
|
||||
filter_controller
|
||||
.did_receive_row_changed(row_id.clone())
|
||||
.await;
|
||||
sort_controller
|
||||
.read()
|
||||
.await
|
||||
.did_receive_row_changed(row_id)
|
||||
.await;
|
||||
if let Some(filter_controller) = weak_filter_controller.upgrade() {
|
||||
filter_controller
|
||||
.did_receive_row_changed(row_id.clone())
|
||||
.await;
|
||||
}
|
||||
if let Some(sort_controller) = weak_sort_controller.upgrade() {
|
||||
sort_controller
|
||||
.read()
|
||||
.await
|
||||
.did_receive_row_changed(row_id)
|
||||
.await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -513,7 +542,7 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
|
||||
/// Returns the current calendar settings
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
pub async fn v_get_layout_settings(&self, layout_ty: &DatabaseLayout) -> LayoutSettingParams {
|
||||
let mut layout_setting = LayoutSettingParams::default();
|
||||
match layout_ty {
|
||||
@ -751,7 +780,7 @@ impl DatabaseViewEditor {
|
||||
Some(events)
|
||||
}
|
||||
|
||||
pub async fn handle_block_event(&self, event: Cow<'_, DatabaseRowEvent>) {
|
||||
pub async fn handle_row_event(&self, event: Cow<'_, DatabaseRowEvent>) {
|
||||
let changeset = match event.into_owned() {
|
||||
DatabaseRowEvent::InsertRow(row) => {
|
||||
RowsChangesetPB::from_insert(self.view_id.clone(), vec![row.into()])
|
||||
|
@ -1,4 +1,3 @@
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -31,10 +30,8 @@ impl DatabaseViews {
|
||||
database: MutexDatabase,
|
||||
cell_cache: CellCache,
|
||||
database_view_data: Arc<dyn DatabaseViewData>,
|
||||
row_event_rx: RowEventReceiver,
|
||||
) -> FlowyResult<Self> {
|
||||
let editor_map = Arc::new(RwLock::new(HashMap::default()));
|
||||
listen_on_database_row_event(row_event_rx, editor_map.clone());
|
||||
Ok(Self {
|
||||
database,
|
||||
database_view_data,
|
||||
@ -126,26 +123,6 @@ impl DatabaseViews {
|
||||
}
|
||||
}
|
||||
|
||||
fn listen_on_database_row_event(
|
||||
mut row_event_rx: broadcast::Receiver<DatabaseRowEvent>,
|
||||
view_editors: Arc<RwLock<HashMap<String, Arc<DatabaseViewEditor>>>>,
|
||||
) {
|
||||
tokio::spawn(async move {
|
||||
while let Ok(event) = row_event_rx.recv().await {
|
||||
let read_guard = view_editors.read().await;
|
||||
let view_editors = read_guard.values();
|
||||
let event = if view_editors.len() == 1 {
|
||||
Cow::Owned(event)
|
||||
} else {
|
||||
Cow::Borrowed(&event)
|
||||
};
|
||||
for view_editor in view_editors {
|
||||
view_editor.handle_block_event(event.clone()).await;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn gen_handler_id() -> String {
|
||||
nanoid!(10)
|
||||
}
|
||||
|
@ -7,10 +7,15 @@ use strum::IntoEnumIterator;
|
||||
use strum_macros::EnumIter;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CURRENCY_SYMBOL: Vec<String> = NumberFormat::iter()
|
||||
pub static ref CURRENCY_SYMBOL: Vec<String> = sorted_symbol();
|
||||
}
|
||||
|
||||
fn sorted_symbol() -> Vec<String> {
|
||||
let mut symbols = NumberFormat::iter()
|
||||
.map(|format| format.symbol())
|
||||
.collect::<Vec<String>>();
|
||||
pub static ref STRIP_SYMBOL: Vec<String> = vec![",".to_owned(), ".".to_owned()];
|
||||
symbols.sort_by(|a, b| b.len().cmp(&a.len()));
|
||||
symbols
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter, Serialize, Deserialize)]
|
||||
|
@ -47,13 +47,13 @@ mod tests {
|
||||
};
|
||||
|
||||
for (num_str, visible) in [("123", true), ("1234", false), ("", false)] {
|
||||
let data = NumberCellFormat::from_format_str(num_str, true, &NumberFormat::Num).unwrap();
|
||||
let data = NumberCellFormat::from_format_str(num_str, &NumberFormat::Num).unwrap_or_default();
|
||||
assert_eq!(number_filter.is_visible(&data), visible);
|
||||
}
|
||||
|
||||
let format = NumberFormat::USD;
|
||||
for (num_str, visible) in [("$123", true), ("1234", false), ("", false)] {
|
||||
let data = NumberCellFormat::from_format_str(num_str, true, &format).unwrap();
|
||||
let data = NumberCellFormat::from_format_str(num_str, &format).unwrap();
|
||||
assert_eq!(number_filter.is_visible(&data), visible);
|
||||
}
|
||||
}
|
||||
@ -64,7 +64,7 @@ mod tests {
|
||||
content: "12".to_owned(),
|
||||
};
|
||||
for (num_str, visible) in [("123", true), ("10", false), ("30", true), ("", false)] {
|
||||
let data = NumberCellFormat::from_format_str(num_str, true, &NumberFormat::Num).unwrap();
|
||||
let data = NumberCellFormat::from_format_str(num_str, &NumberFormat::Num).unwrap_or_default();
|
||||
assert_eq!(number_filter.is_visible(&data), visible);
|
||||
}
|
||||
}
|
||||
@ -76,7 +76,7 @@ mod tests {
|
||||
content: "100".to_owned(),
|
||||
};
|
||||
for (num_str, visible) in [("12", true), ("1234", false), ("30", true), ("", false)] {
|
||||
let data = NumberCellFormat::from_format_str(num_str, true, &NumberFormat::Num).unwrap();
|
||||
let data = NumberCellFormat::from_format_str(num_str, &NumberFormat::Num).unwrap_or_default();
|
||||
assert_eq!(number_filter.is_visible(&data), visible);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use collab_database::fields::Field;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::cell::CellDataDecoder;
|
||||
use crate::services::field::{strip_currency_symbol, NumberFormat, NumberTypeOption};
|
||||
use crate::services::field::{FieldBuilder, NumberCellData};
|
||||
use crate::services::field::{NumberFormat, NumberTypeOption};
|
||||
|
||||
/// Testing when the input is not a number.
|
||||
#[test]
|
||||
fn number_type_option_invalid_input_test() {
|
||||
fn number_type_option_input_test() {
|
||||
let type_option = NumberTypeOption::default();
|
||||
let field_type = FieldType::Number;
|
||||
let field = FieldBuilder::from_field_type(field_type.clone()).build();
|
||||
@ -20,492 +19,65 @@ mod tests {
|
||||
|
||||
// Input is letter
|
||||
assert_number(&type_option, "abc", "", &field_type, &field);
|
||||
|
||||
assert_number(&type_option, "-123", "-123", &field_type, &field);
|
||||
|
||||
assert_number(&type_option, "abc-123", "-123", &field_type, &field);
|
||||
|
||||
assert_number(&type_option, "+123", "123", &field_type, &field);
|
||||
|
||||
assert_number(&type_option, "0.2", "0.2", &field_type, &field);
|
||||
|
||||
assert_number(&type_option, "-0.2", "-0.2", &field_type, &field);
|
||||
assert_number(&type_option, "-$0.2", "0.2", &field_type, &field);
|
||||
}
|
||||
|
||||
/// Testing the strip_currency_symbol function. It should return the string without the input symbol.
|
||||
#[test]
|
||||
fn number_type_option_strip_symbol_test() {
|
||||
// Remove the $ symbol
|
||||
assert_eq!(strip_currency_symbol("$18,443"), "18,443".to_owned());
|
||||
// Remove the ¥ symbol
|
||||
assert_eq!(strip_currency_symbol("¥0.2"), "0.2".to_owned());
|
||||
}
|
||||
|
||||
/// Format the input number to the corresponding format string.
|
||||
#[test]
|
||||
fn number_type_option_format_number_test() {
|
||||
let mut type_option = NumberTypeOption::default();
|
||||
fn dollar_type_option_test() {
|
||||
let field_type = FieldType::Number;
|
||||
let field = FieldBuilder::from_field_type(field_type.clone()).build();
|
||||
let mut type_option = NumberTypeOption::new();
|
||||
type_option.format = NumberFormat::USD;
|
||||
let field = FieldBuilder::new(field_type.clone(), type_option.clone()).build();
|
||||
|
||||
for format in NumberFormat::iter() {
|
||||
type_option.format = format;
|
||||
match format {
|
||||
NumberFormat::Num => {
|
||||
assert_number(&type_option, "18443", "18443", &field_type, &field);
|
||||
},
|
||||
NumberFormat::USD => {
|
||||
assert_number(&type_option, "18443", "$18,443", &field_type, &field);
|
||||
},
|
||||
NumberFormat::CanadianDollar => {
|
||||
assert_number(&type_option, "18443", "CA$18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::EUR => assert_number(&type_option, "18443", "€18.443", &field_type, &field),
|
||||
NumberFormat::Pound => assert_number(&type_option, "18443", "£18,443", &field_type, &field),
|
||||
|
||||
NumberFormat::Yen => {
|
||||
assert_number(&type_option, "18443", "¥18,443", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Ruble => {
|
||||
assert_number(&type_option, "18443", "18.443RUB", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Rupee => assert_number(&type_option, "18443", "₹18,443", &field_type, &field),
|
||||
NumberFormat::Won => assert_number(&type_option, "18443", "₩18,443", &field_type, &field),
|
||||
|
||||
NumberFormat::Yuan => {
|
||||
assert_number(&type_option, "18443", "CN¥18,443", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Real => {
|
||||
assert_number(&type_option, "18443", "R$18,443", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Lira => {
|
||||
assert_number(&type_option, "18443", "TRY18.443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Rupiah => {
|
||||
assert_number(&type_option, "18443", "IDR18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Franc => {
|
||||
assert_number(&type_option, "18443", "CHF18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::HongKongDollar => {
|
||||
assert_number(&type_option, "18443", "HZ$18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::NewZealandDollar => {
|
||||
assert_number(&type_option, "18443", "NZ$18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Krona => {
|
||||
assert_number(&type_option, "18443", "18 443SEK", &field_type, &field)
|
||||
},
|
||||
NumberFormat::NorwegianKrone => {
|
||||
assert_number(&type_option, "18443", "18,443NOK", &field_type, &field)
|
||||
},
|
||||
NumberFormat::MexicanPeso => {
|
||||
assert_number(&type_option, "18443", "MX$18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Rand => {
|
||||
assert_number(&type_option, "18443", "ZAR18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::NewTaiwanDollar => {
|
||||
assert_number(&type_option, "18443", "NT$18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::DanishKrone => {
|
||||
assert_number(&type_option, "18443", "18.443DKK", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Baht => {
|
||||
assert_number(&type_option, "18443", "THB18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Forint => {
|
||||
assert_number(&type_option, "18443", "18 443HUF", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Koruna => {
|
||||
assert_number(&type_option, "18443", "18 443CZK", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Shekel => {
|
||||
assert_number(&type_option, "18443", "18 443Kč", &field_type, &field)
|
||||
},
|
||||
NumberFormat::ChileanPeso => {
|
||||
assert_number(&type_option, "18443", "CLP18.443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::PhilippinePeso => {
|
||||
assert_number(&type_option, "18443", "₱18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Dirham => {
|
||||
assert_number(&type_option, "18443", "18,443AED", &field_type, &field)
|
||||
},
|
||||
NumberFormat::ColombianPeso => {
|
||||
assert_number(&type_option, "18443", "COP18.443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Riyal => {
|
||||
assert_number(&type_option, "18443", "SAR18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Ringgit => {
|
||||
assert_number(&type_option, "18443", "MYR18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Leu => assert_number(&type_option, "18443", "18.443RON", &field_type, &field),
|
||||
NumberFormat::ArgentinePeso => {
|
||||
assert_number(&type_option, "18443", "ARS18.443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::UruguayanPeso => {
|
||||
assert_number(&type_option, "18443", "UYU18.443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Percent => {
|
||||
assert_number(&type_option, "18443", "18,443%", &field_type, &field)
|
||||
},
|
||||
}
|
||||
}
|
||||
assert_number(&type_option, "", "", &field_type, &field);
|
||||
assert_number(&type_option, "abc", "", &field_type, &field);
|
||||
assert_number(&type_option, "-123", "-$123", &field_type, &field);
|
||||
assert_number(&type_option, "+123", "$123", &field_type, &field);
|
||||
assert_number(&type_option, "0.2", "$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "-0.2", "-$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "-$0.2", "-$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "-€0.2", "-$0.2", &field_type, &field);
|
||||
}
|
||||
|
||||
/// Format the input String to the corresponding format string.
|
||||
#[test]
|
||||
fn number_type_option_format_str_test() {
|
||||
let mut type_option = NumberTypeOption::default();
|
||||
fn dollar_type_option_test2() {
|
||||
let field_type = FieldType::Number;
|
||||
let field = FieldBuilder::from_field_type(field_type.clone()).build();
|
||||
let mut type_option = NumberTypeOption::new();
|
||||
type_option.format = NumberFormat::USD;
|
||||
let field = FieldBuilder::new(field_type.clone(), type_option.clone()).build();
|
||||
|
||||
for format in NumberFormat::iter() {
|
||||
type_option.format = format;
|
||||
match format {
|
||||
NumberFormat::Num => {
|
||||
assert_number(&type_option, "18443", "18443", &field_type, &field);
|
||||
assert_number(&type_option, "0.2", "0.2", &field_type, &field);
|
||||
assert_number(&type_option, "", "", &field_type, &field);
|
||||
assert_number(&type_option, "abc", "", &field_type, &field);
|
||||
},
|
||||
NumberFormat::USD => {
|
||||
assert_number(&type_option, "$18,44", "$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "$0.2", "$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "$1844", "$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "$1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::CanadianDollar => {
|
||||
assert_number(&type_option, "CA$18,44", "CA$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "CA$0.2", "CA$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "CA$1844", "CA$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "CA$1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::EUR => {
|
||||
assert_number(&type_option, "€18.44", "€18,44", &field_type, &field);
|
||||
assert_number(&type_option, "€0.5", "€0,5", &field_type, &field);
|
||||
assert_number(&type_option, "€1844", "€1.844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "€1.844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Pound => {
|
||||
assert_number(&type_option, "£18,44", "£1,844", &field_type, &field);
|
||||
assert_number(&type_option, "£0.2", "£0.2", &field_type, &field);
|
||||
assert_number(&type_option, "£1844", "£1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "£1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Yen => {
|
||||
assert_number(&type_option, "¥18,44", "¥1,844", &field_type, &field);
|
||||
assert_number(&type_option, "¥0.2", "¥0.2", &field_type, &field);
|
||||
assert_number(&type_option, "¥1844", "¥1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "¥1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Ruble => {
|
||||
assert_number(&type_option, "RUB18.44", "18,44RUB", &field_type, &field);
|
||||
assert_number(&type_option, "0.5", "0,5RUB", &field_type, &field);
|
||||
assert_number(&type_option, "RUB1844", "1.844RUB", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "1.844RUB", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Rupee => {
|
||||
assert_number(&type_option, "₹18,44", "₹1,844", &field_type, &field);
|
||||
assert_number(&type_option, "₹0.2", "₹0.2", &field_type, &field);
|
||||
assert_number(&type_option, "₹1844", "₹1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "₹1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Won => {
|
||||
assert_number(&type_option, "₩18,44", "₩1,844", &field_type, &field);
|
||||
assert_number(&type_option, "₩0.3", "₩0", &field_type, &field);
|
||||
assert_number(&type_option, "₩1844", "₩1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "₩1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Yuan => {
|
||||
assert_number(&type_option, "CN¥18,44", "CN¥1,844", &field_type, &field);
|
||||
assert_number(&type_option, "CN¥0.2", "CN¥0.2", &field_type, &field);
|
||||
assert_number(&type_option, "CN¥1844", "CN¥1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "CN¥1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Real => {
|
||||
assert_number(&type_option, "R$18,44", "R$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "R$0.2", "R$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "R$1844", "R$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "R$1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Lira => {
|
||||
assert_number(&type_option, "TRY18.44", "TRY18,44", &field_type, &field);
|
||||
assert_number(&type_option, "TRY0.5", "TRY0,5", &field_type, &field);
|
||||
assert_number(&type_option, "TRY1844", "TRY1.844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "TRY1.844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Rupiah => {
|
||||
assert_number(&type_option, "IDR18,44", "IDR1,844", &field_type, &field);
|
||||
assert_number(&type_option, "IDR0.2", "IDR0.2", &field_type, &field);
|
||||
assert_number(&type_option, "IDR1844", "IDR1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "IDR1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Franc => {
|
||||
assert_number(&type_option, "CHF18,44", "CHF1,844", &field_type, &field);
|
||||
assert_number(&type_option, "CHF0.2", "CHF0.2", &field_type, &field);
|
||||
assert_number(&type_option, "CHF1844", "CHF1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "CHF1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::HongKongDollar => {
|
||||
assert_number(&type_option, "HZ$18,44", "HZ$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "HZ$0.2", "HZ$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "HZ$1844", "HZ$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "HZ$1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::NewZealandDollar => {
|
||||
assert_number(&type_option, "NZ$18,44", "NZ$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "NZ$0.2", "NZ$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "NZ$1844", "NZ$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "NZ$1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Krona => {
|
||||
assert_number(&type_option, "SEK18,44", "18,44SEK", &field_type, &field);
|
||||
assert_number(&type_option, "SEK0.2", "0,2SEK", &field_type, &field);
|
||||
assert_number(&type_option, "SEK1844", "1 844SEK", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "1 844SEK", &field_type, &field);
|
||||
},
|
||||
NumberFormat::NorwegianKrone => {
|
||||
assert_number(&type_option, "NOK18,44", "1,844NOK", &field_type, &field);
|
||||
assert_number(&type_option, "NOK0.2", "0.2NOK", &field_type, &field);
|
||||
assert_number(&type_option, "NOK1844", "1,844NOK", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "1,844NOK", &field_type, &field);
|
||||
},
|
||||
NumberFormat::MexicanPeso => {
|
||||
assert_number(&type_option, "MX$18,44", "MX$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "MX$0.2", "MX$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "MX$1844", "MX$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "MX$1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Rand => {
|
||||
assert_number(&type_option, "ZAR18,44", "ZAR1,844", &field_type, &field);
|
||||
assert_number(&type_option, "ZAR0.2", "ZAR0.2", &field_type, &field);
|
||||
assert_number(&type_option, "ZAR1844", "ZAR1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "ZAR1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::NewTaiwanDollar => {
|
||||
assert_number(&type_option, "NT$18,44", "NT$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "NT$0.2", "NT$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "NT$1844", "NT$1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "NT$1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::DanishKrone => {
|
||||
assert_number(&type_option, "DKK18.44", "18,44DKK", &field_type, &field);
|
||||
assert_number(&type_option, "DKK0.5", "0,5DKK", &field_type, &field);
|
||||
assert_number(&type_option, "DKK1844", "1.844DKK", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "1.844DKK", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Baht => {
|
||||
assert_number(&type_option, "THB18,44", "THB1,844", &field_type, &field);
|
||||
assert_number(&type_option, "THB0.2", "THB0.2", &field_type, &field);
|
||||
assert_number(&type_option, "THB1844", "THB1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "THB1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Forint => {
|
||||
assert_number(&type_option, "HUF18,44", "18HUF", &field_type, &field);
|
||||
assert_number(&type_option, "HUF0.3", "0HUF", &field_type, &field);
|
||||
assert_number(&type_option, "HUF1844", "1 844HUF", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "1 844HUF", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Koruna => {
|
||||
assert_number(&type_option, "CZK18,44", "18,44CZK", &field_type, &field);
|
||||
assert_number(&type_option, "CZK0.2", "0,2CZK", &field_type, &field);
|
||||
assert_number(&type_option, "CZK1844", "1 844CZK", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "1 844CZK", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Shekel => {
|
||||
assert_number(&type_option, "Kč18,44", "18,44Kč", &field_type, &field);
|
||||
assert_number(&type_option, "Kč0.2", "0,2Kč", &field_type, &field);
|
||||
assert_number(&type_option, "Kč1844", "1 844Kč", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "1 844Kč", &field_type, &field);
|
||||
},
|
||||
NumberFormat::ChileanPeso => {
|
||||
assert_number(&type_option, "CLP18.44", "CLP18", &field_type, &field);
|
||||
assert_number(&type_option, "0.5", "CLP0", &field_type, &field);
|
||||
assert_number(&type_option, "CLP1844", "CLP1.844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "CLP1.844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::PhilippinePeso => {
|
||||
assert_number(&type_option, "₱18,44", "₱1,844", &field_type, &field);
|
||||
assert_number(&type_option, "₱0.2", "₱0.2", &field_type, &field);
|
||||
assert_number(&type_option, "₱1844", "₱1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "₱1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Dirham => {
|
||||
assert_number(&type_option, "AED18,44", "1,844AED", &field_type, &field);
|
||||
assert_number(&type_option, "AED0.2", "0.2AED", &field_type, &field);
|
||||
assert_number(&type_option, "AED1844", "1,844AED", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "1,844AED", &field_type, &field);
|
||||
},
|
||||
NumberFormat::ColombianPeso => {
|
||||
assert_number(&type_option, "COP18.44", "COP18,44", &field_type, &field);
|
||||
assert_number(&type_option, "0.5", "COP0,5", &field_type, &field);
|
||||
assert_number(&type_option, "COP1844", "COP1.844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "COP1.844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Riyal => {
|
||||
assert_number(&type_option, "SAR18,44", "SAR1,844", &field_type, &field);
|
||||
assert_number(&type_option, "SAR0.2", "SAR0.2", &field_type, &field);
|
||||
assert_number(&type_option, "SAR1844", "SAR1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "SAR1,844", &field_type, &field);
|
||||
},
|
||||
|
||||
NumberFormat::Ringgit => {
|
||||
assert_number(&type_option, "MYR18,44", "MYR1,844", &field_type, &field);
|
||||
assert_number(&type_option, "MYR0.2", "MYR0.2", &field_type, &field);
|
||||
assert_number(&type_option, "MYR1844", "MYR1,844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "MYR1,844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Leu => {
|
||||
assert_number(&type_option, "RON18.44", "18,44RON", &field_type, &field);
|
||||
assert_number(&type_option, "0.5", "0,5RON", &field_type, &field);
|
||||
assert_number(&type_option, "RON1844", "1.844RON", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "1.844RON", &field_type, &field);
|
||||
},
|
||||
NumberFormat::ArgentinePeso => {
|
||||
assert_number(&type_option, "ARS18.44", "ARS18,44", &field_type, &field);
|
||||
assert_number(&type_option, "0.5", "ARS0,5", &field_type, &field);
|
||||
assert_number(&type_option, "ARS1844", "ARS1.844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "ARS1.844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::UruguayanPeso => {
|
||||
assert_number(&type_option, "UYU18.44", "UYU18,44", &field_type, &field);
|
||||
assert_number(&type_option, "0.5", "UYU0,5", &field_type, &field);
|
||||
assert_number(&type_option, "UYU1844", "UYU1.844", &field_type, &field);
|
||||
assert_number(&type_option, "1844", "UYU1.844", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Percent => {
|
||||
assert_number(&type_option, "1", "1%", &field_type, &field);
|
||||
assert_number(&type_option, "10.1", "10.1%", &field_type, &field);
|
||||
assert_number(&type_option, "100", "100%", &field_type, &field);
|
||||
},
|
||||
}
|
||||
}
|
||||
assert_number(
|
||||
&type_option,
|
||||
"99999999999",
|
||||
"$99,999,999,999",
|
||||
&field_type,
|
||||
&field,
|
||||
);
|
||||
assert_number(
|
||||
&type_option,
|
||||
"$99,999,999,999",
|
||||
"$99,999,999,999",
|
||||
&field_type,
|
||||
&field,
|
||||
);
|
||||
}
|
||||
|
||||
/// Carry out the sign positive to input number
|
||||
#[test]
|
||||
fn number_description_sign_test() {
|
||||
let mut type_option = NumberTypeOption {
|
||||
sign_positive: false,
|
||||
..Default::default()
|
||||
};
|
||||
fn other_symbol_to_dollar_type_option_test() {
|
||||
let field_type = FieldType::Number;
|
||||
let field = FieldBuilder::from_field_type(field_type.clone()).build();
|
||||
let mut type_option = NumberTypeOption::new();
|
||||
type_option.format = NumberFormat::USD;
|
||||
let field = FieldBuilder::new(field_type.clone(), type_option.clone()).build();
|
||||
|
||||
for format in NumberFormat::iter() {
|
||||
type_option.format = format;
|
||||
match format {
|
||||
NumberFormat::Num => {
|
||||
assert_number(&type_option, "18443", "18443", &field_type, &field);
|
||||
},
|
||||
NumberFormat::USD => {
|
||||
assert_number(&type_option, "18443", "-$18,443", &field_type, &field);
|
||||
},
|
||||
NumberFormat::CanadianDollar => {
|
||||
assert_number(&type_option, "18443", "-CA$18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::EUR => assert_number(&type_option, "18443", "-€18.443", &field_type, &field),
|
||||
NumberFormat::Pound => {
|
||||
assert_number(&type_option, "18443", "-£18,443", &field_type, &field)
|
||||
},
|
||||
|
||||
NumberFormat::Yen => {
|
||||
assert_number(&type_option, "18443", "-¥18,443", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Ruble => {
|
||||
assert_number(&type_option, "18443", "-18.443RUB", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Rupee => {
|
||||
assert_number(&type_option, "18443", "-₹18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Won => assert_number(&type_option, "18443", "-₩18,443", &field_type, &field),
|
||||
|
||||
NumberFormat::Yuan => {
|
||||
assert_number(&type_option, "18443", "-CN¥18,443", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Real => {
|
||||
assert_number(&type_option, "18443", "-R$18,443", &field_type, &field);
|
||||
},
|
||||
NumberFormat::Lira => {
|
||||
assert_number(&type_option, "18443", "-TRY18.443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Rupiah => {
|
||||
assert_number(&type_option, "18443", "-IDR18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Franc => {
|
||||
assert_number(&type_option, "18443", "-CHF18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::HongKongDollar => {
|
||||
assert_number(&type_option, "18443", "-HZ$18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::NewZealandDollar => {
|
||||
assert_number(&type_option, "18443", "-NZ$18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Krona => {
|
||||
assert_number(&type_option, "18443", "-18 443SEK", &field_type, &field)
|
||||
},
|
||||
NumberFormat::NorwegianKrone => {
|
||||
assert_number(&type_option, "18443", "-18,443NOK", &field_type, &field)
|
||||
},
|
||||
NumberFormat::MexicanPeso => {
|
||||
assert_number(&type_option, "18443", "-MX$18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Rand => {
|
||||
assert_number(&type_option, "18443", "-ZAR18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::NewTaiwanDollar => {
|
||||
assert_number(&type_option, "18443", "-NT$18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::DanishKrone => {
|
||||
assert_number(&type_option, "18443", "-18.443DKK", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Baht => {
|
||||
assert_number(&type_option, "18443", "-THB18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Forint => {
|
||||
assert_number(&type_option, "18443", "-18 443HUF", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Koruna => {
|
||||
assert_number(&type_option, "18443", "-18 443CZK", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Shekel => {
|
||||
assert_number(&type_option, "18443", "-18 443Kč", &field_type, &field)
|
||||
},
|
||||
NumberFormat::ChileanPeso => {
|
||||
assert_number(&type_option, "18443", "-CLP18.443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::PhilippinePeso => {
|
||||
assert_number(&type_option, "18443", "-₱18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Dirham => {
|
||||
assert_number(&type_option, "18443", "-18,443AED", &field_type, &field)
|
||||
},
|
||||
NumberFormat::ColombianPeso => {
|
||||
assert_number(&type_option, "18443", "-COP18.443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Riyal => {
|
||||
assert_number(&type_option, "18443", "-SAR18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Ringgit => {
|
||||
assert_number(&type_option, "18443", "-MYR18,443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Leu => {
|
||||
assert_number(&type_option, "18443", "-18.443RON", &field_type, &field)
|
||||
},
|
||||
NumberFormat::ArgentinePeso => {
|
||||
assert_number(&type_option, "18443", "-ARS18.443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::UruguayanPeso => {
|
||||
assert_number(&type_option, "18443", "-UYU18.443", &field_type, &field)
|
||||
},
|
||||
NumberFormat::Percent => {
|
||||
assert_number(&type_option, "18443", "-18,443%", &field_type, &field)
|
||||
},
|
||||
}
|
||||
}
|
||||
assert_number(&type_option, "€0.2", "$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "-€0.2", "-$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "-CN¥0.2", "-$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "CN¥0.2", "$0.2", &field_type, &field);
|
||||
assert_number(&type_option, "0.2", "$0.2", &field_type, &field);
|
||||
}
|
||||
|
||||
fn assert_number(
|
||||
@ -513,14 +85,14 @@ mod tests {
|
||||
input_str: &str,
|
||||
expected_str: &str,
|
||||
field_type: &FieldType,
|
||||
field_rev: &Field,
|
||||
field: &Field,
|
||||
) {
|
||||
assert_eq!(
|
||||
type_option
|
||||
.decode_cell_str(
|
||||
&NumberCellData(input_str.to_owned()).into(),
|
||||
field_type,
|
||||
field_rev
|
||||
field
|
||||
)
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
|
@ -27,7 +27,6 @@ pub struct NumberTypeOption {
|
||||
pub format: NumberFormat,
|
||||
pub scale: u32,
|
||||
pub symbol: String,
|
||||
pub sign_positive: bool,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
@ -75,13 +74,11 @@ impl From<TypeOptionData> for NumberTypeOption {
|
||||
.unwrap_or_default();
|
||||
let scale = data.get_i64_value("scale").unwrap_or_default() as u32;
|
||||
let symbol = data.get_str_value("symbol").unwrap_or_default();
|
||||
let sign_positive = data.get_bool_value("sign_positive").unwrap_or_default();
|
||||
let name = data.get_str_value("name").unwrap_or_default();
|
||||
Self {
|
||||
format,
|
||||
scale,
|
||||
symbol,
|
||||
sign_positive,
|
||||
name,
|
||||
}
|
||||
}
|
||||
@ -92,7 +89,6 @@ impl From<NumberTypeOption> for TypeOptionData {
|
||||
TypeOptionDataBuilder::new()
|
||||
.insert_i64_value("format", data.format.value())
|
||||
.insert_i64_value("scale", data.scale as i64)
|
||||
.insert_bool_value("sign_positive", data.sign_positive)
|
||||
.insert_str_value("name", data.name)
|
||||
.insert_str_value("symbol", data.symbol)
|
||||
.build()
|
||||
@ -132,20 +128,23 @@ impl NumberTypeOption {
|
||||
Err(_) => Ok(NumberCellFormat::new()),
|
||||
}
|
||||
} else {
|
||||
let num = match EXTRACT_NUM_REGEX.captures(&num_cell_data.0) {
|
||||
let num_str = match EXTRACT_NUM_REGEX.captures(&num_cell_data.0) {
|
||||
Ok(Some(captures)) => captures
|
||||
.get(0)
|
||||
.map(|m| m.as_str().to_string())
|
||||
.unwrap_or_default(),
|
||||
_ => "".to_string(),
|
||||
};
|
||||
match Decimal::from_str(&num) {
|
||||
Ok(value, ..) => Ok(NumberCellFormat::from_decimal(value)),
|
||||
|
||||
match Decimal::from_str(&num_str) {
|
||||
Ok(decimal, ..) => {
|
||||
return Ok(NumberCellFormat::from_decimal(decimal));
|
||||
},
|
||||
Err(_) => Ok(NumberCellFormat::new()),
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => NumberCellFormat::from_format_str(&num_cell_data.0, self.sign_positive, &self.format),
|
||||
_ => NumberCellFormat::from_format_str(&num_cell_data.0, &self.format),
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,17 +154,6 @@ impl NumberTypeOption {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn strip_currency_symbol<T: ToString>(s: T) -> String {
|
||||
let mut s = s.to_string();
|
||||
for symbol in CURRENCY_SYMBOL.iter() {
|
||||
if s.starts_with(symbol) {
|
||||
s = s.strip_prefix(symbol).unwrap_or("").to_string();
|
||||
break;
|
||||
}
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
impl TypeOptionTransform for NumberTypeOption {}
|
||||
|
||||
impl CellDataDecoder for NumberTypeOption {
|
||||
@ -206,9 +194,11 @@ impl CellDataChangeset for NumberTypeOption {
|
||||
changeset: <Self as TypeOption>::CellChangeset,
|
||||
_cell: Option<Cell>,
|
||||
) -> FlowyResult<(Cell, <Self as TypeOption>::CellData)> {
|
||||
let number_cell_data = NumberCellData(changeset.trim().to_string());
|
||||
let num_str = changeset.trim().to_string();
|
||||
let number_cell_data = NumberCellData(num_str);
|
||||
let formatter = self.format_cell_data(&number_cell_data)?;
|
||||
|
||||
tracing::trace!("number: {:?}", number_cell_data);
|
||||
match self.format {
|
||||
NumberFormat::Num => Ok((
|
||||
NumberCellData(formatter.to_string()).into(),
|
||||
@ -245,9 +235,8 @@ impl TypeOptionCellDataCompare for NumberTypeOption {
|
||||
cell_data: &<Self as TypeOption>::CellData,
|
||||
other_cell_data: &<Self as TypeOption>::CellData,
|
||||
) -> Ordering {
|
||||
let left = NumberCellFormat::from_format_str(&cell_data.0, self.sign_positive, &self.format);
|
||||
let right =
|
||||
NumberCellFormat::from_format_str(&other_cell_data.0, self.sign_positive, &self.format);
|
||||
let left = NumberCellFormat::from_format_str(&cell_data.0, &self.format);
|
||||
let right = NumberCellFormat::from_format_str(&other_cell_data.0, &self.format);
|
||||
match (left, right) {
|
||||
(Ok(left), Ok(right)) => {
|
||||
return left.decimal().cmp(right.decimal());
|
||||
@ -266,7 +255,6 @@ impl std::default::Default for NumberTypeOption {
|
||||
format,
|
||||
scale: 0,
|
||||
symbol,
|
||||
sign_positive: true,
|
||||
name: "Number".to_string(),
|
||||
}
|
||||
}
|
||||
@ -274,5 +262,5 @@ impl std::default::Default for NumberTypeOption {
|
||||
|
||||
lazy_static! {
|
||||
static ref SCIENTIFIC_NOTATION_REGEX: Regex = Regex::new(r"([+-]?\d*\.?\d+)e([+-]?\d+)").unwrap();
|
||||
static ref EXTRACT_NUM_REGEX: Regex = Regex::new(r"-?\d+(\.\d+)?").unwrap();
|
||||
pub(crate) static ref EXTRACT_NUM_REGEX: Regex = Regex::new(r"-?\d+(\.\d+)?").unwrap();
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::services::cell::{CellBytesCustomParser, CellProtobufBlobParser, DecodedCellData};
|
||||
use crate::services::field::number_currency::Currency;
|
||||
use crate::services::field::{strip_currency_symbol, NumberFormat, STRIP_SYMBOL};
|
||||
use crate::services::field::{NumberFormat, EXTRACT_NUM_REGEX};
|
||||
use bytes::Bytes;
|
||||
use flowy_error::FlowyResult;
|
||||
use rust_decimal::Decimal;
|
||||
@ -21,29 +21,28 @@ impl NumberCellFormat {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_format_str(s: &str, sign_positive: bool, format: &NumberFormat) -> FlowyResult<Self> {
|
||||
let mut num_str = strip_currency_symbol(s);
|
||||
let currency = format.currency();
|
||||
/// The num_str might contain currency symbol, e.g. $1,000.00
|
||||
pub fn from_format_str(num_str: &str, format: &NumberFormat) -> FlowyResult<Self> {
|
||||
if num_str.is_empty() {
|
||||
return Ok(Self::default());
|
||||
}
|
||||
// If the first char is not '-', then it is a sign.
|
||||
let sign_positive = match num_str.find("-") {
|
||||
None => true,
|
||||
Some(offset) => offset != 0,
|
||||
};
|
||||
|
||||
// Extract number from string.
|
||||
let num_str = extract_number(num_str);
|
||||
match Decimal::from_str(&num_str) {
|
||||
Ok(mut decimal) => {
|
||||
decimal.set_sign_positive(sign_positive);
|
||||
let money = Money::from_decimal(decimal, currency);
|
||||
let money = Money::from_decimal(decimal, format.currency());
|
||||
Ok(Self::from_money(money))
|
||||
},
|
||||
Err(_) => match Money::from_str(&num_str, currency) {
|
||||
Ok(money) => Ok(NumberCellFormat::from_money(money)),
|
||||
Err(_) => {
|
||||
num_str.retain(|c| !STRIP_SYMBOL.contains(&c.to_string()));
|
||||
if num_str.chars().all(char::is_numeric) {
|
||||
Self::from_format_str(&num_str, sign_positive, format)
|
||||
} else {
|
||||
// returns empty string if it can be formatted
|
||||
Ok(Self::default())
|
||||
}
|
||||
},
|
||||
Err(_) => match Money::from_str(&num_str, format.currency()) {
|
||||
Ok(money) => Ok(Self::from_money(money)),
|
||||
Err(_) => Ok(Self::default()),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -71,17 +70,14 @@ impl NumberCellFormat {
|
||||
}
|
||||
}
|
||||
|
||||
// impl FromStr for NumberCellData {
|
||||
// type Err = FlowyError;
|
||||
//
|
||||
// fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
// if s.is_empty() {
|
||||
// return Ok(Self::default());
|
||||
// }
|
||||
// let decimal = Decimal::from_str(s).map_err(internal_error)?;
|
||||
// Ok(Self::from_decimal(decimal))
|
||||
// }
|
||||
// }
|
||||
fn extract_number(num_str: &str) -> String {
|
||||
let mut matches = EXTRACT_NUM_REGEX.find_iter(num_str);
|
||||
let mut values = vec![];
|
||||
while let Some(Ok(m)) = matches.next() {
|
||||
values.push(m.as_str().to_string());
|
||||
}
|
||||
values.join("")
|
||||
}
|
||||
|
||||
impl ToString for NumberCellFormat {
|
||||
fn to_string(&self) -> String {
|
||||
@ -108,7 +104,7 @@ impl CellProtobufBlobParser for NumberCellDataParser {
|
||||
type Object = NumberCellFormat;
|
||||
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
|
||||
match String::from_utf8(bytes.to_vec()) {
|
||||
Ok(s) => NumberCellFormat::from_format_str(&s, true, &NumberFormat::Num),
|
||||
Ok(s) => NumberCellFormat::from_format_str(&s, &NumberFormat::Num),
|
||||
Err(_) => Ok(NumberCellFormat::default()),
|
||||
}
|
||||
}
|
||||
@ -119,7 +115,7 @@ impl CellBytesCustomParser for NumberCellCustomDataParser {
|
||||
type Object = NumberCellFormat;
|
||||
fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
|
||||
match String::from_utf8(bytes.to_vec()) {
|
||||
Ok(s) => NumberCellFormat::from_format_str(&s, true, &self.0),
|
||||
Ok(s) => NumberCellFormat::from_format_str(&s, &self.0),
|
||||
Err(_) => Ok(NumberCellFormat::default()),
|
||||
}
|
||||
}
|
||||
|
@ -141,12 +141,12 @@ where
|
||||
|
||||
let cell_data = self.decode_cell_str(cell, decoded_field_type, field)?;
|
||||
if let Some(cell_data_cache) = self.cell_data_cache.as_ref() {
|
||||
tracing::trace!(
|
||||
"Cell cache update: field_type:{}, cell: {:?}, cell_data: {:?}",
|
||||
decoded_field_type,
|
||||
cell,
|
||||
cell_data
|
||||
);
|
||||
// tracing::trace!(
|
||||
// "Cell cache update: field_type:{}, cell: {:?}, cell_data: {:?}",
|
||||
// decoded_field_type,
|
||||
// cell,
|
||||
// cell_data
|
||||
// );
|
||||
cell_data_cache
|
||||
.write()
|
||||
.insert(key.as_ref(), cell_data.clone());
|
||||
@ -163,12 +163,12 @@ where
|
||||
if let Some(cell_data_cache) = self.cell_data_cache.as_ref() {
|
||||
let field_type = FieldType::from(field.field_type);
|
||||
let key = CellDataCacheKey::new(field, field_type.clone(), cell);
|
||||
tracing::trace!(
|
||||
"Cell cache update: field_type:{}, cell: {:?}, cell_data: {:?}",
|
||||
field_type,
|
||||
cell,
|
||||
cell_data
|
||||
);
|
||||
// tracing::trace!(
|
||||
// "Cell cache update: field_type:{}, cell: {:?}, cell_data: {:?}",
|
||||
// field_type,
|
||||
// cell,
|
||||
// cell_data
|
||||
// );
|
||||
cell_data_cache.write().insert(key.as_ref(), cell_data);
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ use std::sync::Arc;
|
||||
/// * `configuration_writer`: as writer used to write the group configuration to disk
|
||||
///
|
||||
#[tracing::instrument(
|
||||
level = "debug",
|
||||
level = "trace",
|
||||
skip_all,
|
||||
fields(grouping_field_id=%grouping_field.id, grouping_field_type)
|
||||
err
|
||||
|
@ -85,7 +85,7 @@ impl SortController {
|
||||
self.gen_task(task_type, QualityOfService::Background).await;
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "process_sort_task", level = "trace", skip_all, err)]
|
||||
#[tracing::instrument(name = "process_sort_task", level = "debug", skip_all, err)]
|
||||
pub async fn process(&mut self, predicate: &str) -> FlowyResult<()> {
|
||||
let event_type = SortEvent::from_str(predicate).unwrap();
|
||||
let mut rows = self.delegate.get_rows(&self.view_id).await;
|
||||
|
Reference in New Issue
Block a user