fix: number sort (#2570)

* chore: remove sign

* fix: sort number

* chore: update patch

* ci: fix dart test

* chore: fmt
This commit is contained in:
Nathan.fooo
2023-05-21 11:13:22 +08:00
committed by GitHub
parent bb681bdd1e
commit 6c31cf9555
23 changed files with 291 additions and 689 deletions

View File

@ -151,7 +151,6 @@ class RowList {
(rowInfo) => rowInfo.rowPB.id == rowId, (rowInfo) => rowInfo.rowPB.id == rowId,
); );
if (index != -1) { if (index != -1) {
assert(index == oldIndex);
final rowInfo = remove(rowId)!.rowInfo; final rowInfo = remove(rowId)!.rowInfo;
insert(newIndex, rowInfo); insert(newIndex, rowInfo);
} }

View File

@ -34,12 +34,12 @@ default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"] custom-protocol = ["tauri/custom-protocol"]
[patch.crates-io] [patch.crates-io]
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d074c9" } collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d074c9" } collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" }
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d074c9" } collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d074c9" } collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d074c9" } collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" }
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d074c9" } appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" }
#collab = { path = "../../AppFlowy-Collab/collab" } #collab = { path = "../../AppFlowy-Collab/collab" }
#collab-folder = { path = "../../AppFlowy-Collab/collab-folder" } #collab-folder = { path = "../../AppFlowy-Collab/collab-folder" }

View File

@ -85,7 +85,7 @@ checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
[[package]] [[package]]
name = "appflowy-integrate" name = "appflowy-integrate"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d074c9#d074c94471f222e2701fe451f13c51aab39d2bf8" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f"
dependencies = [ dependencies = [
"collab", "collab",
"collab-database", "collab-database",
@ -574,9 +574,9 @@ dependencies = [
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.64.0" version = "0.65.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cexpr", "cexpr",
@ -584,12 +584,13 @@ dependencies = [
"lazy_static", "lazy_static",
"lazycell", "lazycell",
"peeking_take_while", "peeking_take_while",
"prettyplease",
"proc-macro2", "proc-macro2",
"quote", "quote",
"regex", "regex",
"rustc-hash", "rustc-hash",
"shlex", "shlex",
"syn 1.0.109", "syn 2.0.15",
] ]
[[package]] [[package]]
@ -883,7 +884,7 @@ dependencies = [
[[package]] [[package]]
name = "collab" name = "collab"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d074c9#d074c94471f222e2701fe451f13c51aab39d2bf8" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -900,7 +901,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-client-ws" name = "collab-client-ws"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d074c9#d074c94471f222e2701fe451f13c51aab39d2bf8" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f"
dependencies = [ dependencies = [
"bytes", "bytes",
"collab-sync", "collab-sync",
@ -918,7 +919,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-database" name = "collab-database"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d074c9#d074c94471f222e2701fe451f13c51aab39d2bf8" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -942,7 +943,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-derive" name = "collab-derive"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d074c9#d074c94471f222e2701fe451f13c51aab39d2bf8" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -954,7 +955,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-document" name = "collab-document"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d074c9#d074c94471f222e2701fe451f13c51aab39d2bf8" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab", "collab",
@ -971,7 +972,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-folder" name = "collab-folder"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d074c9#d074c94471f222e2701fe451f13c51aab39d2bf8" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab", "collab",
@ -989,7 +990,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-persistence" name = "collab-persistence"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d074c9#d074c94471f222e2701fe451f13c51aab39d2bf8" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f"
dependencies = [ dependencies = [
"bincode", "bincode",
"chrono", "chrono",
@ -1009,7 +1010,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-plugins" name = "collab-plugins"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d074c9#d074c94471f222e2701fe451f13c51aab39d2bf8" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -1035,7 +1036,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-sync" name = "collab-sync"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d074c9#d074c94471f222e2701fe451f13c51aab39d2bf8" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=7a2e97#7a2e97d9bfe746f5db18753ab0b59347ec5bf23f"
dependencies = [ dependencies = [
"bytes", "bytes",
"collab", "collab",
@ -1817,6 +1818,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serial_test", "serial_test",
"tempdir",
"thread-id", "thread-id",
"tokio", "tokio",
] ]
@ -1899,6 +1901,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.28" version = "0.3.28"
@ -2584,9 +2592,9 @@ checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
[[package]] [[package]]
name = "librocksdb-sys" name = "librocksdb-sys"
version = "0.10.0+7.9.2" version = "0.11.0+8.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fe4d5874f5ff2bc616e55e8c6086d478fcda13faf9495768a4aa1c22042d30b" checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e"
dependencies = [ dependencies = [
"bindgen", "bindgen",
"bzip2-sys", "bzip2-sys",
@ -3235,6 +3243,16 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "prettyplease"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ceca8aaf45b5c46ec7ed39fff75f57290368c1846d33d24a122ca81416ab058"
dependencies = [
"proc-macro2",
"syn 2.0.15",
]
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "0.1.5" version = "0.1.5"
@ -3475,6 +3493,19 @@ dependencies = [
"scheduled-thread-pool", "scheduled-thread-pool",
] ]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi",
]
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.7.3" version = "0.7.3"
@ -3520,6 +3551,21 @@ dependencies = [
"rand_core 0.6.4", "rand_core 0.6.4",
] ]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.5.1" version = "0.5.1"
@ -3578,6 +3624,15 @@ dependencies = [
"num_cpus", "num_cpus",
] ]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.1.57" version = "0.1.57"
@ -3639,6 +3694,15 @@ version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "rend" name = "rend"
version = "0.4.0" version = "0.4.0"
@ -3727,9 +3791,9 @@ dependencies = [
[[package]] [[package]]
name = "rocksdb" name = "rocksdb"
version = "0.20.1" version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "015439787fce1e75d55f279078d33ff14b4af5d93d995e8838ee4631301c8a99" checksum = "bb6f170a4041d50a0ce04b0d2e14916d6ca863ea2e422689a5b694395d299ffe"
dependencies = [ dependencies = [
"libc", "libc",
"librocksdb-sys", "librocksdb-sys",
@ -4242,6 +4306,16 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "tempdir"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
dependencies = [
"rand 0.4.6",
"remove_dir_all",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.5.0" version = "3.5.0"

View File

@ -32,11 +32,11 @@ opt-level = 3
incremental = false incremental = false
[patch.crates-io] [patch.crates-io]
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d074c9" } collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d074c9" } collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d074c9" } collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d074c9" } collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" }
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d074c9" } appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "7a2e97" }
#collab = { path = "../AppFlowy-Collab/collab" } #collab = { path = "../AppFlowy-Collab/collab" }
#collab-folder = { path = "../AppFlowy-Collab/collab-folder" } #collab-folder = { path = "../AppFlowy-Collab/collab-folder" }

View File

@ -84,7 +84,7 @@ fn create_log_filter(level: String, with_crates: Vec<String>) -> String {
filters.push(format!("flowy_core={}", level)); filters.push(format!("flowy_core={}", level));
filters.push(format!("flowy_folder2={}", level)); filters.push(format!("flowy_folder2={}", level));
filters.push(format!("collab_folder={}", level)); filters.push(format!("collab_folder={}", level));
// filters.push(format!("collab_persistence={}", level)); filters.push(format!("collab_persistence={}", level));
filters.push(format!("collab_database={}", level)); filters.push(format!("collab_database={}", level));
filters.push(format!("collab_plugins={}", level)); filters.push(format!("collab_plugins={}", level));
filters.push(format!("appflowy_integrate={}", level)); filters.push(format!("appflowy_integrate={}", level));

View File

@ -13,9 +13,6 @@ pub struct NumberTypeOptionPB {
#[pb(index = 3)] #[pb(index = 3)]
pub symbol: String, pub symbol: String,
#[pb(index = 4)]
pub sign_positive: bool,
#[pb(index = 5)] #[pb(index = 5)]
pub name: String, pub name: String,
} }
@ -26,7 +23,6 @@ impl From<NumberTypeOption> for NumberTypeOptionPB {
format: data.format.into(), format: data.format.into(),
scale: data.scale, scale: data.scale,
symbol: data.symbol, symbol: data.symbol,
sign_positive: data.sign_positive,
name: data.name, name: data.name,
} }
} }
@ -38,7 +34,6 @@ impl From<NumberTypeOptionPB> for NumberTypeOption {
format: data.format.into(), format: data.format.into(),
scale: data.scale, scale: data.scale,
symbol: data.symbol, symbol: data.symbol,
sign_positive: data.sign_positive,
name: data.name, name: data.name,
} }
} }

View File

@ -347,7 +347,7 @@ pub(crate) async fn get_cell_handler(
data_result_ok(cell) 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( pub(crate) async fn update_cell_handler(
data: AFPluginData<CellChangesetPB>, data: AFPluginData<CellChangesetPB>,
manager: AFPluginState<Arc<DatabaseManager2>>, manager: AFPluginState<Arc<DatabaseManager2>>,

View File

@ -58,7 +58,7 @@ pub trait CellDataChangeset: TypeOption {
/// FieldType::SingleSelect => SelectOptionChangeset /// FieldType::SingleSelect => SelectOptionChangeset
/// ///
/// cell_rev: It will be None if the cell does not contain any data. /// 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, changeset: C,
cell: Option<Cell>, cell: Option<Cell>,
field: &Field, field: &Field,
@ -194,11 +194,11 @@ pub fn stringify_cell_data(
} }
pub fn insert_text_cell(s: String, field: &Field) -> Cell { 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 { 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 { 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, _ => 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 { 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 { } else {
UNCHECK.to_string() 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 { 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, timezone_id: None,
}) })
.unwrap(); .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 { pub fn insert_select_option_cell(option_ids: Vec<String>, field: &Field) -> Cell {
let changeset = let changeset =
SelectOptionCellChangeset::from_insert_options(option_ids).to_cell_changeset_str(); 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 { pub fn delete_select_option_cell(option_ids: Vec<String>, field: &Field) -> Cell {
let changeset = let changeset =
SelectOptionCellChangeset::from_delete_options(option_ids).to_cell_changeset_str(); 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. /// Deserialize the String into cell specific data type.

View File

@ -6,7 +6,7 @@ use bytes::Bytes;
use collab_database::database::{gen_row_id, timestamp, Database as InnerDatabase}; use collab_database::database::{gen_row_id, timestamp, Database as InnerDatabase};
use collab_database::fields::{Field, TypeOptionData}; use collab_database::fields::{Field, TypeOptionData};
use collab_database::rows::{Cell, Cells, Row, RowCell, RowId}; 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 parking_lot::Mutex;
use tokio::sync::{broadcast, RwLock}; use tokio::sync::{broadcast, RwLock};
@ -23,14 +23,11 @@ use crate::entities::{
}; };
use crate::notification::{send_notification, DatabaseNotification}; use crate::notification::{send_notification, DatabaseNotification};
use crate::services::cell::{ 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, ToCellChangeset,
}; };
use crate::services::database::util::database_view_setting_pb_from_view; 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};
use crate::services::database_view::{
DatabaseViewChanged, DatabaseViewData, DatabaseViews, RowEventSender,
};
use crate::services::field::{ use crate::services::field::{
default_type_option_data_for_type, default_type_option_data_from_type, 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, select_type_option_from_field, transform_type_option, type_option_data_from_pb_or_default,
@ -46,7 +43,6 @@ pub struct DatabaseEditor {
database: MutexDatabase, database: MutexDatabase,
pub cell_cache: CellCache, pub cell_cache: CellCache,
database_views: Arc<DatabaseViews>, database_views: Arc<DatabaseViews>,
row_event_tx: RowEventSender,
} }
impl DatabaseEditor { impl DatabaseEditor {
@ -55,27 +51,18 @@ impl DatabaseEditor {
task_scheduler: Arc<RwLock<TaskDispatcher>>, task_scheduler: Arc<RwLock<TaskDispatcher>>,
) -> FlowyResult<Self> { ) -> FlowyResult<Self> {
let cell_cache = AnyTypeCache::<u64>::new(); let cell_cache = AnyTypeCache::<u64>::new();
let (row_event_tx, row_event_rx) = broadcast::channel(100);
let database_view_data = Arc::new(DatabaseViewDataImpl { let database_view_data = Arc::new(DatabaseViewDataImpl {
database: database.clone(), database: database.clone(),
task_scheduler: task_scheduler.clone(), task_scheduler: task_scheduler.clone(),
cell_cache: cell_cache.clone(), cell_cache: cell_cache.clone(),
}); });
let database_views = Arc::new( let database_views =
DatabaseViews::new( Arc::new(DatabaseViews::new(database.clone(), cell_cache.clone(), database_view_data).await?);
database.clone(),
cell_cache.clone(),
database_view_data,
row_event_rx,
)
.await?,
);
Ok(Self { Ok(Self {
database, database,
cell_cache, cell_cache,
database_views, database_views,
row_event_tx,
}) })
} }
@ -295,7 +282,14 @@ impl DatabaseEditor {
// self.database.lock().views.update_view(view_id, |view| { // self.database.lock().views.update_view(view_id, |view| {
// view.move_row_order(from as u32, to as u32); // 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>> { pub async fn create_row(&self, params: CreateRowParams) -> FlowyResult<Option<Row>> {
@ -319,14 +313,6 @@ impl DatabaseEditor {
); );
if let Some((index, row_order)) = result { 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); let row = self.database.lock().get_row(&row_order.id);
if let Some(row) = row { if let Some(row) = row {
for view in self.database_views.editors().await { for view in self.database_views.editors().await {
@ -423,10 +409,6 @@ impl DatabaseEditor {
let row = self.database.lock().remove_row(row_id); let row = self.database.lock().remove_row(row_id);
if let Some(row) = row { if let Some(row) = row {
tracing::trace!("Did delete 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 { for view in self.database_views.editors().await {
view.v_did_delete_row(&row).await; view.v_did_delete_row(&row).await;
} }
@ -481,15 +463,18 @@ impl DatabaseEditor {
}?; }?;
( (
field, 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 = 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 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( pub async fn update_cell(
&self, &self,
view_id: &str, view_id: &str,
@ -497,6 +482,7 @@ impl DatabaseEditor {
field_id: &str, field_id: &str,
new_cell: Cell, new_cell: Cell,
) -> FlowyResult<()> { ) -> 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) }; let old_row = { self.database.lock().get_row(&row_id) };
self.database.lock().update_row(&row_id, |row_update| { self.database.lock().update_row(&row_id, |row_update| {
row_update.update_cells(|cell_update| { row_update.update_cells(|cell_update| {
@ -506,14 +492,8 @@ impl DatabaseEditor {
let option_row = self.database.lock().get_row(&row_id); let option_row = self.database.lock().get_row(&row_id);
if let Some(new_row) = option_row { 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 { 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;
} }
} }

View File

@ -5,7 +5,7 @@ use std::sync::Arc;
use collab_database::database::{gen_database_filter_id, gen_database_sort_id}; use collab_database::database::{gen_database_filter_id, gen_database_sort_id};
use collab_database::fields::Field; use collab_database::fields::Field;
use collab_database::rows::{Cells, Row, RowCell, RowId}; 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 tokio::sync::{broadcast, RwLock};
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
@ -20,7 +20,7 @@ use crate::entities::{
}; };
use crate::notification::{send_notification, DatabaseNotification}; use crate::notification::{send_notification, DatabaseNotification};
use crate::services::cell::CellCache; 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_filter::make_filter_controller;
use crate::services::database_view::view_group::{ use crate::services::database_view::view_group::{
get_cell_for_row, get_cells_for_field, new_group_controller, new_group_controller_with_field, 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 /// Returns the `index` and `RowRevision` with row_id
fn get_row(&self, view_id: &str, row_id: &RowId) -> Fut<Option<(usize, Arc<Row>)>>; 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_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>>>; 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) { 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 // Send the group notification if the current view has groups
match group_id.as_ref() { 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) => { Some(group_id) => {
self self
.group_controller .group_controller
@ -213,9 +219,17 @@ impl DatabaseViewEditor {
notify_did_update_group_rows(changeset).await; 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 let result = self
.mut_group_controller(|group_controller, field| { .mut_group_controller(|group_controller, field| {
Ok(group_controller.did_update_group_row(old_row, row, &field)) Ok(group_controller.did_update_group_row(old_row, row, &field))
@ -244,20 +258,35 @@ impl DatabaseViewEditor {
for changeset in result.row_changesets { for changeset in result.row_changesets {
notify_did_update_group_rows(changeset).await; 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(); // Each row update will trigger a filter and sort operation. We don't want
let sort_controller = self.sort_controller.clone(); // to block the main thread, so we spawn a new task to do the work.
let row_id = row.id.clone(); 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 { tokio::spawn(async move {
filter_controller if let Some(filter_controller) = weak_filter_controller.upgrade() {
.did_receive_row_changed(row_id.clone()) filter_controller
.await; .did_receive_row_changed(row_id.clone())
sort_controller .await;
.read() }
.await if let Some(sort_controller) = weak_sort_controller.upgrade() {
.did_receive_row_changed(row_id) sort_controller
.await; .read()
.await
.did_receive_row_changed(row_id)
.await;
}
}); });
} }
@ -513,7 +542,7 @@ impl DatabaseViewEditor {
} }
/// Returns the current calendar settings /// 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 { pub async fn v_get_layout_settings(&self, layout_ty: &DatabaseLayout) -> LayoutSettingParams {
let mut layout_setting = LayoutSettingParams::default(); let mut layout_setting = LayoutSettingParams::default();
match layout_ty { match layout_ty {
@ -751,7 +780,7 @@ impl DatabaseViewEditor {
Some(events) 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() { let changeset = match event.into_owned() {
DatabaseRowEvent::InsertRow(row) => { DatabaseRowEvent::InsertRow(row) => {
RowsChangesetPB::from_insert(self.view_id.clone(), vec![row.into()]) RowsChangesetPB::from_insert(self.view_id.clone(), vec![row.into()])

View File

@ -1,4 +1,3 @@
use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
@ -31,10 +30,8 @@ impl DatabaseViews {
database: MutexDatabase, database: MutexDatabase,
cell_cache: CellCache, cell_cache: CellCache,
database_view_data: Arc<dyn DatabaseViewData>, database_view_data: Arc<dyn DatabaseViewData>,
row_event_rx: RowEventReceiver,
) -> FlowyResult<Self> { ) -> FlowyResult<Self> {
let editor_map = Arc::new(RwLock::new(HashMap::default())); let editor_map = Arc::new(RwLock::new(HashMap::default()));
listen_on_database_row_event(row_event_rx, editor_map.clone());
Ok(Self { Ok(Self {
database, database,
database_view_data, 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 { pub fn gen_handler_id() -> String {
nanoid!(10) nanoid!(10)
} }

View File

@ -7,10 +7,15 @@ use strum::IntoEnumIterator;
use strum_macros::EnumIter; use strum_macros::EnumIter;
lazy_static! { 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()) .map(|format| format.symbol())
.collect::<Vec<String>>(); .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)] #[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter, Serialize, Deserialize)]

View File

@ -47,13 +47,13 @@ mod tests {
}; };
for (num_str, visible) in [("123", true), ("1234", false), ("", false)] { 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); assert_eq!(number_filter.is_visible(&data), visible);
} }
let format = NumberFormat::USD; let format = NumberFormat::USD;
for (num_str, visible) in [("$123", true), ("1234", false), ("", false)] { 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); assert_eq!(number_filter.is_visible(&data), visible);
} }
} }
@ -64,7 +64,7 @@ mod tests {
content: "12".to_owned(), content: "12".to_owned(),
}; };
for (num_str, visible) in [("123", true), ("10", false), ("30", true), ("", false)] { 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); assert_eq!(number_filter.is_visible(&data), visible);
} }
} }
@ -76,7 +76,7 @@ mod tests {
content: "100".to_owned(), content: "100".to_owned(),
}; };
for (num_str, visible) in [("12", true), ("1234", false), ("30", true), ("", false)] { 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); assert_eq!(number_filter.is_visible(&data), visible);
} }
} }

View File

@ -1,16 +1,15 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use collab_database::fields::Field; use collab_database::fields::Field;
use strum::IntoEnumIterator;
use crate::entities::FieldType; use crate::entities::FieldType;
use crate::services::cell::CellDataDecoder; use crate::services::cell::CellDataDecoder;
use crate::services::field::{strip_currency_symbol, NumberFormat, NumberTypeOption};
use crate::services::field::{FieldBuilder, NumberCellData}; use crate::services::field::{FieldBuilder, NumberCellData};
use crate::services::field::{NumberFormat, NumberTypeOption};
/// Testing when the input is not a number. /// Testing when the input is not a number.
#[test] #[test]
fn number_type_option_invalid_input_test() { fn number_type_option_input_test() {
let type_option = NumberTypeOption::default(); let type_option = NumberTypeOption::default();
let field_type = FieldType::Number; let field_type = FieldType::Number;
let field = FieldBuilder::from_field_type(field_type.clone()).build(); let field = FieldBuilder::from_field_type(field_type.clone()).build();
@ -20,492 +19,65 @@ mod tests {
// Input is letter // Input is letter
assert_number(&type_option, "abc", "", &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, "abc-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, "+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);
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] #[test]
fn number_type_option_strip_symbol_test() { fn dollar_type_option_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();
let field_type = FieldType::Number; 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() { assert_number(&type_option, "", "", &field_type, &field);
type_option.format = format; assert_number(&type_option, "abc", "", &field_type, &field);
match format { assert_number(&type_option, "-123", "-$123", &field_type, &field);
NumberFormat::Num => { assert_number(&type_option, "+123", "$123", &field_type, &field);
assert_number(&type_option, "18443", "18443", &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);
NumberFormat::USD => { assert_number(&type_option, "-$0.2", "-$0.2", &field_type, &field);
assert_number(&type_option, "18443", "$18,443", &field_type, &field); assert_number(&type_option, "-€0.2", "-$0.2", &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)
},
}
}
} }
/// Format the input String to the corresponding format string.
#[test] #[test]
fn number_type_option_format_str_test() { fn dollar_type_option_test2() {
let mut type_option = NumberTypeOption::default();
let field_type = FieldType::Number; 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() { assert_number(
type_option.format = format; &type_option,
match format { "99999999999",
NumberFormat::Num => { "$99,999,999,999",
assert_number(&type_option, "18443", "18443", &field_type, &field); &field_type,
assert_number(&type_option, "0.2", "0.2", &field_type, &field); &field,
assert_number(&type_option, "", "", &field_type, &field); );
assert_number(&type_option, "abc", "", &field_type, &field); assert_number(
}, &type_option,
NumberFormat::USD => { "$99,999,999,999",
assert_number(&type_option, "$18,44", "$1,844", &field_type, &field); "$99,999,999,999",
assert_number(&type_option, "$0.2", "$0.2", &field_type, &field); &field_type,
assert_number(&type_option, "$1844", "$1,844", &field_type, &field); &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);
},
}
}
} }
/// Carry out the sign positive to input number
#[test] #[test]
fn number_description_sign_test() { fn other_symbol_to_dollar_type_option_test() {
let mut type_option = NumberTypeOption {
sign_positive: false,
..Default::default()
};
let field_type = FieldType::Number; 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() { assert_number(&type_option, "€0.2", "$0.2", &field_type, &field);
type_option.format = format; assert_number(&type_option, "-€0.2", "-$0.2", &field_type, &field);
match format { assert_number(&type_option, "-CN¥0.2", "-$0.2", &field_type, &field);
NumberFormat::Num => { assert_number(&type_option, "CN¥0.2", "$0.2", &field_type, &field);
assert_number(&type_option, "18443", "18443", &field_type, &field); assert_number(&type_option, "0.2", "$0.2", &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)
},
}
}
} }
fn assert_number( fn assert_number(
@ -513,14 +85,14 @@ mod tests {
input_str: &str, input_str: &str,
expected_str: &str, expected_str: &str,
field_type: &FieldType, field_type: &FieldType,
field_rev: &Field, field: &Field,
) { ) {
assert_eq!( assert_eq!(
type_option type_option
.decode_cell_str( .decode_cell_str(
&NumberCellData(input_str.to_owned()).into(), &NumberCellData(input_str.to_owned()).into(),
field_type, field_type,
field_rev field
) )
.unwrap() .unwrap()
.to_string(), .to_string(),

View File

@ -27,7 +27,6 @@ pub struct NumberTypeOption {
pub format: NumberFormat, pub format: NumberFormat,
pub scale: u32, pub scale: u32,
pub symbol: String, pub symbol: String,
pub sign_positive: bool,
pub name: String, pub name: String,
} }
@ -75,13 +74,11 @@ impl From<TypeOptionData> for NumberTypeOption {
.unwrap_or_default(); .unwrap_or_default();
let scale = data.get_i64_value("scale").unwrap_or_default() as u32; let scale = data.get_i64_value("scale").unwrap_or_default() as u32;
let symbol = data.get_str_value("symbol").unwrap_or_default(); 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(); let name = data.get_str_value("name").unwrap_or_default();
Self { Self {
format, format,
scale, scale,
symbol, symbol,
sign_positive,
name, name,
} }
} }
@ -92,7 +89,6 @@ impl From<NumberTypeOption> for TypeOptionData {
TypeOptionDataBuilder::new() TypeOptionDataBuilder::new()
.insert_i64_value("format", data.format.value()) .insert_i64_value("format", data.format.value())
.insert_i64_value("scale", data.scale as i64) .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("name", data.name)
.insert_str_value("symbol", data.symbol) .insert_str_value("symbol", data.symbol)
.build() .build()
@ -132,20 +128,23 @@ impl NumberTypeOption {
Err(_) => Ok(NumberCellFormat::new()), Err(_) => Ok(NumberCellFormat::new()),
} }
} else { } 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 Ok(Some(captures)) => captures
.get(0) .get(0)
.map(|m| m.as_str().to_string()) .map(|m| m.as_str().to_string())
.unwrap_or_default(), .unwrap_or_default(),
_ => "".to_string(), _ => "".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()), 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 TypeOptionTransform for NumberTypeOption {}
impl CellDataDecoder for NumberTypeOption { impl CellDataDecoder for NumberTypeOption {
@ -206,9 +194,11 @@ impl CellDataChangeset for NumberTypeOption {
changeset: <Self as TypeOption>::CellChangeset, changeset: <Self as TypeOption>::CellChangeset,
_cell: Option<Cell>, _cell: Option<Cell>,
) -> FlowyResult<(Cell, <Self as TypeOption>::CellData)> { ) -> 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)?; let formatter = self.format_cell_data(&number_cell_data)?;
tracing::trace!("number: {:?}", number_cell_data);
match self.format { match self.format {
NumberFormat::Num => Ok(( NumberFormat::Num => Ok((
NumberCellData(formatter.to_string()).into(), NumberCellData(formatter.to_string()).into(),
@ -245,9 +235,8 @@ impl TypeOptionCellDataCompare for NumberTypeOption {
cell_data: &<Self as TypeOption>::CellData, cell_data: &<Self as TypeOption>::CellData,
other_cell_data: &<Self as TypeOption>::CellData, other_cell_data: &<Self as TypeOption>::CellData,
) -> Ordering { ) -> Ordering {
let left = NumberCellFormat::from_format_str(&cell_data.0, self.sign_positive, &self.format); let left = NumberCellFormat::from_format_str(&cell_data.0, &self.format);
let right = let right = NumberCellFormat::from_format_str(&other_cell_data.0, &self.format);
NumberCellFormat::from_format_str(&other_cell_data.0, self.sign_positive, &self.format);
match (left, right) { match (left, right) {
(Ok(left), Ok(right)) => { (Ok(left), Ok(right)) => {
return left.decimal().cmp(right.decimal()); return left.decimal().cmp(right.decimal());
@ -266,7 +255,6 @@ impl std::default::Default for NumberTypeOption {
format, format,
scale: 0, scale: 0,
symbol, symbol,
sign_positive: true,
name: "Number".to_string(), name: "Number".to_string(),
} }
} }
@ -274,5 +262,5 @@ impl std::default::Default for NumberTypeOption {
lazy_static! { lazy_static! {
static ref SCIENTIFIC_NOTATION_REGEX: Regex = Regex::new(r"([+-]?\d*\.?\d+)e([+-]?\d+)").unwrap(); 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();
} }

View File

@ -1,6 +1,6 @@
use crate::services::cell::{CellBytesCustomParser, CellProtobufBlobParser, DecodedCellData}; use crate::services::cell::{CellBytesCustomParser, CellProtobufBlobParser, DecodedCellData};
use crate::services::field::number_currency::Currency; 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 bytes::Bytes;
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use rust_decimal::Decimal; use rust_decimal::Decimal;
@ -21,29 +21,28 @@ impl NumberCellFormat {
} }
} }
pub fn from_format_str(s: &str, sign_positive: bool, format: &NumberFormat) -> FlowyResult<Self> { /// The num_str might contain currency symbol, e.g. $1,000.00
let mut num_str = strip_currency_symbol(s); pub fn from_format_str(num_str: &str, format: &NumberFormat) -> FlowyResult<Self> {
let currency = format.currency();
if num_str.is_empty() { if num_str.is_empty() {
return Ok(Self::default()); 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) { match Decimal::from_str(&num_str) {
Ok(mut decimal) => { Ok(mut decimal) => {
decimal.set_sign_positive(sign_positive); 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)) Ok(Self::from_money(money))
}, },
Err(_) => match Money::from_str(&num_str, currency) { Err(_) => match Money::from_str(&num_str, format.currency()) {
Ok(money) => Ok(NumberCellFormat::from_money(money)), Ok(money) => Ok(Self::from_money(money)),
Err(_) => { Err(_) => Ok(Self::default()),
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())
}
},
}, },
} }
} }
@ -71,17 +70,14 @@ impl NumberCellFormat {
} }
} }
// impl FromStr for NumberCellData { fn extract_number(num_str: &str) -> String {
// type Err = FlowyError; let mut matches = EXTRACT_NUM_REGEX.find_iter(num_str);
// let mut values = vec![];
// fn from_str(s: &str) -> Result<Self, Self::Err> { while let Some(Ok(m)) = matches.next() {
// if s.is_empty() { values.push(m.as_str().to_string());
// return Ok(Self::default()); }
// } values.join("")
// let decimal = Decimal::from_str(s).map_err(internal_error)?; }
// Ok(Self::from_decimal(decimal))
// }
// }
impl ToString for NumberCellFormat { impl ToString for NumberCellFormat {
fn to_string(&self) -> String { fn to_string(&self) -> String {
@ -108,7 +104,7 @@ impl CellProtobufBlobParser for NumberCellDataParser {
type Object = NumberCellFormat; type Object = NumberCellFormat;
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> { fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
match String::from_utf8(bytes.to_vec()) { 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()), Err(_) => Ok(NumberCellFormat::default()),
} }
} }
@ -119,7 +115,7 @@ impl CellBytesCustomParser for NumberCellCustomDataParser {
type Object = NumberCellFormat; type Object = NumberCellFormat;
fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> { fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
match String::from_utf8(bytes.to_vec()) { 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()), Err(_) => Ok(NumberCellFormat::default()),
} }
} }

View File

@ -141,12 +141,12 @@ where
let cell_data = self.decode_cell_str(cell, decoded_field_type, field)?; let cell_data = self.decode_cell_str(cell, decoded_field_type, field)?;
if let Some(cell_data_cache) = self.cell_data_cache.as_ref() { if let Some(cell_data_cache) = self.cell_data_cache.as_ref() {
tracing::trace!( // tracing::trace!(
"Cell cache update: field_type:{}, cell: {:?}, cell_data: {:?}", // "Cell cache update: field_type:{}, cell: {:?}, cell_data: {:?}",
decoded_field_type, // decoded_field_type,
cell, // cell,
cell_data // cell_data
); // );
cell_data_cache cell_data_cache
.write() .write()
.insert(key.as_ref(), cell_data.clone()); .insert(key.as_ref(), cell_data.clone());
@ -163,12 +163,12 @@ where
if let Some(cell_data_cache) = self.cell_data_cache.as_ref() { if let Some(cell_data_cache) = self.cell_data_cache.as_ref() {
let field_type = FieldType::from(field.field_type); let field_type = FieldType::from(field.field_type);
let key = CellDataCacheKey::new(field, field_type.clone(), cell); let key = CellDataCacheKey::new(field, field_type.clone(), cell);
tracing::trace!( // tracing::trace!(
"Cell cache update: field_type:{}, cell: {:?}, cell_data: {:?}", // "Cell cache update: field_type:{}, cell: {:?}, cell_data: {:?}",
field_type, // field_type,
cell, // cell,
cell_data // cell_data
); // );
cell_data_cache.write().insert(key.as_ref(), cell_data); cell_data_cache.write().insert(key.as_ref(), cell_data);
} }
} }

View File

@ -25,7 +25,7 @@ use std::sync::Arc;
/// * `configuration_writer`: as writer used to write the group configuration to disk /// * `configuration_writer`: as writer used to write the group configuration to disk
/// ///
#[tracing::instrument( #[tracing::instrument(
level = "debug", level = "trace",
skip_all, skip_all,
fields(grouping_field_id=%grouping_field.id, grouping_field_type) fields(grouping_field_id=%grouping_field.id, grouping_field_type)
err err

View File

@ -85,7 +85,7 @@ impl SortController {
self.gen_task(task_type, QualityOfService::Background).await; 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<()> { pub async fn process(&mut self, predicate: &str) -> FlowyResult<()> {
let event_type = SortEvent::from_str(predicate).unwrap(); let event_type = SortEvent::from_str(predicate).unwrap();
let mut rows = self.delegate.get_rows(&self.view_id).await; let mut rows = self.delegate.get_rows(&self.view_id).await;

View File

@ -3,7 +3,6 @@ use lib_dispatch::prelude::AFPluginData;
use crate::entities::NetworkStatePB; use crate::entities::NetworkStatePB;
#[tracing::instrument(level = "debug", skip_all)]
pub async fn update_network_ty(_data: AFPluginData<NetworkStatePB>) -> Result<(), FlowyError> { pub async fn update_network_ty(_data: AFPluginData<NetworkStatePB>) -> Result<(), FlowyError> {
Ok(()) Ok(())
} }

View File

@ -25,6 +25,7 @@ thread-id = "3.3.0"
log = "0.4" log = "0.4"
bytes = "1.4" bytes = "1.4"
nanoid = "0.4.0" nanoid = "0.4.0"
tempdir = "0.3.7"
[dev-dependencies] [dev-dependencies]
quickcheck = "1.0.3" quickcheck = "1.0.3"

View File

@ -9,7 +9,8 @@ use flowy_user::{
event_map::UserEvent::{InitUser, SignIn, SignOut, SignUp}, event_map::UserEvent::{InitUser, SignIn, SignOut, SignUp},
}; };
use lib_dispatch::prelude::{AFPluginDispatcher, AFPluginRequest, ToBytes}; use lib_dispatch::prelude::{AFPluginDispatcher, AFPluginRequest, ToBytes};
use std::{fs, path::PathBuf, sync::Arc};
use std::sync::Arc;
pub struct ViewTest { pub struct ViewTest {
pub sdk: FlowySDKTest, pub sdk: FlowySDKTest,
@ -118,21 +119,6 @@ async fn create_view(
.parse::<ViewPB>() .parse::<ViewPB>()
} }
pub fn root_dir() -> String {
// https://doc.rust-lang.org/cargo/reference/environment-variables.html
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| "./".to_owned());
let mut path_buf = fs::canonicalize(&PathBuf::from(&manifest_dir)).unwrap();
path_buf.pop(); // rust-lib
path_buf.push("temp");
path_buf.push("flowy");
let root_dir = path_buf.to_str().unwrap().to_string();
if !std::path::Path::new(&root_dir).exists() {
std::fs::create_dir_all(&root_dir).unwrap();
}
root_dir
}
pub fn random_email() -> String { pub fn random_email() -> String {
format!("{}@appflowy.io", nanoid!(20)) format!("{}@appflowy.io", nanoid!(20))
} }

View File

@ -1,4 +1,5 @@
use nanoid::nanoid; use nanoid::nanoid;
use std::env::temp_dir;
use flowy_core::{AppFlowyCore, AppFlowyCoreConfig}; use flowy_core::{AppFlowyCore, AppFlowyCoreConfig};
use flowy_net::http_server::self_host::configuration::get_client_server_configuration; use flowy_net::http_server::self_host::configuration::get_client_server_configuration;
@ -37,8 +38,8 @@ impl std::default::Default for FlowySDKTest {
impl FlowySDKTest { impl FlowySDKTest {
pub fn new() -> Self { pub fn new() -> Self {
let server_config = get_client_server_configuration().unwrap(); let server_config = get_client_server_configuration().unwrap();
let config = let config = AppFlowyCoreConfig::new(temp_dir().to_str().unwrap(), nanoid!(6), server_config)
AppFlowyCoreConfig::new(&root_dir(), nanoid!(6), server_config).log_filter("info", vec![]); .log_filter("info", vec![]);
let sdk = std::thread::spawn(|| AppFlowyCore::new(config)) let sdk = std::thread::spawn(|| AppFlowyCore::new(config))
.join() .join()
.unwrap(); .unwrap();