diff --git a/Cargo.lock b/Cargo.lock index f8b856be0..7e24ba1f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,18 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "accessory" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87537f9ae7cfa78d5b8ebd1a1db25959f5e737126be4d8eb44a5452fc4b63cde" -dependencies = [ - "macroific", - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "addr2line" version = "0.21.0" @@ -433,7 +421,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -486,257 +474,62 @@ dependencies = [ "arc-swap", "assert-json-diff", "assert_matches2", + "async-recursion", "async-trait", + "async_zip", + "base64", "bincode", "bytes", "chrono", - "collab", - "fastrand", - "js-sys", - "lazy_static", - "nanoid", - "parking_lot", - "serde", - "serde_json", - "serde_repr", - "tempfile", - "thiserror 1.0.63", - "tokio", - "tokio-stream", - "tracing", - "tracing-subscriber", - "unicode-segmentation", - "uuid", - "web-sys", - "yrs", -] - -[[package]] -name = "collab-database" -version = "0.2.0" -dependencies = [ - "anyhow", - "assert-json-diff", - "async-trait", - "base64", - "chrono", "chrono-tz", "collab", - "collab-database", - "collab-entity", - "collab-plugins", "csv", "dashmap 5.5.3", "fancy-regex", - "futures", - "getrandom 0.2.15", - "iana-time-zone", - "js-sys", - "lazy_static", - "nanoid", - "percent-encoding", - "rand", - "rayon", - "rust_decimal", - "rusty-money", - "serde", - "serde_json", - "serde_repr", - "sha2", - "strum", - "strum_macros", - "tempfile", - "thiserror 1.0.63", - "tokio", - "tokio-stream", - "tokio-test", - "tokio-util", - "tracing", - "tracing-subscriber", - "uuid", - "yrs", - "zip", -] - -[[package]] -name = "collab-document" -version = "0.2.0" -dependencies = [ - "anyhow", - "arc-swap", - "assert-json-diff", - "collab", - "collab-entity", - "collab-plugins", - "futures", - "getrandom 0.2.15", - "markdown", - "nanoid", - "serde", - "serde_json", - "tempfile", - "thiserror 1.0.63", - "tokio", - "tokio-stream", - "tracing", - "tracing-subscriber", - "uuid", - "yrs", - "zip", -] - -[[package]] -name = "collab-entity" -version = "0.2.0" -dependencies = [ - "anyhow", - "bytes", - "collab", - "getrandom 0.2.15", - "prost 0.13.3", - "prost-build", - "protoc-bin-vendored", - "serde", - "serde_json", - "serde_repr", - "thiserror 1.0.63", - "uuid", - "walkdir", -] - -[[package]] -name = "collab-folder" -version = "0.2.0" -dependencies = [ - "anyhow", - "arc-swap", - "assert-json-diff", - "async-trait", - "chrono", - "collab", - "collab-entity", - "collab-plugins", - "dashmap 5.5.3", + "fastrand", "fs_extra", "futures", - "getrandom 0.2.15", - "nanoid", - "serde", - "serde_json", - "serde_repr", - "tempfile", - "thiserror 1.0.63", - "tokio", - "tokio-stream", - "tracing", - "tracing-subscriber", - "uuid", - "walkdir", - "zip", -] - -[[package]] -name = "collab-importer" -version = "0.1.0" -dependencies = [ - "anyhow", - "assert-json-diff", - "async-recursion", - "async-trait", - "async_zip", - "base64", - "chrono", - "collab", - "collab-database", - "collab-document", - "collab-entity", - "collab-folder", - "csv", - "fancy-regex", - "futures", "futures-lite", "fxhash", "hex", + "iana-time-zone", "indexmap", + "lazy_static", "markdown", "nanoid", + "parking_lot", "percent-encoding", + "prost 0.13.3", + "prost-build", + "protoc-bin-vendored", + "rand", "rayon", + "rocksdb", + "rust_decimal", + "rusty-money", "sanitize-filename", "serde", "serde_json", + "serde_repr", "sha2", - "tempfile", - "thiserror 1.0.63", - "tokio", - "tokio-util", - "tracing", - "tracing-subscriber", - "uuid", - "walkdir", - "zip", -] - -[[package]] -name = "collab-plugins" -version = "0.2.0" -dependencies = [ - "anyhow", - "assert-json-diff", - "async-stream", - "async-trait", - "bincode", - "bytes", - "chrono", - "collab", - "collab-entity", - "futures", - "getrandom 0.2.15", - "indexed_db_futures", - "js-sys", - "lazy_static", - "rand", - "rocksdb", - "serde", - "serde_json", "similar", "smallvec", + "strum", + "strum_macros", "tempfile", "thiserror 1.0.63", "tokio", "tokio-retry", "tokio-stream", + "tokio-test", "tokio-util", "tracing", "tracing-subscriber", - "tracing-wasm", + "unicode-segmentation", "uuid", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test", - "web-sys", + "walkdir", "yrs", -] - -[[package]] -name = "collab-user" -version = "0.2.0" -dependencies = [ - "anyhow", - "assert-json-diff", - "collab", - "collab-entity", - "collab-plugins", - "fs_extra", - "getrandom 0.2.15", - "nanoid", - "serde", - "serde_json", - "tempfile", - "tokio", - "tokio-stream", - "tracing", - "uuid", + "zip", ] [[package]] @@ -748,16 +541,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -877,18 +660,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" -[[package]] -name = "delegate-display" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98a85201f233142ac819bbf6226e36d0b5e129a47bd325084674261c82d4cd66" -dependencies = [ - "macroific", - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "deranged" version = "0.3.11" @@ -928,7 +699,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -963,18 +734,6 @@ dependencies = [ "regex-syntax 0.8.4", ] -[[package]] -name = "fancy_constructor" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71f317e4af73b2f8f608fac190c52eac4b1879d2145df1db2fe48881ca69435" -dependencies = [ - "macroific", - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "fastrand" version = "2.1.0" @@ -1191,12 +950,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hex" version = "0.4.3" @@ -1235,23 +988,6 @@ dependencies = [ "cc", ] -[[package]] -name = "indexed_db_futures" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0704b71f13f81b5933d791abf2de26b33c40935143985220299a357721166706" -dependencies = [ - "accessory", - "cfg-if", - "delegate-display", - "fancy_constructor", - "js-sys", - "uuid", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "indexmap" version = "2.3.0" @@ -1331,7 +1067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1392,53 +1128,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "macroific" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05c00ac596022625d01047c421a0d97d7f09a18e429187b341c201cb631b9dd" -dependencies = [ - "macroific_attr_parse", - "macroific_core", - "macroific_macro", -] - -[[package]] -name = "macroific_attr_parse" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd94d5da95b30ae6e10621ad02340909346ad91661f3f8c0f2b62345e46a2f67" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "macroific_core" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13198c120864097a565ccb3ff947672d969932b7975ebd4085732c9f09435e55" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "macroific_macro" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c9853143cbed7f1e41dc39fee95f9b361bec65c8dc2a01bf609be01b61f5ae" -dependencies = [ - "macroific_attr_parse", - "macroific_core", - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "markdown" version = "1.0.0-alpha.21" @@ -1478,17 +1167,6 @@ dependencies = [ "adler", ] -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - [[package]] name = "multimap" version = "0.10.0" @@ -1539,16 +1217,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" version = "0.32.2" @@ -1596,7 +1264,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2151,7 +1819,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -2195,12 +1863,6 @@ dependencies = [ "regex", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -2298,15 +1960,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - [[package]] name = "simdutf8" version = "0.1.4" @@ -2349,16 +2002,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "strum" version = "0.25.0" @@ -2433,7 +2076,7 @@ dependencies = [ "cfg-if", "fastrand", "rustix", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -2528,15 +2171,8 @@ checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", "pin-project-lite", - "signal-hook-registry", - "socket2", "tokio-macros", - "windows-sys 0.48.0", ] [[package]] @@ -2678,17 +2314,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "tracing-wasm" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" -dependencies = [ - "tracing", - "tracing-subscriber", - "wasm-bindgen", -] - [[package]] name = "typenum" version = "1.17.0" @@ -2795,18 +2420,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.100" @@ -2839,41 +2452,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-bindgen-test" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" -dependencies = [ - "console_error_panic_hook", - "js-sys", - "scoped-tls", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test-macro", -] - -[[package]] -name = "wasm-bindgen-test-macro" -version = "0.3.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "winapi" version = "0.3.9" @@ -2896,7 +2474,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -2911,16 +2489,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -2929,22 +2498,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -2953,46 +2507,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -3005,48 +2541,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/Cargo.toml b/Cargo.toml index 53aea0dd8..10922a210 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,25 +1,8 @@ [workspace] -members = [ - "collab", - "collab-database", - "collab-user", - "collab-entity", - "collab-document", - "collab-folder", - "collab-plugins", - "collab-importer", -] +members = ["collab"] resolver = "2" [workspace.dependencies] -collab = { path = "collab" } -collab-database = { path = "collab-database" } -collab-plugins = { path = "collab-plugins" } -collab-user = { path = "collab-user" } -collab-entity = { path = "collab-entity" } -collab-document = { path = "collab-document" } -collab-folder = { path = "collab-folder" } -collab-importer = { path = "collab-importer" } yrs = { version = "0.24", features = ["sync"] } anyhow = "1.0.94" thiserror = "1.0.39" @@ -37,4 +20,4 @@ futures-lite = { version = "2.6.0", features = ["futures-io"] } [patch.crates-io] # We're using a specific commit here because rust-rocksdb doesn't publish the latest version that includes the memory alignment fix. # For more details, see https://github.com/rust-rocksdb/rust-rocksdb/pull/868 -rocksdb = { git = "https://github.com/rust-rocksdb/rust-rocksdb", rev = "1710120e4549e04ba3baa6a1ee5a5a801fa45a72" } \ No newline at end of file +rocksdb = { git = "https://github.com/rust-rocksdb/rust-rocksdb", rev = "1710120e4549e04ba3baa6a1ee5a5a801fa45a72" } diff --git a/Makefile.toml b/Makefile.toml index 9abc0e62d..eec70be73 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -76,45 +76,3 @@ default_to_workspace = false [env] CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true - -[tasks.wasm_build] -script_runner = "bash" -script = [ - """ - #!/bin/bash - BASE_DIR=$(pwd) - crates=("collab" "collab-document" "collab-folder" "collab-user" "collab-plugins") - - # Iterate over each crate and build it - for crate in "${crates[@]}"; do - echo "🔥🔥🔥 Building $crate with wasm-pack..." - - # Navigate to the crate directory - cd "$BASE_DIR/$crate" || { echo "Failed to enter directory $crate"; exit 1; } - - # Build the crate - wasm-pack build || { echo "Build failed for $crate"; exit 1; } - done - """ -] - -[tasks.wasm_test] -script_runner = "bash" -script = [ - """ - #!/bin/bash - BASE_DIR=$(pwd) - crates=("collab-plugins") - - # Iterate over each crate and build it - for crate in "${crates[@]}"; do - echo "🔥🔥🔥 Running $crate tests with wasm-pack..." - - # Navigate to the crate directory - cd "$BASE_DIR/$crate" || { echo "Failed to enter directory $crate"; exit 1; } - - # Build the crate - wasm-pack test --headless --firefox - done - """ -] diff --git a/README.md b/README.md index 22a176fc4..d65241e35 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,9 @@ # AppFlowy-Collab -`AppFlowy-Collab` is a project that aims to support the collaborative features of AppFlowy. It consists of several crates that are currently under active development: - -* `collab` -* `collab-database` -* `collab-document` -* `collab-folder` -* `collab-plugins` -* `collab-sync` +`AppFlowy-Collab` is a project that aims to support the collaborative features of AppFlowy. The workspace now centers on +the `collab` crate, which houses database, document, folder, importer, plugin, and user functionality under a single +module tree. ![architecture.png](resources/crate_arch.png) @@ -18,23 +13,13 @@ ones are refined. ## collab The `collab` crate is built on top of the [yrs](https://docs.rs/yrs/latest/yrs/) crate, providing a higher level of -abstraction for the collaborative features of AppFlowy. It offers a simple API for creating and managing collaborative -documents. - -## collab-database -The `collab-database` crate provides a simple API for creating and managing collaborative databases. It is built on top -of the `collab` crate. - -## collab-document -The `collab-document` crate provides a simple API for creating and managing collaborative documents. It is built on top -of the `collab` crate. - -## collab-folder -The `collab-folder` crate provides a simple API for creating and managing collaborative folders. It is built on top of -the `collab` crate. +abstraction for the collaborative features of AppFlowy. It exposes cohesive modules: -## collab-plugins -The `collab-plugins` crate contains a list of plugins that can be used with the `collab` crate. +- Entity definitions and protobuf types under `collab::entity`. +- Database, document, folder, importer, plugin, and user services under `collab::database`, `collab::document`, + `collab::folder`, `collab::importer`, `collab::plugins`, and `collab::user`. +- The plugin subsystem (`collab::plugins`) is guarded by the optional `plugins` Cargo feature; enable it when you + need local/remote persistence helpers. -## collab-sync -The `collab-sync` crate supports syncing the collaborative documents to a remote server. \ No newline at end of file +With everything consolidated, consumers only need to depend on the `collab` crate to access the full collaborative +feature set. diff --git a/collab-database/Cargo.toml b/collab-database/Cargo.toml deleted file mode 100644 index 34cb3f668..000000000 --- a/collab-database/Cargo.toml +++ /dev/null @@ -1,63 +0,0 @@ -[package] -name = "collab-database" -version = "0.2.0" -edition = "2024" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -collab = { workspace = true } -collab-entity = { workspace = true } -serde = { workspace = true, features = ["derive", "rc"] } -serde_json.workspace = true -thiserror.workspace = true -anyhow.workspace = true -serde_repr = "0.1" -tokio = { workspace = true, features = ["time", "sync", "rt"] } -tracing.workspace = true -nanoid = "0.4.0" -chrono.workspace = true -lazy_static = "1.4.0" -async-trait.workspace = true -uuid.workspace = true -tokio-stream = { version = "0.1.14", features = ["sync"] } -strum = "0.25" -strum_macros = "0.25" -rayon = "1.10.0" -dashmap = "5" -futures = "0.3.30" -csv = { version = "1.3.0" } -yrs.workspace = true -tokio-util = "0.7" -rusty-money = { version = "0.4.1", features = ["iso"] } -fancy-regex = "0.13.0" -rust_decimal = "1.36.0" -chrono-tz = "0.10.0" -percent-encoding = "2.3.1" -sha2 = "0.10.8" -base64 = "0.22.1" -iana-time-zone = "0.1.61" - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2", features = ["js"] } -js-sys = "0.3" - -[dev-dependencies] -collab-plugins = { workspace = true, features = ["verbose_log"] } -collab-database = { path = "../collab-database", features = ["verbose_log"] } -tempfile = "3.8.0" -assert-json-diff = "2.0.2" -lazy_static = "1.4.0" -tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } -rand = "0.8.4" -futures = "0.3.30" -zip = "0.6.6" -tokio = { version = "1.38", features = ["full"] } -tokio-test = "0.4" - - -[features] -verbose_log = [] -import_csv = [] diff --git a/collab-database/src/error.rs b/collab-database/src/error.rs deleted file mode 100644 index 14edd615e..000000000 --- a/collab-database/src/error.rs +++ /dev/null @@ -1,67 +0,0 @@ -use collab_entity::CollabValidateError; -use collab_entity::uuid_validation::RowId; - -#[derive(Debug, thiserror::Error)] -pub enum DatabaseError { - #[error("The database's id is invalid: {0}")] - InvalidDatabaseID(&'static str), - - #[error("The database view's id is invalid: {0}")] - InvalidViewID(&'static str), - - #[error("The database view's id is invalid: {0}")] - InvalidDatabaseViewId(String), - - #[error("The database row's id is invalid: {0}")] - InvalidRowID(&'static str), - - #[error("The database is not existing")] - DatabaseNotExist, - - #[error("row: {row_id} not found, reason: {reason}")] - DatabaseRowNotFound { row_id: RowId, reason: String }, - - #[error("The database view is not existing")] - DatabaseViewNotExist, - - #[error(transparent)] - SerdeJson(#[from] serde_json::Error), - - #[error(transparent)] - UuidError(#[from] uuid::Error), - - #[error("No required data:{0}")] - NoRequiredData(String), - - #[error("Record already exist")] - RecordAlreadyExist, - - #[error("Record not found")] - RecordNotFound, - - #[error("Action cancelled")] - ActionCancelled, - - #[error("Invalid CSV:{0}")] - InvalidCSV(String), - - #[error("Import data failed: {0}")] - ImportData(String), - - #[error("Internal failure: {0}")] - Internal(#[from] anyhow::Error), -} - -impl DatabaseError { - pub fn is_no_required_data(&self) -> bool { - matches!(self, DatabaseError::NoRequiredData(_)) - } -} - -impl From for DatabaseError { - fn from(error: CollabValidateError) -> Self { - match error { - CollabValidateError::NoRequiredData(data) => DatabaseError::NoRequiredData(data), - } - } -} diff --git a/collab-database/src/macros.rs b/collab-database/src/macros.rs deleted file mode 100644 index b32b24c0a..000000000 --- a/collab-database/src/macros.rs +++ /dev/null @@ -1,226 +0,0 @@ -#[macro_export] -macro_rules! impl_str_update { - ($setter1: ident, $setter2: ident, $key: expr) => { - pub fn $setter1>(self, value: T) -> Self { - self.map_ref.try_update(self.txn, $key, value.as_ref()); - self - } - pub fn $setter2>(self, value: Option) -> Self { - if let Some(value) = value { - self.map_ref.try_update(self.txn, $key, value.as_ref()); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_replace_str_update { - ($replace_str: ident, $key: expr) => { - pub fn $replace_str String>(self, f: F) -> Self { - if let Some(s) = self.map_ref.get_str_with_txn(self.txn, $key) { - let new_id = f(&s); - self.map_ref.insert_with_txn(self.txn, $key, new_id); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_option_str_update { - ($setter1: ident, $setter2: ident, $key: expr) => { - pub fn $setter1(self, value: Option) -> Self { - self.map_ref.insert_with_txn(self.txn, $key, value); - self - } - pub fn $setter2>(self, value: Option) -> Self { - if let Some(value) = value { - self.map_ref.insert_with_txn(self.txn, $key, value.as_ref()); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_i64_update { - ($setter1: ident, $setter2: ident, $key: expr) => { - pub fn $setter1(self, value: i64) -> Self { - self.map_ref.insert(self.txn, $key, Any::BigInt(value)); - self - } - - pub fn $setter2(self, value: Option) -> Self { - if let Some(value) = value { - self.map_ref.insert(self.txn, $key, Any::BigInt(value)); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_i32_update { - ($setter1: ident, $setter2: ident, $key: expr) => { - pub fn $setter1(self, value: i32) -> Self { - self - .map_ref - .insert(self.txn, $key, Any::BigInt(value as i64)); - self - } - - pub fn $setter2(self, value: Option) -> Self { - if let Some(value) = value { - self - .map_ref - .insert(self.txn, $key, Any::BigInt(value as i64)); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_u8_update { - ($setter1: ident, $setter2: ident, $key: expr) => { - pub fn $setter1(self, value: u8) -> Self { - self - .map_ref - .insert(self.txn, $key, Any::BigInt(value as i64)); - self - } - - pub fn $setter2(self, value: Option) -> Self { - if let Some(value) = value { - self - .map_ref - .insert(self.txn, $key, Any::BigInt(value as i64)); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_bool_update { - ($setter1: ident, $setter2: ident, $key: expr) => { - pub fn $setter1(self, value: bool) -> Self { - self.map_ref.insert(self.txn, $key, value); - self - } - pub fn $setter2(self, value: Option) -> Self { - if let Some(value) = value { - self.map_ref.insert(self.txn, $key, value); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_any_update { - ($setter1: ident, $setter2: ident, $key:expr, $value: ident) => { - pub fn $setter1(self, value: $value) -> Self { - self.map_ref.insert(self.txn, $key, value); - self - } - pub fn $setter2(self, value: Option<$value>) -> Self { - if let Some(value) = value { - self.map_ref.insert(self.txn, $key, value); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_order_update { - ($set_orders: ident, - $remove: ident, - $move_to: ident, - $insert: ident, - $iter_mut: ident, - $key: expr, - $ty: ident, - $array_ty: ident - ) => { - pub fn $set_orders(self, orders: Vec<$ty>) -> Self { - let array_ref: ArrayRef = self.map_ref.get_or_init(self.txn, $key); - let array = $array_ty::new(array_ref); - array.extends_with_txn(self.txn, orders); - self - } - - pub fn $remove(self, id: &str) -> Self { - if let Some(array) = self - .map_ref - .get_with_txn::<_, ArrayRef>(self.txn, $key) - .map(|array_ref| $array_ty::new(array_ref)) - { - array.remove_with_txn(self.txn, id); - } - self - } - - pub fn $move_to(self, from_id: &str, to_id: &str) -> Self { - if let Some(array) = self - .map_ref - .get_with_txn::<_, ArrayRef>(self.txn, $key) - .map(|array_ref| $array_ty::new(array_ref)) - { - array.move_to(self.txn, from_id, to_id); - } - self - } - - pub fn $insert>(self, object: T, position: &OrderObjectPosition) -> Self { - let object = object.into(); - if let Some(array) = self - .map_ref - .get_with_txn::<_, ArrayRef>(self.txn, $key) - .map(|array_ref| $array_ty::new(array_ref)) - { - match position { - OrderObjectPosition::Start => array.push_front_with_txn(self.txn, object), - OrderObjectPosition::Before(next_object_id) => { - array.insert_before_with_txn(self.txn, object, &next_object_id) - }, - OrderObjectPosition::After(prev_object_id) => { - array.insert_after_with_txn(self.txn, object, &prev_object_id) - }, - OrderObjectPosition::End => array.push_back_with_txn(self.txn, object), - }; - } - self - } - - pub fn $iter_mut(self, mut f: F) -> Self { - if let Some(array) = self - .map_ref - .get_with_txn::<_, ArrayRef>(self.txn, $key) - .map(|array_ref| $array_ty::new(array_ref)) - { - for mut row_order in array.get_objects_with_txn(self.txn) { - array.remove_with_txn(self.txn, &row_order.id.to_string()); - f(&mut row_order); - array.push_back(self.txn, row_order); - } - } - - self - } - }; -} - -#[macro_export] -macro_rules! impl_array_update { - ($setter: ident, $key: expr, $value: ident) => { - pub fn $setter(self, value: $value) -> Self { - self - .map_ref - .insert(self.txn, $key, ArrayPrelim::new(value.into())); - self - } - }; -} diff --git a/collab-derive/Cargo.toml b/collab-derive/Cargo.toml deleted file mode 100644 index 49106e7c8..000000000 --- a/collab-derive/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "collab-derive" -version = "0.2.0" -edition = "2024" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -proc-macro2 = "1.0" -quote = "1.0" -syn = { version = "1.0.109", features = ["extra-traits", "visit"] } -yrs.workspace = true -serde_json.workspace = true - -[lib] -name = "collab_derive" -proc-macro = true diff --git a/collab-derive/src/collab.rs b/collab-derive/src/collab.rs deleted file mode 100644 index 0eecb7639..000000000 --- a/collab-derive/src/collab.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::internal::{ASTContainer, ASTResult}; -use crate::yrs_token::make_yrs_token_steam; -use proc_macro2::TokenStream; - -pub fn expand_derive(input: &syn::DeriveInput) -> Result> { - let ast_result = ASTResult::new(); - let cont = match ASTContainer::from_ast(&ast_result, input) { - Some(cont) => cont, - None => return Err(ast_result.check().unwrap_err()), - }; - - let mut token_stream: TokenStream = TokenStream::default(); - if let Some(yrs_token_stream) = make_yrs_token_steam(&ast_result, &cont) { - token_stream.extend(yrs_token_stream); - } - - ast_result.check()?; - Ok(token_stream) -} diff --git a/collab-derive/src/internal/ast.rs b/collab-derive/src/internal/ast.rs deleted file mode 100644 index c1b2826ba..000000000 --- a/collab-derive/src/internal/ast.rs +++ /dev/null @@ -1,283 +0,0 @@ -#![allow(clippy::all)] -#![allow(unused_attributes)] -#![allow(unused_assignments)] - -use crate::internal::ctxt::ASTResult; -use proc_macro2::{Ident, TokenStream}; -use quote::ToTokens; -use std::fmt; -use std::fmt::Display; -use syn::Meta::{List, NameValue}; -use syn::NestedMeta::Meta; -use syn::{self, punctuated::Punctuated, Fields, LitStr, Path, Token}; - -pub struct ASTContainer<'a> { - /// The struct or enum name (without generics). - pub ident: syn::Ident, - - pub path: Option, - - /// The contents of the struct or enum. - pub data: ASTData<'a>, -} - -impl<'a> ASTContainer<'a> { - pub fn from_ast(ast_result: &ASTResult, ast: &'a syn::DeriveInput) -> Option> { - let data = match &ast.data { - syn::Data::Struct(data) => { - // https://docs.rs/syn/1.0.48/syn/struct.DataStruct.html - let (style, fields) = struct_from_ast(ast_result, &data.fields); - ASTData::Struct(style, fields) - }, - syn::Data::Union(_) => { - ast_result.error_spanned_by(ast, "Does not support derive for unions"); - return None; - }, - syn::Data::Enum(data) => { - // https://docs.rs/syn/1.0.48/syn/struct.DataEnum.html - ASTData::Enum(enum_from_ast(ast_result, &ast.ident, &data.variants)) - }, - }; - - let ident = ast.ident.clone(); - let path = get_key(ast_result, &ident, &ast.attrs); - let item = ASTContainer { ident, path, data }; - Some(item) - } -} - -pub enum ASTData<'a> { - Struct(ASTStyle, Vec>), - Enum(Vec>), -} - -impl<'a> ASTData<'a> { - pub fn all_fields(&'a self) -> Box> + 'a> { - match self { - ASTData::Enum(variants) => { - Box::new(variants.iter().flat_map(|variant| variant.fields.iter())) - }, - ASTData::Struct(_, fields) => Box::new(fields.iter()), - } - } -} - -/// A variant of an enum. -pub struct ASTEnumVariant<'a> { - pub ident: syn::Ident, - pub style: ASTStyle, - pub fields: Vec>, - pub original: &'a syn::Variant, -} - -pub struct ASTField<'a> { - pub member: syn::Member, - pub ty: &'a syn::Type, - pub yrs_attr: YrsAttribute, - pub original: &'a syn::Field, -} - -impl<'a> ASTField<'a> { - pub fn new(ast_result: &ASTResult, field: &'a syn::Field, index: usize) -> Result { - Ok(ASTField { - member: match &field.ident { - Some(ident) => syn::Member::Named(ident.clone()), - None => syn::Member::Unnamed(index.into()), - }, - ty: &field.ty, - yrs_attr: YrsAttribute::from_ast(ast_result, field), - original: field, - }) - } -} - -pub const YRS: Symbol = Symbol("yrs"); -pub const PRS_TY: Symbol = Symbol("ty"); -pub struct YrsAttribute { - #[allow(dead_code)] - ty: Option, -} - -impl YrsAttribute { - /// Extract out the `#[yrs(...)]` attributes from a struct field. - pub fn from_ast(ast_result: &ASTResult, field: &syn::Field) -> Self { - let mut ty = ASTFieldAttr::none(ast_result, PRS_TY); - for meta_item in field - .attrs - .iter() - .flat_map(|attr| get_yrs_nested_meta(ast_result, attr)) - .flatten() - { - match &meta_item { - // Parse '#[yrs(ty = x)]' - Meta(NameValue(m)) if m.path == PRS_TY => { - if let syn::Lit::Str(lit) = &m.lit { - ty.set(&m.path, lit.clone()); - } - }, - - _ => { - ast_result.error_spanned_by(meta_item, "unexpected meta in field attribute"); - }, - } - } - YrsAttribute { ty: ty.get() } - } -} - -fn get_yrs_nested_meta(cx: &ASTResult, attr: &syn::Attribute) -> Result, ()> { - // Only handle the attribute that we have defined - if attr.path != YRS { - return Ok(vec![]); - } - - match attr.parse_meta() { - Ok(List(meta)) => Ok(meta.nested.into_iter().collect()), - Ok(_) => Ok(vec![]), - Err(err) => { - cx.error_spanned_by(attr, "attribute must be str, e.g. #[yrs(xx = \"xxx\")]"); - cx.syn_error(err); - Err(()) - }, - } -} - -pub struct ASTFieldAttr<'c, T> { - ast_result: &'c ASTResult, - name: Symbol, - tokens: TokenStream, - value: Option, -} - -impl<'c, T> ASTFieldAttr<'c, T> { - pub(crate) fn none(ast_result: &'c ASTResult, name: Symbol) -> Self { - ASTFieldAttr { - ast_result, - name, - tokens: TokenStream::new(), - value: None, - } - } - - pub(crate) fn set(&mut self, obj: A, value: T) { - let tokens = obj.into_token_stream(); - if self.value.is_some() { - self - .ast_result - .error_spanned_by(tokens, format!("duplicate attribute `{}`", self.name)); - } else { - self.tokens = tokens; - self.value = Some(value); - } - } - - pub(crate) fn get(self) -> Option { - self.value - } -} - -#[derive(Copy, Clone)] -pub enum ASTStyle { - Struct, - Tuple, - NewType, - Unit, -} - -pub fn struct_from_ast<'a>(cx: &ASTResult, fields: &'a Fields) -> (ASTStyle, Vec>) { - match fields { - syn::Fields::Named(fields) => (ASTStyle::Struct, fields_from_ast(cx, &fields.named)), - syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { - (ASTStyle::NewType, fields_from_ast(cx, &fields.unnamed)) - }, - syn::Fields::Unnamed(fields) => (ASTStyle::Tuple, fields_from_ast(cx, &fields.unnamed)), - syn::Fields::Unit => (ASTStyle::Unit, Vec::new()), - } -} - -fn enum_from_ast<'a>( - cx: &ASTResult, - _ident: &Ident, - variants: &'a Punctuated, -) -> Vec> { - variants - .iter() - .flat_map(|variant| { - let (style, fields) = struct_from_ast(cx, &variant.fields); - Some(ASTEnumVariant { - ident: variant.ident.clone(), - style, - fields, - original: variant, - }) - }) - .collect() -} - -fn fields_from_ast<'a>( - ast_result: &ASTResult, - fields: &'a Punctuated, -) -> Vec> { - fields - .iter() - .enumerate() - .flat_map(|(index, field)| ASTField::new(ast_result, field, index).ok()) - .collect() -} - -#[derive(Copy, Clone)] -pub struct Symbol(&'static str); - -impl PartialEq for Ident { - fn eq(&self, word: &Symbol) -> bool { - self == word.0 - } -} - -impl<'a> PartialEq for &'a Ident { - fn eq(&self, word: &Symbol) -> bool { - *self == word.0 - } -} - -impl PartialEq for Path { - fn eq(&self, word: &Symbol) -> bool { - self.is_ident(word.0) - } -} - -impl<'a> PartialEq for &'a Path { - fn eq(&self, word: &Symbol) -> bool { - self.is_ident(word.0) - } -} - -impl Display for Symbol { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str(self.0) - } -} - -pub const KEY: Symbol = Symbol("collab_key"); - -fn get_key( - ast_result: &ASTResult, - struct_name: &Ident, - attrs: &[syn::Attribute], -) -> Option { - let mut key = None; - attrs - .iter() - .filter(|attr| attr.path.segments.iter().any(|s| s.ident == KEY)) - .for_each(|attr| { - if let Ok(NameValue(named_value)) = attr.parse_meta() { - if key.is_some() { - ast_result.error_spanned_by(struct_name, "Duplicate key type definition"); - } - if let syn::Lit::Str(s) = named_value.lit { - key = Some(s.value()); - } - } - }); - key -} diff --git a/collab-derive/src/internal/ctxt.rs b/collab-derive/src/internal/ctxt.rs deleted file mode 100644 index 39940e0be..000000000 --- a/collab-derive/src/internal/ctxt.rs +++ /dev/null @@ -1,44 +0,0 @@ -use quote::ToTokens; -use std::{cell::RefCell, fmt::Display, thread}; - -#[derive(Default)] -pub struct ASTResult { - errors: RefCell>>, -} - -impl ASTResult { - pub fn new() -> Self { - ASTResult { - errors: RefCell::new(Some(Vec::new())), - } - } - - pub fn error_spanned_by(&self, obj: A, msg: T) { - self - .errors - .borrow_mut() - .as_mut() - .unwrap() - .push(syn::Error::new_spanned(obj.into_token_stream(), msg)); - } - - pub fn syn_error(&self, err: syn::Error) { - self.errors.borrow_mut().as_mut().unwrap().push(err); - } - - pub fn check(self) -> Result<(), Vec> { - let errors = self.errors.borrow_mut().take().unwrap(); - match errors.len() { - 0 => Ok(()), - _ => Err(errors), - } - } -} - -impl Drop for ASTResult { - fn drop(&mut self) { - if !thread::panicking() && self.errors.borrow().is_some() { - panic!("forgot to check for errors"); - } - } -} diff --git a/collab-derive/src/internal/mod.rs b/collab-derive/src/internal/mod.rs deleted file mode 100644 index f03fb890d..000000000 --- a/collab-derive/src/internal/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod ast; -mod ctxt; - -pub use ast::*; -pub use ctxt::*; diff --git a/collab-derive/src/lib.rs b/collab-derive/src/lib.rs deleted file mode 100644 index d8986b350..000000000 --- a/collab-derive/src/lib.rs +++ /dev/null @@ -1,25 +0,0 @@ -mod collab; -mod internal; -mod yrs_token; - -#[macro_use] -extern crate quote; -extern crate proc_macro; - -use proc_macro::TokenStream; -use quote::quote; -use syn::parse_macro_input; -use syn::DeriveInput; - -#[proc_macro_derive(Collab, attributes(collab, collab_key))] -pub fn derive_collab(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - collab::expand_derive(&input) - .unwrap_or_else(to_compile_errors) - .into() -} - -fn to_compile_errors(errors: Vec) -> proc_macro2::TokenStream { - let compile_errors = errors.iter().map(syn::Error::to_compile_error); - quote!(#(#compile_errors)*) -} diff --git a/collab-derive/src/yrs_token.rs b/collab-derive/src/yrs_token.rs deleted file mode 100644 index 24f931b21..000000000 --- a/collab-derive/src/yrs_token.rs +++ /dev/null @@ -1,351 +0,0 @@ -use crate::internal::{ASTContainer, ASTResult}; -use proc_macro2::{Ident, TokenStream}; - -use syn::{AngleBracketedGenericArguments, PathSegment, Type}; - -pub fn make_yrs_token_steam(ast_result: &ASTResult, ast: &ASTContainer) -> Option { - let map_token_stream = token_stream_for_yrs_map(ast_result, ast); - let token_stream: TokenStream = quote! { - #map_token_stream - - - }; - Some(token_stream) -} - -fn token_stream_for_yrs_map(ast_result: &ASTResult, ast: &ASTContainer) -> Option { - let struct_name = ast.ident.clone(); - let struct_map_modifier = format_ident!("{}MapRef", struct_name.to_string()); - let setter_getter_stream_token = ast - .data - .all_fields() - .flat_map(|field| setter_getter_token_stream(ast_result, &field.member, field.ty)); - - let into_inner_token_stream = ast - .data - .all_fields() - .flat_map(|field| into_inner_token_stream(ast_result, &field.member, field.ty)); - - Some(quote! { - pub struct #struct_map_modifier { - map_ref: collab::preclude::MapRefWrapper, - } - - impl #struct_map_modifier { - pub fn new(map_ref: collab::preclude::MapRefWrapper) -> Self { - Self { map_ref } - } - - #(#setter_getter_stream_token)* - - pub fn into_object(&self, txn: &collab::preclude::Transaction) -> #struct_name { - #struct_name { - #(#into_inner_token_stream)* - } - } - } - - impl collab::preclude::CustomMapRef for #struct_map_modifier { - fn from_map_ref(map_ref: collab::preclude::MapRefWrapper) -> Self { - Self { map_ref} - } - } - - impl std::ops::Deref for #struct_map_modifier { - type Target = collab::preclude::MapRefWrapper; - fn deref(&self) -> &Self::Target { - &self.map_ref - } - } - - }) -} - -fn into_inner_token_stream( - ast_result: &ASTResult, - member: &syn::Member, - ty: &Type, -) -> Option { - let ident_type = IdentType::from_ty(ast_result, ty); - into_inner_field_token_stream(ast_result, member, ty, &ident_type, false) -} - -fn into_inner_field_token_stream( - ast_result: &ASTResult, - member: &syn::Member, - ty: &Type, - ident_type: &IdentType, - is_option: bool, -) -> Option { - let ident = get_member_ident(ast_result, member)?; - let getter = format_ident!("get_{}", ident.to_string()); - match ident_type { - IdentType::StringType - | IdentType::I64Type - | IdentType::F64Type - | IdentType::BoolType - | IdentType::ArrayType { .. } - | IdentType::HashMapType { .. } => { - if is_option { - Some(quote! { - #ident: self.#getter(txn), - }) - } else { - Some(quote! { - #ident: self.#getter(txn).unwrap_or_default(), - }) - } - }, - IdentType::Others => Some(quote! { - #ident: self.#getter::<#ty>(txn).unwrap_or_default(), - }), - IdentType::OptionType { - ident_type, - inner_ty, - } => into_inner_field_token_stream(ast_result, member, inner_ty, ident_type, true), - } -} - -fn setter_getter_token_steam_for_item_type( - key: String, - setter: Ident, - getter: Ident, - ty: &Type, - ident: &Ident, - ident_type: &IdentType, -) -> Option { - match ident_type { - IdentType::StringType => Some(quote! { - pub fn #setter(&mut self, txn: &mut collab::preclude::TransactionMut, value: #ty) { - self.map_ref.insert_with_txn(txn, #key, value) - } - pub fn #getter(&self, txn: &collab::preclude::Transaction) -> Option<#ty> { - self.map_ref.get_str_with_txn(txn, #key) - } - }), - IdentType::I64Type => Some(quote! { - pub fn #setter(&mut self, txn: &mut collab::preclude::TransactionMut, value: #ty) { - self.map_ref.insert_with_txn(txn, #key, value) - } - pub fn #getter(&self, txn: &collab::preclude::Transaction) -> Option<#ty> { - self.map_ref.get_i64_with_txn(txn, #key) - } - }), - IdentType::F64Type => Some(quote! { - pub fn #setter(&mut self, txn: &mut collab::preclude::TransactionMut, value: #ty) { - self.map_ref.insert_with_txn(txn, #key, value) - } - pub fn #getter(&self, txn: &collab::preclude::Transaction) -> Option<#ty> { - self.map_ref.get_f64_with_txn(txn, #key) - } - }), - IdentType::BoolType => Some(quote! { - pub fn #setter(&mut self, txn: &mut collab::preclude::TransactionMut, value: #ty) { - self.map_ref.insert_with_txn(txn, #key, value) - } - pub fn #getter(&self, txn: &collab::preclude::Transaction) -> Option<#ty> { - self.map_ref.get_bool_with_txn(txn, #key) - } - }), - IdentType::HashMapType { value_type } => { - let update = format_ident!("update_{}_key_value", ident.to_string()); - Some(quote! { - pub fn #update(&mut self, txn: &mut collab::preclude::TransactionMut, key: &str, value: #value_type) { - if let Some(map_ref) = self.map_ref.get_map_with_txn(txn, #key) { - map_ref.insert_with_txn(txn, key, value); - } - } - - pub fn #setter(&mut self, txn: &mut collab::preclude::TransactionMut, value: #ty) { - self.map_ref.insert_json_with_txn(txn, #key, value) - } - - pub fn #getter(&self, txn: &collab::preclude::Transaction) -> Option<#ty> { - self.map_ref.get_json_with_txn(txn, #key) - } - }) - }, - IdentType::Others => Some(quote! { - pub fn #setter(&mut self, txn: &mut collab::preclude::TransactionMut, value: T) { - self.map_ref.insert_json_with_txn(txn, #key, value); - } - - pub fn #getter(&self, txn: &collab::preclude::Transaction) -> Option<#ty> { - self.map_ref.get_json_with_txn::<#ty>(txn, #key) - } - }), - IdentType::OptionType { - ident_type, - inner_ty, - } => setter_getter_token_steam_for_item_type(key, setter, getter, inner_ty, ident, ident_type), - IdentType::ArrayType { - ident_type: _, - inner_ty: _, - } => Some(quote! { - pub fn #setter(&mut self, txn: &mut collab::preclude::TransactionMut, value: #ty) { - self.map_ref.insert_json_with_txn(txn, #key, value) - } - - pub fn #getter(&self, txn: &collab::preclude::Transaction) -> Option<#ty> { - self.map_ref.get_json_with_txn(txn, #key) - } - }), - } -} -fn setter_getter_token_stream( - ast_result: &ASTResult, - member: &syn::Member, - ty: &Type, -) -> Option { - let ident = get_member_ident(ast_result, member)?; - let key = ident.to_string(); - let setter = format_ident!("set_{}", ident.to_string()); - let getter = format_ident!("get_{}", ident.to_string()); - let ident_type = IdentType::from_ty(ast_result, ty); - setter_getter_token_steam_for_item_type(key, setter, getter, ty, ident, &ident_type) -} - -pub(crate) fn get_member_ident<'a>( - ast_result: &ASTResult, - member: &'a syn::Member, -) -> Option<&'a syn::Ident> { - if let syn::Member::Named(ref ident) = member { - Some(ident) - } else { - ast_result.error_spanned_by( - member, - "Unsupported member, shouldn't be self.0".to_string(), - ); - None - } -} - -#[derive(Debug, Eq, PartialEq)] -enum IdentType { - StringType, - I64Type, - F64Type, - BoolType, - HashMapType { - value_type: Ident, - }, - OptionType { - ident_type: Box, - inner_ty: Type, - }, - ArrayType { - ident_type: Box, - inner_ty: Type, - }, - Others, -} - -impl IdentType { - pub fn from_ty(ast_result: &ASTResult, ty: &Type) -> Self { - if let Type::Path(p) = &ty { - let mut ident_type = match p.path.get_ident() { - None => IdentType::Others, - Some(ident) => match ident.to_string().as_ref() { - "String" => IdentType::StringType, - "bool" => IdentType::BoolType, - "i64" => IdentType::I64Type, - "f64" => IdentType::F64Type, - _ => IdentType::Others, - }, - }; - - if ident_type == IdentType::Others { - if let Some(seg) = p.path.segments.last() { - if seg.ident == "HashMap" { - let types = get_bracketed_value_type_from(ast_result, seg); - let ident = parse_ty(types[1]).unwrap(); - ident_type = IdentType::HashMapType { value_type: ident }; - } - - if seg.ident == "Vec" { - let types = get_bracketed_value_type_from(ast_result, seg); - let item_type = IdentType::from_ty(ast_result, types[0]); - ident_type = IdentType::ArrayType { - ident_type: Box::new(item_type), - inner_ty: types[0].clone(), - }; - } - - if seg.ident == "Option" { - let types = get_bracketed_value_type_from(ast_result, seg); - let item_type = IdentType::from_ty(ast_result, types[0]); - ident_type = IdentType::OptionType { - ident_type: Box::new(item_type), - inner_ty: types[0].clone(), - }; - - // if let Type::Path(p) = types[0] { - // let inner_ty = p.path.get_ident().cloned().unwrap(); - // let item_type = IdentType::from_ty(ast_result, types[0]); - // ident_type = IdentType::OptionType { - // ident_type: Box::new(item_type), - // inner_ty: types[0].clone(), - // }; - // } else { - // ast_result.error_spanned_by( - // types[0], - // "Can not infer the bracket inner type of the Option", - // ); - // IdentType::Others - // }; - } - } - } - ident_type - } else { - IdentType::Others - } - } -} - -fn get_bracketed_value_type_from<'a>( - ast_result: &ASTResult, - seg: &'a PathSegment, -) -> Vec<&'a Type> { - if let syn::PathArguments::AngleBracketed(ref bracketed) = seg.arguments { - return match seg.ident.to_string().as_ref() { - "HashMap" => parse_bracketed(bracketed), - "Vec" => parse_bracketed(bracketed), - "Option" => parse_bracketed(bracketed), - _ => { - let msg = format!("Unsupported type: {}", seg.ident); - ast_result.error_spanned_by(&seg.ident, msg); - vec![] - }, - }; - } - vec![] -} - -fn parse_bracketed(bracketed: &AngleBracketedGenericArguments) -> Vec<&Type> { - bracketed - .args - .iter() - .flat_map(|arg| { - if let syn::GenericArgument::Type(ref ty_in_bracket) = arg { - Some(ty_in_bracket) - } else { - None - } - }) - .collect::>() -} - -fn parse_ty(ty: &Type) -> Option { - if let Type::Path(ref p) = ty { - if p.path.segments.len() != 1 { - return None; - } - - return match p.path.segments.last() { - Some(seg) => Some(seg.ident.clone()), - None => return None, - }; - } - None -} diff --git a/collab-document/Cargo.toml b/collab-document/Cargo.toml deleted file mode 100644 index 17c171485..000000000 --- a/collab-document/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "collab-document" -version = "0.2.0" -edition = "2024" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -collab = { workspace = true } -collab-entity = { workspace = true } -serde.workspace = true -serde_json.workspace = true -nanoid = "0.4.0" -thiserror = "1.0.30" -anyhow.workspace = true -tracing.workspace = true -arc-swap.workspace = true -tokio = { workspace = true, features = ["sync", "rt"] } -tokio-stream = { version = "0.1.14", features = ["sync"] } -uuid.workspace = true -markdown = "1.0.0-alpha.21" - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2", features = ["js"] } - -[dev-dependencies] -tokio = { version = "1.26", features = ["macros", "rt"] } -tempfile = "3.8.0" -tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } -collab-plugins = { workspace = true } -zip = "0.6.6" -futures = "0.3.30" -assert-json-diff = "2.0.2" -yrs.workspace = true - -[features] -verbose_log = [] diff --git a/collab-document/src/error.rs b/collab-document/src/error.rs deleted file mode 100644 index eef380506..000000000 --- a/collab-document/src/error.rs +++ /dev/null @@ -1,69 +0,0 @@ -use collab_entity::CollabValidateError; - -#[derive(Debug, thiserror::Error)] -pub enum DocumentError { - #[error(transparent)] - Internal(#[from] anyhow::Error), - - #[error(transparent)] - CollabError(#[from] collab::error::CollabError), - - #[error("Could not create block")] - BlockCreateError, - - #[error("The block already exists")] - BlockAlreadyExists, - - #[error("The block is not found")] - BlockIsNotFound, - - #[error("The page id empty")] - PageIdIsEmpty, - - #[error("Could not convert json to data")] - ConvertDataError, - - #[error("The parent is not found")] - ParentIsNotFound, - - #[error("Could not create the root block due to an unspecified error")] - CreateRootBlockError, - - #[error("Could not delete block")] - DeleteBlockError, - - #[error("text_id or delta is empty")] - TextActionParamsError, - - #[error("Lack of document required data")] - NoRequiredData, - - #[error("The external id is not found")] - ExternalIdIsNotFound, - - #[error("Unable to parse document to plain text")] - ParseDocumentError, - - #[error("Unable to parse markdown to document data")] - ParseMarkdownError, - - #[error("Unable to parse delta json to text delta")] - ParseDeltaJsonToTextDeltaError, - - #[error("No children found")] - NoBlockChildrenFound, - - #[error("Unknown block type: {0}")] - UnknownBlockType(String), - - #[error("Unable to find the page block")] - PageBlockNotFound, -} - -impl From for DocumentError { - fn from(error: CollabValidateError) -> Self { - match error { - CollabValidateError::NoRequiredData(_) => DocumentError::NoRequiredData, - } - } -} diff --git a/collab-document/src/lib.rs b/collab-document/src/lib.rs deleted file mode 100644 index 7a3948310..000000000 --- a/collab-document/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod block_parser; -pub mod blocks; -pub mod document; -pub mod document_awareness; -pub mod document_data; -pub mod document_remapper; -pub mod error; -pub mod importer; diff --git a/collab-document/tests/main.rs b/collab-document/tests/main.rs deleted file mode 100644 index fccada72f..000000000 --- a/collab-document/tests/main.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[cfg(not(target_arch = "wasm32"))] -mod block_parser; -#[cfg(not(target_arch = "wasm32"))] -mod blocks; -#[cfg(not(target_arch = "wasm32"))] -mod document; -#[cfg(not(target_arch = "wasm32"))] -mod util; - -#[cfg(not(target_arch = "wasm32"))] -mod conversions; - -#[cfg(not(target_arch = "wasm32"))] -mod importer; - -#[cfg(not(target_arch = "wasm32"))] -mod remapper; diff --git a/collab-entity/Cargo.toml b/collab-entity/Cargo.toml deleted file mode 100644 index 847795d8a..000000000 --- a/collab-entity/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "collab-entity" -version = "0.2.0" -edition = "2024" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -uuid.workspace = true -serde.workspace = true -serde_json.workspace = true -serde_repr = "0.1" -collab = { workspace = true } -anyhow.workspace = true -bytes = { workspace = true, features = ["serde"] } -prost = "0.13.3" -thiserror = "1.0.61" - -[build-dependencies] -prost-build = "0.12" -walkdir = ">=2.0.0" -protoc-bin-vendored = "3.0.0" - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2", features = ["js"] } - - diff --git a/collab-entity/src/lib.rs b/collab-entity/src/lib.rs deleted file mode 100644 index 30ea1d8cb..000000000 --- a/collab-entity/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub use collab_object::*; - -mod collab_object; -pub mod define; -pub mod proto; -pub mod reminder; -pub mod uuid_validation; - -pub use collab::entity::*; diff --git a/collab-entity/src/proto/collab.rs b/collab-entity/src/proto/collab.rs deleted file mode 100644 index e0e552258..000000000 --- a/collab-entity/src/proto/collab.rs +++ /dev/null @@ -1,233 +0,0 @@ -// This file is @generated by prost-build. -/// Originating from an AppFlowy Client. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ClientOrigin { - /// User id. - #[prost(int64, tag = "1")] - pub uid: i64, - /// Device id. - #[prost(string, tag = "2")] - pub device_id: ::prost::alloc::string::String, -} -/// Unknown origin. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct EmptyOrigin {} -/// Originating from the AppFlowy Server. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ServerOrigin {} -/// Origin of a collab message. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CollabOrigin { - #[prost(oneof = "collab_origin::Origin", tags = "1, 2, 3")] - pub origin: ::core::option::Option, -} -/// Nested message and enum types in `CollabOrigin`. -pub mod collab_origin { - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Origin { - #[prost(message, tag = "1")] - Empty(super::EmptyOrigin), - #[prost(message, tag = "2")] - Client(super::ClientOrigin), - #[prost(message, tag = "3")] - Server(super::ServerOrigin), - } -} -/// Collab Type. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum CollabType { - Unknown = 0, - Document = 1, - Database = 2, - WorkspaceDatabase = 3, - Folder = 4, - DatabaseRow = 5, - UserAwareness = 6, -} -impl CollabType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - CollabType::Unknown => "COLLAB_TYPE_UNKNOWN", - CollabType::Document => "COLLAB_TYPE_DOCUMENT", - CollabType::Database => "COLLAB_TYPE_DATABASE", - CollabType::WorkspaceDatabase => "COLLAB_TYPE_WORKSPACE_DATABASE", - CollabType::Folder => "COLLAB_TYPE_FOLDER", - CollabType::DatabaseRow => "COLLAB_TYPE_DATABASE_ROW", - CollabType::UserAwareness => "COLLAB_TYPE_USER_AWARENESS", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "COLLAB_TYPE_UNKNOWN" => Some(Self::Unknown), - "COLLAB_TYPE_DOCUMENT" => Some(Self::Document), - "COLLAB_TYPE_DATABASE" => Some(Self::Database), - "COLLAB_TYPE_WORKSPACE_DATABASE" => Some(Self::WorkspaceDatabase), - "COLLAB_TYPE_FOLDER" => Some(Self::Folder), - "COLLAB_TYPE_DATABASE_ROW" => Some(Self::DatabaseRow), - "COLLAB_TYPE_USER_AWARENESS" => Some(Self::UserAwareness), - _ => None, - } - } -} -/// Encoded collaborative document. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct EncodedCollab { - /// yrs state vector - #[prost(bytes = "vec", tag = "1")] - pub state_vector: ::prost::alloc::vec::Vec, - /// yrs document state - #[prost(bytes = "vec", tag = "2")] - pub doc_state: ::prost::alloc::vec::Vec, - /// yrs encoder version used for the state vector and doc state - #[prost(enumeration = "EncoderVersion", tag = "3")] - pub encoder_version: i32, -} -/// yrs encoder version. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum EncoderVersion { - Unknown = 0, - V1 = 1, - V2 = 2, -} -impl EncoderVersion { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - EncoderVersion::Unknown => "ENCODER_VERSION_UNKNOWN", - EncoderVersion::V1 => "ENCODER_VERSION_V1", - EncoderVersion::V2 => "ENCODER_VERSION_V2", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "ENCODER_VERSION_UNKNOWN" => Some(Self::Unknown), - "ENCODER_VERSION_V1" => Some(Self::V1), - "ENCODER_VERSION_V2" => Some(Self::V2), - _ => None, - } - } -} -/// Embeddings and the associated collab metadata. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CollabEmbeddingsParams { - /// Fragment id. - #[prost(string, tag = "1")] - pub fragment_id: ::prost::alloc::string::String, - /// Collab object id. - #[prost(string, tag = "2")] - pub object_id: ::prost::alloc::string::String, - /// Collab type. - #[prost(enumeration = "CollabType", tag = "3")] - pub collab_type: i32, - /// Embedding content type. - #[prost(enumeration = "EmbeddingContentType", tag = "4")] - pub content_type: i32, - /// Embedding content as string. - #[prost(string, tag = "5")] - pub content: ::prost::alloc::string::String, - /// Embedding as float array. - #[prost(float, repeated, tag = "6")] - pub embedding: ::prost::alloc::vec::Vec, -} -/// Wrapper over a collection of embeddings, together with metadata associated on the collection level. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CollabEmbeddings { - /// OpenAPI tokens consumed. - #[prost(uint32, tag = "1")] - pub tokens_consumed: u32, - /// List of embeddings. - #[prost(message, repeated, tag = "2")] - pub embeddings: ::prost::alloc::vec::Vec, -} -/// Payload for sending and receive collab over http. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CollabParams { - #[prost(string, tag = "1")] - pub object_id: ::prost::alloc::string::String, - /// Serialized EncodedCollab object, which could either be in bincode or protobuf serialization format. - #[prost(bytes = "vec", tag = "2")] - pub encoded_collab: ::prost::alloc::vec::Vec, - /// Collab type. - #[prost(enumeration = "CollabType", tag = "3")] - pub collab_type: i32, - /// Document embeddings. - #[prost(message, optional, tag = "4")] - pub embeddings: ::core::option::Option, -} -/// Payload for creating batch of collab over http. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BatchCreateCollabParams { - /// Workspace id. - #[prost(string, tag = "1")] - pub workspace_id: ::prost::alloc::string::String, - /// List of collab params. - #[prost(message, repeated, tag = "2")] - pub params_list: ::prost::alloc::vec::Vec, -} -/// Payload for creating new collab or update existing collab over http. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CreateCollabParams { - /// Workspace id. - #[prost(string, tag = "1")] - pub workspace_id: ::prost::alloc::string::String, - /// Object id. - #[prost(string, tag = "2")] - pub object_id: ::prost::alloc::string::String, - /// Serialized EncodedCollab object, which could either be in bincode or protobuf serialization format. - #[prost(bytes = "vec", tag = "3")] - pub encoded_collab: ::prost::alloc::vec::Vec, - /// Collab type. - #[prost(enumeration = "CollabType", tag = "4")] - pub collab_type: i32, -} -/// Types of embeddings content. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum EmbeddingContentType { - /// Unknown content type. - Unknown = 0, - /// Plain text - PlainText = 1, -} -impl EmbeddingContentType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - EmbeddingContentType::Unknown => "EMBEDDING_CONTENT_TYPE_UNKNOWN", - EmbeddingContentType::PlainText => "EMBEDDING_CONTENT_TYPE_PLAIN_TEXT", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "EMBEDDING_CONTENT_TYPE_UNKNOWN" => Some(Self::Unknown), - "EMBEDDING_CONTENT_TYPE_PLAIN_TEXT" => Some(Self::PlainText), - _ => None, - } - } -} diff --git a/collab-folder/Cargo.toml b/collab-folder/Cargo.toml deleted file mode 100644 index bfa86cb3c..000000000 --- a/collab-folder/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -edition = "2024" -name = "collab-folder" -version = "0.2.0" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -anyhow.workspace = true -chrono.workspace = true -collab = { workspace = true } -collab-entity.workspace = true -serde.workspace = true -serde_json.workspace = true -serde_repr = "0.1" -thiserror = "1.0.30" -tokio = { workspace = true, features = ["rt", "sync"] } -tokio-stream = { version = "0.1.14", features = ["sync"] } -tracing.workspace = true -dashmap = "5" -arc-swap = "1.7" -uuid.workspace = true -async-trait.workspace = true - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2", features = ["js"] } - -[dev-dependencies] -assert-json-diff = "2.0.2" -collab-plugins = { workspace = true } -fs_extra = "1.2.0" -nanoid = "0.4.0" -tempfile = "3.8.0" -tokio = { version = "1.26", features = ["rt", "macros"] } -tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } -walkdir = "2.3.2" -zip = "0.6.6" -futures = "0.3.30" diff --git a/collab-folder/src/error.rs b/collab-folder/src/error.rs deleted file mode 100644 index e4a5d41d9..000000000 --- a/collab-folder/src/error.rs +++ /dev/null @@ -1,21 +0,0 @@ -use collab_entity::CollabValidateError; - -#[derive(Debug, thiserror::Error)] -pub enum FolderError { - #[error(transparent)] - Internal(#[from] anyhow::Error), - - #[error(transparent)] - CollabError(#[from] collab::error::CollabError), - - #[error("Lack of folder required data:{0}")] - NoRequiredData(String), -} - -impl From for FolderError { - fn from(error: CollabValidateError) -> Self { - match error { - CollabValidateError::NoRequiredData(data) => FolderError::NoRequiredData(data), - } - } -} diff --git a/collab-folder/src/macros.rs b/collab-folder/src/macros.rs deleted file mode 100644 index e5b88dc7c..000000000 --- a/collab-folder/src/macros.rs +++ /dev/null @@ -1,180 +0,0 @@ -#[macro_export] -macro_rules! impl_str_update { - ($setter1: ident, $setter2: ident, $key: expr) => { - pub fn $setter1>(self, value: T) -> Self { - self.map_ref.insert(self.txn, $key, value.as_ref()); - self - } - pub fn $setter2>(self, value: Option) -> Self { - if let Some(value) = value { - self.map_ref.insert(self.txn, $key, value.as_ref()); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_option_str_update { - ($setter1: ident, $setter2: ident, $key: expr) => { - pub fn $setter1(self, value: Option) -> Self { - self.map_ref.insert_with_txn(self.txn, $key, value); - self - } - pub fn $setter2>(self, value: Option) -> Self { - if let Some(value) = value { - self.map_ref.insert_with_txn(self.txn, $key, value.as_ref()); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_i64_update { - ($setter1: ident, $setter2: ident, $key: expr) => { - pub fn $setter1(self, value: i64) -> Self { - self.map_ref.insert(self.txn, $key, Any::BigInt(value)); - self - } - - pub fn $setter2(self, value: Option) -> Self { - if let Some(value) = value { - self.map_ref.insert(self.txn, $key, Any::BigInt(value)); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_option_i64_update { - ($setter1: ident, $key: expr) => { - pub fn $setter1(self, value: Option) -> Self { - if let Some(value) = value { - self.map_ref.insert(self.txn, $key, Any::BigInt(value)); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_bool_update { - ($setter1: ident, $setter2: ident, $key: expr) => { - pub fn $setter1(self, value: bool) -> Self { - self.map_ref.insert(self.txn, $key, value); - self - } - pub fn $setter2(self, value: Option) -> Self { - if let Some(value) = value { - self.map_ref.insert(self.txn, $key, value); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_any_update { - ($setter1: ident, $setter2: ident, $key:expr, $value: ident) => { - pub fn $setter1(self, value: $value) -> Self { - self.map_ref.insert(self.txn, $key, value); - self - } - pub fn $setter2(self, value: Option<$value>) -> Self { - if let Some(value) = value { - self.map_ref.insert(self.txn, $key, value); - } - self - } - }; -} - -#[macro_export] -macro_rules! impl_array_update { - ($setter: ident, $key: expr, $value: ident) => { - pub fn $setter(self, value: $value) -> Self { - self - .map_ref - .insert_array_with_txn(self.txn, $key, value.into()); - self - } - }; -} - -#[macro_export] -macro_rules! impl_section_op { - ($section_type:expr, $set_fn:ident, $add_fn:ident, $delete_fn:ident, $get_my_fn:ident, $get_all_fn:ident, $remove_all_fn:ident, $move_fn:ident) => { - // Add view IDs as either favorites or recents - pub fn $add_fn(&mut self, ids: Vec, uid: i64) { - let mut txn = self.collab.transact_mut(); - for id in ids { - if let Ok(view_uuid) = uuid::Uuid::parse_str(&id) { - self.body.views.update_view( - &mut txn, - &view_uuid, - |update| update.$set_fn(true).done(), - uid, - ); - } - } - } - - pub fn $delete_fn(&mut self, ids: Vec, uid: i64) { - let mut txn = self.collab.transact_mut(); - for id in ids { - if let Ok(view_uuid) = uuid::Uuid::parse_str(&id) { - self.body.views.update_view( - &mut txn, - &view_uuid, - |update| update.$set_fn(false).done(), - uid, - ); - } - } - } - - // Get all section items for the current user - pub fn $get_my_fn(&self, uid: i64) -> Vec { - let txn = self.collab.transact(); - self - .body - .section - .section_op(&txn, $section_type, uid) - .map(|op| op.get_all_section_item(&txn)) - .unwrap_or_default() - } - - // Get all sections - pub fn $get_all_fn(&self, uid: i64) -> Vec { - let txn = self.collab.transact(); - self - .body - .section - .section_op(&txn, $section_type, uid) - .map(|op| op.get_sections(&txn)) - .unwrap_or_default() - .into_iter() - .flat_map(|(_user_id, items)| items) - .collect() - } - - // Clear all items in a section - pub fn $remove_all_fn(&mut self, uid: i64) { - let mut txn = self.collab.transact_mut(); - if let Some(op) = self.body.section.section_op(&txn, $section_type, uid) { - op.clear(&mut txn) - } - } - - // Move the position of a single section item to after another section item. If - // prev_id is None, the item will be moved to the beginning of the section. - pub fn $move_fn(&mut self, id: &str, prev_id: Option<&str>, uid: i64) { - let mut txn = self.collab.transact_mut(); - if let Some(op) = self.body.section.section_op(&txn, $section_type, uid) { - op.move_section_item_with_txn(&mut txn, id, prev_id); - } - } - }; -} diff --git a/collab-folder/test_uuid_conversion_main.rs b/collab-folder/test_uuid_conversion_main.rs deleted file mode 100644 index a2777f834..000000000 --- a/collab-folder/test_uuid_conversion_main.rs +++ /dev/null @@ -1,31 +0,0 @@ -use collab_entity::uuid_validation::*; -use uuid::Uuid; - -#[test] -fn test_uuid_conversions() { - // Test 1: Converting valid UUID strings - let uuid_str = "550e8400-e29b-41d4-a716-446655440000"; - let db_id = try_parse_database_id(uuid_str).expect("Should parse valid UUID"); - assert_eq!(db_id.to_string(), uuid_str); - - // Test 2: Test serialization/deserialization - let json = serde_json::to_string(&db_id).unwrap(); - assert_eq!(json, format!("\"{}\"", uuid_str), "Should serialize as string"); - - - // Test 4: All ID type conversions - let view_id = view_id_from_any_string("view_1"); - let workspace_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, "workspace_1".as_bytes()); - let db_view_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, "db_view_1".as_bytes()); - let doc_id = document_id_from_any_string("doc_1"); - let block_id = block_id_from_any_string("block_1"); - - // Verify they produce consistent UUIDs - assert_eq!(view_id_from_any_string("view_1"), view_id); - assert_eq!(Uuid::new_v5(&Uuid::NAMESPACE_OID, "workspace_1".as_bytes()), workspace_id); - assert_eq!(Uuid::new_v5(&Uuid::NAMESPACE_OID, "db_view_1".as_bytes()), db_view_id); - assert_eq!(document_id_from_any_string("doc_1"), doc_id); - assert_eq!(block_id_from_any_string("block_1"), block_id); - - println!("✅ All UUID conversion tests passed!"); -} diff --git a/collab-importer/Cargo.toml b/collab-importer/Cargo.toml deleted file mode 100644 index 1376cc3e2..000000000 --- a/collab-importer/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -name = "collab-importer" -version = "0.1.0" -edition = "2024" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -collab-folder = { workspace = true } -collab-database = { workspace = true } -collab-document = { workspace = true } -collab = { workspace = true } -collab-entity = { workspace = true } -thiserror.workspace = true -anyhow.workspace = true -chrono.workspace = true -walkdir = "2.5.0" -uuid.workspace = true -serde = { version = "1.0.204", features = ["derive"] } -serde_json = "1.0.120" -markdown = "1.0.0-alpha.21" -tracing.workspace = true -percent-encoding = "2.3.1" -fancy-regex = "0.13.0" -fxhash = "0.2.1" -tokio = { workspace = true, features = ["io-util", "fs"] } -tokio-util = "0.7" -rayon = "1.10.0" -sha2 = "0.10.8" -base64 = "0.22.1" -hex = "0.4.3" -async_zip = { version = "0.0.17", features = ["full"] } -async-trait.workspace = true -futures = "0.3.30" -async-recursion = "1.1" -futures-lite.workspace = true -sanitize-filename = "0.5.0" -zip = "0.6.6" -csv = { version = "1.3.0" } -indexmap = { version = "2.3", features = ["serde"] } - -[dev-dependencies] -tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } -tokio = { workspace = true, features = ["full"] } -nanoid = "0.4.0" -assert-json-diff = "2.0.2" -tempfile = "3.10.1" diff --git a/collab-importer/src/error.rs b/collab-importer/src/error.rs deleted file mode 100644 index e7dcf470c..000000000 --- a/collab-importer/src/error.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::str::Utf8Error; - -#[derive(Debug, thiserror::Error)] -pub enum ImporterError { - #[error("Invalid path: {0}")] - InvalidPath(String), - - #[error("Invalid path format")] - InvalidPathFormat, - - #[error("{0}")] - InvalidFileType(String), - - #[error(transparent)] - ImportMarkdownError(#[from] collab_document::error::DocumentError), - - #[error(transparent)] - ImportCsvError(#[from] collab_database::error::DatabaseError), - - #[error("Parse markdown error: {0}")] - ParseMarkdownError(markdown::message::Message), - - #[error(transparent)] - Utf8Error(#[from] Utf8Error), - - #[error(transparent)] - IOError(#[from] std::io::Error), - - #[error("File not found")] - FileNotFound, - - #[error("Can not import file")] - CannotImport, - - #[error(transparent)] - Internal(#[from] anyhow::Error), -} diff --git a/collab-plugins/Cargo.toml b/collab-plugins/Cargo.toml deleted file mode 100644 index 56e220d96..000000000 --- a/collab-plugins/Cargo.toml +++ /dev/null @@ -1,64 +0,0 @@ -[package] -name = "collab-plugins" -version = "0.2.0" -edition = "2024" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -yrs.workspace = true -collab-entity = { workspace = true } - -tokio = { workspace = true, features = ["sync", "rt", "macros"] } -futures = { version = "0.3" } -tracing.workspace = true -anyhow.workspace = true - -tokio-retry = "0.3" -async-trait.workspace = true -thiserror.workspace = true -serde.workspace = true -serde_json.workspace = true -similar = { version = "2.2.1" } -tokio-stream = { version = "0.1.14", features = ["sync"] } -uuid.workspace = true -bytes.workspace = true -rand = { version = "0.8", optional = true } -lazy_static = "1.4.0" -smallvec = { version = "1.10", features = ["write", "union", "const_generics", "const_new"] } -chrono = { version = "0.4.22", default-features = false, features = ["clock"] } -bincode = "1.3.3" - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -collab = { workspace = true } -rocksdb = { version = "0.22.0", default-features = false, features = ["zstd"] } - - -[dev-dependencies] -tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } -tokio = { version = "1.26.0", features = ["macros"] } -rand = { version = "0.8" } -tempfile = "3.8.0" -assert-json-diff = "2.0.2" -tokio-util = { version = "0.7", features = ["codec"] } - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2", features = ["js"] } -collab = { workspace = true } -indexed_db_futures = { version = "0.4" } -js-sys = "0.3" -async-stream = "0.3" -wasm-bindgen = "0.2" -web-sys = { version = "0.3", features = ["console", "Window"] } -wasm-bindgen-futures = "0.4" -tracing-wasm = "0.2" - -[target.'cfg(target_arch = "wasm32")'.dev-dependencies] -wasm-bindgen-test = "0.3.40" - -[features] -default = [] -postgres_plugin = ["rand"] -verbose_log = [] \ No newline at end of file diff --git a/collab-plugins/src/cloud_storage/channel.rs b/collab-plugins/src/cloud_storage/channel.rs deleted file mode 100644 index 4bfc95b29..000000000 --- a/collab-plugins/src/cloud_storage/channel.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::cloud_storage::error::SyncError; -use futures::Sink; -use std::fmt::Debug; -use std::pin::Pin; -use std::task::{Context, Poll}; -use tokio::sync::mpsc::UnboundedSender; -use tokio_stream::Stream; - -#[allow(dead_code)] -pub trait CollabConnect: Sink + Stream {} - -pub struct TokioUnboundedSink(pub UnboundedSender); - -impl Sink for TokioUnboundedSink -where - T: Send + Sync + 'static + Debug, -{ - type Error = SyncError; - - fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - // An unbounded channel can always accept messages without blocking, so we always return Ready. - Poll::Ready(Ok(())) - } - - fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> { - let _ = self.0.send(item); - Ok(()) - } - - fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - // There is no buffering in an unbounded channel, so we always return Ready. - Poll::Ready(Ok(())) - } - - fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - // An unbounded channel is closed by dropping the sender, so we don't need to do anything here. - Poll::Ready(Ok(())) - } -} diff --git a/collab-plugins/src/cloud_storage/error.rs b/collab-plugins/src/cloud_storage/error.rs deleted file mode 100644 index 882a479f3..000000000 --- a/collab-plugins/src/cloud_storage/error.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[derive(Debug, thiserror::Error)] -pub enum SyncError { - #[error("failed to deserialize message: {0}")] - DecodingError(#[from] yrs::encoding::read::Error), - - #[error(transparent)] - SerdeError(#[from] serde_json::Error), - - #[error(transparent)] - TokioTask(#[from] tokio::task::JoinError), - - #[error(transparent)] - IO(#[from] std::io::Error), - - #[error("Internal failure: {0}")] - Internal(#[from] Box), -} diff --git a/collab-plugins/src/cloud_storage/mod.rs b/collab-plugins/src/cloud_storage/mod.rs deleted file mode 100644 index cc3fe51ce..000000000 --- a/collab-plugins/src/cloud_storage/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -pub use remote_collab::{ - RemoteCollabSnapshot, RemoteCollabState, RemoteCollabStorage, RemoteUpdateReceiver, - RemoteUpdateSender, -}; -pub use yrs::Update as YrsUpdate; -pub use yrs::merge_updates_v1; -pub use yrs::updates::decoder::Decode; - -pub mod postgres; - -mod channel; -mod error; -mod msg; -mod remote_collab; -mod sink; diff --git a/collab-plugins/src/cloud_storage/msg.rs b/collab-plugins/src/cloud_storage/msg.rs deleted file mode 100644 index 666ebe26f..000000000 --- a/collab-plugins/src/cloud_storage/msg.rs +++ /dev/null @@ -1,170 +0,0 @@ -use std::cmp::Ordering; -use std::collections::BinaryHeap; -use std::fmt::Display; -use std::ops::{Deref, DerefMut}; - -use tokio::sync::oneshot; - -pub type MsgId = u64; - -#[allow(dead_code)] -pub trait CollabSinkMessage: Clone + Send + Sync + 'static + Ord + Display { - fn object_id(&self) -> &str; - /// Returns the length of the message in bytes. - fn length(&self) -> usize; - /// Returns true if the message can be merged with other messages. - fn mergeable(&self) -> bool; - - fn merge(&mut self, other: &Self) -> bool; - - fn is_init_msg(&self) -> bool; - - /// Determine if the message can be deferred base on the current state of the sink. - fn deferrable(&self) -> bool; -} -pub(crate) struct PendingMsgQueue { - queue: BinaryHeap>, -} - -impl PendingMsgQueue -where - Msg: Ord + Clone + Display, -{ - pub(crate) fn new() -> Self { - Self { - queue: Default::default(), - } - } - - pub(crate) fn push_msg(&mut self, msg_id: MsgId, msg: Msg) { - self.queue.push(PendingMessage::new(msg, msg_id)); - } -} - -impl Deref for PendingMsgQueue -where - Msg: Ord, -{ - type Target = BinaryHeap>; - - fn deref(&self) -> &Self::Target { - &self.queue - } -} - -impl DerefMut for PendingMsgQueue -where - Msg: Ord, -{ - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.queue - } -} - -#[derive(Debug)] -pub(crate) struct PendingMessage { - msg: Msg, - msg_id: MsgId, - state: MessageState, - tx: Option>, -} - -impl PendingMessage -where - Msg: Clone + Display, -{ - pub fn new(msg: Msg, msg_id: MsgId) -> Self { - Self { - msg, - msg_id, - state: MessageState::Pending, - tx: None, - } - } - - pub fn get_msg(&self) -> &Msg { - &self.msg - } - - pub fn state(&self) -> &MessageState { - &self.state - } - - pub fn set_state(&mut self, new_state: MessageState) { - self.state = new_state; - if self.state.is_done() && self.tx.is_some() { - self.tx.take().map(|tx| tx.send(self.msg_id)); - } - } - - pub fn set_ret(&mut self, tx: oneshot::Sender) { - self.tx = Some(tx); - } - - pub fn msg_id(&self) -> MsgId { - self.msg_id - } -} - -impl PendingMessage -where - Msg: CollabSinkMessage, -{ - pub fn is_mergeable(&self) -> bool { - self.msg.mergeable() - } - - pub fn is_init(&self) -> bool { - self.msg.is_init_msg() - } - - pub fn merge(&mut self, other: &Self) -> bool { - self.msg.merge(other.get_msg()) - } -} - -impl Eq for PendingMessage where Msg: Eq {} - -impl PartialEq for PendingMessage -where - Msg: PartialEq, -{ - fn eq(&self, other: &Self) -> bool { - self.msg == other.msg - } -} - -impl PartialOrd for PendingMessage -where - Msg: PartialOrd + Ord, -{ - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for PendingMessage -where - Msg: Ord, -{ - fn cmp(&self, other: &Self) -> Ordering { - self.msg.cmp(&other.msg) - } -} - -#[derive(Debug, Eq, PartialEq, Clone)] -pub(crate) enum MessageState { - Pending, - Processing, - Done, - Timeout, -} - -impl MessageState { - pub fn is_done(&self) -> bool { - matches!(self, MessageState::Done) - } - pub fn is_processing(&self) -> bool { - matches!(self, MessageState::Processing) - } -} diff --git a/collab-plugins/src/cloud_storage/postgres/mod.rs b/collab-plugins/src/cloud_storage/postgres/mod.rs deleted file mode 100644 index b103d532d..000000000 --- a/collab-plugins/src/cloud_storage/postgres/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub use plugin::*; - -mod plugin; diff --git a/collab-plugins/src/cloud_storage/postgres/plugin.rs b/collab-plugins/src/cloud_storage/postgres/plugin.rs deleted file mode 100644 index 6ddf11b47..000000000 --- a/collab-plugins/src/cloud_storage/postgres/plugin.rs +++ /dev/null @@ -1,162 +0,0 @@ -use collab::lock::RwLock; -use std::future::Future; -use std::pin::Pin; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Weak}; -use std::time::Duration; - -use tokio_retry::strategy::FibonacciBackoff; -use tokio_retry::{Action, Retry}; -use tokio_stream::StreamExt; -use tokio_stream::wrappers::WatchStream; - -use collab::core::collab_plugin::CollabPluginType; -use collab::core::origin::CollabOrigin; -use collab::preclude::{Collab, CollabPlugin}; -use collab_entity::CollabObject; - -use crate::CollabKVDB; -use crate::cloud_storage::remote_collab::{RemoteCollab, RemoteCollabStorage}; -use crate::cloud_storage::sink::{SinkConfig, SinkStrategy}; - -pub struct SupabaseDBPlugin { - uid: i64, - object: CollabObject, - local_collab: Weak>, - local_collab_storage: Weak, - remote_collab: Arc, - remote_collab_storage: Arc, - pending_updates: Arc>>>, - is_first_sync_done: Arc, -} - -impl SupabaseDBPlugin { - pub fn new( - uid: i64, - object: CollabObject, - local_collab: Weak>, - sync_per_secs: u64, - remote_collab_storage: Arc, - local_collab_storage: Weak, - ) -> Self { - let pending_updates = Arc::new(RwLock::from(Vec::new())); - let is_first_sync_done = Arc::new(AtomicBool::new(false)); - - let config = SinkConfig::new() - .with_timeout(10) - .with_strategy(SinkStrategy::FixInterval(Duration::from_secs( - sync_per_secs, - ))); - let remote_collab = Arc::new(RemoteCollab::new( - object.clone(), - remote_collab_storage.clone(), - config, - local_collab.clone(), - )); - - // Subscribe the sync state from the remote collab - let remote_sync_state = remote_collab.subscribe_sync_state(); - let mut remote_sync_state_stream = WatchStream::new(remote_sync_state); - let weak_local_collab = local_collab.clone(); - tokio::spawn(async move { - while let Some(new_state) = remote_sync_state_stream.next().await { - if let Some(local_collab) = weak_local_collab.upgrade() { - local_collab.read().await.set_sync_state(new_state); - } - } - }); - - Self { - uid, - object, - local_collab, - remote_collab, - pending_updates, - is_first_sync_done, - local_collab_storage, - remote_collab_storage, - } - } -} - -impl CollabPlugin for SupabaseDBPlugin { - fn did_init(&self, _collab: &Collab, _object_id: &str) { - // TODO(nathan): retry action might take a long time even if the network is ready or enable of - // the [RemoteCollabStorage] is true - let retry_strategy = FibonacciBackoff::from_millis(2000); - let action = InitSyncAction { - uid: self.uid, - object: self.object.clone(), - remote_collab: Arc::downgrade(&self.remote_collab), - local_collab: self.local_collab.clone(), - local_collab_storage: self.local_collab_storage.clone(), - remote_collab_storage: Arc::downgrade(&self.remote_collab_storage), - pending_updates: Arc::downgrade(&self.pending_updates), - is_first_sync_done: Arc::downgrade(&self.is_first_sync_done), - }; - - tokio::spawn(async move { - let _ = Retry::spawn(retry_strategy, action).await; - }); - } - - fn receive_local_update(&self, origin: &CollabOrigin, object_id: &str, update: &[u8]) { - if self.is_first_sync_done.load(Ordering::SeqCst) { - if let Err(e) = self.remote_collab.push_update(update) { - tracing::error!( - "Collab {} failed to apply update from {}: {}", - object_id, - origin, - e - ); - }; - } else { - self.pending_updates.blocking_write().push(update.to_vec()); - } - } - - fn plugin_type(&self) -> CollabPluginType { - CollabPluginType::CloudStorage - } -} - -#[allow(dead_code)] -struct InitSyncAction { - uid: i64, - object: CollabObject, - remote_collab: Weak, - local_collab: Weak>, - local_collab_storage: Weak, - remote_collab_storage: Weak, - pending_updates: Weak>>>, - is_first_sync_done: Weak, -} - -impl Action for InitSyncAction { - type Future = Pin> + Send>>; - type Item = (); - type Error = anyhow::Error; - - fn run(&mut self) -> Self::Future { - let weak_remote_collab = self.remote_collab.clone(); - let weak_pending_updates = self.pending_updates.clone(); - let weak_is_first_sync_done = self.is_first_sync_done.clone(); - - Box::pin(async move { - if let (Some(remote_collab), Some(pending_updates), Some(is_first_sync_done)) = ( - weak_remote_collab.upgrade(), - weak_pending_updates.upgrade(), - weak_is_first_sync_done.upgrade(), - ) { - for update in &*pending_updates.read().await { - remote_collab.push_update(update)?; - } - - is_first_sync_done.store(true, Ordering::SeqCst); - Ok(()) - } else { - Ok(()) - } - }) - } -} diff --git a/collab-plugins/src/cloud_storage/remote_collab.rs b/collab-plugins/src/cloud_storage/remote_collab.rs deleted file mode 100644 index 3c32d882f..000000000 --- a/collab-plugins/src/cloud_storage/remote_collab.rs +++ /dev/null @@ -1,620 +0,0 @@ -use std::cmp::Ordering; -use std::fmt::{Display, Formatter}; -use std::sync::atomic::{AtomicBool, AtomicU64}; -use std::sync::{Arc, Weak}; -use std::time::{Duration, SystemTime}; - -use anyhow::{Error, anyhow}; -use async_trait::async_trait; -use collab::core::collab::{CollabOptions, DataSource, TransactionMutExt, default_client_id}; -use collab::core::collab_state::SyncState; -use collab::core::origin::CollabOrigin; -use collab::lock::RwLock; -use collab::preclude::Collab; -use collab_entity::CollabObject; -use rand::random; -use serde::Deserialize; -use tokio::spawn; -use tokio::sync::mpsc::unbounded_channel; -use tokio::sync::watch; -use tokio_stream::StreamExt; -use tokio_stream::wrappers::WatchStream; -use tracing::trace; -use yrs::updates::decoder::Decode; -use yrs::{ReadTxn, Transact, Update, merge_updates_v1}; - -use crate::cloud_storage::channel::TokioUnboundedSink; -use crate::cloud_storage::msg::{CollabSinkMessage, MsgId}; -use crate::cloud_storage::sink::{ - CollabSink, CollabSinkRunner, MsgIdCounter, SinkConfig, SinkState, -}; - -/// The [RemoteCollab] is used to sync the local collab to the remote. -pub struct RemoteCollab { - object: CollabObject, - collab: Arc>, - storage: Arc, - /// The [CollabSink] is used to queue the [Message] and continuously try to send them - /// to the remote via the [RemoteCollabStorage]. - sink: Arc, Message>>, - sync_state: Arc>, - #[allow(dead_code)] - is_init_sync_finish: Arc, -} - -impl Drop for RemoteCollab { - fn drop(&mut self) { - tracing::trace!("{} remote collab dropped", self.object); - } -} - -impl RemoteCollab { - /// Create a new remote collab. - /// `timeout` is the time to wait for the server to ack the message. - /// If the server does not ack the message in time, the message will be sent again. - pub fn new( - object: CollabObject, - storage: Arc, - config: SinkConfig, - local_collab: Weak>, - ) -> Self { - let is_init_sync_finish = Arc::new(AtomicBool::new(false)); - let sync_state = Arc::new(watch::channel(SyncState::InitSyncBegin).0); - let options = CollabOptions::new(object.object_id, default_client_id()); - let collab = Arc::new(RwLock::from( - Collab::new_with_options(CollabOrigin::Server, options).unwrap(), - )); - let (sink, mut stream) = unbounded_channel::(); - let weak_storage = Arc::downgrade(&storage); - let (notifier, notifier_rx) = watch::channel(false); - let (sync_state_tx, sink_state_rx) = watch::channel(SinkState::Init); - let collab_sink = Arc::new(CollabSink::new( - object.uid, - TokioUnboundedSink(sink), - notifier, - sync_state_tx, - RngMsgIdCounter::new(), - config, - )); - - // spawns an asynchronous task to continuously listen to the updates stream - // and process them as they come in. - let cloned_is_init_sync_finish = is_init_sync_finish.clone(); - if let Some(mut collab_stream) = storage.subscribe_remote_updates(&object) { - spawn(async move { - while let Some(update) = collab_stream.recv().await { - if !cloned_is_init_sync_finish.load(std::sync::atomic::Ordering::SeqCst) { - continue; - } - if let Some(local_collab) = local_collab.upgrade() { - match Update::decode_v1(&update) { - Ok(update) => { - let mut collab = local_collab.write().await; - let mut txn = collab.transact_mut(); - if let Err(e) = txn.try_apply_update(update) { - tracing::error!("apply remote update failed: {:?}", e); - } - }, - Err(e) => tracing::error!("🔴Failed to decode remote update: {:?}", e), - } - } - } - }); - } - - let weak_collab_sink = Arc::downgrade(&collab_sink); - let weak_sync_state = Arc::downgrade(&sync_state); - let mut sink_state_stream = WatchStream::new(sink_state_rx); - // Subscribe the sink state stream and update the sync state in the background. - spawn(async move { - while let Some(collab_state) = sink_state_stream.next().await { - if let Some(sync_state) = weak_sync_state.upgrade() { - match collab_state { - SinkState::Syncing => { - let _ = sync_state.send(SyncState::Syncing); - }, - SinkState::Finished => { - let _ = sync_state.send(SyncState::SyncFinished); - }, - SinkState::Init => { - let _ = sync_state.send(SyncState::InitSyncBegin); - }, - } - } - } - }); - - // Spawn a task to receive updates from the [CollabSink] and send updates to - // the remote storage. - let cloned_is_init_sync_finish = is_init_sync_finish.clone(); - spawn(async move { - while let Some(message) = stream.recv().await { - if let Some(storage) = weak_storage.upgrade() { - if !storage.is_enable() { - // If the storage is not enable, it will wait for 300ms and try again. - // Return the time slice to the tokio scheduler. - tokio::time::sleep(Duration::from_millis(300)).await; - continue; - } - let is_init_msg = message.is_init_msg(); - trace!("send message: {}", message); - match message.split() { - Ok((object, msg_id, payload)) => { - // If the message is init message, it will flush all the updates to the remote. - if is_init_msg { - tracing::trace!("send init sync {}:{}", object, msg_id); - match storage.send_init_sync(&object, msg_id, payload).await { - Ok(_) => { - if let Some(collab_sink) = weak_collab_sink.upgrade() { - collab_sink - .ack_msg(&object.object_id.to_string(), msg_id) - .await; - cloned_is_init_sync_finish.store(true, std::sync::atomic::Ordering::SeqCst); - } - }, - Err(e) => { - tracing::error!( - "send {}:{} init sync failed: {:?}", - object.object_id, - msg_id, - e - ) - }, - } - } else { - tracing::trace!("send update {}:{}", object, msg_id); - match storage.send_update(&object, msg_id, payload).await { - Ok(_) => { - tracing::debug!("ack update {}:{}", object, msg_id); - if let Some(collab_sink) = weak_collab_sink.upgrade() { - collab_sink - .ack_msg(&object.object_id.to_string(), msg_id) - .await; - } - }, - Err(e) => tracing::error!( - "send {}:{} update failed: {:?}", - object.object_id, - msg_id, - e - ), - } - } - }, - Err(e) => tracing::error!("🔴Failed to split message: {:?}", e), - } - } - } - }); - - // Spawn a task that boost the [CollabSink] - spawn(CollabSinkRunner::run( - Arc::downgrade(&collab_sink), - notifier_rx, - )); - Self { - object, - collab, - storage, - sink: collab_sink, - sync_state, - is_init_sync_finish, - } - } - - pub fn subscribe_sync_state(&self) -> watch::Receiver { - self.sync_state.subscribe() - } - - /// Return the update of the remote collab. - /// If the remote collab contains any updates, it will return None. - /// Otherwise, it will merge the updates into one and return the merged update. - #[allow(dead_code)] - pub async fn sync(&self, local_collab: Weak>) -> Result, Error> { - let mut remote_update = vec![]; - // It would be better if creating a edge function that calculate the diff between the local and remote. - // The local only need to send its state vector to the remote. In this way, the local does not need to - // get all the updates from remote. - // TODO(nathan): create a edge function to calculate the diff between the local and remote. - tracing::trace!("Try init sync:{}", self.object); - let collab_doc_state = self.storage.get_doc_state(&self.object).await?; - { - let mut remote_collab = self.collab.write().await; - let mut txn = remote_collab.transact_mut(); - - match collab_doc_state { - DataSource::Disk { .. } => {}, - DataSource::DocStateV1(doc_state) => { - if let Ok(update) = Update::decode_v1(&doc_state) { - if let Err(e) = txn.try_apply_update(update) { - tracing::error!("apply update failed: {:?}", e); - } - } else { - tracing::error!("🔴decode update failed"); - } - remote_update = doc_state; - }, - DataSource::DocStateV2(doc_state) => { - if let Ok(update) = Update::decode_v2(&doc_state) { - if let Err(e) = txn.try_apply_update(update) { - tracing::error!("apply update failed: {:?}", e); - } - } else { - tracing::error!("🔴decode update failed"); - } - remote_update = doc_state; - }, - } - - let _ = self.sync_state.send(SyncState::InitSyncBegin); - // Encode the remote collab state as update for local collab. - let local_collab = local_collab - .upgrade() - .ok_or(anyhow!("local collab is dropped"))?; - let mut local_lock = local_collab.write().await; - let encode_update = self - .collab - .read() - .await - .transact() - .encode_state_as_update_v1(&local_lock.transact().state_vector()); - if let Ok(update) = Update::decode_v1(&encode_update) { - { - // Don't use the with_transact_mut here, because it carries the origin information. So - // the update will consider as a local update. But here is apply the remote update. - // TODO: nathan define a sync protocol for cloud storage. - tracing::trace!( - "{}: apply remote update with diff len:{}", - self.object, - encode_update.len() - ); - local_lock - .get_mut_awareness() - .doc_mut() - .transact_mut() - .apply_update(update)?; - drop(local_lock); - - if let Err(e) = self.sync_state.send(SyncState::InitSyncEnd) { - tracing::error!("🔴Failed to send sync state: {:?}", e); - } - } - } - } - - // Encode the local collab state as update for remote collab. - let mut remote_lock = self.collab.write().await; - let remote_state_vector = remote_lock.transact().state_vector(); - let encode_update = local_collab - .upgrade() - .ok_or(anyhow!("local collab is dropped"))? - .read() - .await - .transact() - .encode_state_as_update_v1(&remote_state_vector); - - if let Ok(decode_update) = Update::decode_v1(&encode_update) { - tracing::trace!( - "{}: sync updates to remote:{}", - self.object, - encode_update.len() - ); - - // Apply the update to the remote collab and send the update to the remote. - remote_lock.transact_mut().apply_update(decode_update)?; - drop(remote_lock); - - self.sink.queue_msg(|msg_id| Message { - object: self.object.clone(), - payloads: vec![encode_update], - meta: MessageMeta::Init { msg_id }, - object_id_string: self.object.object_id.to_string(), - }); - } - Ok(remote_update) - } - - pub fn push_update(&self, update: &[u8]) -> Result<(), Error> { - if let Ok(decode_update) = Update::decode_v1(update) { - self - .collab - .blocking_write() - .transact_mut() - .apply_update(decode_update)?; - - self.sink.queue_msg(|msg_id| Message { - object: self.object.clone(), - payloads: vec![update.to_vec()], - meta: MessageMeta::Update { msg_id }, - object_id_string: self.object.object_id.to_string(), - }); - } - - Ok(()) - } - - #[allow(dead_code)] - pub fn clear(&self) { - self.sink.remove_all_pending_msgs(); - } -} - -#[derive(Debug, Clone)] -pub struct RemoteCollabState { - /// The current edit count of the remote collab. - pub current_edit_count: i64, - /// The edit count of the remote collab when the snapshot is created. - pub snapshot_edit_count: i64, - /// The last snapshot of the remote collab. - pub snapshot_created_at: i64, -} - -#[derive(Deserialize)] -pub struct RemoteCollabSnapshot { - pub sid: i64, - pub oid: String, - pub blob: Vec, - pub created_at: i64, -} - -/// The [RemoteCollabStorage] is used to store the updates of the remote collab. The [RemoteCollab] -/// is the remote collab that maps to the local collab. -/// Any storage that implements this trait can be used as the remote collab storage. -#[async_trait] -pub trait RemoteCollabStorage: Send + Sync + 'static { - /// Return true if the remote storage is enabled. - /// If the remote storage is disabled, the [RemoteCollab] will not sync the updates to the remote - /// storage. - fn is_enable(&self) -> bool; - - /// Get all the updates of the remote collab. - async fn get_doc_state(&self, object: &CollabObject) -> Result; - - /// Get the latest snapshot of the remote collab. - async fn get_snapshots(&self, object_id: &str, limit: usize) -> Vec; - - /// Return the remote state of the collab. It contains the current edit count, the last snapshot - /// edit count and the last snapshot created time. - async fn get_collab_state( - &self, - object_id: &str, - ) -> Result, anyhow::Error>; - - /// Create a snapshot of the remote collab. The update contains the full state of the [Collab] - async fn create_snapshot( - &self, - object: &CollabObject, - snapshot: Vec, - ) -> Result; - - /// Send the update to the remote storage. - async fn send_update( - &self, - object: &CollabObject, - id: MsgId, - update: Vec, - ) -> Result<(), anyhow::Error>; - - /// The init sync is used to send the initial state of the remote collab to the remote storage. - /// The init_update contains all the missing updates of the remote collab compared to the local. - async fn send_init_sync( - &self, - object: &CollabObject, - id: MsgId, - init_update: Vec, - ) -> Result<(), anyhow::Error>; - - /// Subscribe the remote updates. - fn subscribe_remote_updates(&self, object: &CollabObject) -> Option; -} - -pub type RemoteUpdateSender = tokio::sync::mpsc::UnboundedSender>; -pub type RemoteUpdateReceiver = tokio::sync::mpsc::UnboundedReceiver>; - -#[async_trait] -impl RemoteCollabStorage for Arc -where - T: RemoteCollabStorage, -{ - fn is_enable(&self) -> bool { - (**self).is_enable() - } - - async fn get_doc_state(&self, object: &CollabObject) -> Result { - (**self).get_doc_state(object).await - } - - async fn get_snapshots(&self, object_id: &str, limit: usize) -> Vec { - (**self).get_snapshots(object_id, limit).await - } - - async fn get_collab_state(&self, object_id: &str) -> Result, Error> { - (**self).get_collab_state(object_id).await - } - - async fn create_snapshot(&self, object: &CollabObject, update: Vec) -> Result { - (**self).create_snapshot(object, update).await - } - - async fn send_update( - &self, - object: &CollabObject, - id: MsgId, - update: Vec, - ) -> Result<(), Error> { - (**self).send_update(object, id, update).await - } - - async fn send_init_sync( - &self, - object: &CollabObject, - id: MsgId, - init_update: Vec, - ) -> Result<(), Error> { - (**self).send_init_sync(object, id, init_update).await - } - - fn subscribe_remote_updates(&self, object: &CollabObject) -> Option { - (**self).subscribe_remote_updates(object) - } -} - -#[derive(Clone, Debug)] -pub enum MessageMeta { - Init { msg_id: MsgId }, - Update { msg_id: MsgId }, -} - -impl MessageMeta { - pub fn msg_id(&self) -> &MsgId { - match self { - Self::Init { msg_id, .. } => msg_id, - Self::Update { msg_id, .. } => msg_id, - } - } - - pub fn is_init(&self) -> bool { - matches!(self, Self::Init { .. }) - } -} - -/// A message that is sent to the remote. -#[derive(Clone, Debug)] -struct Message { - object: CollabObject, - meta: MessageMeta, - payloads: Vec>, - object_id_string: String, -} - -impl Message { - fn payload_len(&self) -> usize { - self.payloads.iter().map(|p| p.len()).sum() - } - - fn split(mut self) -> Result<(CollabObject, MsgId, Vec), anyhow::Error> { - let update = if self.payloads.len() == 1 { - self.payloads.pop().unwrap() - } else { - let updates = self - .payloads - .iter() - .map(|update| update.as_ref()) - .collect::>(); - merge_updates_v1(updates)? - }; - let msg_id = *self.meta.msg_id(); - Ok((self.object, msg_id, update)) - } -} - -impl CollabSinkMessage for Message { - fn object_id(&self) -> &str { - &self.object_id_string - } - - fn length(&self) -> usize { - self.payload_len() - } - - fn mergeable(&self) -> bool { - match self.meta { - MessageMeta::Init { .. } => false, - // Special characters, emojis, and characters from many other languages can take 2, 3, or - // even 4 bytes in UTF-8. So assuming that these are standard English characters and encoded - // using UTF-8, each character will take 1 byte. 4096 can hold 4096 characters. - // The default max message size is 4kb. - MessageMeta::Update { .. } => self.payload_len() < (1024 * 4), - } - } - - fn merge(&mut self, other: &Self) -> bool { - self.payloads.extend(other.payloads.clone()); - true - } - - fn is_init_msg(&self) -> bool { - matches!(self.meta, MessageMeta::Init { .. }) - } - - fn deferrable(&self) -> bool { - // If the message is not init message, it can be pending. - !self.meta.is_init() - } -} - -impl Eq for Message {} - -impl PartialEq for Message { - fn eq(&self, other: &Self) -> bool { - self.meta.msg_id() == other.meta.msg_id() - } -} - -impl PartialOrd for Message { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Message { - fn cmp(&self, other: &Self) -> Ordering { - // Init message has higher priority than update message. - match (&self.meta, &other.meta) { - (MessageMeta::Init { msg_id: msg_id_a }, MessageMeta::Init { msg_id: msg_id_b }) => { - msg_id_a.cmp(msg_id_b) - }, - (MessageMeta::Init { .. }, MessageMeta::Update { .. }) => Ordering::Greater, - (MessageMeta::Update { .. }, MessageMeta::Init { .. }) => Ordering::Less, - ( - MessageMeta::Update { - msg_id: msg_id_a, .. - }, - MessageMeta::Update { - msg_id: msg_id_b, .. - }, - ) => msg_id_a.cmp(msg_id_b).reverse(), - } - } -} - -impl Display for Message { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!( - "{} update: [msg_id:{}|payload_len:{}]", - self.object, - self.meta.msg_id(), - self.payload_len(), - )) - } -} - -#[derive(Debug, thiserror::Error)] -enum CollabError { - #[error("Internal error")] - Internal(#[from] anyhow::Error), -} - -const RANDOM_MASK: u64 = (1 << 12) - 1; - -struct RngMsgIdCounter(AtomicU64); - -impl RngMsgIdCounter { - pub fn new() -> Self { - let timestamp = SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .expect("Clock moved backwards!") - .as_millis() as u64; - - let random: u64 = (random::() as u64) & RANDOM_MASK; - let value = (timestamp << 16) | random; - Self(AtomicU64::new(value)) - } -} - -impl MsgIdCounter for RngMsgIdCounter { - #[inline] - fn next(&self) -> MsgId { - self.0.fetch_add(1, std::sync::atomic::Ordering::SeqCst) - } -} diff --git a/collab-plugins/src/cloud_storage/sink.rs b/collab-plugins/src/cloud_storage/sink.rs deleted file mode 100644 index c1f93e57b..000000000 --- a/collab-plugins/src/cloud_storage/sink.rs +++ /dev/null @@ -1,436 +0,0 @@ -use std::marker::PhantomData; -use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::{Arc, Weak}; -use std::time::Duration; - -use collab::lock::Mutex; -use futures::SinkExt; -use tokio::spawn; -use tokio::sync::{mpsc, oneshot, watch}; -use tokio::time::{Instant, Interval}; -use tracing::{debug, trace}; - -use crate::cloud_storage::error::SyncError; -use crate::cloud_storage::msg::{CollabSinkMessage, MessageState, PendingMsgQueue}; - -pub const DEFAULT_SYNC_TIMEOUT: u64 = 2; -#[derive(Clone, Debug)] -pub enum SinkState { - Init, - /// The sink is syncing the messages to the remote. - Syncing, - /// All the messages are synced to the remote. - Finished, -} - -impl SinkState { - #[allow(dead_code)] - pub fn is_init(&self) -> bool { - matches!(self, SinkState::Init) - } -} - -/// Use to sync the [Msg] to the remote. -pub struct CollabSink { - uid: i64, - /// The [Sink] is used to send the messages to the remote. It might be a websocket sink or - /// other sink that implements the [SinkExt] trait. - sender: Arc>, - - /// The [PendingMsgQueue] is used to queue the messages that are waiting to be sent to the - /// remote. It will merge the messages if possible. - pending_msg_queue: Arc>>, //FIXME: this should be a channel - msg_id_counter: Arc, - - /// The [watch::Sender] is used to notify the [CollabSinkRunner] to process the pending messages. - /// Sending `false` will stop the [CollabSinkRunner]. - notifier: Arc>, - config: SinkConfig, - - /// Stop the [IntervalRunner] if the sink strategy is [SinkStrategy::FixInterval]. - #[allow(dead_code)] - interval_runner_stop_tx: Option>, - - /// Used to calculate the time interval between two messages. Only used when the sink strategy - /// is [SinkStrategy::FixInterval]. - instant: Mutex, - state_notifier: Arc>, -} - -impl Drop for CollabSink { - fn drop(&mut self) { - let _ = self.notifier.send(true); - } -} - -impl CollabSink -where - E: std::error::Error + Send + Sync + 'static, - Sink: SinkExt + Send + Sync + Unpin + 'static, - Msg: CollabSinkMessage, -{ - pub fn new( - uid: i64, - sink: Sink, - notifier: watch::Sender, - sync_state_tx: watch::Sender, - msg_id_counter: C, - config: SinkConfig, - ) -> Self - where - C: MsgIdCounter, - { - let notifier = Arc::new(notifier); - let state_notifier = Arc::new(sync_state_tx); - let sender = Arc::new(Mutex::from(sink)); - let pending_msg_queue = PendingMsgQueue::new(); - let pending_msg_queue = Arc::new(Mutex::from(pending_msg_queue)); - let msg_id_counter = Arc::new(msg_id_counter); - // - let instant = Mutex::from(Instant::now()); - let mut interval_runner_stop_tx = None; - if let SinkStrategy::FixInterval(duration) = &config.strategy { - let weak_notifier = Arc::downgrade(¬ifier); - let (tx, rx) = mpsc::channel(1); - interval_runner_stop_tx = Some(tx); - spawn(IntervalRunner::new(*duration).run(weak_notifier, rx)); - } - Self { - uid, - sender, - pending_msg_queue, - msg_id_counter, - notifier, - state_notifier, - config, - instant, - interval_runner_stop_tx, - } - } - - /// Put the message into the queue and notify the sink to process the next message. - /// After the [Msg] was pushed into the [PendingMsgQueue]. The queue will pop the next msg base on - /// its priority. And the message priority is determined by the [Msg] that implement the [Ord] and - /// [PartialOrd] trait. Check out the [CollabMessage] for more details. - /// - pub fn queue_msg(&self, f: impl FnOnce(MsgId) -> Msg) { - { - let mut pending_msgs = self.pending_msg_queue.blocking_lock(); - let msg_id = self.msg_id_counter.next(); - let msg = f(msg_id); - pending_msgs.push_msg(msg_id, msg); - drop(pending_msgs); - } - - self.notify(); - } - - pub fn remove_all_pending_msgs(&self) { - self.pending_msg_queue.blocking_lock().clear(); - } - - /// Notify the sink to process the next message and mark the current message as done. - pub async fn ack_msg(&self, object_id: &str, msg_id: MsgId) { - trace!("receive {} message:{}", object_id, msg_id); - let mut lock = self.pending_msg_queue.lock().await; - if let Some(mut pending_msg) = lock.peek_mut() { - // In most cases, the msg_id of the pending_msg is the same as the passed-in msg_id. However, - // due to network issues, the client might send multiple messages with the same msg_id. - // Therefore, the msg_id might not always match the msg_id of the pending_msg. - debug_assert!( - pending_msg.msg_id() >= msg_id, - "{}: pending msg_id: {}, receive msg:{}", - object_id, - pending_msg.msg_id(), - msg_id - ); - if pending_msg.msg_id() == msg_id { - debug!("{} message:{} was sent", object_id, msg_id); - pending_msg.set_state(MessageState::Done); - self.notify(); - } - }; - } - - async fn process_next_msg(&self) -> Result<(), SyncError> { - // Check if the next message can be deferred. If not, try to send the message immediately. The - // default value is true. - let deferrable = self - .pending_msg_queue - .try_lock() - .map(|pending_msgs| { - pending_msgs - .peek() - .map(|msg| msg.get_msg().deferrable()) - .unwrap_or(true) - }) - .unwrap_or(true); - - if !deferrable { - self.try_send_msg_immediately().await; - return Ok(()); - } - - // Check the elapsed time from the last message. Return if the elapsed time is less than - // the fix interval. - if let SinkStrategy::FixInterval(duration) = &self.config.strategy { - let elapsed = self.instant.lock().await.elapsed(); - // trace!( - // "elapsed interval: {:?}, fix interval: {:?}", - // elapsed, - // duration - // ); - if elapsed < *duration { - return Ok(()); - } - } - - // Reset the instant if the strategy is [SinkStrategy::FixInterval]. - if self.config.strategy.is_fix_interval() { - *self.instant.lock().await = Instant::now(); - } - - self.try_send_msg_immediately().await; - Ok(()) - } - - async fn try_send_msg_immediately(&self) -> Option<()> { - let (tx, rx) = oneshot::channel(); - let collab_msg = { - let mut pending_msg_queue = self.pending_msg_queue.lock().await; - let mut sending_msg = pending_msg_queue.pop()?; - if sending_msg.state().is_done() { - // Notify to process the next pending message - self.notify(); - return None; - } - - // Do nothing if the message is still processing. - if sending_msg.state().is_processing() { - return None; - } - - // If the message can merge other messages, try to merge the next message until the - // message is not mergeable. - if sending_msg.is_mergeable() { - while let Some(pending_msg) = pending_msg_queue.pop() { - debug!("Try merge collab message: {}", pending_msg.get_msg()); - - if !sending_msg.merge(&pending_msg) { - pending_msg_queue.push(pending_msg); - break; - } - } - } - - sending_msg.set_state(MessageState::Processing); - sending_msg.set_ret(tx); - if !sending_msg.is_init() { - let _ = self.state_notifier.send(SinkState::Syncing); - } - let collab_msg = sending_msg.get_msg().clone(); - pending_msg_queue.push(sending_msg); - collab_msg - }; - - let mut sender = self.sender.lock().await; - tracing::debug!("[Client {}]: {}", self.uid, collab_msg); - sender.send(collab_msg).await.ok()?; - // Wait for the message to be acked. - // If the message is not acked within the timeout, resend the message. - match tokio::time::timeout(self.config.timeout, rx).await { - Ok(_) => { - if let Ok(mut pending_msgs) = self.pending_msg_queue.try_lock() { - let pending_msg = pending_msgs.pop(); - trace!( - "{} was sent, current pending messages: {}", - pending_msg - .map(|msg| msg.get_msg().to_string()) - .unwrap_or("".to_string()), - pending_msgs.len() - ); - if pending_msgs.is_empty() { - if let Err(e) = self.state_notifier.send(SinkState::Finished) { - tracing::error!("send sink state failed: {}", e); - } - } - } - self.notify() - }, - Err(_) => { - let mut lock = self.pending_msg_queue.lock().await; - if let Some(mut pending_msg) = lock.peek_mut() { - pending_msg.set_state(MessageState::Timeout); - } - self.notify(); - }, - } - None - } - - /// Notify the sink to process the next message. - pub(crate) fn notify(&self) { - let _ = self.notifier.send(false); - } - - /// Stop the sink. - #[allow(dead_code)] - fn stop(&self) { - let _ = self.notifier.send(true); - } -} - -pub struct CollabSinkRunner(PhantomData); - -impl CollabSinkRunner { - /// The runner will stop if the [CollabSink] was dropped or the notifier was closed. - pub async fn run( - weak_sink: Weak>, - mut notifier: watch::Receiver, - ) where - E: std::error::Error + Send + Sync + 'static, - Sink: SinkExt + Send + Sync + Unpin + 'static, - Msg: CollabSinkMessage, - { - if let Some(sink) = weak_sink.upgrade() { - sink.notify(); - } - loop { - // stops the runner if the notifier was closed. - if notifier.changed().await.is_err() { - break; - } - - // stops the runner if the value of notifier is `true` - if *notifier.borrow() { - break; - } - - if let Some(sync_sink) = weak_sink.upgrade() { - let _ = sync_sink.process_next_msg().await; - } else { - break; - } - } - } -} - -pub struct SinkConfig { - /// `timeout` is the time to wait for the remote to ack the message. If the remote - /// does not ack the message in time, the message will be sent again. - pub timeout: Duration, - /// `max_zip_size` is the maximum size of the messages to be merged. - pub max_merge_size: usize, - /// `strategy` is the strategy to send the messages. - pub strategy: SinkStrategy, -} - -impl SinkConfig { - pub fn new() -> Self { - Self::default() - } - pub fn with_timeout(mut self, secs: u64) -> Self { - let timeout_duration = Duration::from_secs(secs); - if let SinkStrategy::FixInterval(duration) = self.strategy { - if timeout_duration < duration { - tracing::warn!("The timeout duration should greater than the fix interval duration"); - } - } - self.timeout = timeout_duration; - self - } - - /// `with_max_merge_size` is the maximum size of the messages to be merged. - #[allow(dead_code)] - pub fn with_max_merge_size(mut self, max_merge_size: usize) -> Self { - self.max_merge_size = max_merge_size; - self - } - - pub fn with_strategy(mut self, strategy: SinkStrategy) -> Self { - if let SinkStrategy::FixInterval(duration) = strategy { - if self.timeout < duration { - tracing::warn!("The timeout duration should greater than the fix interval duration"); - } - } - self.strategy = strategy; - self - } -} - -impl Default for SinkConfig { - fn default() -> Self { - Self { - timeout: Duration::from_secs(DEFAULT_SYNC_TIMEOUT), - max_merge_size: 4096, - strategy: SinkStrategy::Asap, - } - } -} - -pub enum SinkStrategy { - /// Send the message as soon as possible. - Asap, - /// Send the message in a fixed interval. - /// This can reduce the number of times the message is sent. Especially if using the AWS - /// as the storage layer, the cost of sending the message is high. However, it may increase - /// the latency of the message. - FixInterval(Duration), -} - -impl SinkStrategy { - pub fn is_fix_interval(&self) -> bool { - matches!(self, SinkStrategy::FixInterval(_)) - } -} - -pub type MsgId = u64; - -pub trait MsgIdCounter: Send + Sync + 'static { - /// Get the next message id. The message id should be unique. - fn next(&self) -> MsgId; -} - -#[derive(Debug, Default)] -pub struct DefaultMsgIdCounter(Arc); - -impl MsgIdCounter for DefaultMsgIdCounter { - fn next(&self) -> MsgId { - self.0.fetch_add(1, Ordering::SeqCst) - } -} - -struct IntervalRunner { - interval: Option, -} - -impl IntervalRunner { - fn new(duration: Duration) -> Self { - Self { - interval: Some(tokio::time::interval(duration)), - } - } -} - -impl IntervalRunner { - pub async fn run(mut self, sender: Weak>, mut stop_rx: mpsc::Receiver<()>) { - let mut interval = self - .interval - .take() - .expect("Interval should only take once"); - loop { - tokio::select! { - _ = stop_rx.recv() => { - break; - }, - _ = interval.tick() => { - if let Some(sender) = sender.upgrade() { - let _ = sender.send(false); - } else { - break; - } - } - } - } - } -} diff --git a/collab-plugins/src/lib.rs b/collab-plugins/src/lib.rs deleted file mode 100644 index 290c3d242..000000000 --- a/collab-plugins/src/lib.rs +++ /dev/null @@ -1,29 +0,0 @@ -pub mod local_storage; - -#[macro_export] -macro_rules! if_native { - ($($item:item)*) => {$( - #[cfg(not(target_arch = "wasm32"))] - $item - )*} -} - -#[macro_export] -macro_rules! if_wasm { - ($($item:item)*) => {$( - #[cfg(target_arch = "wasm32")] - $item - )*} -} - -#[cfg(all(feature = "postgres_plugin", not(target_arch = "wasm32")))] -pub mod cloud_storage; -pub mod connect_state; - -if_native! { - pub type CollabKVDB = local_storage::rocksdb::kv_impl::KVTransactionDBRocksdbImpl; -} - -if_wasm! { - pub type CollabKVDB = local_storage::indexeddb::CollabIndexeddb; -} diff --git a/collab-plugins/src/local_storage/indexeddb/indexeddb_plugin.rs b/collab-plugins/src/local_storage/indexeddb/indexeddb_plugin.rs deleted file mode 100644 index 57ee63fba..000000000 --- a/collab-plugins/src/local_storage/indexeddb/indexeddb_plugin.rs +++ /dev/null @@ -1,165 +0,0 @@ -use crate::local_storage::indexeddb::kv_impl::CollabIndexeddb; -use crate::local_storage::kv::keys::{make_doc_state_key, make_state_vector_key}; - -use async_stream::stream; -use collab::core::origin::CollabOrigin; -use collab::preclude::{Collab, CollabPlugin}; -use collab_entity::CollabType; -use futures::stream::StreamExt; - -use crate::local_storage::kv::PersistenceError; -use collab::core::collab::make_yrs_doc; -use collab::core::transaction::DocTransactionExtension; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::Ordering::SeqCst; -use std::sync::{Arc, Weak}; -use tracing::{error, instrument}; -use yrs::{Doc, TransactionMut}; - -pub struct IndexeddbDiskPlugin { - uid: i64, - #[allow(dead_code)] - object_id: String, - #[allow(dead_code)] - collab_type: CollabType, - collab_db: Weak, - did_load: Arc, - edit_sender: DocEditStreamSender, -} - -impl IndexeddbDiskPlugin { - pub fn new( - uid: i64, - object_id: String, - collab_type: CollabType, - collab_db: Weak, - ) -> Self { - let did_load = Arc::new(AtomicBool::new(false)); - let (edit_sender, rx) = tokio::sync::mpsc::unbounded_channel(); - let edit_stream = DocEditStream::new(uid, &object_id, collab_db.clone(), rx); - tokio::task::spawn_local(edit_stream.run()); - Self { - uid, - object_id, - collab_type, - did_load, - collab_db, - edit_sender, - } - } - - #[instrument(skip_all)] - fn flush_doc(&self, db: Arc, object_id: &str) { - let uid = self.uid; - let object_id = object_id.to_string(); - tokio::task::spawn_local(async move { - let doc = make_yrs_doc(false); - db.load_doc(uid, &object_id, doc.clone()).await.unwrap(); - let encoded_collab = doc.get_encoded_collab_v1(); - db.flush_doc(uid, &object_id, &encoded_collab) - .await - .unwrap(); - }); - } -} - -impl CollabPlugin for IndexeddbDiskPlugin { - fn init(&self, object_id: &str, _origin: &CollabOrigin, doc: &Doc) { - if let Some(db) = self.collab_db.upgrade() { - let object_id = object_id.to_string(); - let doc = doc.clone(); - let uid = self.uid; - - tokio::task::spawn_local(async move { - match db.load_doc(uid, &object_id, doc.clone()).await { - Ok(_) => {}, - Err(err) => { - if err.is_record_not_found() { - let encoded_collab = doc.get_encoded_collab_v1(); - let f = || async move { - let doc_id = db.create_doc_id(uid, object_id).await?; - let doc_state_key = make_doc_state_key(doc_id); - let sv_key = make_state_vector_key(doc_id); - db.set_data(doc_state_key, encoded_collab.doc_state).await?; - db.set_data(sv_key, encoded_collab.state_vector).await?; - Ok::<(), PersistenceError>(()) - }; - if let Err(err) = f().await { - error!("failed to create doc_id: {:?}", err); - } - } else { - error!("failed to get encoded collab: {:?}", err); - } - }, - } - }); - } else { - tracing::warn!("collab_db is dropped"); - } - } - - fn receive_update(&self, _object_id: &str, _txn: &TransactionMut, update: &[u8]) { - // Only push update if the doc is loaded - if !self.did_load.load(SeqCst) { - return; - } - if let Err(err) = self.edit_sender.send(DocUpdate::Update(update.to_vec())) { - error!("failed to send update: {}", err); - } - } - - fn did_init(&self, _collab: &Collab, _object_id: &str, _last_sync_at: i64) { - self.did_load.store(true, SeqCst); - } - - fn flush(&self, object_id: &str, _doc: &Doc) { - if let Some(db) = self.collab_db.upgrade() { - self.flush_doc(db, object_id); - } - } -} - -type DocEditStreamSender = tokio::sync::mpsc::UnboundedSender; -type DocEditStreamReceiver = tokio::sync::mpsc::UnboundedReceiver; -struct DocEditStream { - uid: i64, - object_id: String, - collab_db: Weak, - receiver: Option, -} - -#[derive(Clone)] -enum DocUpdate { - Update(Vec), -} - -impl DocEditStream { - fn new( - uid: i64, - object_id: &str, - collab_db: Weak, - receiver: DocEditStreamReceiver, - ) -> Self { - Self { - uid, - object_id: object_id.to_string(), - collab_db, - receiver: Some(receiver), - } - } - - async fn run(mut self) { - let mut receiver = self.receiver.take().expect("Only take once"); - while let Some(data) = receiver.recv().await { - match data { - DocUpdate::Update(update) => { - if let Some(db) = self.collab_db.upgrade() { - if let Err(err) = db.push_update(self.uid, &self.object_id, &update).await { - error!("failed to push update: {}", err); - } - } - }, - } - } - } -} diff --git a/collab-plugins/src/local_storage/indexeddb/kv_impl.rs b/collab-plugins/src/local_storage/indexeddb/kv_impl.rs deleted file mode 100644 index 2d359ba1c..000000000 --- a/collab-plugins/src/local_storage/indexeddb/kv_impl.rs +++ /dev/null @@ -1,441 +0,0 @@ -use crate::local_storage::kv::PersistenceError; -use collab::entity::EncodedCollab; -use indexed_db_futures::prelude::*; -use js_sys::{ArrayBuffer, Uint8Array}; - -use crate::local_storage::kv::keys::{ - Clock, DOC_ID_LEN, DocID, clock_from_key, make_doc_end_key, make_doc_id_key_v1, - make_doc_start_key, make_doc_state_key, make_doc_update_key, make_state_vector_key, -}; -use crate::local_storage::kv::oid::{LOCAL_DOC_ID_GEN, OID}; -use anyhow::anyhow; -use collab::core::collab::TransactionMutExt; -use collab::lock::RwLock; -use indexed_db_futures::web_sys::IdbKeyRange; -use std::sync::Arc; -use tracing::error; -use wasm_bindgen::{JsCast, JsValue}; -use yrs::updates::decoder::Decode; -use yrs::{Doc, Transact, Update}; - -pub struct CollabIndexeddb { - db: Arc>, -} - -unsafe impl Send for CollabIndexeddb {} -unsafe impl Sync for CollabIndexeddb {} - -const COLLAB_KV_STORE: &str = "collab_kv"; -impl CollabIndexeddb { - pub async fn new() -> Result { - let mut db_req = IdbDatabase::open_u32("appflowy_indexeddb", 1)?; - db_req.set_on_upgrade_needed(Some(|evt: &IdbVersionChangeEvent| -> Result<(), JsValue> { - if evt - .db() - .object_store_names() - .find(|n| n == COLLAB_KV_STORE) - .is_none() - { - evt.db().create_object_store(COLLAB_KV_STORE)?; - } - Ok(()) - })); - let db = Arc::new(RwLock::new(db_req.await?)); - Ok(Self { db }) - } - - pub async fn with_write_transaction( - &self, - f: impl FnOnce(&IdbTransactionActionImpl<'_>) -> Result, - ) -> Result { - let db_write_guard = self.db.write_err().await; - let txn = db_write_guard - .transaction_on_one_with_mode(COLLAB_KV_STORE, IdbTransactionMode::Readwrite)?; - let action_impl = IdbTransactionActionImpl::new(txn)?; - let output = f(&action_impl)?; - action_impl.tx.await.into_result()?; - Ok(output) - } - - pub async fn get_data( - &self, - store: &IdbObjectStore<'_>, - key: K, - ) -> Result, PersistenceError> - where - K: AsRef<[u8]>, - { - let js_key = to_js_value(key.as_ref()); - match store.get(&js_key)?.await? { - None => Err(PersistenceError::RecordNotFound(format!( - "object with given key:{:?} is not found", - js_key - ))), - Some(value) => Ok(Uint8Array::new(&value).to_vec()), - } - } - - pub async fn set_data(&self, key: K, value: V) -> Result<(), PersistenceError> - where - K: AsRef<[u8]>, - V: AsRef<[u8]>, - { - let write_guard = self.db.write_err().await; - let transaction = - write_guard.transaction_on_one_with_mode(COLLAB_KV_STORE, IdbTransactionMode::Readwrite)?; - let store = store_from_transaction(&transaction)?; - self.set_data_with_store(&store, key, value).await?; - transaction_result_to_result(transaction.await)?; - Ok(()) - } - - pub async fn set_data_with_store( - &self, - store: &IdbObjectStore<'_>, - key: K, - value: V, - ) -> Result<(), PersistenceError> - where - K: AsRef<[u8]>, - V: AsRef<[u8]>, - { - let js_key = to_js_value(key.as_ref()); - let js_value = to_js_value(value.as_ref()); - store.put_key_val(&js_key, &js_value)?.await?; - Ok(()) - } - - pub async fn create_doc( - &self, - uid: i64, - object_id: &str, - encoded_collab: &EncodedCollab, - ) -> Result<(), PersistenceError> { - let doc_id = self.create_doc_id(uid, object_id).await?; - let doc_state_key = make_doc_state_key(doc_id); - let sv_key = make_state_vector_key(doc_id); - - let read_guard = self.db.write_err().await; - let transaction = - read_guard.transaction_on_one_with_mode(COLLAB_KV_STORE, IdbTransactionMode::Readwrite)?; - let store = store_from_transaction(&transaction)?; - self - .set_data_with_store(&store, doc_state_key, &encoded_collab.doc_state) - .await?; - self - .set_data_with_store(&store, sv_key, &encoded_collab.state_vector) - .await?; - - transaction_result_to_result(transaction.await)?; - Ok(()) - } - - pub async fn load_doc( - &self, - uid: i64, - object_id: &str, - doc: Doc, - ) -> Result<(), PersistenceError> { - let read_guard = self.db.read_err().await; - let transaction = - read_guard.transaction_on_one_with_mode(COLLAB_KV_STORE, IdbTransactionMode::Readonly)?; - let store = store_from_transaction(&transaction)?; - let doc_id = self - .get_doc_id(&store, uid, object_id) - .await - .ok_or_else(|| { - PersistenceError::RecordNotFound(format!("doc_id for object_id:{} is not found", object_id)) - })?; - - let doc_state_key = make_doc_state_key(doc_id); - let doc_state = self.get_data(&store, doc_state_key).await?; - let updates = fetch_updates(&store, doc_id).await?; - - let mut txn = doc - .try_transact_mut() - .map_err(|err| PersistenceError::Internal(anyhow!("Transact mut fail. error: {:?}", err)))?; - let doc_state_update = Update::decode_v1(doc_state.as_ref()).map_err(PersistenceError::Yrs)?; - txn.try_apply_update(doc_state_update)?; - - for update in updates { - if let Ok(update) = Update::decode_v1(update.as_ref()) { - txn.try_apply_update(update)?; - } - } - - drop(txn); - Ok(()) - } - - pub async fn get_encoded_collab( - &self, - uid: i64, - object_id: &str, - ) -> Result { - let read_guard = self.db.read_err().await; - let transaction = - read_guard.transaction_on_one_with_mode(COLLAB_KV_STORE, IdbTransactionMode::Readonly)?; - let store = store_from_transaction(&transaction)?; - - let doc_id = self - .get_doc_id(&store, uid, object_id) - .await - .ok_or_else(|| { - PersistenceError::RecordNotFound(format!("doc_id for object_id:{} is not found", object_id)) - })?; - - let doc_state_key = make_doc_state_key(doc_id); - let sv_key = make_state_vector_key(doc_id); - - let doc_stata = self.get_data(&store, doc_state_key).await?; - let sv = self.get_data(&store, sv_key).await?; - - Ok(EncodedCollab::new_v1(sv, doc_stata)) - } - - pub async fn is_exist(&self, uid: i64, object_id: &str) -> Result { - let read_guard = self.db.read_err().await; - let transaction = - read_guard.transaction_on_one_with_mode(COLLAB_KV_STORE, IdbTransactionMode::Readonly)?; - let store = store_from_transaction(&transaction)?; - Ok(self.get_doc_id(&store, uid, object_id).await.is_some()) - } - - pub async fn delete_doc(&self, uid: i64, object_id: &str) -> Result<(), PersistenceError> { - let write_guard = self.db.write_err().await; - let transaction = - write_guard.transaction_on_one_with_mode(COLLAB_KV_STORE, IdbTransactionMode::Readwrite)?; - let store = store_from_transaction(&transaction)?; - let doc_id = self - .get_doc_id(&store, uid, object_id) - .await - .ok_or_else(|| { - PersistenceError::RecordNotFound(format!("doc_id for object_id:{} is not found", object_id)) - })?; - - self.delete_all_updates(&store, doc_id).await?; - - // delete the doc state and state vector - let doc_state_key = make_doc_state_key(doc_id); - let sv_key = make_state_vector_key(doc_id); - store.delete(&to_js_value(doc_state_key.as_ref()))?; - store.delete(&to_js_value(sv_key.as_ref()))?; - transaction_result_to_result(transaction.await)?; - Ok(()) - } - - pub async fn flush_doc( - &self, - uid: i64, - object_id: &str, - encoded: &EncodedCollab, - ) -> Result<(), PersistenceError> { - let write_guard = self.db.write_err().await; - let transaction = - write_guard.transaction_on_one_with_mode(COLLAB_KV_STORE, IdbTransactionMode::Readwrite)?; - let store = store_from_transaction(&transaction)?; - let doc_id = self - .get_doc_id(&store, uid, object_id) - .await - .ok_or_else(|| { - PersistenceError::RecordNotFound(format!("doc_id for object_id:{} is not found", object_id)) - })?; - self.delete_all_updates(&store, doc_id).await?; - - // save the new doc state and state vector - let doc_state_key = make_doc_state_key(doc_id); - let sv_key = make_state_vector_key(doc_id); - self - .set_data_with_store(&store, doc_state_key, &encoded.doc_state) - .await?; - self - .set_data_with_store(&store, sv_key, &encoded.state_vector) - .await?; - transaction_result_to_result(transaction.await)?; - Ok(()) - } - - pub async fn push_update( - &self, - uid: i64, - object_id: &str, - update: &[u8], - ) -> Result<(), PersistenceError> { - let write_guard = self.db.write_err().await; - let transaction = - write_guard.transaction_on_one_with_mode(COLLAB_KV_STORE, IdbTransactionMode::Readwrite)?; - let store = store_from_transaction(&transaction)?; - let doc_id = self - .get_doc_id(&store, uid, object_id) - .await - .ok_or_else(|| { - PersistenceError::RecordNotFound(format!("doc_id for object_id:{} is not found", object_id)) - })?; - self.put_update(&store, doc_id, update).await?; - transaction_result_to_result(transaction.await)?; - Ok(()) - } - - async fn delete_all_updates( - &self, - store: &IdbObjectStore<'_>, - doc_id: DocID, - ) -> Result<(), PersistenceError> { - let start = to_js_value(make_doc_start_key(doc_id)); - let end = to_js_value(make_doc_end_key(doc_id)); - let key_range = IdbKeyRange::bound(&start, &end).map_err(|err| { - PersistenceError::Internal(anyhow!("Get last update key fail. error: {:?}", err)) - })?; - - let cursor_request = store - .open_cursor_with_range(&key_range)? - .await? - .ok_or_else(|| { - PersistenceError::Internal(anyhow!("Open cursor fail. error: {:?}", "cursor is none")) - })?; - - // Delete the first key - let _ = cursor_request.delete(); - while cursor_request.continue_cursor()?.await? { - if let Err(err) = cursor_request.delete() { - error!("failed to delete cursor: {:?}", err) - } - } - - Ok(()) - } - - pub async fn get_all_updates( - &self, - uid: i64, - object_id: &str, - ) -> Result>, PersistenceError> { - let read_guard = self.db.read_err().await; - let transaction = - read_guard.transaction_on_one_with_mode(COLLAB_KV_STORE, IdbTransactionMode::Readonly)?; - let store = store_from_transaction(&transaction)?; - let doc_id = self - .get_doc_id(&store, uid, object_id) - .await - .ok_or_else(|| { - PersistenceError::RecordNotFound(format!("doc_id for object_id:{} is not found", object_id)) - })?; - - fetch_updates(&store, doc_id).await - } - - async fn put_update( - &self, - store: &IdbObjectStore<'_>, - id: OID, - update: &[u8], - ) -> Result<(), PersistenceError> { - let max_key = JsValue::from(Uint8Array::from( - make_doc_update_key(id, Clock::MAX).as_ref(), - )); - - let key_range = IdbKeyRange::upper_bound(&max_key).map_err(|err| { - PersistenceError::Internal(anyhow!("Get last update key fail. error: {:?}", err)) - })?; - let cursor = store - .open_cursor_with_range_and_direction(&key_range, IdbCursorDirection::Prev)? - .await? - .ok_or_else(|| { - PersistenceError::Internal(anyhow!("Open cursor fail. error: {:?}", "cursor is none")) - })?; - - let clock = cursor - .key() - .map(|key| { - let array_buffer = key.dyn_into::().unwrap(); - let uint8_array = Uint8Array::new(&array_buffer); - let mut vec = vec![0; uint8_array.length() as usize]; - uint8_array.copy_to(&mut vec); - let clock_byte = clock_from_key(&vec); - Clock::from_be_bytes(clock_byte.try_into().unwrap()) - }) - .unwrap_or_else(|| 0); - - let next_clock = clock + 1; - let update_key = make_doc_update_key(id, next_clock); - self.set_data_with_store(store, update_key, update).await?; - Ok(()) - } - - pub async fn get_doc_id( - &self, - store: &IdbObjectStore<'_>, - uid: i64, - workspace_id: &K, - object_id: &K, - ) -> Option - where - K: AsRef<[u8]> + ?Sized, - { - let uid_id_bytes = &uid.to_be_bytes(); - let key = make_doc_id_key_v1(uid_id_bytes, workspace_id.as_ref(), object_id.as_ref()); - let value = self.get_data(store, key).await.ok()?; - let mut bytes = [0; DOC_ID_LEN]; - bytes[0..DOC_ID_LEN].copy_from_slice(value.as_ref()); - Some(OID::from_be_bytes(bytes)) - } -} - -fn to_js_value>(key: K) -> JsValue { - JsValue::from(Uint8Array::from(key.as_ref())) -} - -fn store_from_transaction<'a>( - txn: &'a IdbTransaction<'a>, -) -> Result, PersistenceError> { - txn - .object_store(COLLAB_KV_STORE) - .map_err(PersistenceError::from) -} - -pub struct IdbTransactionActionImpl<'a> { - tx: IdbTransaction<'a>, -} - -impl<'a> IdbTransactionActionImpl<'a> { - fn new(tx: IdbTransaction<'a>) -> Result { - Ok(Self { tx }) - } -} - -fn transaction_result_to_result(result: IdbTransactionResult) -> Result<(), PersistenceError> { - match result { - IdbTransactionResult::Success => Ok(()), - IdbTransactionResult::Error(err) => Err(PersistenceError::from(err)), - IdbTransactionResult::Abort => Err(PersistenceError::Internal(anyhow!("Transaction aborted"))), - } -} - -async fn fetch_updates( - store: &IdbObjectStore<'_>, - doc_id: DocID, -) -> Result>, PersistenceError> { - let start = to_js_value(make_doc_update_key(doc_id, 0).as_ref()); - let end = to_js_value(make_doc_update_key(doc_id, Clock::MAX).as_ref()); - let key_range = IdbKeyRange::bound(&start, &end).map_err(|err| { - PersistenceError::Internal(anyhow!("Get last update key fail. error: {:?}", err)) - })?; - let cursor_request = store.open_cursor_with_range(&key_range)?.await?; - if cursor_request.is_none() { - return Ok(Vec::new()); - } - - let cursor_request = cursor_request.unwrap(); - let mut js_values = Vec::new(); - js_values.push(cursor_request.value()); - while cursor_request.continue_cursor()?.await? { - js_values.push(cursor_request.value()); - } - - Ok( - js_values - .into_iter() - .map(|js_value| js_value.dyn_into::().unwrap().to_vec()) - .collect(), - ) -} diff --git a/collab-plugins/src/local_storage/indexeddb/mod.rs b/collab-plugins/src/local_storage/indexeddb/mod.rs deleted file mode 100644 index 47c970dc3..000000000 --- a/collab-plugins/src/local_storage/indexeddb/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod indexeddb_plugin; -mod kv_impl; - -pub use indexeddb_plugin::*; -pub use kv_impl::*; diff --git a/collab-plugins/src/local_storage/kv/error.rs b/collab-plugins/src/local_storage/kv/error.rs deleted file mode 100644 index c04dda923..000000000 --- a/collab-plugins/src/local_storage/kv/error.rs +++ /dev/null @@ -1,79 +0,0 @@ -#[derive(Debug, thiserror::Error)] -pub enum PersistenceError { - #[cfg(not(target_arch = "wasm32"))] - #[error("Rocksdb corruption:{0}")] - RocksdbCorruption(String), - - #[cfg(not(target_arch = "wasm32"))] - #[error("Rocksdb repair:{0}")] - RocksdbRepairFail(String), - - #[cfg(not(target_arch = "wasm32"))] - #[error("{0}")] - RocksdbBusy(String), - - // If the database is already locked by another process, it will return an IO error. It - // happens when the database is already opened by another process. - #[cfg(not(target_arch = "wasm32"))] - #[error("{0}")] - RocksdbIOError(String), - - #[error(transparent)] - Bincode(#[from] bincode::Error), - - #[error("{0}")] - RecordNotFound(String), - - #[error("The document already exist")] - DocumentAlreadyExist, - - #[error("Unexpected empty updates")] - UnexpectedEmptyUpdates, - - #[error(transparent)] - Yrs(#[from] yrs::encoding::read::Error), - - #[error("Failed to apply update from persistent store: {0}")] - Update(#[from] yrs::error::UpdateError), - - #[error("invalid data: {0}")] - InvalidData(String), - - #[error("Duplicate update key")] - DuplicateUpdateKey, - - #[error("Can't find the latest update key")] - LatestUpdateKeyNotExist, - - #[error(transparent)] - Collab(#[from] collab::error::CollabError), - - #[error(transparent)] - Internal(#[from] anyhow::Error), -} - -impl PersistenceError { - pub fn is_record_not_found(&self) -> bool { - matches!(self, PersistenceError::RecordNotFound(_)) - } -} - -#[cfg(target_arch = "wasm32")] -impl From for PersistenceError { - fn from(value: indexed_db_futures::web_sys::DomException) -> Self { - PersistenceError::Internal(anyhow::anyhow!("DOMException: {:?}", value)) - } -} - -#[cfg(not(target_arch = "wasm32"))] -impl From for PersistenceError { - fn from(value: rocksdb::Error) -> Self { - match value.kind() { - rocksdb::ErrorKind::NotFound => PersistenceError::UnexpectedEmptyUpdates, - rocksdb::ErrorKind::Corruption => PersistenceError::RocksdbCorruption(value.into_string()), - rocksdb::ErrorKind::IOError => PersistenceError::RocksdbIOError(value.into_string()), - rocksdb::ErrorKind::Busy => PersistenceError::RocksdbBusy(value.into_string()), - _ => PersistenceError::Internal(value.into()), - } - } -} diff --git a/collab-plugins/src/local_storage/mod.rs b/collab-plugins/src/local_storage/mod.rs deleted file mode 100644 index 7aa724de4..000000000 --- a/collab-plugins/src/local_storage/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod kv; - -#[cfg(not(target_arch = "wasm32"))] -pub mod rocksdb; - -#[cfg(target_arch = "wasm32")] -pub mod indexeddb; - -mod storage_config; - -pub use storage_config::*; diff --git a/collab-plugins/tests/web/edit_collab_test.rs b/collab-plugins/tests/web/edit_collab_test.rs deleted file mode 100644 index 7d7b5285e..000000000 --- a/collab-plugins/tests/web/edit_collab_test.rs +++ /dev/null @@ -1,117 +0,0 @@ -use assert_json_diff::assert_json_eq; -use collab::core::collab::MutexCollab; -use collab::preclude::CollabBuilder; -use collab_entity::CollabType; -use collab_plugins::local_storage::indexeddb::CollabIndexeddb; -use collab_plugins::local_storage::indexeddb::IndexeddbDiskPlugin; -use js_sys::Promise; -use serde_json::json; -use std::sync::{Arc, Once}; -use tokio::task::LocalSet; -use uuid::Uuid; -use wasm_bindgen::prelude::*; -use wasm_bindgen_futures::JsFuture; -use wasm_bindgen_test::wasm_bindgen_test; -use web_sys::window; - -#[wasm_bindgen_test] -async fn edit_collab_with_indexeddb_test() { - let local = LocalSet::new(); - local - .run_until(async { - setup_log(); - let object_id = Uuid::new_v4().to_string(); - let uid: i64 = 1; - let db = Arc::new(CollabIndexeddb::new().await.unwrap()); - let collab = create_collab(uid, object_id.clone(), &db).await; - collab.lock().insert("message", "hello world"); - let json_1 = collab.lock().to_json_value(); - drop(collab); - - // sleep 2 secs to wait for the disk plugin to flush the data - sleep(2000).await; - let collab_from_disk = create_collab(uid, object_id.clone(), &db).await; - let json_2 = collab_from_disk.lock().to_json_value(); - assert_json_eq!( - json_2, - json!({ - "message": "hello world" - }) - ); - assert_json_eq!(json_1, json_2); - }) - .await; -} - -#[wasm_bindgen_test] -async fn flush_collab_with_indexeddb_test() { - let local = LocalSet::new(); - local - .run_until(async { - setup_log(); - let object_id = Uuid::new_v4().to_string(); - let uid: i64 = 1; - let db = Arc::new(CollabIndexeddb::new().await.unwrap()); - let collab = create_collab(uid, object_id.clone(), &db).await; - collab.lock().insert("1", "a"); - sleep(100).await; - collab.lock().insert("2", "b"); - sleep(100).await; - collab.lock().insert("3", "c"); - sleep(100).await; - let json_1 = collab.lock().to_json_value(); - collab.lock().flush(); - - // sleep 2 secs to wait for the disk plugin to flush the data - sleep(2000).await; - - // after flush, all the updates will be removed. Only the final doc state will be saved to disk - let updates = db.get_all_updates(uid, &object_id).await.unwrap(); - assert_eq!(updates.len(), 0); - - let collab_from_disk = create_collab(uid, object_id.clone(), &db).await; - let json_2 = collab_from_disk.lock().to_json_value(); - assert_json_eq!(json_1, json_2); - }) - .await; -} - -pub fn setup_log() { - static START: Once = Once::new(); - START.call_once(|| { - tracing_wasm::set_as_global_default(); - }); -} - -pub async fn create_collab( - uid: i64, - doc_id: String, - db: &Arc, -) -> Arc { - let collab = Arc::new( - CollabBuilder::new(uid, &doc_id) - .with_device_id("1") - .build() - .unwrap(), - ); - let disk_plugin = IndexeddbDiskPlugin::new(uid, doc_id, CollabType::Document, Arc::downgrade(db)); - collab.lock().add_plugin(Box::new(disk_plugin)); - collab.lock().initialize(); - sleep(1000).await; - collab -} - -async fn sleep(ms: i32) { - let promise = Promise::new(&mut |resolve, _| { - let closure = Closure::once_into_js(move || { - resolve.call0(&JsValue::NULL).unwrap(); - }); - - window() - .unwrap() - .set_timeout_with_callback_and_timeout_and_arguments_0(closure.as_ref().unchecked_ref(), ms) - .unwrap(); - }); - - JsFuture::from(promise).await.unwrap(); -} diff --git a/collab-plugins/tests/web/indexeddb_test.rs b/collab-plugins/tests/web/indexeddb_test.rs deleted file mode 100644 index 3edfd2769..000000000 --- a/collab-plugins/tests/web/indexeddb_test.rs +++ /dev/null @@ -1,118 +0,0 @@ -use collab::entity::EncodedCollab; -use collab_plugins::local_storage::indexeddb::CollabIndexeddb; -use tokio::task::LocalSet; -use uuid::Uuid; -use wasm_bindgen_test::*; -use yrs::Doc; - -#[wasm_bindgen_test] -async fn indexeddb_put_and_get_encoded_collab_test() { - let local = LocalSet::new(); - local - .run_until(async { - let db = CollabIndexeddb::new().await.unwrap(); - let object_id = Uuid::new_v4().to_string(); - let uid: i64 = 1; - let encoded_collab = EncodedCollab { - state_vector: vec![1, 2, 3].into(), - doc_state: vec![4, 5, 6].into(), - version: collab::entity::EncoderVersion::V1, - }; - - db.create_doc(uid, &object_id, &encoded_collab) - .await - .unwrap(); - let encoded_collab_from_db = db.get_encoded_collab(uid, &object_id).await.unwrap(); - - assert_eq!( - encoded_collab.state_vector, - encoded_collab_from_db.state_vector - ); - assert_eq!(encoded_collab.doc_state, encoded_collab_from_db.doc_state); - }) - .await; -} - -#[wasm_bindgen_test] -async fn indexeddb_get_non_exist_encoded_collab_test() { - let local = LocalSet::new(); - local - .run_until(async { - let db = CollabIndexeddb::new().await.unwrap(); - let object_id = Uuid::new_v4().to_string(); - let doc = Doc::new(); - let uid: i64 = 1; - let error = db.load_doc(uid, &object_id, doc).await.unwrap_err(); - assert!(error.is_record_not_found()); - }) - .await; -} - -#[wasm_bindgen_test] -async fn indexeddb_push_update_test() { - let local = LocalSet::new(); - local - .run_until(async { - let db = CollabIndexeddb::new().await.unwrap(); - let object_id = Uuid::new_v4().to_string(); - let uid: i64 = 1; - - db.create_doc_id(uid, &object_id).await.unwrap(); - let update_1 = vec![1, 2, 3]; - db.push_update(uid, &object_id, &update_1).await.unwrap(); - - let update_2 = vec![4, 5, 6]; - db.push_update(uid, &object_id, &update_2).await.unwrap(); - - let update_3 = vec![7, 8, 9]; - db.push_update(uid, &object_id, &update_3).await.unwrap(); - - let update_4 = vec![10, 11, 12]; - db.push_update(uid, &object_id, &update_4).await.unwrap(); - - let updates = db.get_all_updates(uid, &object_id).await.unwrap(); - assert_eq!(updates.len(), 4); - assert_eq!(updates[0], update_1); - assert_eq!(updates[1], update_2); - assert_eq!(updates[2], update_3); - assert_eq!(updates[3], update_4); - }) - .await; -} - -#[wasm_bindgen_test] -async fn indexeddb_flush_doc_test() { - let local = LocalSet::new(); - local - .run_until(async { - let db = CollabIndexeddb::new().await.unwrap(); - let object_id = Uuid::new_v4().to_string(); - let uid: i64 = 1; - - db.create_doc_id(uid, &object_id).await.unwrap(); - let update_1 = vec![1, 2, 3]; - db.push_update(uid, &object_id, &update_1).await.unwrap(); - - let update_2 = vec![4, 5, 6]; - db.push_update(uid, &object_id, &update_2).await.unwrap(); - - let update_3 = vec![7, 8, 9]; - db.push_update(uid, &object_id, &update_3).await.unwrap(); - - let update_4 = vec![10, 11, 12]; - db.push_update(uid, &object_id, &update_4).await.unwrap(); - - let encoded_collab = EncodedCollab { - state_vector: vec![1, 2, 3].into(), - doc_state: vec![4, 5, 6].into(), - version: collab::entity::EncoderVersion::V1, - }; - db.flush_doc(uid, &object_id, &encoded_collab) - .await - .unwrap(); - - let updates = db.get_all_updates(uid, &object_id).await.unwrap(); - assert_eq!(updates.len(), 0); - }) - .await; -} diff --git a/collab-plugins/tests/web/mod.rs b/collab-plugins/tests/web/mod.rs deleted file mode 100644 index 821bd1efd..000000000 --- a/collab-plugins/tests/web/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -use wasm_bindgen_test::wasm_bindgen_test_configure; -wasm_bindgen_test_configure!(run_in_browser); - -mod edit_collab_test; -mod indexeddb_test; diff --git a/collab-plugins/tests/web/setup_tests.js b/collab-plugins/tests/web/setup_tests.js deleted file mode 100644 index 5ea989ae2..000000000 --- a/collab-plugins/tests/web/setup_tests.js +++ /dev/null @@ -1,6 +0,0 @@ -function get_current_timestamp() { - return Date.now(); -} - -// Expose the function to the global scope so it's accessible to the WASM module -global.get_current_timestamp = get_current_timestamp; diff --git a/collab-plugins/tests/web/test.md b/collab-plugins/tests/web/test.md deleted file mode 100644 index cd90faa9e..000000000 --- a/collab-plugins/tests/web/test.md +++ /dev/null @@ -1,17 +0,0 @@ - -## Run clippy for web - -```shell -cargo clippy --target=wasm32-unknown-unknown --fix --allow-dirty --features="wasm_build" -``` - -## Run tests in Chrome -```shell -wasm-pack test --chrome -``` - -## Build for web - -```shell -wasm-pack build -``` \ No newline at end of file diff --git a/collab-user/Cargo.toml b/collab-user/Cargo.toml deleted file mode 100644 index 9bd8154a4..000000000 --- a/collab-user/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "collab-user" -version = "0.2.0" -edition = "2024" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -uuid.workspace = true -serde.workspace = true -serde_json.workspace = true -anyhow.workspace = true -collab = { workspace = true } -collab-entity = { workspace = true } -tokio = { workspace = true, features = ["rt", "sync"] } -tokio-stream = { version = "0.1.14", features = ["sync"] } -tracing.workspace = true - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2", features = ["js"] } - -[dev-dependencies] -assert-json-diff = "2.0.2" -collab-plugins = { workspace = true } -fs_extra = "1.2.0" -nanoid = "0.4.0" -tempfile = "3.8.0" -tokio = { version = "1.26", features = ["rt", "macros"] } -uuid.workspace = true diff --git a/collab-user/src/lib.rs b/collab-user/src/lib.rs deleted file mode 100644 index 988f6671f..000000000 --- a/collab-user/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod reminder; -mod user_awareness; - -pub mod core { - pub use crate::reminder::*; - pub use crate::user_awareness::*; -} diff --git a/collab-user/tests/main.rs b/collab-user/tests/main.rs deleted file mode 100644 index 46078b37a..000000000 --- a/collab-user/tests/main.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod reminder_test; -mod util; diff --git a/collab/Cargo.toml b/collab/Cargo.toml index 8fa08c985..68f03fddd 100644 --- a/collab/Cargo.toml +++ b/collab/Cargo.toml @@ -16,7 +16,7 @@ serde = { workspace = true, features = ["rc"] } serde_json.workspace = true bytes = { workspace = true, features = ["serde"] } tracing.workspace = true -tokio = { workspace = true, features = ["sync", "rt"] } +tokio = { workspace = true, features = ["sync", "rt", "macros", "fs", "io-util"] } tokio-stream = { version = "0.1.14", features = ["sync"] } async-trait.workspace = true arc-swap.workspace = true @@ -27,24 +27,60 @@ unicode-segmentation = "1.10.1" lazy_static = "1.4.0" fastrand = "2.1.0" parking_lot = "0.12" - -[target.'cfg(target_arch = "wasm32")'.dependencies] -web-sys = { version = "0.3" } -js-sys = "0.3" +prost = "0.13.3" +futures = "0.3" +futures-lite.workspace = true +tokio-retry = "0.3" +similar = "2.2.1" +rand = { version = "0.8", optional = true } +smallvec = { version = "1.10", features = ["write", "union", "const_generics", "const_new"] } +nanoid = "0.4.0" +markdown = "1.0.0-alpha.21" +dashmap = "5" +strum = "0.25" +strum_macros = "0.25" +rayon = "1.10.0" +csv = "1.3.0" +tokio-util = "0.7" +rusty-money = { version = "0.4.1", features = ["iso"] } +fancy-regex = "0.13.0" +rust_decimal = "1.36.0" +chrono-tz = "0.10.0" +percent-encoding = "2.3.1" +sha2 = "0.10.8" +base64 = "0.22.1" +iana-time-zone = "0.1.61" +walkdir = "2.5.0" +fxhash = "0.2.1" +hex = "0.4.3" +async_zip = { version = "0.0.17", features = ["full"] } +async-recursion = "1.1" +sanitize-filename = "0.5.0" +indexmap = { version = "2.3", features = ["serde"] } +zip = "0.6.6" +rocksdb = { version = "0.22.0", default-features = false, features = ["zstd"], optional = true } [dev-dependencies] tokio = { workspace = true, features = ["macros", "sync", "rt"] } tempfile = "3.8.0" -collab = { path = "", features = ["default"] } -nanoid = "0.4.0" +collab = { path = "", default-features = false } chrono.workspace = true assert-json-diff = "2.0.2" tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } assert_matches2 = "0.1.2" +fs_extra = "1.2.0" +rand = "0.8.4" +tokio-test = "0.4" [features] default = [] +plugins = ["dep:rocksdb"] verbose_log = [] trace_transact = [] lock_timeout = [] -rwlock_reason = [] \ No newline at end of file +rwlock_reason = [] +import_csv = [] + +[build-dependencies] +prost-build = "0.12" +protoc-bin-vendored = "3.0.0" diff --git a/collab/MERGE_TODO.md b/collab/MERGE_TODO.md new file mode 100644 index 000000000..853e8d553 --- /dev/null +++ b/collab/MERGE_TODO.md @@ -0,0 +1,117 @@ +# Merge TODO: Consolidate Satellite Crates into `collab` + +This document tracks the work required to merge the standalone crates +(`collab-entity`, `collab-plugins`, `collab-document`, `collab-folder`, +`collab-user`, `collab-database`, and `collab-importer`) into the primary +`collab` crate. Tasks are ordered from lowest-level dependencies to the +highest-level consumers so that each merge simplifies the remaining ones. + +> **Move-only policy:** Each merge should relocate code and adjust module +> imports without altering business logic or behavior. Fix compiler errors by +> updating `mod` declarations and `use` paths rather than rewriting +> implementations. + +## Overall Preparation + +- [ ] Agree on success criteria (public API surface, feature flags, WASM + support, build targets). +- [ ] Capture a dependency snapshot (workspace `Cargo.toml`, crate feature + matrices, `build.rs` scripts, protobuf generation, and CI steps). +- [ ] Set up a tracking branch and ensure the workspace builds and tests pass + prior to any changes. +- [ ] Document the current module layout of `collab` to decide where each + crate's code will live after consolidation. +- [ ] Establish a move-only checklist: confirm every commit limits itself to + file moves, module path updates, and import fixes (no functional edits). +- [ ] Capture a map of current `use` paths so import updates can be applied + immediately after each relocation. + +## Merge Order and Tasks + +### 1. Integrate `collab-entity` (foundation crate) + +- [x] Move `collab-entity/src` modules into a new `collab::entity` (or similar) + module tree, preserving protobuf-generated code structure. +- [x] Fold `collab-entity`'s `build.rs` (prost invocation) and `proto/` + artifacts into the `collab` build script, ensuring path updates and reuse + of generated files. +- [x] Copy crate feature flags (if any) and shared dependencies (`prost`, + `bytes`, etc.) into `collab/Cargo.toml`, deduplicating versions. +- [x] Replace `collab-entity` imports across the workspace with the new + in-crate module path; remove the dependency from workspace members. +- [x] Run `cargo fmt`, `cargo check --all-features`, and targeted tests for + crates previously depending on `collab-entity`. + +### 2. Integrate `collab-plugins` (optional extensions) + +- [x] Relocate `collab-plugins/src` into `collab::plugins`, preserving + conditional `rocksdb`/WASM support. +- [x] Merge any plugin-specific feature flags and dependencies (e.g., + `tokio-retry`, optional `rand`, `rocksdb`) into `collab/Cargo.toml`. +- [x] Update `build.rs` or initialization hooks if plugins require runtime + registration; document the new public API surface. +- [x] Adjust downstream crates' dev-dependencies to use the in-crate modules. + +### 3. Integrate `collab-document` (document model) + +- [x] Move document modules into `collab::document`, ensuring the async APIs + still expose the same types. +- [x] Consolidate overlapping dependencies (`markdown`, `nanoid`, + `tokio-stream`) and align feature gating for WASM builds. +- [x] Update crate exports and re-export any types that other crates expect + from `collab-document`. +- [x] Remove the crate from the workspace manifest and update import paths. + +### 4. Integrate `collab-folder` (folder hierarchy) + +- [x] Migrate folder modules into `collab::folder`, including observers, + migration utilities, and section management code. +- [x] Resolve naming conflicts with existing `collab` modules (especially + shared types such as `ViewId`). +- [x] Transfer tests and fixtures; adapt them to the consolidated module + layout. +- [x] Drop the workspace dependency and update consumers (e.g., importer, + database) to the new module path. + +### 5. Integrate `collab-user` (user/session services) + +- [x] Embed user management modules under `collab::user` and relocate async + task handling utilities. +- [x] Merge dependency declarations (`tokio`, `tokio-stream`) and ensure + feature flags or cfg gates remain accurate for WASM builds. +- [x] Update references in higher-level crates and remove the standalone + package. + +### 6. Integrate `collab-database` (structured data layer) + +- [x] Bring database modules into `collab::database`, including import/export + helpers, locking abstractions, and type definitions. +- [x] Reconcile overlapping dependencies (e.g., `rayon`, `csv`, `rust_decimal`, + timezone utilities) with the consolidated `collab` manifest. +- [x] Port optional features such as `verbose_log` and `import_csv`, ensuring + they remain toggleable after the merge. +- [x] Update all runtime and dev consumers (including tests) to the new module + path, then remove the crate entry from the workspace. + +### 7. Integrate `collab-importer` (top-level orchestration) + +- [x] Move importer modules into `collab::importer`, wiring them to the newly + in-house folder, database, and document modules. +- [x] Simplify dependency configuration now that the importer references + in-crate modules; remove duplicate third-party dependencies where + possible. +- [x] Ensure importer-specific assets (e.g., `sanitize-filename`, `async_zip`) + are justified in the merged crate and documented. +- [x] Run the importer integration tests and regression scenarios that combine + folder/document/database flows. + +## Final Cleanup + +- [x] Delete the obsolete crate directories and adjust the workspace + `Cargo.toml`/`Cargo.lock` entries. +- [x] Update documentation (README, docs/) to reference the consolidated + `collab` crate API. +- [x] Review CI scripts for references to removed crates and update packaging + or publishing workflows. +- [x] Communicate the migration (release notes, internal announcements) and + plan for versioning the new unified crate. diff --git a/collab-entity/build.rs b/collab/build.rs similarity index 81% rename from collab-entity/build.rs rename to collab/build.rs index 8509928b9..f001701d3 100644 --- a/collab-entity/build.rs +++ b/collab/build.rs @@ -13,20 +13,20 @@ fn main() -> Result<(), Box> { }); let proto_files = vec![ - "proto/common.proto", - "proto/encoding.proto", - "proto/params.proto", + "proto/entity/common.proto", + "proto/entity/encoding.proto", + "proto/entity/params.proto", ]; for proto_file in &proto_files { println!("cargo:rerun-if-changed={}", proto_file); } prost_build::Config::new() - .out_dir("src/proto/") - .compile_protos(&proto_files, &["proto/"])?; + .out_dir("src/entity/proto/") + .compile_protos(&proto_files, &["proto/entity/"])?; // Run rustfmt on the generated files. - let files = std::fs::read_dir("src/")? + let files = std::fs::read_dir("src/entity/proto/")? .filter_map(Result::ok) .filter(|entry| { entry diff --git a/collab-entity/proto/common.proto b/collab/proto/entity/common.proto similarity index 100% rename from collab-entity/proto/common.proto rename to collab/proto/entity/common.proto diff --git a/collab-entity/proto/encoding.proto b/collab/proto/entity/encoding.proto similarity index 100% rename from collab-entity/proto/encoding.proto rename to collab/proto/entity/encoding.proto diff --git a/collab-entity/proto/params.proto b/collab/proto/entity/params.proto similarity index 100% rename from collab-entity/proto/params.proto rename to collab/proto/entity/params.proto diff --git a/collab/src/core/fill.rs b/collab/src/core/fill.rs index b49af2c1b..36b0fdb83 100644 --- a/collab/src/core/fill.rs +++ b/collab/src/core/fill.rs @@ -1,24 +1,19 @@ +use crate::error::CollabError; use crate::util::ArrayExt; use yrs::types::TypeRef; use yrs::{Any, Array, ArrayPrelim, ArrayRef, Map, MapPrelim, MapRef, SharedRef, TransactionMut}; -#[derive(Debug, thiserror::Error)] -pub enum FillError { - #[error("cannot fill {0} with: {0}")] - InvalidData(TypeRef, String), -} - /// Trait that allows to fill shared refs with data. pub trait FillRef where R: SharedRef, { - fn fill(self, txn: &mut TransactionMut, shared_ref: &R) -> Result<(), FillError>; + fn fill(self, txn: &mut TransactionMut, shared_ref: &R) -> Result<(), CollabError>; } impl FillRef for Any { - fn fill(self, txn: &mut TransactionMut, shared_ref: &MapRef) -> Result<(), FillError> { + fn fill(self, txn: &mut TransactionMut, shared_ref: &MapRef) -> Result<(), CollabError> { match self { Any::Map(map) => { for (key, value) in map.iter() { @@ -40,13 +35,13 @@ impl FillRef for Any { } Ok(()) }, - _ => Err(FillError::InvalidData(TypeRef::Map, self.to_string())), + _ => Err(CollabError::FillInvalidData(TypeRef::Map, self.to_string())), } } } impl FillRef for Any { - fn fill(self, txn: &mut TransactionMut, shared_ref: &ArrayRef) -> Result<(), FillError> { + fn fill(self, txn: &mut TransactionMut, shared_ref: &ArrayRef) -> Result<(), CollabError> { match self { Any::Array(array) => { shared_ref.clear(txn); @@ -56,7 +51,10 @@ impl FillRef for Any { } Ok(()) }, - _ => Err(FillError::InvalidData(TypeRef::Array, self.to_string())), + _ => Err(CollabError::FillInvalidData( + TypeRef::Array, + self.to_string(), + )), } } } diff --git a/collab-database/src/blocks/block.rs b/collab/src/database/blocks/block.rs similarity index 91% rename from collab-database/src/blocks/block.rs rename to collab/src/database/blocks/block.rs index d888c30ee..7496c6fe2 100644 --- a/collab-database/src/blocks/block.rs +++ b/collab/src/database/blocks/block.rs @@ -1,17 +1,17 @@ -use crate::error::DatabaseError; -use crate::rows::{ +use crate::database::rows::{ Cell, CreateRowParams, DatabaseRow, Row, RowChangeSender, RowDetail, RowMeta, RowMetaKey, RowMetaUpdate, RowUpdate, meta_id_from_row_id, }; -use crate::views::RowOrder; -use collab_entity::uuid_validation::{DatabaseId, RowId}; +use crate::database::views::RowOrder; +use crate::entity::uuid_validation::{DatabaseId, RowId}; +use crate::error::CollabError; -use collab::lock::RwLock; +use crate::lock::RwLock; use std::sync::Arc; use tokio::sync::broadcast; use tokio::sync::broadcast::Sender; -use crate::database_trait::{DatabaseRowCollabService, DatabaseRowDataVariant}; +use crate::database::database_trait::{DatabaseRowCollabService, DatabaseRowDataVariant}; use tracing::{instrument, trace}; use yrs::block::ClientID; @@ -21,8 +21,7 @@ pub enum BlockEvent { DidFetchRow(Vec), } -pub type InitRowChan = - tokio::sync::oneshot::Sender>, DatabaseError>>; +pub type InitRowChan = tokio::sync::oneshot::Sender>, CollabError>>; /// Each [Block] contains a list of [DatabaseRow]s. Each [DatabaseRow] represents a row in the database. /// Currently, we only use one [Block] to manage all the rows in the database. In the future, we @@ -54,7 +53,7 @@ impl Block { self.notifier.subscribe() } - pub async fn batch_load_rows(&self, row_ids: Vec) -> Result<(), DatabaseError> { + pub async fn batch_load_rows(&self, row_ids: Vec) -> Result<(), CollabError> { let cloned_notifier = self.notifier.clone(); let mut row_on_disk_details = vec![]; for row_id in row_ids.into_iter() { @@ -93,7 +92,7 @@ impl Block { &self, row_params: T, _client_id: ClientID, - ) -> Result { + ) -> Result { let params = row_params.into(); let row: Row = params.clone().into(); let row_id = row.id; @@ -211,18 +210,18 @@ impl Block { pub async fn get_or_init_database_row( &self, row_id: &RowId, - ) -> Result>, DatabaseError> { + ) -> Result>, CollabError> { let (tx, rx) = tokio::sync::oneshot::channel(); self.init_database_row(row_id, Some(tx)); rx.await - .map_err(|e| DatabaseError::Internal(anyhow::anyhow!(e)))? + .map_err(|e| CollabError::Internal(anyhow::anyhow!(e)))? } pub async fn init_database_rows( &self, row_ids: Vec, auto_fetch: bool, - ) -> Result>>, DatabaseError> { + ) -> Result>>, CollabError> { // Retain only rows that are not in the cache let uncached_rows = self .collab_service diff --git a/collab-database/src/blocks/mod.rs b/collab/src/database/blocks/mod.rs similarity index 100% rename from collab-database/src/blocks/mod.rs rename to collab/src/database/blocks/mod.rs diff --git a/collab-database/src/database.rs b/collab/src/database/database.rs similarity index 94% rename from collab-database/src/database.rs rename to collab/src/database/database.rs index 5c7594f09..fc76043bb 100644 --- a/collab-database/src/database.rs +++ b/collab/src/database/database.rs @@ -5,51 +5,53 @@ use std::ops::{Deref, DerefMut}; use anyhow::anyhow; -use crate::blocks::{Block, BlockEvent, InitRowChan}; -use crate::database_state::DatabaseNotify; -use crate::error::DatabaseError; -use crate::fields::{ +use crate::database::blocks::{Block, BlockEvent, InitRowChan}; +use crate::database::database_state::DatabaseNotify; +use crate::database::fields::{ Field, FieldChangeReceiver, FieldMap, FieldUpdate, TypeOptionCellReader, TypeOptionCellWriter, type_option_cell_reader, type_option_cell_writer, }; -use crate::meta::MetaMap; -use crate::rows::{ +use crate::database::meta::MetaMap; +use crate::database::rows::{ CreateRowParams, CreateRowParamsValidator, DatabaseRow, Row, RowCell, RowChangeReceiver, RowDetail, RowMeta, RowMetaKey, RowMetaUpdate, RowUpdate, meta_id_from_row_id, }; -use crate::util::encoded_collab; -use crate::views::define::DATABASE_VIEW_ROW_ORDERS; -use crate::views::{ +use crate::database::util::encoded_collab; +use crate::database::views::define::DATABASE_VIEW_ROW_ORDERS; +use crate::database::views::{ CalculationMap, DatabaseLayout, DatabaseViewUpdate, DatabaseViews, FieldOrder, FieldSettingsByFieldIdMap, FieldSettingsMap, FilterMap, GroupSettingMap, LayoutSetting, OrderArray, OrderObjectPosition, RowOrder, RowOrderArray, SortMap, ViewChangeReceiver, }; -use crate::workspace_database::DatabaseMeta; -use collab_entity::uuid_validation::{RowId, try_parse_database_view_id}; +use crate::database::workspace_database::DatabaseMeta; +use crate::entity::uuid_validation::{RowId, try_parse_database_view_id}; +use crate::error::CollabError; -use crate::entity::{ +use crate::database::entity::{ CreateDatabaseParams, CreateViewParams, CreateViewParamsValidator, DatabaseView, DatabaseViewMeta, EncodedCollabInfo, EncodedDatabase, FieldType, }; -use crate::template::entity::DatabaseTemplate; - -use collab::core::origin::CollabOrigin; -use collab::lock::RwLock; -use collab::preclude::{ +use crate::database::template::entity::DatabaseTemplate; + +use crate::core::origin::CollabOrigin; +use crate::entity::CollabType; +use crate::entity::define::{DATABASE, DATABASE_ID, DATABASE_METAS}; +use crate::entity::uuid_validation::{DatabaseId, DatabaseViewId}; +use crate::lock::RwLock; +use crate::preclude::{ Any, Array, Collab, FillRef, JsonValue, Map, MapExt, MapPrelim, MapRef, ReadTxn, ToJson, TransactionMut, YrsValue, }; -use collab::util::{AnyExt, ArrayExt}; -use collab_entity::CollabType; -use collab_entity::define::{DATABASE, DATABASE_ID, DATABASE_METAS}; -use collab_entity::uuid_validation::{DatabaseId, DatabaseViewId}; +use crate::util::{AnyExt, ArrayExt}; use futures::stream; use futures::stream::{BoxStream, StreamExt}; use nanoid::nanoid; -use crate::database_trait::{DatabaseCollabService, DatabaseDataVariant, DatabaseRowCollabService}; -use collab::core::collab::CollabOptions; +use crate::core::collab::CollabOptions; +use crate::database::database_trait::{ + DatabaseCollabService, DatabaseDataVariant, DatabaseRowCollabService, +}; use futures::future::join_all; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -99,12 +101,12 @@ pub async fn default_database_collab( client_id: ClientID, params: Option, context: DatabaseContext, -) -> Result<(DatabaseBody, Collab), DatabaseError> { +) -> Result<(DatabaseBody, Collab), CollabError> { let collab = Collab::new_with_options( CollabOrigin::Empty, CollabOptions::new(*database_id, client_id), ) - .map_err(|e| DatabaseError::Internal(e.into()))?; + .map_err(|e| CollabError::Internal(e.into()))?; let collab = match params { None => DatabaseBody::create(collab, *database_id, context, vec![], vec![], vec![]).await?, Some(params) => { @@ -129,12 +131,14 @@ impl Database { pub async fn arc_open( database_id: &str, context: DatabaseContext, - ) -> Result>, DatabaseError> { + ) -> Result>, CollabError> { if database_id.is_empty() { - return Err(DatabaseError::InvalidDatabaseID("database_id is empty")); + return Err(CollabError::DatabaseInvalidId( + "database_id is empty".to_string(), + )); } - let object_id = Uuid::parse_str(database_id).map_err(|e| DatabaseError::Internal(e.into()))?; + let object_id = Uuid::parse_str(database_id).map_err(|e| CollabError::Internal(e.into()))?; let collab = context .database_collab_service .clone() @@ -144,12 +148,14 @@ impl Database { Ok(collab) } - pub async fn open(database_id: &str, context: DatabaseContext) -> Result { + pub async fn open(database_id: &str, context: DatabaseContext) -> Result { if database_id.is_empty() { - return Err(DatabaseError::InvalidDatabaseID("database_id is empty")); + return Err(CollabError::DatabaseInvalidId( + "database_id is empty".to_string(), + )); } - let object_id = Uuid::parse_str(database_id).map_err(|e| DatabaseError::Internal(e.into()))?; + let object_id = Uuid::parse_str(database_id).map_err(|e| CollabError::Internal(e.into()))?; let database = context .database_collab_service .clone() @@ -162,7 +168,7 @@ impl Database { pub async fn create( context: DatabaseContext, params: CreateDatabaseParams, - ) -> Result { + ) -> Result { trace!( "[Database] create {}, client_id: {}", params.database_id, @@ -187,7 +193,7 @@ impl Database { pub async fn arc_create( context: DatabaseContext, params: CreateDatabaseParams, - ) -> Result>, DatabaseError> { + ) -> Result>, CollabError> { trace!( "[Database] create {}, client_id: {}", params.database_id, @@ -212,7 +218,7 @@ impl Database { template: T, database_collab_service: Arc, database_row_collab_service: Arc, - ) -> Result + ) -> Result where T: TryInto + Send + Sync + 'static, >::Error: ToString, @@ -220,10 +226,10 @@ impl Database { let params = tokio::task::spawn_blocking(move || { template .try_into() - .map_err(|err| DatabaseError::ImportData(err.to_string())) + .map_err(|err| CollabError::DatabaseImportData(err.to_string())) }) .await - .map_err(|e| DatabaseError::Internal(e.into()))?? + .map_err(|e| CollabError::Internal(e.into()))?? .into_params()?; let context = DatabaseContext { @@ -240,7 +246,7 @@ impl Database { pub async fn create_arc_with_view( params: CreateDatabaseParams, context: DatabaseContext, - ) -> Result>, DatabaseError> { + ) -> Result>, CollabError> { let database = Self::arc_create(context, params).await?; Ok(database) } @@ -248,12 +254,12 @@ impl Database { pub async fn create_with_view( params: CreateDatabaseParams, context: DatabaseContext, - ) -> Result { + ) -> Result { let database = Self::create(context, params).await?; Ok(database) } - pub async fn encode_database_collabs(&self) -> Result { + pub async fn encode_database_collabs(&self) -> Result { let database_id = *self.collab.object_id(); let encoded_database_collab = EncodedCollabInfo { object_id: database_id, @@ -303,7 +309,7 @@ impl Database { }) } - pub fn validate(&self) -> Result<(), DatabaseError> { + pub fn validate(&self) -> Result<(), CollabError> { CollabType::Database.validate_require_data(&self.collab)?; Ok(()) } @@ -371,7 +377,7 @@ impl Database { } /// Return the database id with a transaction - pub fn get_database_id(&self) -> Result { + pub fn get_database_id(&self) -> Result { let txn = self.collab.transact(); self.body.get_database_id(&txn) } @@ -380,7 +386,7 @@ impl Database { /// This row will be inserted to the end of rows of each view that /// reference the given database. Return the row order if the row is /// created successfully. Otherwise, return None. - pub async fn create_row(&mut self, params: CreateRowParams) -> Result { + pub async fn create_row(&mut self, params: CreateRowParams) -> Result { let client_id = self.collab_service.database_client_id().await; let params = CreateRowParamsValidator::validate(params)?; let row_order = self.body.block.create_new_row(params, client_id).await?; @@ -423,7 +429,7 @@ impl Database { &mut self, view_id: &str, params: CreateRowParams, - ) -> Result<(usize, RowOrder), DatabaseError> { + ) -> Result<(usize, RowOrder), CollabError> { let client_id = self.collab_service.database_client_id().await; let row_position = params.row_position.clone(); let row_order = self.body.create_row(params, client_id).await?; @@ -495,7 +501,7 @@ impl Database { } /// Return the [Row] with the given row id. - pub async fn get_row(&self, row_id: &RowId) -> Result { + pub async fn get_row(&self, row_id: &RowId) -> Result { let row = self.body.block.get_database_row(row_id).await; let database_id = self.get_database_id()?; match row { @@ -548,7 +554,7 @@ impl Database { chunk_size: usize, cancel_token: Option, auto_fetch: bool, - ) -> BoxStream<'a, Result>, DatabaseError>> { + ) -> BoxStream<'a, Result>, CollabError>> { let row_ids_chunk_stream = stream::iter( row_ids .into_iter() @@ -566,7 +572,7 @@ impl Database { async move { if let Some(ref token) = cancel_token { if token.is_cancelled() { - return Err(DatabaseError::ActionCancelled); + return Err(CollabError::DatabaseActionCancelled); } } @@ -616,7 +622,7 @@ impl Database { chunk_size: usize, cancel_token: Option, auto_fetch: bool, - ) -> Result>, DatabaseError> { + ) -> Result>, CollabError> { let row_orders = self.get_row_orders_for_view(view_id); self .get_rows_from_row_orders(row_orders, chunk_size, cancel_token, auto_fetch) @@ -653,7 +659,7 @@ impl Database { chunk_size: usize, cancel_token: Option, auto_fetch: bool, - ) -> Result>, DatabaseError> { + ) -> Result>, CollabError> { let row_ids = row_orders.iter().map(|order| order.id).collect(); let rows_stream = self.init_database_rows(row_ids, chunk_size, cancel_token, auto_fetch); let database_id = self.get_database_id()?; @@ -1350,7 +1356,7 @@ impl Database { } /// Create a linked view to existing database - pub fn create_linked_view(&mut self, params: CreateViewParams) -> Result<(), DatabaseError> { + pub fn create_linked_view(&mut self, params: CreateViewParams) -> Result<(), CollabError> { let mut txn = self.collab.transact_mut(); let inline_view_id = self.body.get_inline_view_id(&txn); let inline_view_id = self.body.parse_view_id(&inline_view_id)?; @@ -1395,7 +1401,7 @@ impl Database { pub async fn duplicate_row( &self, row_id: &RowId, - ) -> Result, DatabaseError> { + ) -> Result, CollabError> { let database_id = self.get_database_id()?; let Some(database_row) = self.body.block.get_database_row(row_id).await else { return Ok(None); @@ -1454,7 +1460,7 @@ impl Database { &self, chunk_size: usize, auto_fetch: bool, - ) -> Result { + ) -> Result { let txn = self.collab.transact(); let database_id = self.body.get_database_id(&txn)?; @@ -1489,7 +1495,7 @@ impl Database { self.body.views.get_view(&txn, &view_id) } - pub async fn to_json_value(&self) -> Result { + pub async fn to_json_value(&self) -> Result { let database_data = self.get_database_data(20, false).await?; Ok(serde_json::to_value(&database_data).unwrap()) } @@ -1499,7 +1505,7 @@ impl Database { chunk_size: usize, cancel_token: Option, auto_fetch: bool, - ) -> Result>, DatabaseError> { + ) -> Result>, CollabError> { let row_orders = { let txn = self.collab.transact(); let inline_view_id = self.body.get_inline_view_id(&txn); @@ -1517,7 +1523,7 @@ impl Database { pub async fn collect_all_rows( &self, auto_fetch: bool, - ) -> Result>, DatabaseError> { + ) -> Result>, CollabError> { let rows_stream = self.get_all_rows(20, None, auto_fetch).await?; Ok(rows_stream.collect::>().await) } @@ -1620,13 +1626,13 @@ pub fn gen_database_file_id() -> String { uuid::Uuid::new_v4().to_string() } -pub fn gen_row_id() -> collab_entity::uuid_validation::RowId { +pub fn gen_row_id() -> crate::entity::uuid_validation::RowId { uuid::Uuid::new_v4() } pub fn get_row_document_id( - row_id: &collab_entity::uuid_validation::RowId, -) -> Result { + row_id: &crate::entity::uuid_validation::RowId, +) -> Result { Ok(meta_id_from_row_id(row_id, RowMetaKey::DocumentId)) } @@ -1667,21 +1673,21 @@ pub struct DatabaseData { } impl DatabaseData { - pub fn to_json(&self) -> Result { + pub fn to_json(&self) -> Result { let s = serde_json::to_string(self)?; Ok(s) } - pub fn from_json(json: &str) -> Result { + pub fn from_json(json: &str) -> Result { let database = serde_json::from_str(json)?; Ok(database) } - pub fn to_json_bytes(&self) -> Result, DatabaseError> { + pub fn to_json_bytes(&self) -> Result, CollabError> { Ok(self.to_json()?.as_bytes().to_vec()) } - pub fn from_json_bytes(json: Vec) -> Result { + pub fn from_json_bytes(json: Vec) -> Result { let database = serde_json::from_slice(&json)?; Ok(database) } @@ -1708,21 +1714,21 @@ pub fn get_database_row_ids(collab: &Collab) -> Option> { ) } -pub fn reset_inline_view_id(collab: &mut Collab, f: F) -> Result<(), DatabaseError> +pub fn reset_inline_view_id(collab: &mut Collab, f: F) -> Result<(), CollabError> where F: FnOnce(String) -> String, { let mut txn = collab.context.transact_mut(); if let Some(container) = collab.data.get_with_path(&txn, [DATABASE, DATABASE_METAS]) { let map = MetaMap::new(container); - let inline_view_id = map.get_inline_view_id(&txn).ok_or_else(|| { - DatabaseError::NoRequiredData("Can not find the inline view id".to_string()) - })?; + let inline_view_id = map + .get_inline_view_id(&txn) + .ok_or_else(|| CollabError::NoRequiredData("Can not find the inline view id".to_string()))?; let new_inline_view_id = f(inline_view_id); map.set_inline_view_id(&mut txn, &new_inline_view_id); Ok(()) } else { - Err(DatabaseError::NoRequiredData( + Err(CollabError::NoRequiredData( "Can not find the database metas".to_string(), )) } @@ -1788,14 +1794,14 @@ pub struct DatabaseBody { } impl DatabaseBody { - pub fn open(collab: Collab, context: DatabaseContext) -> Result<(Self, Collab), DatabaseError> { + pub fn open(collab: Collab, context: DatabaseContext) -> Result<(Self, Collab), CollabError> { CollabType::Database.validate_require_data(&collab)?; let body = Self::from_collab( &collab, context.database_row_collab_service, Some(context.notifier), ) - .ok_or_else(|| DatabaseError::NoRequiredData("Can not open database".to_string()))?; + .ok_or_else(|| CollabError::NoRequiredData("Can not open database".to_string()))?; Ok((body, collab)) } @@ -1806,7 +1812,7 @@ impl DatabaseBody { new_rows: Vec, new_fields: Vec, new_views: Vec, - ) -> Result<(Self, Collab), DatabaseError> { + ) -> Result<(Self, Collab), CollabError> { let origin = collab.origin().clone(); let mut txn = collab.context.transact_mut(); let root: MapRef = collab.data.get_or_init(&mut txn, DATABASE); @@ -1891,7 +1897,7 @@ impl DatabaseBody { }; let root: MapRef = collab.data.get_with_txn(&txn, DATABASE)?; let database_id_str: String = root.get_with_txn(&txn, DATABASE_ID)?; - let database_id = collab_entity::uuid_validation::try_parse_database_id(&database_id_str)?; + let database_id = crate::entity::uuid_validation::try_parse_database_id(&database_id_str)?; let fields: MapRef = root.get_with_txn(&txn, FIELDS)?; // { DATABASE: { FIELDS: {:} } } let views: MapRef = root.get_with_txn(&txn, VIEWS)?; // { DATABASE: { FIELDS: {:}, VIEWS: {:} } } let metas: MapRef = root.get_with_txn(&txn, DATABASE_METAS)?; // { DATABASE: { FIELDS: {:}, VIEWS: {:}, METAS: {:} } } @@ -1960,13 +1966,13 @@ impl DatabaseBody { inline_view_id } - pub fn get_database_id(&self, txn: &T) -> Result { + pub fn get_database_id(&self, txn: &T) -> Result { let database_id_str: String = self .root .get_with_txn(txn, DATABASE_ID) - .ok_or_else(|| DatabaseError::Internal(anyhow!("Database ID not found")))?; - collab_entity::uuid_validation::try_parse_database_id(&database_id_str).ok_or_else(|| { - DatabaseError::Internal(anyhow!("Invalid database ID format: {}", database_id_str)) + .ok_or_else(|| CollabError::Internal(anyhow!("Database ID not found")))?; + crate::entity::uuid_validation::try_parse_database_id(&database_id_str).ok_or_else(|| { + CollabError::Internal(anyhow!("Invalid database ID format: {}", database_id_str)) }) } @@ -1977,7 +1983,7 @@ impl DatabaseBody { &self, params: CreateRowParams, client_id: ClientID, - ) -> Result { + ) -> Result { let row_order = self.block.create_new_row(params, client_id).await?; Ok(row_order) } @@ -2163,7 +2169,7 @@ impl DatabaseBody { params: CreateViewParams, field_orders: Vec, row_orders: Vec, - ) -> Result<(), DatabaseError> { + ) -> Result<(), CollabError> { let params = CreateViewParamsValidator::validate(params)?; let database_id = self.get_database_id(txn)?; let view = DatabaseView { @@ -2197,7 +2203,7 @@ impl DatabaseBody { params: CreateViewParams, field_orders: Vec, row_orders: Vec, - ) -> Result<(), DatabaseError> { + ) -> Result<(), CollabError> { let mut params = CreateViewParamsValidator::validate(params)?; let (deps_fields, deps_field_settings) = params.take_deps_fields(); @@ -2223,9 +2229,9 @@ impl DatabaseBody { } /// Helper function to safely convert string view ID to DatabaseViewId - fn parse_view_id(&self, view_id: &str) -> Result { + fn parse_view_id(&self, view_id: &str) -> Result { try_parse_database_view_id(view_id).ok_or_else(|| { - DatabaseError::InvalidDatabaseViewId(format!("Invalid UUID format for view_id: {}", view_id)) + CollabError::DatabaseInvalidViewId(format!("Invalid UUID format for view_id: {}", view_id)) }) } } @@ -2233,7 +2239,7 @@ impl DatabaseBody { pub fn try_fixing_database( collab: &mut Collab, database_meta: DatabaseMeta, -) -> Result<(), DatabaseError> { +) -> Result<(), CollabError> { // check if inline view id let inline_view_id = { let txn = collab.context.transact(); diff --git a/collab-database/src/database_remapper.rs b/collab/src/database/database_remapper.rs similarity index 87% rename from collab-database/src/database_remapper.rs rename to collab/src/database/database_remapper.rs index 71e711b2a..27603c2e1 100644 --- a/collab-database/src/database_remapper.rs +++ b/collab/src/database/database_remapper.rs @@ -1,22 +1,23 @@ -use collab::core::collab::{CollabOptions, DataSource}; -use collab::core::origin::CollabOrigin; +use crate::core::collab::{CollabOptions, DataSource}; +use crate::core::origin::CollabOrigin; -use collab::preclude::*; +use crate::preclude::*; use std::collections::HashMap; use std::sync::Arc; use uuid::Uuid; -use crate::database::timestamp; -use crate::database::{ +use crate::database::database::timestamp; +use crate::database::database::{ Database, DatabaseBody, DatabaseContext, DatabaseData, default_database_collab, }; -use crate::database_trait::NoPersistenceDatabaseCollabService; -use crate::entity::{CreateDatabaseParams, CreateViewParams, DatabaseView}; -use crate::error::DatabaseError; -use crate::rows::{CreateRowParams, Row, RowMeta}; -use crate::views::{OrderObjectPosition, RowOrder}; -use collab_entity::CollabType; -use collab_entity::uuid_validation::RowId; +use crate::database::database_trait::NoPersistenceDatabaseCollabService; +use crate::database::entity::{CreateDatabaseParams, CreateViewParams, DatabaseView}; +use crate::database::rows::{CreateRowParams, Row, RowMeta}; +use crate::database::util::encoded_collab; +use crate::database::views::{OrderObjectPosition, RowOrder}; +use crate::entity::CollabType; +use crate::entity::uuid_validation::RowId; +use crate::error::CollabError; pub struct DatabaseCollabRemapper { id_mapping: HashMap, @@ -48,7 +49,7 @@ impl DatabaseCollabRemapper { database_id: &str, user_id: &str, db_state: &[u8], - ) -> Result, DatabaseError> { + ) -> Result, CollabError> { let database_data = self .collab_bytes_to_database_data(database_id, user_id, db_state) .await?; @@ -65,19 +66,19 @@ impl DatabaseCollabRemapper { database_id: &str, user_id: &str, db_state: &[u8], - ) -> Result { + ) -> Result { let client_id = user_id.parse::().unwrap_or(0); let data_source = DataSource::DocStateV1(db_state.to_owned()); let database_uuid = - Uuid::parse_str(database_id).map_err(|err| DatabaseError::Internal(err.into()))?; + Uuid::parse_str(database_id).map_err(|err| CollabError::Internal(err.into()))?; let options = CollabOptions::new(database_uuid, client_id).with_data_source(data_source); let collab = Collab::new_with_options(CollabOrigin::Empty, options) - .map_err(|e| DatabaseError::Internal(anyhow::Error::new(e)))?; + .map_err(|e| CollabError::Internal(anyhow::Error::new(e)))?; let collab_service = Arc::new(NoPersistenceDatabaseCollabService::new(client_id)); let database_body = DatabaseBody::from_collab(&collab, collab_service.clone(), None) .ok_or_else(|| { - DatabaseError::NoRequiredData("Cannot parse database from collab".to_string()) + CollabError::NoRequiredData("Cannot parse database from collab".to_string()) })?; let database = Database { collab, @@ -93,7 +94,7 @@ impl DatabaseCollabRemapper { database_data: DatabaseData, _database_id: &str, user_id: &str, - ) -> Result, DatabaseError> { + ) -> Result, CollabError> { let client_id = user_id.parse::().unwrap_or(0); let remapped_database_id = database_data.database_id; @@ -112,7 +113,7 @@ impl DatabaseCollabRemapper { ) .await?; - let encoded_collab = crate::util::encoded_collab(&collab, &CollabType::Database)?; + let encoded_collab = encoded_collab(&collab, &CollabType::Database)?; let bytes = encoded_collab.doc_state.to_vec(); @@ -226,7 +227,7 @@ impl DatabaseCollabRemapper { pub fn remap_database_data( &self, mut database_data: DatabaseData, - ) -> Result { + ) -> Result { if let Some(new_database_id) = self.id_mapping.get(&database_data.database_id) { database_data.database_id = *new_database_id; } diff --git a/collab-database/src/database_state.rs b/collab/src/database/database_state.rs similarity index 78% rename from collab-database/src/database_state.rs rename to collab/src/database/database_state.rs index d9cba2010..799b18982 100644 --- a/collab-database/src/database_state.rs +++ b/collab/src/database/database_state.rs @@ -1,8 +1,8 @@ -use crate::fields::FieldChangeSender; +use crate::database::fields::FieldChangeSender; use tokio::sync::broadcast; -use crate::rows::RowChangeSender; -use crate::views::ViewChangeSender; +use crate::database::rows::RowChangeSender; +use crate::database::views::ViewChangeSender; #[derive(Clone)] pub struct DatabaseNotify { diff --git a/collab-database/src/database_trait.rs b/collab/src/database/database_trait.rs similarity index 87% rename from collab-database/src/database_trait.rs rename to collab/src/database/database_trait.rs index 6a0c272c7..33308df48 100644 --- a/collab-database/src/database_trait.rs +++ b/collab/src/database/database_trait.rs @@ -1,19 +1,18 @@ -use crate::database::{Database, DatabaseBody, DatabaseContext, default_database_collab}; - -use crate::entity::CreateDatabaseParams; -use crate::error::DatabaseError; -use crate::rows::{DatabaseRow, Row, RowChangeSender, default_database_row_from_row}; +use crate::database::database::{Database, DatabaseBody, DatabaseContext, default_database_collab}; + +use crate::core::collab::{CollabOptions, DataSource}; +use crate::core::collab_plugin::CollabPersistence; +use crate::core::origin::CollabOrigin; +use crate::database::entity::CreateDatabaseParams; +use crate::database::rows::{DatabaseRow, Row, RowChangeSender, default_database_row_from_row}; +use crate::entity::CollabType; +use crate::entity::EncodedCollab; +use crate::entity::uuid_validation::{ObjectId, RowId}; +use crate::error::CollabError; +use crate::lock::RwLock; +use crate::preclude::Collab; use anyhow::anyhow; use async_trait::async_trait; -use collab::core::collab::{CollabOptions, DataSource}; -use collab::core::collab_plugin::CollabPersistence; -use collab::core::origin::CollabOrigin; -use collab::entity::EncodedCollab; -use collab::error::CollabError; -use collab::lock::RwLock; -use collab::preclude::Collab; -use collab_entity::CollabType; -use collab_entity::uuid_validation::{ObjectId, RowId}; use dashmap::DashMap; use futures::future::join_all; use rayon::prelude::*; @@ -59,7 +58,7 @@ pub trait DatabaseCollabService: Send + Sync + 'static { is_new: bool, data: Option, context: DatabaseContext, - ) -> Result>, DatabaseError> { + ) -> Result>, CollabError> { let database = self .build_database(object_id, is_new, data, context) .await?; @@ -72,13 +71,13 @@ pub trait DatabaseCollabService: Send + Sync + 'static { is_new: bool, data: Option, context: DatabaseContext, - ) -> Result; + ) -> Result; async fn build_workspace_database_collab( &self, object_id: &ObjectId, encoded_collab: Option, - ) -> Result; + ) -> Result; fn persistence(&self) -> Option>; } @@ -92,21 +91,21 @@ pub trait DatabaseRowCollabService: Send + Sync + 'static { row_id: &RowId, data: DatabaseRowDataVariant, sender: Option, - ) -> Result>, DatabaseError>; + ) -> Result>, CollabError>; async fn build_arc_database_row( &self, row_id: &RowId, data: Option, sender: Option, - ) -> Result>, DatabaseError>; + ) -> Result>, CollabError>; async fn batch_build_arc_database_row( &self, row_ids: &[RowId], sender: Option, auto_fetch: bool, - ) -> Result>>, DatabaseError>; + ) -> Result>>, CollabError>; } #[async_trait] @@ -117,13 +116,13 @@ pub trait DatabaseCollabReader: Send + Sync + 'static { &self, object_id: &ObjectId, collab_type: CollabType, - ) -> Result; + ) -> Result; async fn reader_batch_get_collabs( &self, object_ids: Vec, collab_type: CollabType, - ) -> Result; + ) -> Result; fn reader_persistence(&self) -> Option> { None @@ -147,7 +146,7 @@ where _is_new: bool, data: Option, context: DatabaseContext, - ) -> Result { + ) -> Result { let client_id = self.reader_client_id().await; let collab_service = context.database_collab_service.clone(); let collab_type = CollabType::Database; @@ -182,7 +181,7 @@ where &self, object_id: &ObjectId, encoded_collab: Option, - ) -> Result { + ) -> Result { let collab_type = CollabType::WorkspaceDatabase; let client_id = self.reader_client_id().await; match encoded_collab { @@ -219,7 +218,7 @@ where row_id: &RowId, data: DatabaseRowDataVariant, sender: Option, - ) -> Result>, DatabaseError> { + ) -> Result>, CollabError> { let client_id = self.reader_client_id().await; let collab_type = CollabType::DatabaseRow; let data = data.into_encode_collab(client_id); @@ -241,7 +240,7 @@ where row_id: &RowId, data: Option, sender: Option, - ) -> Result>, DatabaseError> { + ) -> Result>, CollabError> { if let Some(cache) = self.database_row_cache() { if let Some(cached_row) = cache.get(row_id) { return Ok(cached_row.clone()); @@ -269,7 +268,7 @@ where row_ids: &[RowId], sender: Option, _auto_fetch: bool, - ) -> Result>>, DatabaseError> { + ) -> Result>>, CollabError> { let mut result = HashMap::new(); let mut uncached_row_ids = Vec::new(); @@ -308,7 +307,7 @@ where sender, ) .await?; - Ok::<_, DatabaseError>((row_id, database_row)) + Ok::<_, CollabError>((row_id, database_row)) } }); @@ -330,7 +329,7 @@ async fn build_collab( object_id: &ObjectId, _object_type: CollabType, encoded_collab: EncodedCollab, -) -> Result { +) -> Result { let options = CollabOptions::new(*object_id, client_id).with_data_source(encoded_collab.into()); Ok(Collab::new_with_options(CollabOrigin::Empty, options).unwrap()) } @@ -367,8 +366,8 @@ impl DatabaseCollabReader for NoPersistenceDatabaseCollabService { &self, object_id: &ObjectId, _collab_type: CollabType, - ) -> Result { - Err(DatabaseError::Internal(anyhow!( + ) -> Result { + Err(CollabError::Internal(anyhow!( "No persistence service available to get collab for {}", object_id ))) @@ -378,7 +377,7 @@ impl DatabaseCollabReader for NoPersistenceDatabaseCollabService { &self, object_ids: Vec, collab_type: CollabType, - ) -> Result { + ) -> Result { let map: HashMap = object_ids .into_par_iter() .filter_map(|object_id| { @@ -386,14 +385,14 @@ impl DatabaseCollabReader for NoPersistenceDatabaseCollabService { let options = CollabOptions::new(object_id, self.client_id) .with_data_source(CollabPersistenceImpl { persistence }.into()); let result = Collab::new_with_options(CollabOrigin::Empty, options) - .map_err(|err| DatabaseError::Internal(err.into())) + .map_err(|err| CollabError::Internal(err.into())) .and_then(|collab| { collab .encode_collab_v1(|collab| { collab_type.validate_require_data(collab)?; Ok(()) }) - .map_err(DatabaseError::Internal) + .map_err(CollabError::Internal) }); match result { @@ -417,7 +416,7 @@ pub trait DatabaseCollabPersistenceService: Send + Sync + 'static { &self, object_id: &ObjectId, encoded_collab: EncodedCollab, - ) -> Result<(), DatabaseError>; + ) -> Result<(), CollabError>; fn get_encoded_collab( &self, @@ -425,7 +424,7 @@ pub trait DatabaseCollabPersistenceService: Send + Sync + 'static { collab_type: CollabType, ) -> Option; - fn delete_collab(&self, object_id: &ObjectId) -> Result<(), DatabaseError>; + fn delete_collab(&self, object_id: &ObjectId) -> Result<(), CollabError>; fn is_collab_exist(&self, object_id: &ObjectId) -> bool; } diff --git a/collab-database/src/entity.rs b/collab/src/database/entity.rs similarity index 90% rename from collab-database/src/entity.rs rename to collab/src/database/entity.rs index cbeda5473..d31e34816 100644 --- a/collab-database/src/entity.rs +++ b/collab/src/database/entity.rs @@ -1,29 +1,31 @@ #![allow(clippy::upper_case_acronyms)] -use crate::database::{DatabaseData, gen_database_id, gen_database_view_id, gen_row_id, timestamp}; -use crate::error::DatabaseError; -use crate::fields::checkbox_type_option::CheckboxTypeOption; -use crate::fields::checklist_type_option::ChecklistTypeOption; -use crate::fields::date_type_option::{DateTypeOption, TimeTypeOption}; -use crate::fields::media_type_option::MediaTypeOption; -use crate::fields::number_type_option::NumberTypeOption; -use crate::fields::person_type_option::PersonTypeOption; -use crate::fields::relation_type_option::RelationTypeOption; -use crate::fields::select_type_option::{MultiSelectTypeOption, SingleSelectTypeOption}; -use crate::fields::summary_type_option::SummarizationTypeOption; -use crate::fields::text_type_option::RichTextTypeOption; -use crate::fields::timestamp_type_option::TimestampTypeOption; -use crate::fields::translate_type_option::TranslateTypeOption; -use crate::fields::url_type_option::URLTypeOption; -use crate::fields::{Field, TypeOptionData}; -use crate::rows::CreateRowParams; -use crate::views::{ +use crate::database::database::{ + DatabaseData, gen_database_id, gen_database_view_id, gen_row_id, timestamp, +}; +use crate::database::fields::checkbox_type_option::CheckboxTypeOption; +use crate::database::fields::checklist_type_option::ChecklistTypeOption; +use crate::database::fields::date_type_option::{DateTypeOption, TimeTypeOption}; +use crate::database::fields::media_type_option::MediaTypeOption; +use crate::database::fields::number_type_option::NumberTypeOption; +use crate::database::fields::person_type_option::PersonTypeOption; +use crate::database::fields::relation_type_option::RelationTypeOption; +use crate::database::fields::select_type_option::{MultiSelectTypeOption, SingleSelectTypeOption}; +use crate::database::fields::summary_type_option::SummarizationTypeOption; +use crate::database::fields::text_type_option::RichTextTypeOption; +use crate::database::fields::timestamp_type_option::TimestampTypeOption; +use crate::database::fields::translate_type_option::TranslateTypeOption; +use crate::database::fields::url_type_option::URLTypeOption; +use crate::database::fields::{Field, TypeOptionData}; +use crate::database::rows::CreateRowParams; +use crate::database::views::{ DatabaseLayout, FieldOrder, FieldSettingsByFieldIdMap, FieldSettingsMap, FilterMap, GroupSettingMap, LayoutSetting, LayoutSettings, OrderObjectPosition, RowOrder, SortMap, }; +use crate::error::CollabError; -use collab::entity::EncodedCollab; -use collab_entity::CollabType; -use collab_entity::uuid_validation::{DatabaseId, DatabaseViewId}; +use crate::entity::CollabType; +use crate::entity::EncodedCollab; +use crate::entity::uuid_validation::{DatabaseId, DatabaseViewId}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use std::collections::HashMap; @@ -199,7 +201,7 @@ impl From for CreateViewParams { pub(crate) struct CreateViewParamsValidator; impl CreateViewParamsValidator { - pub(crate) fn validate(params: CreateViewParams) -> Result { + pub(crate) fn validate(params: CreateViewParams) -> Result { Ok(params) } } diff --git a/collab-database/src/fields/field.rs b/collab/src/database/fields/field.rs similarity index 69% rename from collab-database/src/fields/field.rs rename to collab/src/database/fields/field.rs index e470af8b6..affc9c89b 100644 --- a/collab-database/src/fields/field.rs +++ b/collab/src/database/fields/field.rs @@ -1,11 +1,10 @@ use serde::{Deserialize, Serialize}; -use collab::preclude::{Any, Map, MapExt, MapRef, ReadTxn, TransactionMut, YrsValue}; +use crate::preclude::{Any, Map, MapExt, MapRef, ReadTxn, TransactionMut, YrsValue}; -use crate::database::gen_field_id; -use crate::entity::{FieldType, default_type_option_data_from_type}; -use crate::fields::{TypeOptionData, TypeOptions, TypeOptionsUpdate}; -use crate::{impl_bool_update, impl_i64_update, impl_str_update}; +use crate::database::database::gen_field_id; +use crate::database::entity::{FieldType, default_type_option_data_from_type}; +use crate::database::fields::{TypeOptionData, TypeOptions, TypeOptionsUpdate}; #[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] pub struct Field { @@ -98,16 +97,97 @@ impl<'a, 'b, 'c> FieldUpdate<'a, 'b, 'c> { Self { id, map_ref, txn } } - impl_str_update!(set_name, set_name_if_not_none, FIELD_NAME); - impl_str_update!(set_icon, set_icon_if_not_none, FIELD_ICON); - impl_bool_update!(set_primary, set_primary_if_not_none, FIELD_PRIMARY); - impl_i64_update!(set_field_type, set_field_type_if_not_none, FIELD_TYPE); - impl_i64_update!(set_created_at, set_created_at_if_not_none, CREATED_AT); - impl_i64_update!( - set_last_modified, - set_last_modified_if_not_none, - LAST_MODIFIED - ); + pub fn set_name>(self, value: T) -> Self { + self + .map_ref + .try_update(self.txn, FIELD_NAME, value.as_ref()); + self + } + + pub fn set_name_if_not_none>(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .try_update(self.txn, FIELD_NAME, value.as_ref()); + } + self + } + + pub fn set_icon>(self, value: T) -> Self { + self + .map_ref + .try_update(self.txn, FIELD_ICON, value.as_ref()); + self + } + + pub fn set_icon_if_not_none>(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .try_update(self.txn, FIELD_ICON, value.as_ref()); + } + self + } + + pub fn set_primary(self, value: bool) -> Self { + self.map_ref.insert(self.txn, FIELD_PRIMARY, value); + self + } + + pub fn set_primary_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self.map_ref.insert(self.txn, FIELD_PRIMARY, value); + } + self + } + + pub fn set_field_type(self, value: i64) -> Self { + self + .map_ref + .insert(self.txn, FIELD_TYPE, Any::BigInt(value)); + self + } + + pub fn set_field_type_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, FIELD_TYPE, Any::BigInt(value)); + } + self + } + + pub fn set_created_at(self, value: i64) -> Self { + self + .map_ref + .insert(self.txn, CREATED_AT, Any::BigInt(value)); + self + } + + pub fn set_created_at_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, CREATED_AT, Any::BigInt(value)); + } + self + } + + pub fn set_last_modified(self, value: i64) -> Self { + self + .map_ref + .insert(self.txn, LAST_MODIFIED, Any::BigInt(value)); + self + } + + pub fn set_last_modified_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, LAST_MODIFIED, Any::BigInt(value)); + } + self + } pub fn set_type_options(self, type_options: TypeOptions) -> Self { let map_ref: MapRef = self.map_ref.get_or_init(self.txn, FIELD_TYPE_OPTION); diff --git a/collab-database/src/fields/field_id.rs b/collab/src/database/fields/field_id.rs similarity index 100% rename from collab-database/src/fields/field_id.rs rename to collab/src/database/fields/field_id.rs diff --git a/collab-database/src/fields/field_map.rs b/collab/src/database/fields/field_map.rs similarity index 94% rename from collab-database/src/fields/field_map.rs rename to collab/src/database/fields/field_map.rs index 4a7d8cc27..41cde1c09 100644 --- a/collab-database/src/fields/field_map.rs +++ b/collab/src/database/fields/field_map.rs @@ -1,11 +1,11 @@ -use collab::preclude::{Map, MapExt, MapRef, ReadTxn, Subscription, TransactionMut}; +use crate::preclude::{Map, MapExt, MapRef, ReadTxn, Subscription, TransactionMut}; -use crate::database::timestamp; -use crate::fields::{ +use crate::database::database::timestamp; +use crate::database::fields::{ Field, FieldBuilder, FieldChangeSender, FieldUpdate, field_from_map_ref, field_from_value, field_id_from_value, primary_field_id_from_value, subscribe_field_change, }; -use crate::views::FieldOrder; +use crate::database::views::FieldOrder; /// A map of fields pub struct FieldMap { diff --git a/collab-database/src/fields/field_observer.rs b/collab/src/database/fields/field_observer.rs similarity index 92% rename from collab-database/src/fields/field_observer.rs rename to collab/src/database/fields/field_observer.rs index f2c30724c..c48c79a2e 100644 --- a/collab-database/src/fields/field_observer.rs +++ b/collab/src/database/fields/field_observer.rs @@ -1,5 +1,5 @@ -use crate::fields::{Field, field_from_map_ref, field_from_value}; -use collab::preclude::{DeepObservable, EntryChange, Event, MapRef, Subscription}; +use crate::database::fields::{Field, field_from_map_ref, field_from_value}; +use crate::preclude::{DeepObservable, EntryChange, Event, MapRef, Subscription}; use tokio::sync::broadcast; use tracing::warn; diff --git a/collab-database/src/fields/field_settings.rs b/collab/src/database/fields/field_settings.rs similarity index 98% rename from collab-database/src/fields/field_settings.rs rename to collab/src/database/fields/field_settings.rs index c58e7acdc..fbf457268 100644 --- a/collab-database/src/fields/field_settings.rs +++ b/collab/src/database/fields/field_settings.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; -use collab::util::AnyMapExt; +use crate::util::AnyMapExt; use strum::IntoEnumIterator; use yrs::Any; -use crate::views::{ +use crate::database::views::{ DatabaseLayout, FieldSettingsByFieldIdMap, FieldSettingsMap, FieldSettingsMapBuilder, }; diff --git a/collab-database/src/fields/mod.rs b/collab/src/database/fields/mod.rs similarity index 100% rename from collab-database/src/fields/mod.rs rename to collab/src/database/fields/mod.rs diff --git a/collab-database/src/fields/type_option/checkbox_type_option.rs b/collab/src/database/fields/type_option/checkbox_type_option.rs similarity index 96% rename from collab-database/src/fields/type_option/checkbox_type_option.rs rename to collab/src/database/fields/type_option/checkbox_type_option.rs index 14964a5a9..d48f4588d 100644 --- a/collab-database/src/fields/type_option/checkbox_type_option.rs +++ b/collab/src/database/fields/type_option/checkbox_type_option.rs @@ -1,12 +1,12 @@ use std::sync::Arc; -use crate::entity::FieldType; -use crate::fields::{ +use crate::database::entity::FieldType; +use crate::database::fields::{ TypeOptionCellReader, TypeOptionCellWriter, TypeOptionData, TypeOptionDataBuilder, }; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; -use collab::util::AnyMapExt; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; use serde_json::Value; diff --git a/collab-database/src/fields/type_option/checklist_type_option.rs b/collab/src/database/fields/type_option/checklist_type_option.rs similarity index 93% rename from collab-database/src/fields/type_option/checklist_type_option.rs rename to collab/src/database/fields/type_option/checklist_type_option.rs index 46538b9fa..cd8a86bbf 100644 --- a/collab-database/src/fields/type_option/checklist_type_option.rs +++ b/collab/src/database/fields/type_option/checklist_type_option.rs @@ -1,9 +1,9 @@ use super::{TypeOptionData, TypeOptionDataBuilder}; -use crate::fields::select_type_option::SELECTION_IDS_SEPARATOR; -use crate::fields::{TypeOptionCellReader, TypeOptionCellWriter}; -use crate::rows::Cell; -use crate::template::check_list_parse::ChecklistCellData; +use crate::database::fields::select_type_option::SELECTION_IDS_SEPARATOR; +use crate::database::fields::{TypeOptionCellReader, TypeOptionCellWriter}; +use crate::database::rows::Cell; +use crate::database::template::check_list_parse::ChecklistCellData; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; diff --git a/collab-database/src/fields/type_option/date_type_option.rs b/collab/src/database/fields/type_option/date_type_option.rs similarity index 98% rename from collab-database/src/fields/type_option/date_type_option.rs rename to collab/src/database/fields/type_option/date_type_option.rs index d7dd4b5c7..e455c4e3e 100644 --- a/collab-database/src/fields/type_option/date_type_option.rs +++ b/collab/src/database/fields/type_option/date_type_option.rs @@ -1,23 +1,23 @@ -use crate::entity::FieldType; +use crate::database::entity::FieldType; -use crate::error::DatabaseError; +use crate::error::CollabError; use chrono::{DateTime, Timelike}; use chrono::{Datelike, Local, TimeZone}; -use crate::fields::{ +use crate::database::fields::{ TypeOptionCellReader, TypeOptionCellWriter, TypeOptionData, TypeOptionDataBuilder, }; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; +use crate::util::AnyMapExt; use chrono::{FixedOffset, MappedLocalTime, NaiveDateTime, NaiveTime, Offset}; use chrono_tz::Tz; -use collab::util::AnyMapExt; use serde::de::Visitor; use serde::{Deserialize, Serialize}; use std::fmt; -use crate::template::time_parse::TimeCellData; -use crate::template::util::{ToCellString, TypeOptionCellData}; +use crate::database::template::time_parse::TimeCellData; +use crate::database::template::util::{ToCellString, TypeOptionCellData}; use serde_json::{Value, json}; use std::str::FromStr; pub use strum::IntoEnumIterator; @@ -248,7 +248,7 @@ impl DateTypeOption { &self, include_time: bool, time_str: Option<&str>, - ) -> Result, DatabaseError> { + ) -> Result, CollabError> { match (include_time, time_str) { (true, Some(time_str)) => { let result = diff --git a/collab-database/src/fields/type_option/media_type_option.rs b/collab/src/database/fields/type_option/media_type_option.rs similarity index 97% rename from collab-database/src/fields/type_option/media_type_option.rs rename to collab/src/database/fields/type_option/media_type_option.rs index 9e5c94f3f..5371b1131 100644 --- a/collab-database/src/fields/type_option/media_type_option.rs +++ b/collab/src/database/fields/type_option/media_type_option.rs @@ -1,14 +1,14 @@ -use crate::database::gen_database_file_id; -use crate::entity::FieldType; -use crate::fields::{ +use crate::database::database::gen_database_file_id; +use crate::database::entity::FieldType; +use crate::database::fields::{ TypeOptionCellReader, TypeOptionCellWriter, TypeOptionData, TypeOptionDataBuilder, }; -use crate::rows::{Cell, new_cell_builder}; +use crate::database::rows::{Cell, new_cell_builder}; -use crate::error::DatabaseError; -use crate::template::entity::CELL_DATA; -use crate::template::util::{ToCellString, TypeOptionCellData}; -use collab::util::AnyMapExt; +use crate::database::template::entity::CELL_DATA; +use crate::database::template::util::{ToCellString, TypeOptionCellData}; +use crate::error::CollabError; +use crate::util::AnyMapExt; use serde::{Deserialize, Deserializer, Serialize}; use serde_json::{Value, json}; use serde_repr::Serialize_repr; @@ -147,7 +147,7 @@ impl ToCellString for MediaCellData { } impl FromStr for MediaCellData { - type Err = DatabaseError; + type Err = CollabError; fn from_str(s: &str) -> Result { if s.is_empty() { diff --git a/collab-database/src/fields/type_option/mod.rs b/collab/src/database/fields/type_option/mod.rs similarity index 86% rename from collab-database/src/fields/type_option/mod.rs rename to collab/src/database/fields/type_option/mod.rs index 880665983..3d98ee68d 100644 --- a/collab-database/src/fields/type_option/mod.rs +++ b/collab/src/database/fields/type_option/mod.rs @@ -15,24 +15,24 @@ pub mod url_type_option; use std::collections::HashMap; use std::ops::{Deref, DerefMut}; -use crate::entity::FieldType; -use crate::fields::checklist_type_option::ChecklistTypeOption; -use crate::fields::date_type_option::{DateTypeOption, TimeTypeOption}; -use crate::fields::media_type_option::MediaTypeOption; -use crate::fields::number_type_option::NumberTypeOption; -use crate::fields::person_type_option::PersonTypeOption; -use crate::fields::relation_type_option::RelationTypeOption; -use crate::fields::select_type_option::{MultiSelectTypeOption, SingleSelectTypeOption}; -use crate::fields::summary_type_option::SummarizationTypeOption; -use crate::fields::timestamp_type_option::TimestampTypeOption; -use crate::fields::translate_type_option::TranslateTypeOption; -use crate::fields::type_option::checkbox_type_option::CheckboxTypeOption; -use crate::fields::type_option::text_type_option::RichTextTypeOption; -use crate::fields::url_type_option::URLTypeOption; -use crate::rows::Cell; -use crate::template::entity::CELL_DATA; -use collab::preclude::{Any, FillRef, Map, MapRef, ReadTxn, ToJson, TransactionMut}; -use collab::util::{AnyExt, AnyMapExt}; +use crate::database::entity::FieldType; +use crate::database::fields::checklist_type_option::ChecklistTypeOption; +use crate::database::fields::date_type_option::{DateTypeOption, TimeTypeOption}; +use crate::database::fields::media_type_option::MediaTypeOption; +use crate::database::fields::number_type_option::NumberTypeOption; +use crate::database::fields::person_type_option::PersonTypeOption; +use crate::database::fields::relation_type_option::RelationTypeOption; +use crate::database::fields::select_type_option::{MultiSelectTypeOption, SingleSelectTypeOption}; +use crate::database::fields::summary_type_option::SummarizationTypeOption; +use crate::database::fields::timestamp_type_option::TimestampTypeOption; +use crate::database::fields::translate_type_option::TranslateTypeOption; +use crate::database::fields::type_option::checkbox_type_option::CheckboxTypeOption; +use crate::database::fields::type_option::text_type_option::RichTextTypeOption; +use crate::database::fields::url_type_option::URLTypeOption; +use crate::database::rows::Cell; +use crate::database::template::entity::CELL_DATA; +use crate::preclude::{Any, FillRef, Map, MapRef, ReadTxn, ToJson, TransactionMut}; +use crate::util::{AnyExt, AnyMapExt}; use serde::{Deserialize, Serialize}; /// It's used to store lists of field's type option data diff --git a/collab-database/src/fields/type_option/number_type_option.rs b/collab/src/database/fields/type_option/number_type_option.rs similarity index 98% rename from collab-database/src/fields/type_option/number_type_option.rs rename to collab/src/database/fields/type_option/number_type_option.rs index c94e689ce..ff6ab7903 100644 --- a/collab-database/src/fields/type_option/number_type_option.rs +++ b/collab/src/database/fields/type_option/number_type_option.rs @@ -1,17 +1,17 @@ #![allow(clippy::upper_case_acronyms)] -use crate::error::DatabaseError; -use crate::fields::number_type_option::number_currency::Currency; -use crate::fields::{ +use crate::database::fields::number_type_option::number_currency::Currency; +use crate::database::fields::{ TypeOptionCellReader, TypeOptionCellWriter, TypeOptionData, TypeOptionDataBuilder, }; +use crate::error::CollabError; use std::fmt::Display; -use collab::preclude::Any; +use crate::preclude::Any; -use crate::entity::FieldType; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::number_parse::NumberCellData; +use crate::database::entity::FieldType; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::number_parse::NumberCellData; use fancy_regex::Regex; use lazy_static::lazy_static; @@ -107,7 +107,7 @@ impl NumberTypeOption { pub fn format_cell_data>( &self, num_cell_data: T, - ) -> Result { + ) -> Result { match self.format { NumberFormat::Num => { if SCIENTIFIC_NOTATION_REGEX @@ -182,7 +182,7 @@ impl NumberCellFormat { } /// The num_str might contain currency symbol, e.g. $1,000.00 - pub fn from_format_str(num_str: &str, format: &NumberFormat) -> Result { + pub fn from_format_str(num_str: &str, format: &NumberFormat) -> Result { if num_str.is_empty() { return Ok(Self::default()); } @@ -765,9 +765,9 @@ impl NumberFormat { #[cfg(test)] mod tests { - use collab::util::AnyMapExt; + use crate::util::AnyMapExt; - use crate::template::entity::CELL_DATA; + use crate::database::template::entity::CELL_DATA; use super::*; /// Testing when the input is not a number. diff --git a/collab-database/src/fields/type_option/person_type_option.rs b/collab/src/database/fields/type_option/person_type_option.rs similarity index 97% rename from collab-database/src/fields/type_option/person_type_option.rs rename to collab/src/database/fields/type_option/person_type_option.rs index 0b0636826..f3a1efec2 100644 --- a/collab-database/src/fields/type_option/person_type_option.rs +++ b/collab/src/database/fields/type_option/person_type_option.rs @@ -1,8 +1,8 @@ -use collab::util::AnyMapExt; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; use serde_json::Value; -use crate::{ +use crate::database::{ fields::{TypeOptionCellReader, TypeOptionCellWriter, TypeOptionData, TypeOptionDataBuilder}, rows::Cell, }; diff --git a/collab-database/src/fields/type_option/relation_type_option.rs b/collab/src/database/fields/type_option/relation_type_option.rs similarity index 84% rename from collab-database/src/fields/type_option/relation_type_option.rs rename to collab/src/database/fields/type_option/relation_type_option.rs index 5c1a83508..707838f67 100644 --- a/collab-database/src/fields/type_option/relation_type_option.rs +++ b/collab/src/database/fields/type_option/relation_type_option.rs @@ -1,9 +1,9 @@ use super::{TypeOptionData, TypeOptionDataBuilder}; -use crate::fields::{TypeOptionCellReader, TypeOptionCellWriter}; -use crate::rows::Cell; -use crate::template::relation_parse::RelationCellData; -use crate::template::util::ToCellString; -use collab::util::AnyMapExt; +use crate::database::fields::{TypeOptionCellReader, TypeOptionCellWriter}; +use crate::database::rows::Cell; +use crate::database::template::relation_parse::RelationCellData; +use crate::database::template::util::ToCellString; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; use std::str::FromStr; diff --git a/collab-database/src/fields/type_option/select_type_option.rs b/collab/src/database/fields/type_option/select_type_option.rs similarity index 98% rename from collab-database/src/fields/type_option/select_type_option.rs rename to collab/src/database/fields/type_option/select_type_option.rs index 7a56f7ed5..a274fb2f5 100644 --- a/collab-database/src/fields/type_option/select_type_option.rs +++ b/collab/src/database/fields/type_option/select_type_option.rs @@ -1,15 +1,15 @@ -use crate::database::gen_option_id; +use crate::database::database::gen_option_id; -use crate::entity::FieldType; -use crate::error::DatabaseError; -use crate::fields::{ +use crate::database::entity::FieldType; +use crate::database::fields::{ TypeOptionCellReader, TypeOptionCellWriter, TypeOptionData, TypeOptionDataBuilder, }; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; +use crate::error::CollabError; -use crate::template::util::{ToCellString, TypeOptionCellData}; -use collab::util::AnyMapExt; +use crate::database::template::util::{ToCellString, TypeOptionCellData}; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; use std::ops::{Deref, DerefMut}; @@ -385,7 +385,7 @@ impl From<&Cell> for SelectOptionIds { } impl FromStr for SelectOptionIds { - type Err = DatabaseError; + type Err = CollabError; fn from_str(s: &str) -> Result { if s.is_empty() { diff --git a/collab-database/src/fields/type_option/summary_type_option.rs b/collab/src/database/fields/type_option/summary_type_option.rs similarity index 86% rename from collab-database/src/fields/type_option/summary_type_option.rs rename to collab/src/database/fields/type_option/summary_type_option.rs index 055dd927b..ee161bedc 100644 --- a/collab-database/src/fields/type_option/summary_type_option.rs +++ b/collab/src/database/fields/type_option/summary_type_option.rs @@ -1,8 +1,8 @@ use super::{TypeOptionData, TypeOptionDataBuilder}; -use crate::fields::{TypeOptionCellReader, TypeOptionCellWriter}; -use crate::rows::Cell; -use crate::template::summary_parse::SummaryCellData; -use collab::util::AnyMapExt; +use crate::database::fields::{TypeOptionCellReader, TypeOptionCellWriter}; +use crate::database::rows::Cell; +use crate::database::template::summary_parse::SummaryCellData; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; diff --git a/collab-database/src/fields/type_option/text_type_option.rs b/collab/src/database/fields/type_option/text_type_option.rs similarity index 92% rename from collab-database/src/fields/type_option/text_type_option.rs rename to collab/src/database/fields/type_option/text_type_option.rs index e4c002c0a..f52fce3f2 100644 --- a/collab-database/src/fields/type_option/text_type_option.rs +++ b/collab/src/database/fields/type_option/text_type_option.rs @@ -1,9 +1,9 @@ -use crate::entity::FieldType; -use crate::fields::{ +use crate::database::entity::FieldType; +use crate::database::fields::{ TypeOptionCellReader, TypeOptionCellWriter, TypeOptionData, TypeOptionDataBuilder, }; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; @@ -54,7 +54,7 @@ impl From for TypeOptionData { #[cfg(test)] mod tests { use super::*; - use collab::util::AnyMapExt; + use crate::util::AnyMapExt; use serde_json::Value; #[test] diff --git a/collab-database/src/fields/type_option/timestamp_type_option.rs b/collab/src/database/fields/type_option/timestamp_type_option.rs similarity index 96% rename from collab-database/src/fields/type_option/timestamp_type_option.rs rename to collab/src/database/fields/type_option/timestamp_type_option.rs index 52c22efa5..554732d77 100644 --- a/collab-database/src/fields/type_option/timestamp_type_option.rs +++ b/collab/src/database/fields/type_option/timestamp_type_option.rs @@ -1,13 +1,13 @@ -use crate::entity::FieldType; -use crate::fields::date_type_option::{DateFormat, TimeFormat}; -use crate::fields::{ +use crate::database::entity::FieldType; +use crate::database::fields::date_type_option::{DateFormat, TimeFormat}; +use crate::database::fields::{ TypeOptionCellReader, TypeOptionCellWriter, TypeOptionData, TypeOptionDataBuilder, }; -use crate::rows::Cell; -use crate::template::timestamp_parse::TimestampCellData; +use crate::database::rows::Cell; +use crate::database::template::timestamp_parse::TimestampCellData; +use crate::util::AnyMapExt; use chrono::{DateTime, Local, Offset, TimeZone}; use chrono_tz::Tz; -use collab::util::AnyMapExt; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; use std::str::FromStr; @@ -161,7 +161,7 @@ impl From for TypeOptionData { #[cfg(test)] mod tests { use super::*; - use crate::template::entity::CELL_DATA; + use crate::database::template::entity::CELL_DATA; use serde_json::json; #[test] diff --git a/collab-database/src/fields/type_option/translate_type_option.rs b/collab/src/database/fields/type_option/translate_type_option.rs similarity index 91% rename from collab-database/src/fields/type_option/translate_type_option.rs rename to collab/src/database/fields/type_option/translate_type_option.rs index 7a6bd11ca..e5b05ee10 100644 --- a/collab-database/src/fields/type_option/translate_type_option.rs +++ b/collab/src/database/fields/type_option/translate_type_option.rs @@ -1,7 +1,7 @@ use super::{TypeOptionData, TypeOptionDataBuilder}; -use crate::fields::{TypeOptionCellReader, TypeOptionCellWriter}; -use crate::rows::Cell; -use crate::template::translate_parse::TranslateCellData; +use crate::database::fields::{TypeOptionCellReader, TypeOptionCellWriter}; +use crate::database::rows::Cell; +use crate::database::template::translate_parse::TranslateCellData; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; use yrs::{Any, encoding::serde::from_any}; diff --git a/collab-database/src/fields/type_option/url_type_option.rs b/collab/src/database/fields/type_option/url_type_option.rs similarity index 86% rename from collab-database/src/fields/type_option/url_type_option.rs rename to collab/src/database/fields/type_option/url_type_option.rs index a4c5b5572..04e7377fe 100644 --- a/collab-database/src/fields/type_option/url_type_option.rs +++ b/collab/src/database/fields/type_option/url_type_option.rs @@ -1,13 +1,13 @@ -use crate::entity::FieldType; -use crate::error::DatabaseError; -use crate::fields::{ +use crate::database::entity::FieldType; +use crate::database::fields::{ TypeOptionCellReader, TypeOptionCellWriter, TypeOptionData, TypeOptionDataBuilder, }; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; -use crate::template::util::{ToCellString, TypeOptionCellData}; -use collab::preclude::Any; -use collab::util::AnyMapExt; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; +use crate::database::template::util::{ToCellString, TypeOptionCellData}; +use crate::error::CollabError; +use crate::preclude::Any; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; use serde_json::Value; use yrs::encoding::serde::from_any; @@ -86,8 +86,8 @@ impl URLCellData { } } - pub fn to_json(&self) -> Result { - serde_json::to_string(self).map_err(|err| DatabaseError::Internal(err.into())) + pub fn to_json(&self) -> Result { + serde_json::to_string(self).map_err(|err| CollabError::Internal(err.into())) } } diff --git a/collab-database/src/meta/meta_map.rs b/collab/src/database/meta/meta_map.rs similarity index 88% rename from collab-database/src/meta/meta_map.rs rename to collab/src/database/meta/meta_map.rs index 1d9505053..41a11ad26 100644 --- a/collab-database/src/meta/meta_map.rs +++ b/collab/src/database/meta/meta_map.rs @@ -1,5 +1,5 @@ -use collab::preclude::{Any, Map, MapRef, ReadTxn, TransactionMut}; -use collab_entity::define::DATABASE_INLINE_VIEW; +use crate::entity::define::DATABASE_INLINE_VIEW; +use crate::preclude::{Any, Map, MapRef, ReadTxn, TransactionMut}; use std::ops::Deref; use tracing::error; diff --git a/collab-database/src/meta/mod.rs b/collab/src/database/meta/mod.rs similarity index 100% rename from collab-database/src/meta/mod.rs rename to collab/src/database/meta/mod.rs diff --git a/collab-database/src/lib.rs b/collab/src/database/mod.rs similarity index 85% rename from collab-database/src/lib.rs rename to collab/src/database/mod.rs index 5b00524ba..a868879b0 100644 --- a/collab-database/src/lib.rs +++ b/collab/src/database/mod.rs @@ -1,17 +1,15 @@ -pub mod database; -pub mod database_remapper; -pub mod fields; -pub mod meta; -pub mod rows; -pub mod views; -pub mod workspace_database; +#![allow(clippy::module_inception)] -#[macro_use] -mod macros; pub mod blocks; +pub mod database; +pub mod database_remapper; pub mod database_state; pub mod database_trait; pub mod entity; -pub mod error; +pub mod fields; +pub mod meta; +pub mod rows; pub mod template; pub mod util; +pub mod views; +pub mod workspace_database; diff --git a/collab-database/src/rows/cell.rs b/collab/src/database/rows/cell.rs similarity index 88% rename from collab-database/src/rows/cell.rs rename to collab/src/database/rows/cell.rs index 87b8e9f5d..c222deba2 100644 --- a/collab-database/src/rows/cell.rs +++ b/collab/src/database/rows/cell.rs @@ -1,13 +1,13 @@ use std::collections::HashMap; use std::ops::Deref; -use collab::preclude::{Any, FillRef, Map, MapRef, TransactionMut}; -use collab::util::AnyMapExt; +use crate::preclude::{Any, FillRef, Map, MapRef, TransactionMut}; +use crate::util::AnyMapExt; -use crate::database::timestamp; -use crate::rows::{CREATED_AT, LAST_MODIFIED}; -use crate::template::entity::CELL_DATA; -use collab_entity::uuid_validation::RowId; +use crate::database::database::timestamp; +use crate::database::rows::{CREATED_AT, LAST_MODIFIED}; +use crate::database::template::entity::CELL_DATA; +use crate::entity::uuid_validation::RowId; pub type Cells = HashMap; diff --git a/collab-database/src/rows/comment.rs b/collab/src/database/rows/comment.rs similarity index 89% rename from collab-database/src/rows/comment.rs rename to collab/src/database/rows/comment.rs index 7b94afbd7..20e5a7b38 100644 --- a/collab-database/src/rows/comment.rs +++ b/collab/src/database/rows/comment.rs @@ -1,5 +1,5 @@ -use collab::preclude::Any; -use collab::util::deserialize_i64_from_numeric; +use crate::preclude::Any; +use crate::util::deserialize_i64_from_numeric; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] diff --git a/collab-database/src/rows/mod.rs b/collab/src/database/rows/mod.rs similarity index 100% rename from collab-database/src/rows/mod.rs rename to collab/src/database/rows/mod.rs diff --git a/collab-database/src/rows/row.rs b/collab/src/database/rows/row.rs similarity index 89% rename from collab-database/src/rows/row.rs rename to collab/src/database/rows/row.rs index 538b8df24..b8e4dbde7 100644 --- a/collab-database/src/rows/row.rs +++ b/collab/src/database/rows/row.rs @@ -1,4 +1,4 @@ -use collab::preclude::{ +use crate::preclude::{ Any, ArrayRef, Collab, FillRef, Map, MapExt, MapRef, ReadTxn, ToJson, TransactionMut, YrsValue, }; use std::borrow::{Borrow, BorrowMut}; @@ -9,25 +9,24 @@ use strum_macros::EnumIter; #[cfg(feature = "verbose_log")] use tracing::trace; -use collab::preclude::encoding::serde::from_any; -use collab::util::AnyExt; -use collab_entity::CollabType; -use collab_entity::define::DATABASE_ROW_DATA; -use collab_entity::uuid_validation::{DatabaseId, RowId}; +use crate::entity::CollabType; +use crate::entity::define::DATABASE_ROW_DATA; +use crate::entity::uuid_validation::{DatabaseId, RowId}; +use crate::preclude::encoding::serde::from_any; +use crate::util::AnyExt; -use crate::database::timestamp; +use crate::database::database::timestamp; -use crate::error::DatabaseError; -use crate::rows::{ +use crate::database::rows::{ Cell, Cells, CellsUpdate, RowChangeSender, RowMeta, RowMetaUpdate, subscribe_row_data_change, }; +use crate::error::CollabError; -use crate::util::encoded_collab; -use crate::views::{OrderObjectPosition, RowOrder}; -use crate::{impl_bool_update, impl_i32_update, impl_i64_update}; -use collab::core::collab::CollabOptions; -use collab::core::origin::CollabOrigin; -use collab::entity::EncodedCollab; +use crate::core::collab::CollabOptions; +use crate::core::origin::CollabOrigin; +use crate::database::util::encoded_collab; +use crate::database::views::{OrderObjectPosition, RowOrder}; +use crate::entity::EncodedCollab; use serde::{Deserialize, Serialize}; use tracing::error; use uuid::Uuid; @@ -49,14 +48,14 @@ pub struct DatabaseRow { pub fn default_database_row_from_row(row: Row, client_id: ClientID) -> EncodedCollab { let collab = default_database_row_collab(row, client_id); collab - .encode_collab_v1(|_collab| Ok::<_, DatabaseError>(())) + .encode_collab_v1(|_collab| Ok::<_, CollabError>(())) .unwrap() } pub fn default_database_row_data(row: Row, client_id: ClientID) -> EncodedCollab { let collab = default_database_row_collab(row, client_id); collab - .encode_collab_v1(|_collab| Ok::<_, DatabaseError>(())) + .encode_collab_v1(|_collab| Ok::<_, CollabError>(())) .unwrap() } @@ -80,7 +79,7 @@ impl DatabaseRow { row_id: RowId, mut collab: Collab, change_tx: Option, - ) -> Result { + ) -> Result { let body = DatabaseRowBody::open(row_id, &mut collab)?; if let Some(change_tx) = change_tx { subscribe_row_data_change(row_id, &body.data, change_tx); @@ -109,12 +108,12 @@ impl DatabaseRow { } } - pub fn encoded_collab(&self) -> Result { + pub fn encoded_collab(&self) -> Result { let row_encoded = encoded_collab(&self.collab, &CollabType::DatabaseRow)?; Ok(row_encoded) } - pub fn validate(&self) -> Result<(), DatabaseError> { + pub fn validate(&self) -> Result<(), CollabError> { CollabType::DatabaseRow.validate_require_data(&self.collab)?; Ok(()) } @@ -214,7 +213,7 @@ pub struct DatabaseRowBody { } impl DatabaseRowBody { - pub fn open(row_id: RowId, collab: &mut Collab) -> Result { + pub fn open(row_id: RowId, collab: &mut Collab) -> Result { CollabType::DatabaseRow.validate_require_data(collab)?; Ok(Self::create_with_data(row_id, collab, None)) } @@ -272,7 +271,7 @@ impl DatabaseRowBody { &mut self, txn: &mut TransactionMut, new_row_id: RowId, - ) -> Result<(), DatabaseError> { + ) -> Result<(), CollabError> { self.update(txn, |update| { update.set_row_id(new_row_id); }); @@ -282,7 +281,7 @@ impl DatabaseRowBody { /// Attempts to get the document id for the row. /// Returns None if there is no document. - pub fn document_id(&self, txn: &T) -> Result, DatabaseError> { + pub fn document_id(&self, txn: &T) -> Result, CollabError> { let row_uuid = self.row_id; let is_doc_empty_key = meta_id_from_row_id(&row_uuid, RowMetaKey::IsDocumentEmpty); let is_doc_empty = self.meta.get(txn, &is_doc_empty_key); @@ -514,14 +513,65 @@ impl<'a, 'b> RowUpdate<'a, 'b> { } } - impl_bool_update!(set_visibility, set_visibility_if_not_none, ROW_VISIBILITY); - impl_i32_update!(set_height, set_height_at_if_not_none, ROW_HEIGHT); - impl_i64_update!(set_created_at, set_created_at_if_not_none, CREATED_AT); - impl_i64_update!( - set_last_modified, - set_last_modified_if_not_none, - LAST_MODIFIED - ); + pub fn set_visibility(self, value: bool) -> Self { + self.map_ref.insert(self.txn, ROW_VISIBILITY, value); + self + } + + pub fn set_visibility_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self.map_ref.insert(self.txn, ROW_VISIBILITY, value); + } + self + } + + pub fn set_height(self, value: i32) -> Self { + self + .map_ref + .insert(self.txn, ROW_HEIGHT, Any::BigInt(value as i64)); + self + } + + pub fn set_height_at_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, ROW_HEIGHT, Any::BigInt(value as i64)); + } + self + } + + pub fn set_created_at(self, value: i64) -> Self { + self + .map_ref + .insert(self.txn, CREATED_AT, Any::BigInt(value)); + self + } + + pub fn set_created_at_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, CREATED_AT, Any::BigInt(value)); + } + self + } + + pub fn set_last_modified(self, value: i64) -> Self { + self + .map_ref + .insert(self.txn, LAST_MODIFIED, Any::BigInt(value)); + self + } + + pub fn set_last_modified_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, LAST_MODIFIED, Any::BigInt(value)); + } + self + } pub fn set_database_id(self, database_id: DatabaseId) -> Self { self @@ -658,7 +708,7 @@ pub struct CreateRowParams { pub(crate) struct CreateRowParamsValidator; impl CreateRowParamsValidator { - pub(crate) fn validate(mut params: CreateRowParams) -> Result { + pub(crate) fn validate(mut params: CreateRowParams) -> Result { // RowId is always valid since it's a UUID type let timestamp = timestamp(); diff --git a/collab-database/src/rows/row_id.rs b/collab/src/database/rows/row_id.rs similarity index 100% rename from collab-database/src/rows/row_id.rs rename to collab/src/database/rows/row_id.rs diff --git a/collab-database/src/rows/row_meta.rs b/collab/src/database/rows/row_meta.rs similarity index 97% rename from collab-database/src/rows/row_meta.rs rename to collab/src/database/rows/row_meta.rs index 77a374191..8259624a6 100644 --- a/collab-database/src/rows/row_meta.rs +++ b/collab/src/database/rows/row_meta.rs @@ -1,9 +1,9 @@ -use collab::preclude::{Map, MapExt, MapRef, ReadTxn, TransactionMut}; +use crate::preclude::{Map, MapExt, MapRef, ReadTxn, TransactionMut}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use uuid::Uuid; -use crate::{ +use crate::database::{ entity::FileUploadType, rows::{RowMetaKey, meta_id_from_row_id}, }; diff --git a/collab-database/src/rows/row_observer.rs b/collab/src/database/rows/row_observer.rs similarity index 95% rename from collab-database/src/rows/row_observer.rs rename to collab/src/database/rows/row_observer.rs index d0c347e8a..65bc31152 100644 --- a/collab-database/src/rows/row_observer.rs +++ b/collab/src/database/rows/row_observer.rs @@ -1,12 +1,12 @@ -use crate::rows::{Cell, ROW_CELLS, ROW_HEIGHT, ROW_VISIBILITY, Row}; -use collab_entity::uuid_validation::RowId; +use crate::database::rows::{Cell, ROW_CELLS, ROW_HEIGHT, ROW_VISIBILITY, Row}; +use crate::entity::uuid_validation::RowId; -use collab::preclude::{DeepObservable, EntryChange, Event, MapRef, TransactionMut}; -use collab::preclude::{PathSegment, ToJson}; +use crate::preclude::{DeepObservable, EntryChange, Event, MapRef, TransactionMut}; +use crate::preclude::{PathSegment, ToJson}; use std::ops::Deref; -use collab::preclude::map::MapEvent; -use collab::util::AnyExt; +use crate::preclude::map::MapEvent; +use crate::util::AnyExt; use tokio::sync::broadcast; use tracing::trace; diff --git a/collab-database/src/template/builder.rs b/collab/src/database/template/builder.rs similarity index 87% rename from collab-database/src/template/builder.rs rename to collab/src/database/template/builder.rs index f74daf288..a11ff422a 100644 --- a/collab-database/src/template/builder.rs +++ b/collab/src/database/template/builder.rs @@ -1,28 +1,28 @@ -use crate::database::{gen_field_id, gen_row_id}; -use crate::template::entity::{ +use crate::database::database::{gen_field_id, gen_row_id}; +use crate::database::template::entity::{ CELL_DATA, CellTemplateData, DatabaseTemplate, DatabaseViewTemplate, FieldTemplate, RowTemplate, }; -use collab_entity::uuid_validation::{DatabaseId, DatabaseViewId}; +use crate::entity::uuid_validation::{DatabaseId, DatabaseViewId}; -use crate::entity::FieldType; -use crate::fields::checkbox_type_option::CheckboxTypeOption; -use crate::fields::date_type_option::{DateFormat, DateTypeOption}; -use crate::fields::media_type_option::MediaTypeOption; -use crate::fields::number_type_option::NumberTypeOption; -use crate::fields::select_type_option::SelectTypeOption; -use crate::fields::text_type_option::RichTextTypeOption; -use crate::fields::timestamp_type_option::TimestampTypeOption; -use crate::rows::new_cell_builder; -use crate::template::check_list_parse::ChecklistCellData; -use crate::template::csv::CSVResource; -use crate::template::date_parse::replace_cells_with_timestamp; -use crate::template::media_parse::replace_cells_with_files; -use crate::template::option_parse::{ +use crate::database::entity::FieldType; +use crate::database::fields::checkbox_type_option::CheckboxTypeOption; +use crate::database::fields::date_type_option::{DateFormat, DateTypeOption}; +use crate::database::fields::media_type_option::MediaTypeOption; +use crate::database::fields::number_type_option::NumberTypeOption; +use crate::database::fields::select_type_option::SelectTypeOption; +use crate::database::fields::text_type_option::RichTextTypeOption; +use crate::database::fields::timestamp_type_option::TimestampTypeOption; +use crate::database::rows::new_cell_builder; +use crate::database::template::check_list_parse::ChecklistCellData; +use crate::database::template::csv::CSVResource; +use crate::database::template::date_parse::replace_cells_with_timestamp; +use crate::database::template::media_parse::replace_cells_with_files; +use crate::database::template::option_parse::{ SELECT_OPTION_SEPARATOR, build_options_from_cells, replace_cells_with_options_id, }; -use crate::views::DatabaseLayout; +use crate::database::views::DatabaseLayout; -use collab::preclude::Any; +use crate::preclude::Any; use std::collections::HashMap; diff --git a/collab-database/src/template/check_list_parse.rs b/collab/src/database/template/check_list_parse.rs similarity index 89% rename from collab-database/src/template/check_list_parse.rs rename to collab/src/database/template/check_list_parse.rs index b664a7943..49fc8c363 100644 --- a/collab-database/src/template/check_list_parse.rs +++ b/collab/src/database/template/check_list_parse.rs @@ -1,11 +1,11 @@ -use crate::database::gen_option_id; -use crate::entity::FieldType; -use crate::fields::select_type_option::{SelectOption, SelectOptionColor}; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; -use crate::template::option_parse::SELECT_OPTION_COLOR_COUNT; -use crate::template::util::{ToCellString, TypeOptionCellData}; -use collab::util::AnyMapExt; +use crate::database::database::gen_option_id; +use crate::database::entity::FieldType; +use crate::database::fields::select_type_option::{SelectOption, SelectOptionColor}; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; +use crate::database::template::option_parse::SELECT_OPTION_COLOR_COUNT; +use crate::database::template::util::{ToCellString, TypeOptionCellData}; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; #[derive(Default, Clone, Debug, Serialize, Deserialize)] @@ -98,7 +98,7 @@ impl ToCellString for ChecklistCellData { #[cfg(test)] mod tests { use super::*; - use crate::rows::Cell; + use crate::database::rows::Cell; #[test] fn test_checklist_cell_data_from_names_and_selected() { diff --git a/collab-database/src/template/checkbox_parse.rs b/collab/src/database/template/checkbox_parse.rs similarity index 100% rename from collab-database/src/template/checkbox_parse.rs rename to collab/src/database/template/checkbox_parse.rs diff --git a/collab-database/src/template/csv.rs b/collab/src/database/template/csv.rs similarity index 95% rename from collab-database/src/template/csv.rs rename to collab/src/database/template/csv.rs index 0c5bf8296..3cc17458b 100644 --- a/collab-database/src/template/csv.rs +++ b/collab/src/database/template/csv.rs @@ -1,10 +1,10 @@ -use crate::database::{gen_database_id, gen_database_view_id}; -use crate::entity::FieldType; -use crate::error::DatabaseError; -use crate::template::builder::{DatabaseTemplateBuilder, FileUrlBuilder}; -use crate::template::date_parse::cast_string_to_timestamp; -use crate::template::entity::DatabaseTemplate; -use collab_entity::uuid_validation::{DatabaseId, DatabaseViewId}; +use crate::database::database::{gen_database_id, gen_database_view_id}; +use crate::database::entity::FieldType; +use crate::database::template::builder::{DatabaseTemplateBuilder, FileUrlBuilder}; +use crate::database::template::date_parse::cast_string_to_timestamp; +use crate::database::template::entity::DatabaseTemplate; +use crate::entity::uuid_validation::{DatabaseId, DatabaseViewId}; +use crate::error::CollabError; use percent_encoding::percent_decode_str; use rayon::prelude::*; use std::collections::{HashMap, HashSet}; @@ -35,7 +35,7 @@ impl CSVTemplate { reader: impl io::Read, auto_field_type: bool, mut csv_resource: Option, - ) -> Result { + ) -> Result { let mut fields: Vec = vec![]; let mut reader = csv::Reader::from_reader(reader); @@ -47,7 +47,7 @@ impl CSVTemplate { }); } } else { - return Err(DatabaseError::InvalidCSV("No header".to_string())); + return Err(CollabError::DatabaseInvalidCsv("No header".to_string())); } let rows: Vec> = reader @@ -84,7 +84,7 @@ impl CSVTemplate { pub async fn try_into_database_template( self, file_url_builder: Option>, - ) -> Result { + ) -> Result { let CSVTemplate { fields, rows, diff --git a/collab-database/src/template/date_parse.rs b/collab/src/database/template/date_parse.rs similarity index 100% rename from collab-database/src/template/date_parse.rs rename to collab/src/database/template/date_parse.rs diff --git a/collab-database/src/template/entity.rs b/collab/src/database/template/entity.rs similarity index 72% rename from collab-database/src/template/entity.rs rename to collab/src/database/template/entity.rs index 22e169314..4834445d4 100644 --- a/collab-database/src/template/entity.rs +++ b/collab/src/database/template/entity.rs @@ -1,10 +1,10 @@ -use crate::entity::{CreateDatabaseParams, FieldType}; -use crate::views::{DatabaseLayout, LayoutSettings}; -use collab::preclude::Any; -use collab_entity::uuid_validation::{DatabaseId, DatabaseViewId}; +use crate::database::entity::{CreateDatabaseParams, FieldType}; +use crate::database::views::{DatabaseLayout, LayoutSettings}; +use crate::entity::uuid_validation::{DatabaseId, DatabaseViewId}; +use crate::preclude::Any; -use crate::error::DatabaseError; -use crate::template::util::create_database_params_from_template; +use crate::database::template::util::create_database_params_from_template; +use crate::error::CollabError; use std::collections::HashMap; pub const CELL_DATA: &str = "data"; @@ -17,7 +17,7 @@ pub struct DatabaseTemplate { } impl DatabaseTemplate { - pub fn into_params(self) -> Result { + pub fn into_params(self) -> Result { create_database_params_from_template(self) } } diff --git a/collab-database/src/template/media_parse.rs b/collab/src/database/template/media_parse.rs similarity index 87% rename from collab-database/src/template/media_parse.rs rename to collab/src/database/template/media_parse.rs index 3c19f150d..66f7d7d04 100644 --- a/collab-database/src/template/media_parse.rs +++ b/collab/src/database/template/media_parse.rs @@ -1,7 +1,9 @@ -use crate::fields::media_type_option::{MediaCellData, MediaFile, MediaFileType, MediaUploadType}; -use crate::template::builder::FileUrlBuilder; -use crate::template::csv::CSVResource; -use collab_entity::uuid_validation::DatabaseId; +use crate::database::fields::media_type_option::{ + MediaCellData, MediaFile, MediaFileType, MediaUploadType, +}; +use crate::database::template::builder::FileUrlBuilder; +use crate::database::template::csv::CSVResource; +use crate::entity::uuid_validation::DatabaseId; use futures::stream::{FuturesOrdered, StreamExt}; use std::path::PathBuf; diff --git a/collab-database/src/template/mod.rs b/collab/src/database/template/mod.rs similarity index 100% rename from collab-database/src/template/mod.rs rename to collab/src/database/template/mod.rs diff --git a/collab-database/src/template/number_parse.rs b/collab/src/database/template/number_parse.rs similarity index 78% rename from collab-database/src/template/number_parse.rs rename to collab/src/database/template/number_parse.rs index cab3bc27f..92d2eb2b1 100644 --- a/collab-database/src/template/number_parse.rs +++ b/collab/src/database/template/number_parse.rs @@ -1,8 +1,8 @@ -use crate::entity::FieldType; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; -use crate::template::util::{ToCellString, TypeOptionCellData}; -use collab::util::AnyMapExt; +use crate::database::entity::FieldType; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; +use crate::database::template::util::{ToCellString, TypeOptionCellData}; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Serialize)] diff --git a/collab-database/src/template/option_parse.rs b/collab/src/database/template/option_parse.rs similarity index 90% rename from collab-database/src/template/option_parse.rs rename to collab/src/database/template/option_parse.rs index 1486d583e..3dba431c2 100644 --- a/collab-database/src/template/option_parse.rs +++ b/collab/src/database/template/option_parse.rs @@ -1,5 +1,5 @@ -use crate::database::gen_option_id; -use crate::fields::select_type_option::{SelectOption, SelectOptionColor}; +use crate::database::database::gen_option_id; +use crate::database::fields::select_type_option::{SelectOption, SelectOptionColor}; use std::collections::HashSet; pub(crate) const SELECT_OPTION_SEPARATOR: &str = ","; diff --git a/collab-database/src/template/relation_parse.rs b/collab/src/database/template/relation_parse.rs similarity index 81% rename from collab-database/src/template/relation_parse.rs rename to collab/src/database/template/relation_parse.rs index 4c48f273c..7bafc6a3d 100644 --- a/collab-database/src/template/relation_parse.rs +++ b/collab/src/database/template/relation_parse.rs @@ -1,11 +1,11 @@ -use crate::entity::FieldType; +use crate::database::entity::FieldType; use std::str::FromStr; -use crate::error::DatabaseError; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; -use crate::template::util::{ToCellString, TypeOptionCellData}; -use collab_entity::uuid_validation::RowId; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; +use crate::database::template::util::{ToCellString, TypeOptionCellData}; +use crate::entity::uuid_validation::RowId; +use crate::error::CollabError; use serde::{Deserialize, Serialize}; use std::sync::Arc; use yrs::Any; @@ -16,7 +16,7 @@ pub struct RelationCellData { } impl FromStr for RelationCellData { - type Err = DatabaseError; + type Err = CollabError; fn from_str(s: &str) -> Result { if s.is_empty() { @@ -26,7 +26,7 @@ impl FromStr for RelationCellData { let mut ids = Vec::new(); for id_str in s.split(", ") { let row_id = uuid::Uuid::parse_str(id_str).map_err(|_| { - DatabaseError::Internal(anyhow::anyhow!("Invalid row ID in relation: {}", id_str)) + CollabError::Internal(anyhow::anyhow!("Invalid row ID in relation: {}", id_str)) })?; ids.push(row_id); } diff --git a/collab-database/src/template/summary_parse.rs b/collab/src/database/template/summary_parse.rs similarity index 78% rename from collab-database/src/template/summary_parse.rs rename to collab/src/database/template/summary_parse.rs index 1eab4de72..5988ba1b6 100644 --- a/collab-database/src/template/summary_parse.rs +++ b/collab/src/database/template/summary_parse.rs @@ -1,8 +1,8 @@ -use crate::entity::FieldType; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; -use crate::template::util::{ToCellString, TypeOptionCellData}; -use collab::util::AnyMapExt; +use crate::database::entity::FieldType; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; +use crate::database::template::util::{ToCellString, TypeOptionCellData}; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; #[derive(Default, Debug, Clone, Serialize, Deserialize)] diff --git a/collab-database/src/template/time_parse.rs b/collab/src/database/template/time_parse.rs similarity index 79% rename from collab-database/src/template/time_parse.rs rename to collab/src/database/template/time_parse.rs index 2dd901343..f0a52222d 100644 --- a/collab-database/src/template/time_parse.rs +++ b/collab/src/database/template/time_parse.rs @@ -1,8 +1,8 @@ -use crate::entity::FieldType; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; -use crate::template::util::{ToCellString, TypeOptionCellData}; -use collab::util::AnyMapExt; +use crate::database::entity::FieldType; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; +use crate::database::template::util::{ToCellString, TypeOptionCellData}; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Serialize, Deserialize)] diff --git a/collab-database/src/template/timestamp_parse.rs b/collab/src/database/template/timestamp_parse.rs similarity index 87% rename from collab-database/src/template/timestamp_parse.rs rename to collab/src/database/template/timestamp_parse.rs index 556426fbf..f63cef5be 100644 --- a/collab-database/src/template/timestamp_parse.rs +++ b/collab/src/database/template/timestamp_parse.rs @@ -1,9 +1,9 @@ -use crate::entity::FieldType; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; +use crate::database::entity::FieldType; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; -use crate::template::util::{ToCellString, TypeOptionCellData}; -use collab::util::AnyMapExt; +use crate::database::template::util::{ToCellString, TypeOptionCellData}; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Serialize, Deserialize)] diff --git a/collab-database/src/template/translate_parse.rs b/collab/src/database/template/translate_parse.rs similarity index 78% rename from collab-database/src/template/translate_parse.rs rename to collab/src/database/template/translate_parse.rs index 49c7fe066..718f6fc55 100644 --- a/collab-database/src/template/translate_parse.rs +++ b/collab/src/database/template/translate_parse.rs @@ -1,8 +1,8 @@ -use crate::entity::FieldType; -use crate::rows::{Cell, new_cell_builder}; -use crate::template::entity::CELL_DATA; -use crate::template::util::{ToCellString, TypeOptionCellData}; -use collab::util::AnyMapExt; +use crate::database::entity::FieldType; +use crate::database::rows::{Cell, new_cell_builder}; +use crate::database::template::entity::CELL_DATA; +use crate::database::template::util::{ToCellString, TypeOptionCellData}; +use crate::util::AnyMapExt; use serde::{Deserialize, Serialize}; #[derive(Default, Debug, Clone, Serialize, Deserialize)] diff --git a/collab-database/src/template/util.rs b/collab/src/database/template/util.rs similarity index 79% rename from collab-database/src/template/util.rs rename to collab/src/database/template/util.rs index 1cd5b4b0d..1202ba7f2 100644 --- a/collab-database/src/template/util.rs +++ b/collab/src/database/template/util.rs @@ -1,9 +1,9 @@ -use crate::database::timestamp; -use crate::entity::{CreateDatabaseParams, CreateViewParams}; -use crate::error::DatabaseError; -use crate::fields::Field; -use crate::rows::CreateRowParams; -use crate::template::entity::DatabaseTemplate; +use crate::database::database::timestamp; +use crate::database::entity::{CreateDatabaseParams, CreateViewParams}; +use crate::database::fields::Field; +use crate::database::rows::CreateRowParams; +use crate::database::template::entity::DatabaseTemplate; +use crate::error::CollabError; /// This trait that provides methods to extend the [TypeOption::CellData] functionalities. pub trait TypeOptionCellData { @@ -16,23 +16,21 @@ pub trait ToCellString { fn to_cell_string(&self) -> String; } -pub fn construct_create_database_params( - template: T, -) -> Result +pub fn construct_create_database_params(template: T) -> Result where T: TryInto, >::Error: ToString, { let template = template .try_into() - .map_err(|err| DatabaseError::ImportData(err.to_string()))?; + .map_err(|err| CollabError::DatabaseImportData(err.to_string()))?; let params = create_database_params_from_template(template)?; Ok(params) } pub(crate) fn create_database_params_from_template( template: DatabaseTemplate, -) -> Result { +) -> Result { let database_id = template.database_id; let timestamp = timestamp(); @@ -53,7 +51,7 @@ pub(crate) fn create_database_params_from_template( let mut rows = vec![]; for row_template in template.rows { let row_id = uuid::Uuid::parse_str(&row_template.row_id).map_err(|_| { - DatabaseError::Internal(anyhow::anyhow!("Invalid row ID: {}", row_template.row_id)) + CollabError::Internal(anyhow::anyhow!("Invalid row ID: {}", row_template.row_id)) })?; rows.push(CreateRowParams { id: row_id, diff --git a/collab-database/src/util.rs b/collab/src/database/util.rs similarity index 54% rename from collab-database/src/util.rs rename to collab/src/database/util.rs index 945d24c88..0aba4bd4e 100644 --- a/collab-database/src/util.rs +++ b/collab/src/database/util.rs @@ -1,11 +1,11 @@ -use crate::error::DatabaseError; -use collab::entity::EncodedCollab; -use collab::preclude::Collab; -use collab_entity::CollabType; +use crate::entity::CollabType; +use crate::entity::EncodedCollab; +use crate::error::CollabError; +use crate::preclude::Collab; pub(crate) fn encoded_collab( collab: &Collab, collab_type: &CollabType, -) -> Result { +) -> Result { let encoded_collab = collab.encode_collab_v1(|collab| collab_type.validate_require_data(collab))?; Ok(encoded_collab) diff --git a/collab-database/src/views/calculation.rs b/collab/src/database/views/calculation.rs similarity index 86% rename from collab-database/src/views/calculation.rs rename to collab/src/database/views/calculation.rs index fe3e800bd..aa00ab873 100644 --- a/collab-database/src/views/calculation.rs +++ b/collab/src/database/views/calculation.rs @@ -1,4 +1,4 @@ -use collab::preclude::Any; +use crate::preclude::Any; use std::collections::HashMap; pub type CalculationArray = Vec; diff --git a/collab-database/src/views/define.rs b/collab/src/database/views/define.rs similarity index 100% rename from collab-database/src/views/define.rs rename to collab/src/database/views/define.rs diff --git a/collab-database/src/views/field_order.rs b/collab/src/database/views/field_order.rs similarity index 93% rename from collab-database/src/views/field_order.rs rename to collab/src/database/views/field_order.rs index ffaee6f0b..16e844bda 100644 --- a/collab-database/src/views/field_order.rs +++ b/collab/src/database/views/field_order.rs @@ -1,10 +1,10 @@ use std::ops::{Deref, DerefMut}; -use collab::preclude::{Any, Array, ArrayRef, ReadTxn, TransactionMut, YrsValue}; +use crate::preclude::{Any, Array, ArrayRef, ReadTxn, TransactionMut, YrsValue}; use serde::{Deserialize, Serialize}; -use crate::fields::Field; -use crate::views::{OrderArray, OrderIdentifiable}; +use crate::database::fields::Field; +use crate::database::views::{OrderArray, OrderIdentifiable}; /// Keep track of the order of fields in a database view pub struct FieldOrderArray { diff --git a/collab-database/src/views/field_settings.rs b/collab/src/database/views/field_settings.rs similarity index 97% rename from collab-database/src/views/field_settings.rs rename to collab/src/database/views/field_settings.rs index ed42c2116..e7a13a525 100644 --- a/collab-database/src/views/field_settings.rs +++ b/collab/src/database/views/field_settings.rs @@ -3,10 +3,10 @@ use std::{ ops::{Deref, DerefMut}, }; -use collab::preclude::{ +use crate::preclude::{ Any, FillRef, Map, MapExt, MapRef, ReadTxn, ToJson, TransactionMut, YrsValue, }; -use collab::util::AnyExt; +use crate::util::AnyExt; use serde::{Deserialize, Serialize}; pub type FieldSettingsMap = HashMap; diff --git a/collab-database/src/views/filter.rs b/collab/src/database/views/filter.rs similarity index 85% rename from collab-database/src/views/filter.rs rename to collab/src/database/views/filter.rs index 751c44fe0..a153c8504 100644 --- a/collab-database/src/views/filter.rs +++ b/collab/src/database/views/filter.rs @@ -1,4 +1,4 @@ -use collab::preclude::Any; +use crate::preclude::Any; use std::collections::HashMap; pub type FilterArray = Vec; diff --git a/collab-database/src/views/group.rs b/collab/src/database/views/group.rs similarity index 96% rename from collab-database/src/views/group.rs rename to collab/src/database/views/group.rs index af1da91f2..4b8e43ed0 100644 --- a/collab-database/src/views/group.rs +++ b/collab/src/database/views/group.rs @@ -1,10 +1,10 @@ use std::{collections::HashMap, sync::Arc}; -use collab::preclude::{Any, ArrayRef}; +use crate::preclude::{Any, ArrayRef}; use serde::{Deserialize, Serialize}; use yrs::encoding::serde::{from_any, to_any}; -use crate::database::gen_database_group_id; +use crate::database::database::gen_database_group_id; /// [GroupSettingArray] contains list of [GroupSettingMap] pub type GroupSettingArray = Vec; diff --git a/collab-database/src/views/layout.rs b/collab/src/database/views/layout.rs similarity index 96% rename from collab-database/src/views/layout.rs rename to collab/src/database/views/layout.rs index fbf20d565..1d2ea60f4 100644 --- a/collab-database/src/views/layout.rs +++ b/collab/src/database/views/layout.rs @@ -2,12 +2,12 @@ use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use std::str::FromStr; +use crate::preclude::{Any, FillRef, Map, MapRef, ReadTxn, ToJson, TransactionMut, YrsValue}; use anyhow::bail; -use collab::preclude::{Any, FillRef, Map, MapRef, ReadTxn, ToJson, TransactionMut, YrsValue}; use serde::{Deserialize, Serialize}; use serde_repr::*; -use collab::util::AnyExt; +use crate::util::AnyExt; use strum_macros::EnumIter; /// The [DatabaseLayout] enum is used to represent the layout of the database. diff --git a/collab-database/src/views/layout_settings.rs b/collab/src/database/views/layout_settings.rs similarity index 100% rename from collab-database/src/views/layout_settings.rs rename to collab/src/database/views/layout_settings.rs diff --git a/collab-database/src/views/mod.rs b/collab/src/database/views/mod.rs similarity index 100% rename from collab-database/src/views/mod.rs rename to collab/src/database/views/mod.rs diff --git a/collab-database/src/views/row_order.rs b/collab/src/database/views/row_order.rs similarity index 88% rename from collab-database/src/views/row_order.rs rename to collab/src/database/views/row_order.rs index bb6a94491..f8a7c4236 100644 --- a/collab-database/src/views/row_order.rs +++ b/collab/src/database/views/row_order.rs @@ -1,12 +1,12 @@ use std::ops::{Deref, DerefMut}; -use collab::preclude::{Any, ArrayRef, ReadTxn, YrsValue}; -use collab::util::deserialize_i32_from_numeric; +use crate::preclude::{Any, ArrayRef, ReadTxn, YrsValue}; +use crate::util::deserialize_i32_from_numeric; use serde::{Deserialize, Serialize}; -use crate::rows::Row; -use crate::views::{OrderArray, OrderIdentifiable}; -use collab_entity::uuid_validation::RowId; +use crate::database::rows::Row; +use crate::database::views::{OrderArray, OrderIdentifiable}; +use crate::entity::uuid_validation::RowId; pub struct RowOrderArray { array_ref: ArrayRef, diff --git a/collab-database/src/views/sort.rs b/collab/src/database/views/sort.rs similarity index 84% rename from collab-database/src/views/sort.rs rename to collab/src/database/views/sort.rs index adae4cecd..d8cb04f9a 100644 --- a/collab-database/src/views/sort.rs +++ b/collab/src/database/views/sort.rs @@ -1,4 +1,4 @@ -use collab::preclude::Any; +use crate::preclude::Any; use std::collections::HashMap; pub type SortArray = Vec; diff --git a/collab-database/src/views/view.rs b/collab/src/database/views/view.rs similarity index 71% rename from collab-database/src/views/view.rs rename to collab/src/database/views/view.rs index 4ed53b955..2543cd636 100644 --- a/collab-database/src/views/view.rs +++ b/collab/src/database/views/view.rs @@ -1,21 +1,20 @@ -use collab::preclude::{ +use crate::preclude::{ Any, Array, ArrayRef, FillRef, Map, MapExt, MapRef, ReadTxn, ToJson, TransactionMut, YrsValue, }; -use collab::util::AnyExt; +use crate::util::AnyExt; use std::collections::HashMap; use tracing::trace; use super::CalculationMap; -use crate::entity::{DatabaseView, DatabaseViewMeta}; +use crate::database::entity::{DatabaseView, DatabaseViewMeta}; -use crate::views::define::*; -use crate::views::layout::{DatabaseLayout, LayoutSettings}; -use crate::views::{ +use crate::database::views::define::*; +use crate::database::views::layout::{DatabaseLayout, LayoutSettings}; +use crate::database::views::{ FieldOrder, FieldOrderArray, FieldSettingsByFieldIdMap, FilterArray, FilterMap, GroupSettingArray, GroupSettingMap, LayoutSetting, RowOrder, RowOrderArray, SortArray, SortMap, }; -use crate::{impl_any_update, impl_i64_update, impl_order_update, impl_str_update}; pub struct ViewBuilder<'a, 'b> { map_ref: MapRef, @@ -49,12 +48,12 @@ pub enum OrderObjectPosition { impl OrderObjectPosition { /// Create an After position with a RowId - pub fn after_row(row_id: &collab_entity::uuid_validation::RowId) -> Self { + pub fn after_row(row_id: &crate::entity::uuid_validation::RowId) -> Self { OrderObjectPosition::After(row_id.to_string()) } /// Create a Before position with a RowId - pub fn before_row(row_id: &collab_entity::uuid_validation::RowId) -> Self { + pub fn before_row(row_id: &crate::entity::uuid_validation::RowId) -> Self { OrderObjectPosition::Before(row_id.to_string()) } } @@ -79,44 +78,219 @@ impl<'a, 'b> DatabaseViewUpdate<'a, 'b> { self } - impl_str_update!( - set_database_id, - set_database_id_if_not_none, - VIEW_DATABASE_ID - ); - - impl_i64_update!(set_created_at, set_created_at_if_not_none, VIEW_CREATE_AT); - impl_i64_update!(set_modified_at, set_modified_at_if_not_none, VIEW_MODIFY_AT); - impl_str_update!(set_name, set_name_if_not_none, VIEW_NAME); - - impl_any_update!( - set_layout_type, - set_layout_type_if_not_none, - DATABASE_VIEW_LAYOUT, - DatabaseLayout - ); - - impl_order_update!( - set_row_orders, - remove_row_order, - move_row_order, - insert_row_order, - iter_mut_row_order, - DATABASE_VIEW_ROW_ORDERS, - RowOrder, - RowOrderArray - ); - - impl_order_update!( - set_field_orders, - remove_field_order, - move_field_order, - insert_field_order, - iter_mut_field_order, - DATABASE_VIEW_FIELD_ORDERS, - FieldOrder, - FieldOrderArray - ); + pub fn set_database_id>(self, value: T) -> Self { + self + .map_ref + .try_update(self.txn, VIEW_DATABASE_ID, value.as_ref()); + self + } + + pub fn set_database_id_if_not_none>(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .try_update(self.txn, VIEW_DATABASE_ID, value.as_ref()); + } + self + } + + pub fn set_created_at(self, value: i64) -> Self { + self + .map_ref + .insert(self.txn, VIEW_CREATE_AT, Any::BigInt(value)); + self + } + + pub fn set_created_at_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, VIEW_CREATE_AT, Any::BigInt(value)); + } + self + } + + pub fn set_modified_at(self, value: i64) -> Self { + self + .map_ref + .insert(self.txn, VIEW_MODIFY_AT, Any::BigInt(value)); + self + } + + pub fn set_modified_at_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, VIEW_MODIFY_AT, Any::BigInt(value)); + } + self + } + + pub fn set_name>(self, value: T) -> Self { + self.map_ref.try_update(self.txn, VIEW_NAME, value.as_ref()); + self + } + + pub fn set_name_if_not_none>(self, value: Option) -> Self { + if let Some(value) = value { + self.map_ref.try_update(self.txn, VIEW_NAME, value.as_ref()); + } + self + } + + pub fn set_layout_type(self, value: DatabaseLayout) -> Self { + self.map_ref.insert(self.txn, DATABASE_VIEW_LAYOUT, value); + self + } + + pub fn set_layout_type_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self.map_ref.insert(self.txn, DATABASE_VIEW_LAYOUT, value); + } + self + } + + pub fn set_row_orders(self, orders: Vec) -> Self { + let array_ref: ArrayRef = self.map_ref.get_or_init(self.txn, DATABASE_VIEW_ROW_ORDERS); + let array = RowOrderArray::new(array_ref); + array.extends_with_txn(self.txn, orders); + self + } + + pub fn remove_row_order(self, id: &str) -> Self { + if let Some(array) = self + .map_ref + .get_with_txn::<_, ArrayRef>(self.txn, DATABASE_VIEW_ROW_ORDERS) + .map(RowOrderArray::new) + { + array.remove_with_txn(self.txn, id); + } + self + } + + pub fn move_row_order(self, from_id: &str, to_id: &str) -> Self { + if let Some(array) = self + .map_ref + .get_with_txn::<_, ArrayRef>(self.txn, DATABASE_VIEW_ROW_ORDERS) + .map(RowOrderArray::new) + { + array.move_to(self.txn, from_id, to_id); + } + self + } + + pub fn insert_row_order>( + self, + object: T, + position: &OrderObjectPosition, + ) -> Self { + let object = object.into(); + if let Some(array) = self + .map_ref + .get_with_txn::<_, ArrayRef>(self.txn, DATABASE_VIEW_ROW_ORDERS) + .map(RowOrderArray::new) + { + match position { + OrderObjectPosition::Start => array.push_front_with_txn(self.txn, object), + OrderObjectPosition::Before(next_object_id) => { + array.insert_before_with_txn(self.txn, object, next_object_id) + }, + OrderObjectPosition::After(prev_object_id) => { + array.insert_after_with_txn(self.txn, object, prev_object_id) + }, + OrderObjectPosition::End => array.push_back_with_txn(self.txn, object), + }; + } + self + } + + pub fn iter_mut_row_order(self, mut f: F) -> Self { + if let Some(array) = self + .map_ref + .get_with_txn::<_, ArrayRef>(self.txn, DATABASE_VIEW_ROW_ORDERS) + .map(RowOrderArray::new) + { + for mut row_order in array.get_objects_with_txn(self.txn) { + array.remove_with_txn(self.txn, &row_order.id.to_string()); + f(&mut row_order); + array.push_back(self.txn, row_order); + } + } + + self + } + + pub fn set_field_orders(self, orders: Vec) -> Self { + let array_ref: ArrayRef = self + .map_ref + .get_or_init(self.txn, DATABASE_VIEW_FIELD_ORDERS); + let array = FieldOrderArray::new(array_ref); + array.extends_with_txn(self.txn, orders); + self + } + + pub fn remove_field_order(self, id: &str) -> Self { + if let Some(array) = self + .map_ref + .get_with_txn::<_, ArrayRef>(self.txn, DATABASE_VIEW_FIELD_ORDERS) + .map(FieldOrderArray::new) + { + array.remove_with_txn(self.txn, id); + } + self + } + + pub fn move_field_order(self, from_id: &str, to_id: &str) -> Self { + if let Some(array) = self + .map_ref + .get_with_txn::<_, ArrayRef>(self.txn, DATABASE_VIEW_FIELD_ORDERS) + .map(FieldOrderArray::new) + { + array.move_to(self.txn, from_id, to_id); + } + self + } + + pub fn insert_field_order>( + self, + object: T, + position: &OrderObjectPosition, + ) -> Self { + let object = object.into(); + if let Some(array) = self + .map_ref + .get_with_txn::<_, ArrayRef>(self.txn, DATABASE_VIEW_FIELD_ORDERS) + .map(FieldOrderArray::new) + { + match position { + OrderObjectPosition::Start => array.push_front_with_txn(self.txn, object), + OrderObjectPosition::Before(next_object_id) => { + array.insert_before_with_txn(self.txn, object, next_object_id) + }, + OrderObjectPosition::After(prev_object_id) => { + array.insert_after_with_txn(self.txn, object, prev_object_id) + }, + OrderObjectPosition::End => array.push_back_with_txn(self.txn, object), + }; + } + self + } + + pub fn iter_mut_field_order(self, mut f: F) -> Self { + if let Some(array) = self + .map_ref + .get_with_txn::<_, ArrayRef>(self.txn, DATABASE_VIEW_FIELD_ORDERS) + .map(FieldOrderArray::new) + { + for mut field_order in array.get_objects_with_txn(self.txn) { + array.remove_with_txn(self.txn, &field_order.id.to_string()); + f(&mut field_order); + array.push_back(self.txn, field_order); + } + } + + self + } /// Set layout settings of the current view pub fn set_layout_settings(self, layout_settings: LayoutSettings) -> Self { @@ -300,8 +474,8 @@ pub fn view_meta_from_value(value: YrsValue, txn: &T) -> Option(map_ref: &MapRef, txn: &T) -> Option Result { +) -> Result { let object_uuid = Uuid::parse_str(object_id) - .map_err(|err| DatabaseError::Internal(anyhow!("Invalid object_id UUID: {}", err)))?; + .map_err(|err| CollabError::Internal(anyhow!("Invalid object_id UUID: {}", err)))?; let options = CollabOptions::new(object_uuid, client_id); let mut collab = Collab::new_with_options(CollabOrigin::Empty, options) - .map_err(|err| DatabaseError::Internal(anyhow!("Failed to create collab: {}", err)))?; + .map_err(|err| CollabError::Internal(anyhow!("Failed to create collab: {}", err)))?; let _ = WorkspaceDatabaseBody::create(&mut collab); collab - .encode_collab_v1(|_collab| Ok::<_, DatabaseError>(())) - .map_err(|err| DatabaseError::Internal(anyhow!("Failed to encode collab: {}", err))) + .encode_collab_v1(|_collab| Ok::<_, CollabError>(())) + .map_err(|err| CollabError::Internal(anyhow!("Failed to encode collab: {}", err))) } impl WorkspaceDatabase { - pub fn open(mut collab: Collab) -> Result { + pub fn open(mut collab: Collab) -> Result { CollabType::WorkspaceDatabase.validate_require_data(&collab)?; let body = WorkspaceDatabaseBody::open(&mut collab)?; Ok(Self { body, collab }) @@ -53,12 +53,12 @@ impl WorkspaceDatabase { origin: CollabOrigin, collab_doc_state: DataSource, client_id: ClientID, - ) -> Result { + ) -> Result { let object_uuid = Uuid::parse_str(object_id) - .map_err(|err| DatabaseError::Internal(anyhow!("Invalid object_id UUID: {}", err)))?; + .map_err(|err| CollabError::Internal(anyhow!("Invalid object_id UUID: {}", err)))?; let options = CollabOptions::new(object_uuid, client_id).with_data_source(collab_doc_state); let collab = Collab::new_with_options(origin, options) - .map_err(|err| DatabaseError::Internal(anyhow!("Failed to create collab: {}", err)))?; + .map_err(|err| CollabError::Internal(anyhow!("Failed to create collab: {}", err)))?; Self::open(collab) } @@ -131,16 +131,16 @@ impl WorkspaceDatabase { .find(|record| record.database_id == database_id) } - pub fn validate(&self) -> Result<(), DatabaseError> { + pub fn validate(&self) -> Result<(), CollabError> { CollabType::WorkspaceDatabase.validate_require_data(&self.collab)?; Ok(()) } - pub fn encode_collab_v1(&self) -> Result { + pub fn encode_collab_v1(&self) -> Result { self.validate()?; self .collab - .encode_collab_v1(|_collab| Ok::<_, DatabaseError>(())) + .encode_collab_v1(|_collab| Ok::<_, CollabError>(())) } } @@ -216,12 +216,12 @@ pub struct WorkspaceDatabaseBody { } impl WorkspaceDatabaseBody { - pub fn open(collab: &mut Collab) -> Result { + pub fn open(collab: &mut Collab) -> Result { let txn = collab.context.transact(); let array_ref = collab .data .get_with_txn(&txn, WORKSPACE_DATABASES) - .ok_or_else(|| DatabaseError::NoRequiredData(WORKSPACE_DATABASES.to_string()))?; + .ok_or_else(|| CollabError::NoRequiredData(WORKSPACE_DATABASES.to_string()))?; Ok(Self { array_ref }) } diff --git a/collab-database/src/workspace_database/mod.rs b/collab/src/database/workspace_database/mod.rs similarity index 100% rename from collab-database/src/workspace_database/mod.rs rename to collab/src/database/workspace_database/mod.rs diff --git a/collab-database/src/workspace_database/relation/db_relation.rs b/collab/src/database/workspace_database/relation/db_relation.rs similarity index 85% rename from collab-database/src/workspace_database/relation/db_relation.rs rename to collab/src/database/workspace_database/relation/db_relation.rs index 08cfab20f..88ae19bad 100644 --- a/collab-database/src/workspace_database/relation/db_relation.rs +++ b/collab/src/database/workspace_database/relation/db_relation.rs @@ -1,8 +1,8 @@ -use collab::lock::Mutex; -use collab::preclude::{Collab, Map}; +use crate::lock::Mutex; +use crate::preclude::{Collab, Map}; use std::sync::Arc; -use crate::workspace_database::relation::RowRelationMap; +use crate::database::workspace_database::relation::RowRelationMap; pub struct DatabaseRelation { #[allow(dead_code)] diff --git a/collab-database/src/workspace_database/relation/mod.rs b/collab/src/database/workspace_database/relation/mod.rs similarity index 100% rename from collab-database/src/workspace_database/relation/mod.rs rename to collab/src/database/workspace_database/relation/mod.rs diff --git a/collab-database/src/workspace_database/relation/row_relation.rs b/collab/src/database/workspace_database/relation/row_relation.rs similarity index 99% rename from collab-database/src/workspace_database/relation/row_relation.rs rename to collab/src/database/workspace_database/relation/row_relation.rs index b39c03e7e..ecac995bf 100644 --- a/collab-database/src/workspace_database/relation/row_relation.rs +++ b/collab/src/database/workspace_database/relation/row_relation.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use collab::preclude::{ +use crate::preclude::{ Array, ArrayRef, Map, MapExt, MapPrelim, MapRef, ReadTxn, TransactionMut, YrsValue, }; diff --git a/collab-database/src/workspace_database/relation/row_relation_map.rs b/collab/src/database/workspace_database/relation/row_relation_map.rs similarity index 94% rename from collab-database/src/workspace_database/relation/row_relation_map.rs rename to collab/src/database/workspace_database/relation/row_relation_map.rs index b0fbf4738..8bb4e429f 100644 --- a/collab-database/src/workspace_database/relation/row_relation_map.rs +++ b/collab/src/database/workspace_database/relation/row_relation_map.rs @@ -1,13 +1,13 @@ use std::ops::Deref; -use collab::preclude::{ +use crate::preclude::{ DeepObservable, EntryChange, Event, Map, MapPrelim, MapRef, Subscription, TransactionMut, YrsValue, }; use tokio::sync::broadcast; -use crate::workspace_database::relation::{RowRelation, RowRelationBuilder}; -use crate::workspace_database::row_relation_from_map_ref; +use crate::database::workspace_database::relation::{RowRelation, RowRelationBuilder}; +use crate::database::workspace_database::row_relation_from_map_ref; #[derive(Debug, Clone)] pub enum RowRelationChange { diff --git a/collab-document/src/block_parser/document_parser.rs b/collab/src/document/block_parser/document_parser.rs similarity index 91% rename from collab-document/src/block_parser/document_parser.rs rename to collab/src/document/block_parser/document_parser.rs index 9904a3803..a8dea59d5 100644 --- a/collab-document/src/block_parser/document_parser.rs +++ b/collab/src/document/block_parser/document_parser.rs @@ -1,12 +1,12 @@ -use crate::block_parser::{ +use super::{ BlockParserRegistry, BulletedListParser, CalloutParser, CodeBlockParser, DividerParser, DocumentParserDelegate, FileBlockParser, HeadingParser, ImageParser, LinkPreviewParser, MathEquationParser, NumberedListParser, OutputFormat, PageParser, ParagraphParser, ParseContext, QuoteListParser, SimpleColumnParser, SimpleColumnsParser, SimpleTableCellParser, SimpleTableParser, SimpleTableRowParser, SubpageParser, TodoListParser, ToggleListParser, }; -use crate::blocks::{Block, DocumentData}; -use crate::error::DocumentError; +use crate::document::blocks::{Block, DocumentData}; +use crate::error::CollabError; use std::sync::Arc; #[derive(Debug, Clone)] @@ -72,22 +72,18 @@ impl DocumentParser { &self, document_data: &DocumentData, format: OutputFormat, - ) -> Result { + ) -> Result { // find the page block first let page_block = document_data .blocks .get(&document_data.page_id) - .ok_or(DocumentError::PageBlockNotFound)?; + .ok_or(CollabError::DocumentPageBlockNotFound)?; let context = ParseContext::new(document_data, self, format); self.parse_block(page_block, &context) } - pub fn parse_block( - &self, - block: &Block, - context: &ParseContext, - ) -> Result { + pub fn parse_block(&self, block: &Block, context: &ParseContext) -> Result { let result = self.registry.parse_block(block, context)?; if result.is_container { @@ -115,7 +111,7 @@ impl DocumentParser { &self, child_ids: &[String], context: &ParseContext, - ) -> Result { + ) -> Result { let mut result = "".to_string(); for child_id in child_ids { diff --git a/collab-document/src/block_parser/mod.rs b/collab/src/document/block_parser/mod.rs similarity index 100% rename from collab-document/src/block_parser/mod.rs rename to collab/src/document/block_parser/mod.rs diff --git a/collab-document/src/block_parser/parsers/bulleted_list.rs b/collab/src/document/block_parser/parsers/bulleted_list.rs similarity index 89% rename from collab-document/src/block_parser/parsers/bulleted_list.rs rename to collab/src/document/block_parser/parsers/bulleted_list.rs index 537e9ebcf..a6f7df034 100644 --- a/collab-document/src/block_parser/parsers/bulleted_list.rs +++ b/collab/src/document/block_parser/parsers/bulleted_list.rs @@ -1,9 +1,9 @@ -use crate::block_parser::{ +use super::super::{ BlockParser, DefaultDocumentTextExtractor, DocumentTextExtractor, OutputFormat, ParseContext, ParseResult, }; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the bulleted list block. /// @@ -12,7 +12,7 @@ use crate::error::DocumentError; pub struct BulletedListParser; impl BlockParser for BulletedListParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let text_extractor = DefaultDocumentTextExtractor; let content = text_extractor.extract_text_from_block(block, context)?; diff --git a/collab-document/src/block_parser/parsers/callout.rs b/collab/src/document/block_parser/parsers/callout.rs similarity index 91% rename from collab-document/src/block_parser/parsers/callout.rs rename to collab/src/document/block_parser/parsers/callout.rs index 5f6e282f4..5b2dd2771 100644 --- a/collab-document/src/block_parser/parsers/callout.rs +++ b/collab/src/document/block_parser/parsers/callout.rs @@ -1,11 +1,11 @@ use serde_json::Value; -use crate::block_parser::{ +use super::super::{ BlockParser, DefaultDocumentTextExtractor, DocumentTextExtractor, OutputFormat, ParseContext, ParseResult, }; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the callout block. /// @@ -18,7 +18,7 @@ pub struct CalloutParser; const ICON_KEY: &str = "icon"; impl BlockParser for CalloutParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let text_extractor = DefaultDocumentTextExtractor; let content = text_extractor.extract_text_from_block(block, context)?; diff --git a/collab-document/src/block_parser/parsers/code_block.rs b/collab/src/document/block_parser/parsers/code_block.rs similarity index 90% rename from collab-document/src/block_parser/parsers/code_block.rs rename to collab/src/document/block_parser/parsers/code_block.rs index fe6e14538..d54887358 100644 --- a/collab-document/src/block_parser/parsers/code_block.rs +++ b/collab/src/document/block_parser/parsers/code_block.rs @@ -1,11 +1,11 @@ use serde_json::Value; -use crate::block_parser::{ +use super::super::{ BlockParser, DefaultDocumentTextExtractor, DocumentTextExtractor, OutputFormat, ParseContext, ParseResult, }; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the code block. /// @@ -18,7 +18,7 @@ pub struct CodeBlockParser; const LANGUAGE_KEY: &str = "language"; impl BlockParser for CodeBlockParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let text_extractor = DefaultDocumentTextExtractor; let content = text_extractor.extract_text_from_block(block, context)?; diff --git a/collab-document/src/block_parser/parsers/divider.rs b/collab/src/document/block_parser/parsers/divider.rs similarity index 77% rename from collab-document/src/block_parser/parsers/divider.rs rename to collab/src/document/block_parser/parsers/divider.rs index 62eee0efb..0ba663407 100644 --- a/collab-document/src/block_parser/parsers/divider.rs +++ b/collab/src/document/block_parser/parsers/divider.rs @@ -1,6 +1,6 @@ -use crate::block_parser::{BlockParser, OutputFormat, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, OutputFormat, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the divider block. /// @@ -8,7 +8,7 @@ use crate::error::DocumentError; pub struct DividerParser; impl BlockParser for DividerParser { - fn parse(&self, _block: &Block, context: &ParseContext) -> Result { + fn parse(&self, _block: &Block, context: &ParseContext) -> Result { let formatted_content = match context.format { OutputFormat::Markdown => { let indent = context.get_indent(); diff --git a/collab-document/src/block_parser/parsers/file_block.rs b/collab/src/document/block_parser/parsers/file_block.rs similarity index 88% rename from collab-document/src/block_parser/parsers/file_block.rs rename to collab/src/document/block_parser/parsers/file_block.rs index 10b05451b..52a6d1276 100644 --- a/collab-document/src/block_parser/parsers/file_block.rs +++ b/collab/src/document/block_parser/parsers/file_block.rs @@ -1,8 +1,8 @@ use serde_json::Value; -use crate::block_parser::{BlockParser, OutputFormat, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, OutputFormat, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the file block. /// @@ -16,7 +16,7 @@ const NAME_KEY: &str = "name"; const URL_KEY: &str = "url"; impl BlockParser for FileBlockParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let name = block .data .get(NAME_KEY) diff --git a/collab-document/src/block_parser/parsers/heading.rs b/collab/src/document/block_parser/parsers/heading.rs similarity index 91% rename from collab-document/src/block_parser/parsers/heading.rs rename to collab/src/document/block_parser/parsers/heading.rs index 093d22dc0..ed39452ab 100644 --- a/collab-document/src/block_parser/parsers/heading.rs +++ b/collab/src/document/block_parser/parsers/heading.rs @@ -1,11 +1,11 @@ use serde_json::Value; -use crate::block_parser::{ +use super::super::{ BlockParser, DefaultDocumentTextExtractor, DocumentTextExtractor, OutputFormat, ParseContext, ParseResult, }; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the heading block. /// @@ -21,7 +21,7 @@ const MIN_LEVEL: usize = 1; const LEVEL_KEY: &str = "level"; impl BlockParser for HeadingParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let text_extractor = DefaultDocumentTextExtractor; let content = text_extractor.extract_text_from_block(block, context)?; diff --git a/collab-document/src/block_parser/parsers/image.rs b/collab/src/document/block_parser/parsers/image.rs similarity index 76% rename from collab-document/src/block_parser/parsers/image.rs rename to collab/src/document/block_parser/parsers/image.rs index d0b5fd32a..54ded0e6c 100644 --- a/collab-document/src/block_parser/parsers/image.rs +++ b/collab/src/document/block_parser/parsers/image.rs @@ -1,6 +1,6 @@ -use crate::block_parser::{BlockParser, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the image block. /// @@ -12,7 +12,7 @@ pub struct ImageParser; const URL_KEY: &str = "url"; impl BlockParser for ImageParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { // Extract the URL from block data let url = block .data @@ -21,14 +21,14 @@ impl BlockParser for ImageParser { .unwrap_or(""); let formatted_content = match context.format { - crate::block_parser::OutputFormat::Markdown => { + crate::document::OutputFormat::Markdown => { if url.is_empty() { "![Image]()".to_string() } else { format!("![Image]({})", url) } }, - crate::block_parser::OutputFormat::PlainText => url.to_string(), + crate::document::OutputFormat::PlainText => url.to_string(), }; let children_content = self.parse_children(block, context); diff --git a/collab-document/src/block_parser/parsers/link_preview.rs b/collab/src/document/block_parser/parsers/link_preview.rs similarity index 85% rename from collab-document/src/block_parser/parsers/link_preview.rs rename to collab/src/document/block_parser/parsers/link_preview.rs index 63012916c..ec6321805 100644 --- a/collab-document/src/block_parser/parsers/link_preview.rs +++ b/collab/src/document/block_parser/parsers/link_preview.rs @@ -1,8 +1,8 @@ use serde_json::Value; -use crate::block_parser::{BlockParser, OutputFormat, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, OutputFormat, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the link preview block. /// @@ -14,7 +14,7 @@ pub struct LinkPreviewParser; const URL_KEY: &str = "url"; impl BlockParser for LinkPreviewParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let url = block .data .get(URL_KEY) diff --git a/collab-document/src/block_parser/parsers/math_equation.rs b/collab/src/document/block_parser/parsers/math_equation.rs similarity index 86% rename from collab-document/src/block_parser/parsers/math_equation.rs rename to collab/src/document/block_parser/parsers/math_equation.rs index b9e3880cb..ad9487712 100644 --- a/collab-document/src/block_parser/parsers/math_equation.rs +++ b/collab/src/document/block_parser/parsers/math_equation.rs @@ -1,8 +1,8 @@ use serde_json::Value; -use crate::block_parser::{BlockParser, OutputFormat, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, OutputFormat, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the math equation block. /// @@ -14,7 +14,7 @@ pub struct MathEquationParser; const FORMULA_KEY: &str = "formula"; impl BlockParser for MathEquationParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let formula = block .data .get(FORMULA_KEY) diff --git a/collab-document/src/block_parser/parsers/mod.rs b/collab/src/document/block_parser/parsers/mod.rs similarity index 100% rename from collab-document/src/block_parser/parsers/mod.rs rename to collab/src/document/block_parser/parsers/mod.rs diff --git a/collab-document/src/block_parser/parsers/numbered_list.rs b/collab/src/document/block_parser/parsers/numbered_list.rs similarity index 92% rename from collab-document/src/block_parser/parsers/numbered_list.rs rename to collab/src/document/block_parser/parsers/numbered_list.rs index ebcff5224..60062f1f5 100644 --- a/collab-document/src/block_parser/parsers/numbered_list.rs +++ b/collab/src/document/block_parser/parsers/numbered_list.rs @@ -1,11 +1,11 @@ use serde_json::Value; -use crate::block_parser::{ +use super::super::{ BlockParser, DefaultDocumentTextExtractor, DocumentTextExtractor, OutputFormat, ParseContext, ParseResult, }; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the numbered list block. /// @@ -18,7 +18,7 @@ pub struct NumberedListParser; const NUMBER_KEY: &str = "number"; impl BlockParser for NumberedListParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let text_extractor = DefaultDocumentTextExtractor; let content = text_extractor.extract_text_from_block(block, context)?; diff --git a/collab-document/src/block_parser/parsers/page.rs b/collab/src/document/block_parser/parsers/page.rs similarity index 87% rename from collab-document/src/block_parser/parsers/page.rs rename to collab/src/document/block_parser/parsers/page.rs index 7dcddbbca..13878582c 100644 --- a/collab-document/src/block_parser/parsers/page.rs +++ b/collab/src/document/block_parser/parsers/page.rs @@ -1,6 +1,6 @@ -use crate::block_parser::{BlockParser, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the page block. /// @@ -9,7 +9,7 @@ use crate::error::DocumentError; pub struct PageParser; impl BlockParser for PageParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let children_content = self.parse_children(block, context); Ok(ParseResult::new(children_content)) } diff --git a/collab-document/src/block_parser/parsers/paragraph.rs b/collab/src/document/block_parser/parsers/paragraph.rs similarity index 85% rename from collab-document/src/block_parser/parsers/paragraph.rs rename to collab/src/document/block_parser/parsers/paragraph.rs index 0ad71db83..51cc35192 100644 --- a/collab-document/src/block_parser/parsers/paragraph.rs +++ b/collab/src/document/block_parser/parsers/paragraph.rs @@ -1,8 +1,8 @@ -use crate::block_parser::{ +use super::super::{ BlockParser, DefaultDocumentTextExtractor, DocumentTextExtractor, ParseContext, ParseResult, }; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the paragraph block. /// @@ -11,7 +11,7 @@ use crate::error::DocumentError; pub struct ParagraphParser; impl BlockParser for ParagraphParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let text_extractor = DefaultDocumentTextExtractor; let content = text_extractor.extract_text_from_block(block, context)?; diff --git a/collab-document/src/block_parser/parsers/quote_list.rs b/collab/src/document/block_parser/parsers/quote_list.rs similarity index 89% rename from collab-document/src/block_parser/parsers/quote_list.rs rename to collab/src/document/block_parser/parsers/quote_list.rs index 69d930732..4893e608a 100644 --- a/collab-document/src/block_parser/parsers/quote_list.rs +++ b/collab/src/document/block_parser/parsers/quote_list.rs @@ -1,9 +1,9 @@ -use crate::block_parser::{ +use super::super::{ BlockParser, DefaultDocumentTextExtractor, DocumentTextExtractor, OutputFormat, ParseContext, ParseResult, }; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the quote list block. /// @@ -11,7 +11,7 @@ use crate::error::DocumentError; pub struct QuoteListParser; impl BlockParser for QuoteListParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let text_extractor = DefaultDocumentTextExtractor; let content = text_extractor.extract_text_from_block(block, context)?; diff --git a/collab-document/src/block_parser/parsers/simple_column.rs b/collab/src/document/block_parser/parsers/simple_column.rs similarity index 73% rename from collab-document/src/block_parser/parsers/simple_column.rs rename to collab/src/document/block_parser/parsers/simple_column.rs index 45178f700..202a3e5dc 100644 --- a/collab-document/src/block_parser/parsers/simple_column.rs +++ b/collab/src/document/block_parser/parsers/simple_column.rs @@ -1,6 +1,6 @@ -use crate::block_parser::{BlockParser, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the simple column block. /// @@ -9,7 +9,7 @@ use crate::error::DocumentError; pub struct SimpleColumnParser; impl BlockParser for SimpleColumnParser { - fn parse(&self, _block: &Block, _context: &ParseContext) -> Result { + fn parse(&self, _block: &Block, _context: &ParseContext) -> Result { // simple column block is a container that holds content. // Return empty content but signal that this block has children. Ok(ParseResult::container("".to_string())) diff --git a/collab-document/src/block_parser/parsers/simple_columns.rs b/collab/src/document/block_parser/parsers/simple_columns.rs similarity index 74% rename from collab-document/src/block_parser/parsers/simple_columns.rs rename to collab/src/document/block_parser/parsers/simple_columns.rs index 71e672254..b89820aac 100644 --- a/collab-document/src/block_parser/parsers/simple_columns.rs +++ b/collab/src/document/block_parser/parsers/simple_columns.rs @@ -1,6 +1,6 @@ -use crate::block_parser::{BlockParser, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the simple columns block. /// @@ -9,7 +9,7 @@ use crate::error::DocumentError; pub struct SimpleColumnsParser; impl BlockParser for SimpleColumnsParser { - fn parse(&self, _block: &Block, _context: &ParseContext) -> Result { + fn parse(&self, _block: &Block, _context: &ParseContext) -> Result { // simple columns block is a container that holds multiple simple column blocks. // the children of simple columns are simple column blocks. Ok(ParseResult::container("".to_string())) diff --git a/collab-document/src/block_parser/parsers/simple_table.rs b/collab/src/document/block_parser/parsers/simple_table.rs similarity index 91% rename from collab-document/src/block_parser/parsers/simple_table.rs rename to collab/src/document/block_parser/parsers/simple_table.rs index 1c6d700ae..ec2f2067c 100644 --- a/collab-document/src/block_parser/parsers/simple_table.rs +++ b/collab/src/document/block_parser/parsers/simple_table.rs @@ -1,6 +1,6 @@ -use crate::block_parser::{BlockParser, OutputFormat, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, OutputFormat, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the simple table block. /// @@ -9,7 +9,7 @@ use crate::error::DocumentError; pub struct SimpleTableParser; impl BlockParser for SimpleTableParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { match context.format { OutputFormat::PlainText => { // For plain text, just use the default container behavior diff --git a/collab-document/src/block_parser/parsers/simple_table_cell.rs b/collab/src/document/block_parser/parsers/simple_table_cell.rs similarity index 71% rename from collab-document/src/block_parser/parsers/simple_table_cell.rs rename to collab/src/document/block_parser/parsers/simple_table_cell.rs index 7fccfd028..cd37224f4 100644 --- a/collab-document/src/block_parser/parsers/simple_table_cell.rs +++ b/collab/src/document/block_parser/parsers/simple_table_cell.rs @@ -1,6 +1,6 @@ -use crate::block_parser::{BlockParser, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the simple table cell block. /// @@ -9,7 +9,7 @@ use crate::error::DocumentError; pub struct SimpleTableCellParser; impl BlockParser for SimpleTableCellParser { - fn parse(&self, _block: &Block, _context: &ParseContext) -> Result { + fn parse(&self, _block: &Block, _context: &ParseContext) -> Result { Ok(ParseResult::container("".to_string())) } diff --git a/collab-document/src/block_parser/parsers/simple_table_row.rs b/collab/src/document/block_parser/parsers/simple_table_row.rs similarity index 87% rename from collab-document/src/block_parser/parsers/simple_table_row.rs rename to collab/src/document/block_parser/parsers/simple_table_row.rs index e527b0968..7c7027797 100644 --- a/collab-document/src/block_parser/parsers/simple_table_row.rs +++ b/collab/src/document/block_parser/parsers/simple_table_row.rs @@ -1,6 +1,6 @@ -use crate::block_parser::{BlockParser, OutputFormat, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, OutputFormat, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the simple table row block. /// @@ -9,7 +9,7 @@ use crate::error::DocumentError; pub struct SimpleTableRowParser; impl BlockParser for SimpleTableRowParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { if block.children.is_empty() { return Ok(ParseResult::new("".to_string())); } diff --git a/collab-document/src/block_parser/parsers/subpage.rs b/collab/src/document/block_parser/parsers/subpage.rs similarity index 86% rename from collab-document/src/block_parser/parsers/subpage.rs rename to collab/src/document/block_parser/parsers/subpage.rs index 35eaa3d88..80466d049 100644 --- a/collab-document/src/block_parser/parsers/subpage.rs +++ b/collab/src/document/block_parser/parsers/subpage.rs @@ -1,8 +1,8 @@ use serde_json::Value; -use crate::block_parser::{BlockParser, OutputFormat, ParseContext, ParseResult}; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use super::super::{BlockParser, OutputFormat, ParseContext, ParseResult}; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the subpage block. /// @@ -14,7 +14,7 @@ pub struct SubpageParser; const VIEW_ID_KEY: &str = "viewId"; impl BlockParser for SubpageParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let view_id = block .data .get(VIEW_ID_KEY) diff --git a/collab-document/src/block_parser/parsers/todo_list.rs b/collab/src/document/block_parser/parsers/todo_list.rs similarity index 91% rename from collab-document/src/block_parser/parsers/todo_list.rs rename to collab/src/document/block_parser/parsers/todo_list.rs index f1eb1e683..844ede3fc 100644 --- a/collab-document/src/block_parser/parsers/todo_list.rs +++ b/collab/src/document/block_parser/parsers/todo_list.rs @@ -1,9 +1,9 @@ -use crate::block_parser::{ +use super::super::{ BlockParser, DefaultDocumentTextExtractor, DocumentTextExtractor, OutputFormat, ParseContext, ParseResult, }; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the todo list block. /// @@ -15,7 +15,7 @@ pub struct TodoListParser; const CHECKED_KEY: &str = "checked"; impl BlockParser for TodoListParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let text_extractor = DefaultDocumentTextExtractor; let content = text_extractor.extract_text_from_block(block, context)?; diff --git a/collab-document/src/block_parser/parsers/toggle_list.rs b/collab/src/document/block_parser/parsers/toggle_list.rs similarity index 91% rename from collab-document/src/block_parser/parsers/toggle_list.rs rename to collab/src/document/block_parser/parsers/toggle_list.rs index 69e2615e1..ebad44a40 100644 --- a/collab-document/src/block_parser/parsers/toggle_list.rs +++ b/collab/src/document/block_parser/parsers/toggle_list.rs @@ -1,9 +1,9 @@ -use crate::block_parser::{ +use super::super::{ BlockParser, DefaultDocumentTextExtractor, DocumentTextExtractor, OutputFormat, ParseContext, ParseResult, }; -use crate::blocks::{Block, BlockType}; -use crate::error::DocumentError; +use crate::document::blocks::{Block, BlockType}; +use crate::error::CollabError; /// Parse the toggle list block. /// @@ -12,7 +12,7 @@ use crate::error::DocumentError; pub struct ToggleListParser; impl BlockParser for ToggleListParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result { + fn parse(&self, block: &Block, context: &ParseContext) -> Result { let text_extractor = DefaultDocumentTextExtractor; let content = text_extractor.extract_text_from_block(block, context)?; diff --git a/collab-document/src/block_parser/registry.rs b/collab/src/document/block_parser/registry.rs similarity index 88% rename from collab-document/src/block_parser/registry.rs rename to collab/src/document/block_parser/registry.rs index 98620b697..d358f1176 100644 --- a/collab-document/src/block_parser/registry.rs +++ b/collab/src/document/block_parser/registry.rs @@ -1,6 +1,6 @@ -use crate::block_parser::{BlockParser, ParseContext, ParseResult}; -use crate::blocks::Block; -use crate::error::DocumentError; +use super::{BlockParser, ParseContext, ParseResult}; +use crate::document::blocks::Block; +use crate::error::CollabError; use std::collections::HashMap; use std::fmt::{Debug, Formatter}; use std::sync::Arc; @@ -43,7 +43,7 @@ impl BlockParserRegistry { &self, block: &Block, context: &ParseContext, - ) -> Result { + ) -> Result { if let Some(parser) = self.get_parser(&block.ty) { parser.parse(block, context) } else { diff --git a/collab-document/src/block_parser/text_utils.rs b/collab/src/document/block_parser/text_utils.rs similarity index 83% rename from collab-document/src/block_parser/text_utils.rs rename to collab/src/document/block_parser/text_utils.rs index fd3a313d8..22f468262 100644 --- a/collab-document/src/block_parser/text_utils.rs +++ b/collab/src/document/block_parser/text_utils.rs @@ -1,8 +1,8 @@ -use crate::block_parser::OutputFormat; -use crate::block_parser::traits::ParseContext; -use crate::blocks::{AttrKey, Block, TextDelta}; -use crate::error::DocumentError; -use collab::preclude::{Any, Attrs}; +use super::OutputFormat; +use super::traits::ParseContext; +use crate::document::blocks::{AttrKey, Block, TextDelta}; +use crate::error::CollabError; +use crate::preclude::{Any, Attrs}; pub trait DocumentTextExtractor { /// Get the plain text or markdown text from the block @@ -10,21 +10,21 @@ pub trait DocumentTextExtractor { &self, block: &Block, context: &ParseContext, - ) -> Result; + ) -> Result; /// Get the plain text from the delta json string with delegate support fn extract_plain_text_from_delta_with_context( &self, delta_json: &str, context: Option<&ParseContext>, - ) -> Result; + ) -> Result; /// Get the markdown text from the delta json string with delegate support fn extract_markdown_text_from_delta_with_context( &self, delta_json: &str, context: Option<&ParseContext>, - ) -> Result; + ) -> Result; } pub struct DefaultDocumentTextExtractor; @@ -34,7 +34,7 @@ impl DocumentTextExtractor for DefaultDocumentTextExtractor { &self, block: &Block, context: &ParseContext, - ) -> Result { + ) -> Result { let external_id = block.external_id.as_ref(); if let Some(external_id) = external_id { let delta_json = context @@ -64,9 +64,9 @@ impl DocumentTextExtractor for DefaultDocumentTextExtractor { &self, delta_json: &str, context: Option<&ParseContext>, - ) -> Result { - let deltas: Vec = serde_json::from_str(delta_json) - .map_err(|_| DocumentError::ParseDeltaJsonToTextDeltaError)?; + ) -> Result { + let deltas: Vec = + serde_json::from_str(delta_json).map_err(|_| CollabError::DocumentParseDeltaJson)?; let mut result = "".to_string(); @@ -93,9 +93,9 @@ impl DocumentTextExtractor for DefaultDocumentTextExtractor { &self, delta_json: &str, context: Option<&ParseContext>, - ) -> Result { - let deltas: Vec = serde_json::from_str(delta_json) - .map_err(|_| DocumentError::ParseDeltaJsonToTextDeltaError)?; + ) -> Result { + let deltas: Vec = + serde_json::from_str(delta_json).map_err(|_| CollabError::DocumentParseDeltaJson)?; let mut result = "".to_string(); diff --git a/collab-document/src/block_parser/traits.rs b/collab/src/document/block_parser/traits.rs similarity index 97% rename from collab-document/src/block_parser/traits.rs rename to collab/src/document/block_parser/traits.rs index e723a7cfb..a7f90804d 100644 --- a/collab-document/src/block_parser/traits.rs +++ b/collab/src/document/block_parser/traits.rs @@ -1,11 +1,11 @@ use std::fmt::Debug; -use crate::{ - block_parser::DocumentParser, +use crate::document::{ + DocumentParser, blocks::{Block, DocumentData}, - error::DocumentError, }; -use collab::preclude::Attrs; +use crate::error::CollabError; +use crate::preclude::Attrs; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum OutputFormat { @@ -136,7 +136,7 @@ impl ParseResult { } pub trait BlockParser { - fn parse(&self, block: &Block, context: &ParseContext) -> Result; + fn parse(&self, block: &Block, context: &ParseContext) -> Result; fn block_type(&self) -> &'static str; diff --git a/collab-document/src/blocks/attr_keys.rs b/collab/src/document/blocks/attr_keys.rs similarity index 100% rename from collab-document/src/blocks/attr_keys.rs rename to collab/src/document/blocks/attr_keys.rs diff --git a/collab-document/src/blocks/block.rs b/collab/src/document/blocks/block.rs similarity index 90% rename from collab-document/src/blocks/block.rs rename to collab/src/document/blocks/block.rs index 4363c04d3..68d2b0e2e 100644 --- a/collab-document/src/blocks/block.rs +++ b/collab/src/document/blocks/block.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use crate::blocks::{Block, ChildrenOperation, hashmap_to_json_str, json_str_to_hashmap}; -use crate::error::DocumentError; -use collab::preclude::{Map, MapExt, MapRef, ReadTxn, TransactionMut}; +use super::{Block, ChildrenOperation, hashmap_to_json_str, json_str_to_hashmap}; +use crate::error::CollabError; +use crate::preclude::{Map, MapExt, MapRef, ReadTxn, TransactionMut}; use serde_json::Value; pub const EXTERNAL_TYPE_TEXT: &str = "text"; @@ -49,9 +49,9 @@ impl BlockOperation { &self, txn: &mut TransactionMut, block: Block, - ) -> Result { + ) -> Result { if self.root.get(txn, &block.id).is_some() { - return Err(DocumentError::BlockAlreadyExists); + return Err(CollabError::DocumentBlockAlreadyExists); } let block_id = block.id.clone(); @@ -78,7 +78,7 @@ impl BlockOperation { // Return the created block. self .get_block_with_txn(txn, &block_id) - .ok_or(DocumentError::BlockCreateError) + .ok_or(CollabError::DocumentBlockCreate) } /// Delete a block @@ -86,10 +86,10 @@ impl BlockOperation { &self, txn: &mut TransactionMut, id: &str, - ) -> Result { + ) -> Result { let block = self .get_block_with_txn(txn, id) - .ok_or(DocumentError::BlockIsNotFound)?; + .ok_or(CollabError::DocumentBlockNotFound)?; self.root.remove(txn, id); // Delete the children for each block. @@ -118,11 +118,11 @@ impl BlockOperation { parent_id: Option<&str>, external_id: Option, external_type: Option, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { let map: MapRef = self .root .get_with_txn(txn, id) - .ok_or(DocumentError::BlockIsNotFound)?; + .ok_or(CollabError::DocumentBlockNotFound)?; // Update parent field with the given parent id. if let Some(parent_id) = parent_id { diff --git a/collab-document/src/blocks/block_types.rs b/collab/src/document/blocks/block_types.rs similarity index 98% rename from collab-document/src/blocks/block_types.rs rename to collab/src/document/blocks/block_types.rs index 1b8036d70..0207ee86f 100644 --- a/collab-document/src/blocks/block_types.rs +++ b/collab/src/document/blocks/block_types.rs @@ -2,7 +2,7 @@ use std::{fmt::Display, str::FromStr}; use serde::{Deserialize, Serialize}; -use crate::error::DocumentError; +use crate::error::CollabError; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum BlockType { @@ -119,7 +119,7 @@ impl BlockType { } impl FromStr for BlockType { - type Err = DocumentError; + type Err = CollabError; fn from_str(s: &str) -> Result { Ok(Self::from_block_ty(s)) diff --git a/collab-document/src/blocks/children.rs b/collab/src/document/blocks/children.rs similarity index 99% rename from collab-document/src/blocks/children.rs rename to collab/src/document/blocks/children.rs index f55030e22..344c02022 100644 --- a/collab-document/src/blocks/children.rs +++ b/collab/src/document/blocks/children.rs @@ -1,4 +1,4 @@ -use collab::preclude::*; +use crate::preclude::*; use std::collections::HashMap; #[derive(Clone)] diff --git a/collab-document/src/blocks/entities.rs b/collab/src/document/blocks/entities.rs similarity index 100% rename from collab-document/src/blocks/entities.rs rename to collab/src/document/blocks/entities.rs diff --git a/collab-document/src/blocks/mod.rs b/collab/src/document/blocks/mod.rs similarity index 100% rename from collab-document/src/blocks/mod.rs rename to collab/src/document/blocks/mod.rs diff --git a/collab-document/src/blocks/text.rs b/collab/src/document/blocks/text.rs similarity index 98% rename from collab-document/src/blocks/text.rs rename to collab/src/document/blocks/text.rs index 240144045..2ba1b166d 100644 --- a/collab-document/src/blocks/text.rs +++ b/collab/src/document/blocks/text.rs @@ -1,6 +1,6 @@ -use crate::blocks::text_entities::TextDelta; -use collab::preclude::*; -use collab::util::TextExt; +use super::text_entities::TextDelta; +use crate::preclude::*; +use crate::util::TextExt; use serde::Deserialize; use serde_json::json; use std::collections::HashMap; diff --git a/collab-document/src/blocks/text_entities.rs b/collab/src/document/blocks/text_entities.rs similarity index 99% rename from collab-document/src/blocks/text_entities.rs rename to collab/src/document/blocks/text_entities.rs index 08033576a..0aba6d4fc 100644 --- a/collab-document/src/blocks/text_entities.rs +++ b/collab/src/document/blocks/text_entities.rs @@ -7,7 +7,7 @@ use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor}; use serde::ser::SerializeMap; use serde::{Serialize, Serializer}; -use collab::preclude::{Any, Attrs, Delta, YrsInput}; +use crate::preclude::{Any, Attrs, Delta, YrsInput}; const FIELD_INSERT: &str = "insert"; const FIELD_DELETE: &str = "delete"; diff --git a/collab-document/src/blocks/utils.rs b/collab/src/document/blocks/utils.rs similarity index 91% rename from collab-document/src/blocks/utils.rs rename to collab/src/document/blocks/utils.rs index f23ed714a..651aa52b3 100644 --- a/collab-document/src/blocks/utils.rs +++ b/collab/src/document/blocks/utils.rs @@ -1,8 +1,8 @@ -use crate::blocks::text_entities::TextDelta; -use crate::blocks::{BlockEvent, BlockEventPayload, DeltaType}; -use crate::error::DocumentError; -use collab::preclude::text::YChange; -use collab::preclude::{ +use super::text_entities::TextDelta; +use super::{BlockEvent, BlockEventPayload, DeltaType}; +use crate::error::CollabError; +use crate::preclude::text::YChange; +use crate::preclude::{ Array, Delta, EntryChange, Event, Map, PathSegment, ReadTxn, Text, TextRef, TransactionMut, YrsDelta, YrsValue, }; @@ -10,13 +10,13 @@ use serde_json::Value; use std::collections::HashMap; /// block data json string to hashmap -pub fn json_str_to_hashmap(json_str: &str) -> Result, DocumentError> { - serde_json::from_str(json_str).map_err(|_| DocumentError::ConvertDataError) +pub fn json_str_to_hashmap(json_str: &str) -> Result, CollabError> { + serde_json::from_str(json_str).map_err(|_| CollabError::DocumentConvertData) } /// block data hashmap to json string -pub fn hashmap_to_json_str(data: HashMap) -> Result { - serde_json::to_string(&data).map_err(|_| DocumentError::ConvertDataError) +pub fn hashmap_to_json_str(data: HashMap) -> Result { + serde_json::to_string(&data).map_err(|_| CollabError::DocumentConvertData) } /// parse block change event to BlockEvent diff --git a/collab-document/src/document.rs b/collab/src/document/document.rs similarity index 90% rename from collab-document/src/document.rs rename to collab/src/document/document.rs index f8c56be0e..1e52093a9 100644 --- a/collab-document/src/document.rs +++ b/collab/src/document/document.rs @@ -1,12 +1,12 @@ +use crate::core::collab::CollabOptions; +use crate::core::collab::DataSource; +use crate::core::origin::CollabOrigin; +use crate::entity::CollabType; +use crate::entity::EncodedCollab; +use crate::entity::define::DOCUMENT_ROOT; +use crate::preclude::block::ClientID; +use crate::preclude::*; use anyhow::anyhow; -use collab::core::collab::CollabOptions; -use collab::core::collab::DataSource; -use collab::core::origin::CollabOrigin; -use collab::entity::EncodedCollab; -use collab::preclude::block::ClientID; -use collab::preclude::*; -use collab_entity::CollabType; -use collab_entity::define::DOCUMENT_ROOT; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::borrow::{Borrow, BorrowMut}; @@ -15,16 +15,16 @@ use std::ops::{Deref, DerefMut}; use std::vec; use uuid::Uuid; -use crate::block_parser::DocumentParser; -use crate::block_parser::OutputFormat; -use crate::blocks::BlockType; -use crate::blocks::{ +use super::block_parser::DocumentParser; +use super::block_parser::OutputFormat; +use super::blocks::BlockType; +use super::blocks::{ Block, BlockAction, BlockActionPayload, BlockActionType, BlockEvent, BlockOperation, ChildrenOperation, DocumentData, DocumentMeta, EXTERNAL_TYPE_TEXT, TextDelta, TextOperation, deserialize_text_delta, parse_event, }; -use crate::document_awareness::DocumentAwarenessState; -use crate::error::DocumentError; +use super::document_awareness::DocumentAwarenessState; +use crate::error::CollabError; /// The page_id is a reference that points to the block's id. /// The block that is referenced by this page_id is the first block of the document. @@ -49,7 +49,7 @@ pub struct Document { impl Document { /// Opening a document with given [Collab] /// If the required fields are not present in the current [Collab] instance, it will return an error. - pub fn open(mut collab: Collab) -> Result { + pub fn open(mut collab: Collab) -> Result { CollabType::Document.validate_require_data(&collab)?; let body = DocumentBody::new(&mut collab, None)?; Ok(Self { collab, body }) @@ -62,15 +62,15 @@ impl Document { doc_state: DataSource, document_id: &str, client_id: ClientID, - ) -> Result { + ) -> Result { let document_uuid = Uuid::parse_str(document_id) - .map_err(|_| DocumentError::Internal(anyhow!("Invalid document id:")))?; + .map_err(|_| CollabError::Internal(anyhow!("Invalid document id:")))?; let options = CollabOptions::new(document_uuid, client_id).with_data_source(doc_state); let collab = Collab::new_with_options(origin, options)?; Document::open(collab) } - pub fn create_with_data(mut collab: Collab, data: DocumentData) -> Result { + pub fn create_with_data(mut collab: Collab, data: DocumentData) -> Result { let body = DocumentBody::new(&mut collab, Some(data))?; Ok(Self { collab, body }) } @@ -79,9 +79,9 @@ impl Document { document_id: &str, data: DocumentData, client_id: ClientID, - ) -> Result { + ) -> Result { let document_uuid = Uuid::parse_str(document_id) - .map_err(|_| DocumentError::Internal(anyhow!("Invalid document id:")))?; + .map_err(|_| CollabError::Internal(anyhow!("Invalid document id:")))?; let options = CollabOptions::new(document_uuid, client_id); let collab = Collab::new_with_options(CollabOrigin::Empty, options)?; Self::create_with_data(collab, data) @@ -92,18 +92,18 @@ impl Document { (self.collab, self.body) } - pub fn validate(&self) -> Result<(), DocumentError> { + pub fn validate(&self) -> Result<(), CollabError> { CollabType::Document .validate_require_data(&self.collab) - .map_err(|_| DocumentError::NoRequiredData)?; + .map_err(|_| CollabError::DocumentMissingRequiredData)?; Ok(()) } - pub fn encode_collab(&self) -> Result { + pub fn encode_collab(&self) -> Result { self.collab.encode_collab_v1(|collab| { CollabType::Document .validate_require_data(collab) - .map_err(|_| DocumentError::NoRequiredData) + .map_err(|_| CollabError::DocumentMissingRequiredData) }) } @@ -127,7 +127,7 @@ impl Document { } /// Get document data. - pub fn get_document_data(&self) -> Result { + pub fn get_document_data(&self) -> Result { let txn = self.collab.transact(); self.body.get_document_data(&txn) } @@ -160,7 +160,7 @@ impl Document { } /// Apply actions to the document. - pub fn apply_action(&mut self, actions: Vec) -> Result<(), DocumentError> { + pub fn apply_action(&mut self, actions: Vec) -> Result<(), CollabError> { let mut txn = self.collab.transact_mut(); for action in actions { #[cfg(feature = "verbose_log")] @@ -213,12 +213,12 @@ impl Document { &mut self, block: Block, prev_id: Option, - ) -> Result { + ) -> Result { let mut txn = self.collab.transact_mut(); self.body.insert_block(&mut txn, block, prev_id) } - pub fn delete_block(&mut self, block_id: &str) -> Result<(), DocumentError> { + pub fn delete_block(&mut self, block_id: &str) -> Result<(), CollabError> { let mut txn = self.collab.transact_mut(); self.body.delete_block(&mut txn, block_id) } @@ -236,7 +236,7 @@ impl Document { pub fn get_block_ids>( &self, block_types: Vec, - ) -> Result, DocumentError> { + ) -> Result, CollabError> { let txn = self.collab.transact(); let blocks = self.body.block_operation.get_all_blocks(&txn); let block_ids = blocks @@ -314,7 +314,7 @@ impl Document { &mut self, block_id: T, delta: Vec, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { if delta.is_empty() { return Ok(()); } @@ -326,14 +326,14 @@ impl Document { let external_id = block .external_id .as_ref() - .ok_or(DocumentError::ExternalIdIsNotFound)?; + .ok_or(CollabError::DocumentExternalIdNotFound)?; self .body .text_operation .set_delta(&mut txn, external_id, delta); Ok(()) } else { - Err(DocumentError::BlockIsNotFound) + Err(CollabError::DocumentBlockNotFound) } } @@ -348,7 +348,7 @@ impl Document { &mut self, block_id: &str, data: HashMap, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { let mut txn = self.collab.transact_mut(); self .body @@ -360,7 +360,7 @@ impl Document { block_id: &str, parent_id: Option, prev_id: Option, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { let mut txn = self.collab.transact_mut(); self.body.move_block(&mut txn, block_id, parent_id, prev_id) } @@ -476,7 +476,7 @@ impl BorrowMut for Document { } impl TryFrom for Document { - type Error = DocumentError; + type Error = CollabError; #[inline] fn try_from(collab: Collab) -> Result { @@ -496,10 +496,7 @@ impl DocumentBody { /// not present in the current [Collab] instance, they will be initialized. /// /// If [DocumentData] was provided it will be applied on the document. - pub(crate) fn new( - collab: &mut Collab, - data: Option, - ) -> Result { + pub(crate) fn new(collab: &mut Collab, data: Option) -> Result { let mut txn = collab.context.transact_mut(); // { document: {:} } let root = collab.data.get_or_init_map(&mut txn, DOCUMENT_ROOT); @@ -544,7 +541,7 @@ impl DocumentBody { children_operation: &ChildrenOperation, text_operation: &TextOperation, block_operation: &BlockOperation, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { root.insert(txn, PAGE_ID, data.page_id); for (_, block) in data.blocks { @@ -598,7 +595,7 @@ impl DocumentBody { &mut self, txn: &mut TransactionMut, doc_data: Option, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { self .block_operation .get_all_blocks(txn) @@ -663,7 +660,7 @@ impl DocumentBody { txn: &mut TransactionMut, block: Block, prev_id: Option, - ) -> Result { + ) -> Result { let block = self.block_operation.create_block_with_txn(txn, block)?; self.insert_block_to_parent(txn, &block, prev_id) } @@ -673,16 +670,16 @@ impl DocumentBody { txn: &mut TransactionMut, block: &Block, prev_id: Option, - ) -> Result { + ) -> Result { let parent_id = &block.parent; // If the parent is not found, return an error. if parent_id.is_empty() { - return Err(DocumentError::ParentIsNotFound); + return Err(CollabError::DocumentParentNotFound); } let parent = match self.block_operation.get_block_with_txn(txn, parent_id) { Some(parent) => parent, - None => return Err(DocumentError::ParentIsNotFound), + None => return Err(CollabError::DocumentParentNotFound), }; let parent_children_id = &parent.children; @@ -722,14 +719,10 @@ impl DocumentBody { /// 1. delete all the children of this block /// 2. delete the block from its parent /// 3. delete the block from the block map - pub fn delete_block( - &self, - txn: &mut TransactionMut, - block_id: &str, - ) -> Result<(), DocumentError> { + pub fn delete_block(&self, txn: &mut TransactionMut, block_id: &str) -> Result<(), CollabError> { let block = match self.block_operation.get_block_with_txn(txn, block_id) { Some(block) => block, - None => return Err(DocumentError::BlockIsNotFound), + None => return Err(CollabError::DocumentBlockNotFound), }; let external_id = &block.external_id; @@ -771,10 +764,10 @@ impl DocumentBody { data: HashMap, external_id: Option, external_type: Option, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { let block = match self.block_operation.get_block_with_txn(txn, block_id) { Some(block) => block, - None => return Err(DocumentError::BlockIsNotFound), + None => return Err(CollabError::DocumentBlockNotFound), }; self.block_operation.set_block_with_txn( txn, @@ -786,12 +779,12 @@ impl DocumentBody { ) } - pub fn get_document_data(&self, txn: &T) -> Result { + pub fn get_document_data(&self, txn: &T) -> Result { let page_id = self .root .get(txn, PAGE_ID) .and_then(|v| v.cast::().ok()) - .ok_or(DocumentError::PageIdIsEmpty)?; + .ok_or(CollabError::DocumentPageIdEmpty)?; let blocks = self.block_operation.get_all_blocks(txn); let children_map = self.children_operation.get_all_children(txn); @@ -814,25 +807,25 @@ impl DocumentBody { block_id: &str, parent_id: Option, prev_id: Option, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { // If the parent is not found, return an error. let new_parent = match parent_id { Some(parent_id) => match self.block_operation.get_block_with_txn(txn, &parent_id) { Some(parent) => parent, - None => return Err(DocumentError::ParentIsNotFound), + None => return Err(CollabError::DocumentParentNotFound), }, - None => return Err(DocumentError::ParentIsNotFound), + None => return Err(CollabError::DocumentParentNotFound), }; let block = match self.block_operation.get_block_with_txn(txn, block_id) { Some(block) => block, - None => return Err(DocumentError::BlockIsNotFound), + None => return Err(CollabError::DocumentBlockNotFound), }; // If the old parent is not found, return an error. let old_parent = match self.block_operation.get_block_with_txn(txn, &block.parent) { Some(parent) => parent, - None => return Err(DocumentError::ParentIsNotFound), + None => return Err(CollabError::DocumentParentNotFound), }; let new_parent_children_id = new_parent.children; @@ -876,7 +869,7 @@ impl DocumentBody { &self, txn: &mut TransactionMut, payload: BlockActionPayload, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { if let Some(mut block) = payload.block { // Check if the block's parent_id is empty, if it is empty, assign the parent_id to the block if block.parent.is_empty() && payload.parent_id.is_some() { @@ -884,7 +877,7 @@ impl DocumentBody { } self.insert_block(txn, block, payload.prev_id).map(|_| ()) } else { - Err(DocumentError::BlockIsNotFound) + Err(CollabError::DocumentBlockNotFound) } } @@ -892,14 +885,14 @@ impl DocumentBody { &self, txn: &mut TransactionMut, payload: BlockActionPayload, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { if let Some(block) = payload.block { let data = &block.data; let external_id = block.external_id; let external_type = block.external_type; self.update_block_data(txn, &block.id, data.to_owned(), external_id, external_type) } else { - Err(DocumentError::BlockIsNotFound) + Err(CollabError::DocumentBlockNotFound) } } @@ -907,11 +900,11 @@ impl DocumentBody { &self, txn: &mut TransactionMut, payload: BlockActionPayload, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { if let Some(block) = payload.block { self.delete_block(txn, &block.id) } else { - Err(DocumentError::BlockIsNotFound) + Err(CollabError::DocumentBlockNotFound) } } @@ -919,11 +912,11 @@ impl DocumentBody { &self, txn: &mut TransactionMut, payload: BlockActionPayload, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { if let Some(block) = payload.block { self.move_block(txn, &block.id, payload.parent_id, payload.prev_id) } else { - Err(DocumentError::BlockIsNotFound) + Err(CollabError::DocumentBlockNotFound) } } @@ -931,17 +924,17 @@ impl DocumentBody { &self, txn: &mut TransactionMut, payload: BlockActionPayload, - ) -> Result<(), DocumentError> { + ) -> Result<(), CollabError> { if let Some(text_id) = payload.text_id { if let Some(delta) = payload.delta { let delta = deserialize_text_delta(&delta).ok().unwrap_or_default(); self.text_operation.apply_delta(txn, &text_id, delta); Ok(()) } else { - Err(DocumentError::TextActionParamsError) + Err(CollabError::DocumentTextActionParams) } } else { - Err(DocumentError::TextActionParamsError) + Err(CollabError::DocumentTextActionParams) } } } diff --git a/collab-document/src/document_awareness.rs b/collab/src/document/document_awareness.rs similarity index 100% rename from collab-document/src/document_awareness.rs rename to collab/src/document/document_awareness.rs diff --git a/collab-document/src/document_data.rs b/collab/src/document/document_data.rs similarity index 92% rename from collab-document/src/document_data.rs rename to collab/src/document/document_data.rs index 9bf0468c3..e5de668dc 100644 --- a/collab-document/src/document_data.rs +++ b/collab/src/document/document_data.rs @@ -1,10 +1,10 @@ -use collab::preclude::ClientID; +use crate::preclude::ClientID; use std::collections::HashMap; -use crate::blocks::{Block, DocumentData, DocumentMeta}; +use super::blocks::{Block, DocumentData, DocumentMeta}; use crate::document::Document; -use crate::error::DocumentError; -use collab::entity::EncodedCollab; +use crate::entity::EncodedCollab; +use crate::error::CollabError; use nanoid::nanoid; use uuid::Uuid; @@ -87,7 +87,7 @@ pub fn default_document_data(document_id: &str) -> DocumentData { pub fn default_document_collab_data( document_id: &str, client_id: ClientID, -) -> Result { +) -> Result { let document_data = default_document_data(document_id); let document = Document::create(document_id, document_data, client_id)?; document.encode_collab() @@ -99,6 +99,6 @@ pub fn generate_id() -> String { pub fn page_id_from_document_id(document_id: &str) -> Option { // Use deterministic UUID conversion for consistency - let doc_id = collab_entity::uuid_validation::document_id_from_any_string(document_id); + let doc_id = crate::entity::uuid_validation::document_id_from_any_string(document_id); Some(Uuid::new_v5(&doc_id, PAGE.as_bytes()).to_string()) } diff --git a/collab-document/src/document_remapper.rs b/collab/src/document/document_remapper.rs similarity index 87% rename from collab-document/src/document_remapper.rs rename to collab/src/document/document_remapper.rs index 18bc03a5f..3e47d996d 100644 --- a/collab-document/src/document_remapper.rs +++ b/collab/src/document/document_remapper.rs @@ -1,13 +1,13 @@ -use collab::core::collab::CollabOptions; -use collab::core::collab::DataSource; -use collab::core::origin::CollabOrigin; -use collab::preclude::*; +use crate::core::collab::CollabOptions; +use crate::core::collab::DataSource; +use crate::core::origin::CollabOrigin; +use crate::preclude::*; use std::collections::HashMap; use uuid::Uuid; -use crate::blocks::{Block, DocumentData, DocumentMeta, TextDelta}; +use super::blocks::{Block, DocumentData, DocumentMeta, TextDelta}; use crate::document::Document; -use crate::error::DocumentError; +use crate::error::CollabError; const INLINE_DATABASE_BLOCK_TYPES: &[&str] = &["grid", "board", "calendar"]; const PARENT_ID_KEY: &str = "parent_id"; @@ -37,7 +37,7 @@ impl DocumentCollabRemapper { doc_id: &str, user_id: &str, doc: Document, - ) -> Result { + ) -> Result { let client_id = user_id.parse::().unwrap_or(0); let document_data = doc.get_document_data()?; let remapped_data = self.remap_document_data(document_data)?; @@ -45,7 +45,7 @@ impl DocumentCollabRemapper { let doc_uuid = Uuid::parse_str(doc_id).unwrap_or_else(|_| Uuid::new_v4()); let new_options = CollabOptions::new(doc_uuid, client_id); let new_collab = Collab::new_with_options(CollabOrigin::Empty, new_options) - .map_err(|e| DocumentError::Internal(anyhow::Error::new(e)))?; + .map_err(|e| CollabError::Internal(anyhow::Error::new(e)))?; let new_document = Document::create_with_data(new_collab, remapped_data)?; Ok(new_document) @@ -56,23 +56,20 @@ impl DocumentCollabRemapper { doc_id: &str, user_id: &str, doc_state: &[u8], - ) -> Result, DocumentError> { + ) -> Result, CollabError> { let client_id = user_id.parse::().unwrap_or(0); let doc_uuid = Uuid::parse_str(doc_id).unwrap_or_else(|_| Uuid::new_v4()); let options = CollabOptions::new(doc_uuid, client_id) .with_data_source(DataSource::DocStateV1(doc_state.to_owned())); let collab = Collab::new_with_options(CollabOrigin::Empty, options) - .map_err(|e| DocumentError::Internal(anyhow::Error::new(e)))?; + .map_err(|e| CollabError::Internal(anyhow::Error::new(e)))?; let document = Document::open(collab)?; let new_document = self.remap_collab_doc(doc_id, user_id, document)?; let updated_state = new_document.encode_collab()?; Ok(updated_state.doc_state.to_vec()) } - fn remap_document_data( - &self, - document_data: DocumentData, - ) -> Result { + fn remap_document_data(&self, document_data: DocumentData) -> Result { let remapped_blocks = self.remap_blocks(document_data.blocks); let remapped_text_map = self.remap_text_map(document_data.meta.text_map); @@ -151,7 +148,7 @@ impl DocumentCollabRemapper { fn remap_mention_ids_in_text_deltas( &self, text_deltas: Vec, - ) -> Result>, DocumentError> { + ) -> Result>, CollabError> { let mut updated_deltas = Vec::new(); let mut has_changes = false; @@ -182,10 +179,10 @@ impl DocumentCollabRemapper { fn remap_mention_object_to_string( &self, - mention_data: &collab::preclude::Any, - ) -> Result, DocumentError> { + mention_data: &crate::preclude::Any, + ) -> Result, CollabError> { let mention_str = serde_json::to_string(mention_data) - .map_err(|e| DocumentError::Internal(anyhow::Error::new(e)))?; + .map_err(|e| CollabError::Internal(anyhow::Error::new(e)))?; let mut mention_map: serde_json::Map = match serde_json::from_str(&mention_str) { Ok(map) => map, @@ -199,7 +196,7 @@ impl DocumentCollabRemapper { if let Some(new_page_id) = self.id_mapping.get(page_id) { mention_map.insert(MENTION_PAGE_ID_KEY.to_string(), new_page_id.clone().into()); let updated_str = serde_json::to_string(&mention_map) - .map_err(|e| DocumentError::Internal(anyhow::Error::new(e)))?; + .map_err(|e| CollabError::Internal(anyhow::Error::new(e)))?; return Ok(Some(updated_str)); } } diff --git a/collab-document/src/importer/define.rs b/collab/src/document/importer/define.rs similarity index 100% rename from collab-document/src/importer/define.rs rename to collab/src/document/importer/define.rs diff --git a/collab-document/src/importer/delta.rs b/collab/src/document/importer/delta.rs similarity index 74% rename from collab-document/src/importer/delta.rs rename to collab/src/document/importer/delta.rs index 488f5b256..390fd7478 100644 --- a/collab-document/src/importer/delta.rs +++ b/collab/src/document/importer/delta.rs @@ -1,7 +1,7 @@ +use crate::error::CollabError; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; use std::collections::HashMap; -use thiserror::Error; #[derive(Debug, Deserialize, Serialize, Default)] pub struct Delta { @@ -15,32 +15,16 @@ pub struct Operation { attributes: Vec<(String, Value)>, } -#[derive(Error, Debug)] -pub enum ConversionError { - #[error("Invalid structure: expected an object")] - NotAnObject, - #[error("Missing 'insert' field")] - MissingInsert, - #[error("'insert' field is not a string")] - InsertNotString, - #[error("'attributes' field is not an object")] - AttributesNotObject, - #[error("Invalid attribute")] - InvalidAttribute, - #[error("Invalid insert")] - InvalidInsert, -} - impl TryFrom for Operation { - type Error = ConversionError; + type Error = CollabError; fn try_from(value: Value) -> Result { - let obj = value.as_object().ok_or(ConversionError::NotAnObject)?; + let obj = value.as_object().ok_or(CollabError::DeltaNotObject)?; let insert = obj .get("insert") .and_then(Value::as_str) - .ok_or(ConversionError::MissingInsert)? + .ok_or(CollabError::DeltaMissingInsert)? .to_owned(); let attributes = obj @@ -59,7 +43,7 @@ impl TryFrom for Operation { } impl TryFrom for Value { - type Error = ConversionError; + type Error = CollabError; fn try_from(op: Operation) -> Result { let attributes: HashMap = op.attributes.into_iter().collect(); diff --git a/collab-document/src/importer/md_importer.rs b/collab/src/document/importer/md_importer.rs similarity index 97% rename from collab-document/src/importer/md_importer.rs rename to collab/src/document/importer/md_importer.rs index 6288c4b9f..57bda7d5a 100644 --- a/collab-document/src/importer/md_importer.rs +++ b/collab/src/document/importer/md_importer.rs @@ -1,9 +1,9 @@ -use crate::blocks::{Block, BlockType, DocumentData, DocumentMeta}; -use crate::document_data::generate_id; -use crate::error::DocumentError; -use crate::importer::define::*; -use crate::importer::delta::Delta; -use crate::importer::util::*; +use super::define::*; +use super::delta::Delta; +use super::util::*; +use crate::document::blocks::{Block, BlockType, DocumentData, DocumentMeta}; +use crate::document::document_data::generate_id; +use crate::error::CollabError; use markdown::mdast::AlignKind; use markdown::{Constructs, ParseOptions, mdast, to_mdast}; use serde_json::Value; @@ -46,9 +46,9 @@ impl MDImporter { } } - pub fn import(&self, document_id: &str, md: String) -> Result { + pub fn import(&self, document_id: &str, md: String) -> Result { let md_node = - to_mdast(&md, &self.parse_options).map_err(|_| DocumentError::ParseMarkdownError)?; + to_mdast(&md, &self.parse_options).map_err(|_| CollabError::DocumentParseMarkdown)?; let mut document_data = DocumentData { page_id: document_id.to_string(), diff --git a/collab-document/src/importer/mod.rs b/collab/src/document/importer/mod.rs similarity index 100% rename from collab-document/src/importer/mod.rs rename to collab/src/document/importer/mod.rs diff --git a/collab-document/src/importer/util.rs b/collab/src/document/importer/util.rs similarity index 99% rename from collab-document/src/importer/util.rs rename to collab/src/document/importer/util.rs index 785781dc9..7b62750af 100644 --- a/collab-document/src/importer/util.rs +++ b/collab/src/document/importer/util.rs @@ -1,8 +1,6 @@ +use super::define::*; use super::delta::{Delta, Operation}; -use crate::{ - blocks::{BlockType, DocumentData}, - importer::define::*, -}; +use crate::document::blocks::{BlockType, DocumentData}; use markdown::mdast; use serde_json::Value; use std::collections::HashMap; diff --git a/collab/src/document/mod.rs b/collab/src/document/mod.rs new file mode 100644 index 000000000..6089b1528 --- /dev/null +++ b/collab/src/document/mod.rs @@ -0,0 +1,17 @@ +#![allow(clippy::module_inception)] + +pub mod block_parser; +pub mod blocks; +pub mod document; +pub mod document_awareness; +pub mod document_data; +pub mod document_remapper; +pub mod importer; + +pub use block_parser::*; +pub use blocks::*; +pub use document::*; +pub use document_awareness::*; +pub use document_data::*; +pub use document_remapper::*; +pub use importer::*; diff --git a/collab-entity/src/collab_object.rs b/collab/src/entity/collab_object.rs similarity index 95% rename from collab-entity/src/collab_object.rs rename to collab/src/entity/collab_object.rs index 02f5cb03a..6b59f15a4 100644 --- a/collab-entity/src/collab_object.rs +++ b/collab/src/entity/collab_object.rs @@ -2,14 +2,14 @@ use anyhow::{Error, anyhow}; use std::collections::HashMap; use std::fmt::{Display, Formatter}; -use crate::uuid_validation::ObjectId; - -use crate::define::{ +use super::define::{ DATABASE, DATABASE_ID, DATABASE_INLINE_VIEW, DATABASE_METAS, DATABASE_ROW_DATA, DATABASE_ROW_ID, DOCUMENT_ROOT, FOLDER, FOLDER_META, FOLDER_WORKSPACE_ID, USER_AWARENESS, WORKSPACE_DATABASES, }; -use crate::proto; -use collab::preclude::{ArrayRef, Collab, MapExt, MapRef}; +use super::proto; +use super::uuid_validation::ObjectId; +use crate::error::CollabError; +use crate::preclude::{ArrayRef, Collab, MapExt, MapRef}; use serde_repr::{Deserialize_repr, Serialize_repr}; /// The type of the collab object. It will be used to determine what kind of services should be @@ -32,12 +32,6 @@ pub enum CollabType { Unknown = 6, } -#[derive(Debug, thiserror::Error)] -pub enum CollabValidateError { - #[error("No required data: {0}")] - NoRequiredData(String), -} - impl CollabType { pub fn value(&self) -> i32 { *self as i32 @@ -68,7 +62,7 @@ impl CollabType { /// - `Ok(())` if the collab object contains all the required data for its type. /// - `Err(Error)` if the required data is missing or if the collab object does not meet /// the validation criteria for its type. - pub fn validate_require_data(&self, collab: &Collab) -> Result<(), CollabValidateError> { + pub fn validate_require_data(&self, collab: &Collab) -> Result<(), CollabError> { let txn = collab.transact(); match self { CollabType::Document => { @@ -189,8 +183,8 @@ pub fn validate_data_for_folder(collab: &Collab, workspace_id: &str) -> Result<( } #[inline] -fn no_required_data_error(collab_type: &CollabType, reason: &str) -> CollabValidateError { - CollabValidateError::NoRequiredData(format!("{}:{}", collab_type, reason)) +fn no_required_data_error(collab_type: &CollabType, reason: &str) -> CollabError { + CollabError::NoRequiredData(format!("{}:{}", collab_type, reason)) } impl Display for CollabType { diff --git a/collab-entity/src/define.rs b/collab/src/entity/define.rs similarity index 100% rename from collab-entity/src/define.rs rename to collab/src/entity/define.rs diff --git a/collab/src/entity.rs b/collab/src/entity/mod.rs similarity index 96% rename from collab/src/entity.rs rename to collab/src/entity/mod.rs index ad825581a..0e025598f 100644 --- a/collab/src/entity.rs +++ b/collab/src/entity/mod.rs @@ -1,3 +1,11 @@ +pub mod collab_object; +pub mod define; +pub mod proto; +pub mod reminder; +pub mod uuid_validation; + +pub use collab_object::*; + use bytes::Bytes; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; diff --git a/collab/src/entity/proto/collab.rs b/collab/src/entity/proto/collab.rs new file mode 100644 index 000000000..e055e5569 --- /dev/null +++ b/collab/src/entity/proto/collab.rs @@ -0,0 +1,233 @@ +// This file is @generated by prost-build. +/// Originating from an AppFlowy Client. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClientOrigin { + /// User id. + #[prost(int64, tag = "1")] + pub uid: i64, + /// Device id. + #[prost(string, tag = "2")] + pub device_id: ::prost::alloc::string::String, +} +/// Unknown origin. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EmptyOrigin {} +/// Originating from the AppFlowy Server. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ServerOrigin {} +/// Origin of a collab message. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CollabOrigin { + #[prost(oneof = "collab_origin::Origin", tags = "1, 2, 3")] + pub origin: ::core::option::Option, +} +/// Nested message and enum types in `CollabOrigin`. +pub mod collab_origin { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Origin { + #[prost(message, tag = "1")] + Empty(super::EmptyOrigin), + #[prost(message, tag = "2")] + Client(super::ClientOrigin), + #[prost(message, tag = "3")] + Server(super::ServerOrigin), + } +} +/// Collab Type. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum CollabType { + Unknown = 0, + Document = 1, + Database = 2, + WorkspaceDatabase = 3, + Folder = 4, + DatabaseRow = 5, + UserAwareness = 6, +} +impl CollabType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + CollabType::Unknown => "COLLAB_TYPE_UNKNOWN", + CollabType::Document => "COLLAB_TYPE_DOCUMENT", + CollabType::Database => "COLLAB_TYPE_DATABASE", + CollabType::WorkspaceDatabase => "COLLAB_TYPE_WORKSPACE_DATABASE", + CollabType::Folder => "COLLAB_TYPE_FOLDER", + CollabType::DatabaseRow => "COLLAB_TYPE_DATABASE_ROW", + CollabType::UserAwareness => "COLLAB_TYPE_USER_AWARENESS", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "COLLAB_TYPE_UNKNOWN" => Some(Self::Unknown), + "COLLAB_TYPE_DOCUMENT" => Some(Self::Document), + "COLLAB_TYPE_DATABASE" => Some(Self::Database), + "COLLAB_TYPE_WORKSPACE_DATABASE" => Some(Self::WorkspaceDatabase), + "COLLAB_TYPE_FOLDER" => Some(Self::Folder), + "COLLAB_TYPE_DATABASE_ROW" => Some(Self::DatabaseRow), + "COLLAB_TYPE_USER_AWARENESS" => Some(Self::UserAwareness), + _ => None, + } + } +} +/// Encoded collaborative document. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EncodedCollab { + /// yrs state vector + #[prost(bytes = "vec", tag = "1")] + pub state_vector: ::prost::alloc::vec::Vec, + /// yrs document state + #[prost(bytes = "vec", tag = "2")] + pub doc_state: ::prost::alloc::vec::Vec, + /// yrs encoder version used for the state vector and doc state + #[prost(enumeration = "EncoderVersion", tag = "3")] + pub encoder_version: i32, +} +/// yrs encoder version. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum EncoderVersion { + Unknown = 0, + V1 = 1, + V2 = 2, +} +impl EncoderVersion { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + EncoderVersion::Unknown => "ENCODER_VERSION_UNKNOWN", + EncoderVersion::V1 => "ENCODER_VERSION_V1", + EncoderVersion::V2 => "ENCODER_VERSION_V2", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "ENCODER_VERSION_UNKNOWN" => Some(Self::Unknown), + "ENCODER_VERSION_V1" => Some(Self::V1), + "ENCODER_VERSION_V2" => Some(Self::V2), + _ => None, + } + } +} +/// Embeddings and the associated collab metadata. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CollabEmbeddingsParams { + /// Fragment id. + #[prost(string, tag = "1")] + pub fragment_id: ::prost::alloc::string::String, + /// Collab object id. + #[prost(string, tag = "2")] + pub object_id: ::prost::alloc::string::String, + /// Collab type. + #[prost(enumeration = "CollabType", tag = "3")] + pub collab_type: i32, + /// Embedding content type. + #[prost(enumeration = "EmbeddingContentType", tag = "4")] + pub content_type: i32, + /// Embedding content as string. + #[prost(string, tag = "5")] + pub content: ::prost::alloc::string::String, + /// Embedding as float array. + #[prost(float, repeated, tag = "6")] + pub embedding: ::prost::alloc::vec::Vec, +} +/// Wrapper over a collection of embeddings, together with metadata associated on the collection level. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CollabEmbeddings { + /// OpenAPI tokens consumed. + #[prost(uint32, tag = "1")] + pub tokens_consumed: u32, + /// List of embeddings. + #[prost(message, repeated, tag = "2")] + pub embeddings: ::prost::alloc::vec::Vec, +} +/// Payload for sending and receive collab over http. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CollabParams { + #[prost(string, tag = "1")] + pub object_id: ::prost::alloc::string::String, + /// Serialized EncodedCollab object, which could either be in bincode or protobuf serialization format. + #[prost(bytes = "vec", tag = "2")] + pub encoded_collab: ::prost::alloc::vec::Vec, + /// Collab type. + #[prost(enumeration = "CollabType", tag = "3")] + pub collab_type: i32, + /// Document embeddings. + #[prost(message, optional, tag = "4")] + pub embeddings: ::core::option::Option, +} +/// Payload for creating batch of collab over http. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BatchCreateCollabParams { + /// Workspace id. + #[prost(string, tag = "1")] + pub workspace_id: ::prost::alloc::string::String, + /// List of collab params. + #[prost(message, repeated, tag = "2")] + pub params_list: ::prost::alloc::vec::Vec, +} +/// Payload for creating new collab or update existing collab over http. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateCollabParams { + /// Workspace id. + #[prost(string, tag = "1")] + pub workspace_id: ::prost::alloc::string::String, + /// Object id. + #[prost(string, tag = "2")] + pub object_id: ::prost::alloc::string::String, + /// Serialized EncodedCollab object, which could either be in bincode or protobuf serialization format. + #[prost(bytes = "vec", tag = "3")] + pub encoded_collab: ::prost::alloc::vec::Vec, + /// Collab type. + #[prost(enumeration = "CollabType", tag = "4")] + pub collab_type: i32, +} +/// Types of embeddings content. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum EmbeddingContentType { + /// Unknown content type. + Unknown = 0, + /// Plain text + PlainText = 1, +} +impl EmbeddingContentType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + EmbeddingContentType::Unknown => "EMBEDDING_CONTENT_TYPE_UNKNOWN", + EmbeddingContentType::PlainText => "EMBEDDING_CONTENT_TYPE_PLAIN_TEXT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "EMBEDDING_CONTENT_TYPE_UNKNOWN" => Some(Self::Unknown), + "EMBEDDING_CONTENT_TYPE_PLAIN_TEXT" => Some(Self::PlainText), + _ => None, + } + } +} diff --git a/collab-entity/src/proto/mod.rs b/collab/src/entity/proto/mod.rs similarity index 100% rename from collab-entity/src/proto/mod.rs rename to collab/src/entity/proto/mod.rs diff --git a/collab-entity/src/reminder.rs b/collab/src/entity/reminder.rs similarity index 96% rename from collab-entity/src/reminder.rs rename to collab/src/entity/reminder.rs index 0bfeba146..59a4b2a76 100644 --- a/collab-entity/src/reminder.rs +++ b/collab/src/entity/reminder.rs @@ -2,8 +2,8 @@ use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use std::sync::Arc; +use crate::preclude::{Any, In, Map, MapExt, MapPrelim, MapRef, Out, ReadTxn, TransactionMut}; use anyhow::Result; -use collab::preclude::{Any, In, Map, MapExt, MapPrelim, MapRef, Out, ReadTxn, TransactionMut}; use serde::{Deserialize, Serialize}; use serde_repr::*; @@ -240,9 +240,9 @@ impl From for MapPrelim { #[cfg(test)] mod test { - use crate::reminder::{ObjectType, Reminder}; - use collab::preclude::encoding::serde::from_any; - use collab::preclude::{Doc, Map, MapPrelim, ToJson, Transact}; + use crate::entity::reminder::{ObjectType, Reminder}; + use crate::preclude::encoding::serde::from_any; + use crate::preclude::{Doc, Map, MapPrelim, ToJson, Transact}; #[test] fn legacy_reminder_conversion() { diff --git a/collab-entity/src/uuid_validation.rs b/collab/src/entity/uuid_validation.rs similarity index 99% rename from collab-entity/src/uuid_validation.rs rename to collab/src/entity/uuid_validation.rs index 9e528cb83..1af9ce7cd 100644 --- a/collab-entity/src/uuid_validation.rs +++ b/collab/src/entity/uuid_validation.rs @@ -2,7 +2,7 @@ use anyhow::{Result, anyhow}; use uuid::Uuid; // Re-export type aliases from define module -pub use crate::define::{ +pub use super::define::{ BlockId, DatabaseId, DatabaseViewId, DocumentId, ObjectId, RowId, ViewId, WorkspaceId, }; diff --git a/collab/src/error.rs b/collab/src/error.rs index 64ca42cda..580fc15d7 100644 --- a/collab/src/error.rs +++ b/collab/src/error.rs @@ -1,6 +1,11 @@ use anyhow::anyhow; +use markdown::message::Message; +#[cfg(feature = "lock_timeout")] +use std::time::Duration; use yrs::TransactionAcqError; +use crate::entity::uuid_validation::RowId; + #[derive(Debug, thiserror::Error)] pub enum CollabError { #[error(transparent)] @@ -27,15 +32,199 @@ pub enum CollabError { #[error(transparent)] DecodeUpdate(#[from] yrs::encoding::read::Error), + #[cfg(feature = "plugins")] + #[error("Rocksdb corruption:{0}")] + PersistenceRocksdbCorruption(String), + + #[cfg(feature = "plugins")] + #[error("Rocksdb repair:{0}")] + PersistenceRocksdbRepairFail(String), + + #[cfg(feature = "plugins")] + #[error("{0}")] + PersistenceRocksdbBusy(String), + + #[cfg(feature = "plugins")] + #[error("{0}")] + PersistenceRocksdbIOError(String), + + #[error(transparent)] + Bincode(#[from] bincode::Error), + + #[error("Persistence record not found: {0}")] + PersistenceRecordNotFound(String), + + #[error("The document already exist")] + PersistenceDocumentAlreadyExist, + + #[error("Unexpected empty updates")] + PersistenceUnexpectedEmptyUpdates, + + #[error("invalid data: {0}")] + PersistenceInvalidData(String), + + #[error("Duplicate update key")] + PersistenceDuplicateUpdateKey, + + #[error("Can't find the latest update key")] + PersistenceLatestUpdateKeyNotExist, + #[error("{0}")] NoRequiredData(String), + #[error("Lack of folder required data:{0}")] + FolderMissingRequiredData(String), + #[error(transparent)] Awareness(#[from] crate::core::awareness::Error), #[error("Failed to apply update: {0}")] UpdateFailed(#[from] yrs::error::UpdateError), + #[error("Document: Could not create block")] + DocumentBlockCreate, + + #[error("Document: The block already exists")] + DocumentBlockAlreadyExists, + + #[error("Document: The block is not found")] + DocumentBlockNotFound, + + #[error("Document: The page id is empty")] + DocumentPageIdEmpty, + + #[error("Document: Could not convert json to data")] + DocumentConvertData, + + #[error("Document: The parent is not found")] + DocumentParentNotFound, + + #[error("Document: Could not create the root block due to an unspecified error")] + DocumentCreateRootBlock, + + #[error("Document: Could not delete block")] + DocumentDeleteBlock, + + #[error("Document: text_id or delta is empty")] + DocumentTextActionParams, + + #[error("Document: Lack of required data")] + DocumentMissingRequiredData, + + #[error("Document: The external id is not found")] + DocumentExternalIdNotFound, + + #[error("Document: Unable to parse document to plain text")] + DocumentParse, + + #[error("Document: Unable to parse markdown to document data")] + DocumentParseMarkdown, + + #[error("Document: Unable to parse delta json to text delta")] + DocumentParseDeltaJson, + + #[error("Document: No children found")] + DocumentNoBlockChildren, + + #[error("Document: Unknown block type: {0}")] + DocumentUnknownBlockType(String), + + #[error("Document: Unable to find the page block")] + DocumentPageBlockNotFound, + + #[error("Invalid path: {0}")] + ImporterInvalidPath(String), + + #[error("Invalid path format")] + ImporterInvalidPathFormat, + + #[error("{0}")] + ImporterInvalidFileType(String), + + #[error("Parse markdown error: {0}")] + ImporterParseMarkdown(Message), + + #[error("File not found")] + ImporterFileNotFound, + + #[error("Can not import file")] + ImporterCannotImport, + + #[error("Database: The id is invalid: {0}")] + DatabaseInvalidId(String), + + #[error("Database: The view id is invalid: {0}")] + DatabaseInvalidViewId(String), + + #[error("Database: The row id is invalid: {0}")] + DatabaseInvalidRowId(String), + + #[error("Database: The database is not existing")] + DatabaseNotExist, + + #[error("Database: row {row_id} not found, reason: {reason}")] + DatabaseRowNotFound { row_id: RowId, reason: String }, + + #[error("Database: The view is not existing")] + DatabaseViewNotExist, + + #[error("Database: Record already exist")] + DatabaseRecordAlreadyExist, + + #[error("Database: Record not found")] + DatabaseRecordNotFound, + + #[error("Database: Action cancelled")] + DatabaseActionCancelled, + + #[error("Database: Invalid CSV:{0}")] + DatabaseInvalidCsv(String), + + #[error("Database: Import data failed: {0}")] + DatabaseImportData(String), + + #[error(transparent)] + Uuid(#[from] uuid::Error), + + #[error(transparent)] + Utf8(#[from] std::str::Utf8Error), + + #[error(transparent)] + Io(#[from] std::io::Error), + + #[error("Conversion: invalid structure, expected an object")] + DeltaNotObject, + + #[error("Conversion: missing 'insert' field")] + DeltaMissingInsert, + + #[error("Conversion: 'insert' field is not a string")] + DeltaInsertNotString, + + #[error("Conversion: 'attributes' field is not an object")] + DeltaAttributesNotObject, + + #[error("Conversion: invalid attribute")] + DeltaInvalidAttribute, + + #[error("Conversion: invalid insert")] + DeltaInvalidInsert, + + #[error("cannot fill {0:?} with: {1}")] + FillInvalidData(yrs::types::TypeRef, String), + + #[cfg(feature = "lock_timeout")] + #[error("Read lock timeout: {0:?}")] + RwLockReadTimeout(Duration), + + #[cfg(feature = "lock_timeout")] + #[error("Write lock timeout: {0:?}")] + RwLockWriteTimeout(Duration), + + #[cfg(feature = "lock_timeout")] + #[error("Lock timeout: {0:?}")] + MutexLockTimeout(Duration), + #[error("Internal failure: {0}")] Internal(#[from] anyhow::Error), } @@ -49,3 +238,16 @@ impl From for CollabError { } } } + +#[cfg(feature = "plugins")] +impl From for CollabError { + fn from(value: rocksdb::Error) -> Self { + match value.kind() { + rocksdb::ErrorKind::NotFound => Self::PersistenceUnexpectedEmptyUpdates, + rocksdb::ErrorKind::Corruption => Self::PersistenceRocksdbCorruption(value.into_string()), + rocksdb::ErrorKind::IOError => Self::PersistenceRocksdbIOError(value.into_string()), + rocksdb::ErrorKind::Busy => Self::PersistenceRocksdbBusy(value.into_string()), + _ => Self::Internal(value.into()), + } + } +} diff --git a/collab-folder/src/entities.rs b/collab/src/folder/entities.rs similarity index 94% rename from collab-folder/src/entities.rs rename to collab/src/folder/entities.rs index 2d1f06c98..0ef6e2767 100644 --- a/collab-folder/src/entities.rs +++ b/collab/src/folder/entities.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::{SectionsByUid, View, ViewId, Workspace}; +use super::{SectionsByUid, View, ViewId, Workspace}; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] pub struct FolderData { diff --git a/collab-folder/src/folder.rs b/collab/src/folder/folder.rs similarity index 81% rename from collab-folder/src/folder.rs rename to collab/src/folder/folder.rs index b1812f56b..fe8e41447 100644 --- a/collab-folder/src/folder.rs +++ b/collab/src/folder/folder.rs @@ -1,11 +1,11 @@ +use crate::core::collab::{CollabOptions, DataSource}; +pub use crate::core::origin::CollabOrigin; +use crate::entity::CollabType; +use crate::entity::EncodedCollab; +use crate::entity::define::{FOLDER, FOLDER_META, FOLDER_WORKSPACE_ID}; +use crate::preclude::*; +use crate::util::any_to_json_value; use anyhow::anyhow; -use collab::core::collab::{CollabOptions, DataSource}; -pub use collab::core::origin::CollabOrigin; -use collab::entity::EncodedCollab; -use collab::preclude::*; -use collab::util::any_to_json_value; -use collab_entity::CollabType; -use collab_entity::define::{FOLDER, FOLDER_META, FOLDER_WORKSPACE_ID}; use serde::{Deserialize, Serialize}; use std::borrow::{Borrow, BorrowMut}; use std::collections::{HashMap, HashSet}; @@ -14,16 +14,16 @@ use std::sync::Arc; use tracing::error; use uuid::Uuid; -use crate::error::FolderError; -use crate::folder_observe::ViewChangeSender; -use crate::hierarchy_builder::{FlattedViews, ParentChildViews}; -use crate::revision::RevisionMapping; -use crate::section::{Section, SectionItem, SectionMap}; -use crate::{ +use super::folder_observe::ViewChangeSender; +use super::hierarchy_builder::{FlattedViews, ParentChildViews}; +use super::revision::RevisionMapping; +use super::section::{Section, SectionItem, SectionMap}; +use super::{ FolderData, ParentChildRelations, SectionChangeSender, SpacePermission, TrashInfo, View, - ViewChangeReceiver, ViewId, ViewUpdate, ViewsMap, Workspace, impl_section_op, + ViewChangeReceiver, ViewId, ViewUpdate, ViewsMap, Workspace, }; -use collab_entity::uuid_validation::WorkspaceId; +use crate::entity::uuid_validation::WorkspaceId; +use crate::error::CollabError; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)] #[serde(transparent)] @@ -95,12 +95,14 @@ pub struct Folder { } impl Folder { - pub fn open(mut collab: Collab, notifier: Option) -> Result { + pub fn open(mut collab: Collab, notifier: Option) -> Result { let body = FolderBody::open(&mut collab, notifier)?; let folder = Folder { collab, body }; if folder.get_workspace_id().is_none() { // When the folder is opened, the workspace id must be present. - Err(FolderError::NoRequiredData("missing workspace id".into())) + Err(CollabError::FolderMissingRequiredData( + "missing workspace id".into(), + )) } else { Ok(folder) } @@ -116,9 +118,9 @@ impl Folder { collab_doc_state: DataSource, workspace_id: &str, client_id: ClientID, - ) -> Result { + ) -> Result { let workspace_uuid = Uuid::parse_str(workspace_id) - .map_err(|_| FolderError::Internal(anyhow!("Invalid workspace id format")))?; + .map_err(|_| CollabError::Internal(anyhow!("Invalid workspace id format")))?; let options = CollabOptions::new(workspace_uuid, client_id).with_data_source(collab_doc_state); let collab = Collab::new_with_options(origin, options)?; Self::open(collab, None) @@ -128,19 +130,19 @@ impl Folder { self.collab.remove_all_plugins(); } - pub fn validate(&self) -> Result<(), FolderError> { + pub fn validate(&self) -> Result<(), CollabError> { CollabType::Folder .validate_require_data(&self.collab) - .map_err(|err| FolderError::NoRequiredData(err.to_string()))?; + .map_err(|err| CollabError::FolderMissingRequiredData(err.to_string()))?; Ok(()) } /// Returns the doc state and the state vector. - pub fn encode_collab(&self) -> Result { + pub fn encode_collab(&self) -> Result { self.collab.encode_collab_v1(|collab| { CollabType::Folder .validate_require_data(collab) - .map_err(|err| FolderError::NoRequiredData(err.to_string())) + .map_err(|err| CollabError::FolderMissingRequiredData(err.to_string())) }) } @@ -253,40 +255,202 @@ impl Folder { // Section operations // Favorites - impl_section_op!( - Section::Favorite, - set_favorite, - add_favorite_view_ids, - delete_favorite_view_ids, - get_my_favorite_sections, - get_all_favorites_sections, - remove_all_my_favorite_sections, - move_favorite_view_id - ); + pub fn add_favorite_view_ids(&mut self, ids: Vec, uid: i64) { + let mut txn = self.collab.transact_mut(); + for id in ids { + if let Ok(view_uuid) = uuid::Uuid::parse_str(&id) { + self.body.views.update_view( + &mut txn, + &view_uuid, + |update| update.set_favorite(true).done(), + uid, + ); + } + } + } + + pub fn delete_favorite_view_ids(&mut self, ids: Vec, uid: i64) { + let mut txn = self.collab.transact_mut(); + for id in ids { + if let Ok(view_uuid) = uuid::Uuid::parse_str(&id) { + self.body.views.update_view( + &mut txn, + &view_uuid, + |update| update.set_favorite(false).done(), + uid, + ); + } + } + } + + pub fn get_my_favorite_sections(&self, uid: i64) -> Vec { + let txn = self.collab.transact(); + self + .body + .section + .section_op(&txn, Section::Favorite, uid) + .map(|op| op.get_all_section_item(&txn)) + .unwrap_or_default() + } + + pub fn get_all_favorites_sections(&self, uid: i64) -> Vec { + let txn = self.collab.transact(); + self + .body + .section + .section_op(&txn, Section::Favorite, uid) + .map(|op| op.get_sections(&txn)) + .unwrap_or_default() + .into_iter() + .flat_map(|(_user_id, items)| items) + .collect() + } + + pub fn remove_all_my_favorite_sections(&mut self, uid: i64) { + let mut txn = self.collab.transact_mut(); + if let Some(op) = self.body.section.section_op(&txn, Section::Favorite, uid) { + op.clear(&mut txn); + } + } + + pub fn move_favorite_view_id(&mut self, id: &str, prev_id: Option<&str>, uid: i64) { + let mut txn = self.collab.transact_mut(); + if let Some(op) = self.body.section.section_op(&txn, Section::Favorite, uid) { + op.move_section_item_with_txn(&mut txn, id, prev_id); + } + } // Trash - impl_section_op!( - Section::Trash, - set_trash, - add_trash_view_ids, - delete_trash_view_ids, - get_my_trash_sections, - get_all_trash_sections, - remove_all_my_trash_sections, - move_trash_view_id - ); + pub fn add_trash_view_ids(&mut self, ids: Vec, uid: i64) { + let mut txn = self.collab.transact_mut(); + for id in ids { + if let Ok(view_uuid) = uuid::Uuid::parse_str(&id) { + self.body.views.update_view( + &mut txn, + &view_uuid, + |update| update.set_trash(true).done(), + uid, + ); + } + } + } + + pub fn delete_trash_view_ids(&mut self, ids: Vec, uid: i64) { + let mut txn = self.collab.transact_mut(); + for id in ids { + if let Ok(view_uuid) = uuid::Uuid::parse_str(&id) { + self.body.views.update_view( + &mut txn, + &view_uuid, + |update| update.set_trash(false).done(), + uid, + ); + } + } + } + + pub fn get_my_trash_sections(&self, uid: i64) -> Vec { + let txn = self.collab.transact(); + self + .body + .section + .section_op(&txn, Section::Trash, uid) + .map(|op| op.get_all_section_item(&txn)) + .unwrap_or_default() + } + + pub fn get_all_trash_sections(&self, uid: i64) -> Vec { + let txn = self.collab.transact(); + self + .body + .section + .section_op(&txn, Section::Trash, uid) + .map(|op| op.get_sections(&txn)) + .unwrap_or_default() + .into_iter() + .flat_map(|(_user_id, items)| items) + .collect() + } + + pub fn remove_all_my_trash_sections(&mut self, uid: i64) { + let mut txn = self.collab.transact_mut(); + if let Some(op) = self.body.section.section_op(&txn, Section::Trash, uid) { + op.clear(&mut txn); + } + } + + pub fn move_trash_view_id(&mut self, id: &str, prev_id: Option<&str>, uid: i64) { + let mut txn = self.collab.transact_mut(); + if let Some(op) = self.body.section.section_op(&txn, Section::Trash, uid) { + op.move_section_item_with_txn(&mut txn, id, prev_id); + } + } // Private - impl_section_op!( - Section::Private, - set_private, - add_private_view_ids, - delete_private_view_ids, - get_my_private_sections, - get_all_private_sections, - remove_all_my_private_sections, - move_private_view_id - ); + pub fn add_private_view_ids(&mut self, ids: Vec, uid: i64) { + let mut txn = self.collab.transact_mut(); + for id in ids { + if let Ok(view_uuid) = uuid::Uuid::parse_str(&id) { + self.body.views.update_view( + &mut txn, + &view_uuid, + |update| update.set_private(true).done(), + uid, + ); + } + } + } + + pub fn delete_private_view_ids(&mut self, ids: Vec, uid: i64) { + let mut txn = self.collab.transact_mut(); + for id in ids { + if let Ok(view_uuid) = uuid::Uuid::parse_str(&id) { + self.body.views.update_view( + &mut txn, + &view_uuid, + |update| update.set_private(false).done(), + uid, + ); + } + } + } + + pub fn get_my_private_sections(&self, uid: i64) -> Vec { + let txn = self.collab.transact(); + self + .body + .section + .section_op(&txn, Section::Private, uid) + .map(|op| op.get_all_section_item(&txn)) + .unwrap_or_default() + } + + pub fn get_all_private_sections(&self, uid: i64) -> Vec { + let txn = self.collab.transact(); + self + .body + .section + .section_op(&txn, Section::Private, uid) + .map(|op| op.get_sections(&txn)) + .unwrap_or_default() + .into_iter() + .flat_map(|(_user_id, items)| items) + .collect() + } + + pub fn remove_all_my_private_sections(&mut self, uid: i64) { + let mut txn = self.collab.transact_mut(); + if let Some(op) = self.body.section.section_op(&txn, Section::Private, uid) { + op.clear(&mut txn); + } + } + + pub fn move_private_view_id(&mut self, id: &str, prev_id: Option<&str>, uid: i64) { + let mut txn = self.collab.transact_mut(); + if let Some(op) = self.body.section.section_op(&txn, Section::Private, uid) { + op.move_section_item_with_txn(&mut txn, id, prev_id); + } + } pub fn get_my_trash_info(&self, uid: i64) -> Vec { let txn = self.collab.transact(); @@ -434,17 +598,21 @@ impl BorrowMut for Folder { } } -pub fn check_folder_is_valid(collab: &Collab) -> Result { +pub fn check_folder_is_valid(collab: &Collab) -> Result { let txn = collab.transact(); let meta: MapRef = collab .data .get_with_path(&txn, vec![FOLDER, FOLDER_META]) - .ok_or_else(|| FolderError::NoRequiredData("No meta data".to_string()))?; + .ok_or_else(|| CollabError::FolderMissingRequiredData("No meta data".to_string()))?; match meta.get_with_txn::<_, String>(&txn, FOLDER_WORKSPACE_ID) { - None => Err(FolderError::NoRequiredData("No workspace id".to_string())), + None => Err(CollabError::FolderMissingRequiredData( + "No workspace id".to_string(), + )), Some(workspace_id) => { if workspace_id.is_empty() { - Err(FolderError::NoRequiredData("No workspace id".to_string())) + Err(CollabError::FolderMissingRequiredData( + "No workspace id".to_string(), + )) } else { Ok(workspace_id) } @@ -462,7 +630,7 @@ pub struct FolderBody { } impl FolderBody { - pub fn open(collab: &mut Collab, notifier: Option) -> Result { + pub fn open(collab: &mut Collab, notifier: Option) -> Result { CollabType::Folder.validate_require_data(collab)?; Ok(Self::open_with(collab, notifier, None)) } @@ -851,7 +1019,7 @@ impl FolderBody { pub fn default_folder_data(uid: i64, workspace_id: &str) -> FolderData { let workspace = Workspace { id: Uuid::parse_str(workspace_id) - .unwrap_or_else(|_| collab_entity::uuid_validation::generate_workspace_id()), + .unwrap_or_else(|_| crate::entity::uuid_validation::generate_workspace_id()), name: "".to_string(), child_views: Default::default(), created_at: 0, @@ -875,12 +1043,13 @@ pub fn default_folder_data(uid: i64, workspace_id: &str) -> FolderData { mod tests { use std::collections::HashMap; - use crate::{ + use crate::core::collab::default_client_id; + use crate::core::{collab::CollabOptions, origin::CollabOrigin}; + use crate::folder::{ Folder, FolderData, RepeatedViewIdentifier, SectionItem, SpaceInfo, UserId, View, - ViewIdentifier, Workspace, + ViewIdentifier, ViewLayout, Workspace, }; - use collab::core::collab::default_client_id; - use collab::{core::collab::CollabOptions, core::origin::CollabOrigin, preclude::Collab}; + use crate::preclude::Collab; use uuid::Uuid; #[test] @@ -895,7 +1064,7 @@ mod tests { Uuid::parse_str("00000000-0000-0000-0000-000000000002").unwrap(), workspace_id, "View 1".to_string(), - crate::ViewLayout::Document, + ViewLayout::Document, Some(uid), ); let view_1_id = view_1.id; @@ -903,7 +1072,7 @@ mod tests { Uuid::parse_str("00000000-0000-0000-0000-000000000003").unwrap(), workspace_id, "View 2".to_string(), - crate::ViewLayout::Document, + ViewLayout::Document, Some(uid), ); let view_2_id = view_2.id; @@ -917,7 +1086,7 @@ mod tests { ]), created_at: current_time, is_favorite: false, - layout: crate::ViewLayout::Document, + layout: ViewLayout::Document, icon: None, created_by: None, last_edited_time: current_time, @@ -971,7 +1140,7 @@ mod tests { Uuid::parse_str(&format!("00000000-0000-0000-0000-00000000001{}", i)).unwrap(), space_view_id, format!("View {:?}", i), - crate::ViewLayout::Document, + ViewLayout::Document, Some(uid), ) }) @@ -988,7 +1157,7 @@ mod tests { ), created_at: current_time, is_favorite: false, - layout: crate::ViewLayout::Document, + layout: ViewLayout::Document, icon: None, created_by: None, last_edited_time: current_time, diff --git a/collab-folder/src/folder_diff.rs b/collab/src/folder/folder_diff.rs similarity index 86% rename from collab-folder/src/folder_diff.rs rename to collab/src/folder/folder_diff.rs index ee6e75166..194e3e592 100644 --- a/collab-folder/src/folder_diff.rs +++ b/collab/src/folder/folder_diff.rs @@ -1,32 +1,31 @@ use std::collections::HashSet; use std::sync::Arc; -use arc_swap::ArcSwapOption; -use collab::core::origin::CollabOrigin; -use collab::entity::EncodedCollab; -use collab::error::CollabError; -use collab::preclude::updates::decoder::Decode; -use collab::preclude::{ +use crate::core::origin::CollabOrigin; +use crate::entity::EncodedCollab; +use crate::error::CollabError; +use crate::preclude::updates::decoder::Decode; +use crate::preclude::{ ClientID, DeepObservable, EntryChange, Event, MapExt, ReadTxn, Update, YrsValue, }; +use arc_swap::ArcSwapOption; -use crate::Folder; -use crate::error::FolderError; -use crate::view::FOLDER_VIEW_ID; +use super::Folder; +use super::view::FOLDER_VIEW_ID; impl Folder { pub fn calculate_view_changes( &self, encoded_collab: EncodedCollab, client_id: ClientID, - ) -> Result, FolderError> { + ) -> Result, CollabError> { //TODO: this entire method should be reimplemented into standard diff comparison let changes = Arc::new(ArcSwapOption::default()); let this_txn = self.collab.transact(); let workspace_id = self .body .get_workspace_id(&this_txn) - .ok_or_else(|| FolderError::NoRequiredData("workspace id".to_string()))?; + .ok_or_else(|| CollabError::FolderMissingRequiredData("workspace id".to_string()))?; let mut other = Folder::from_collab_doc_state( CollabOrigin::Empty, @@ -78,7 +77,7 @@ impl Folder { let mut other_txn = other.collab.transact_mut(); let sv = other_txn.state_vector(); let data = this_txn.encode_state_as_update_v1(&sv); - let update = Update::decode_v1(&data).map_err(|err| FolderError::Internal(err.into()))?; + let update = Update::decode_v1(&data).map_err(|err| CollabError::Internal(err.into()))?; other_txn .apply_update(update) diff --git a/collab-folder/src/folder_migration.rs b/collab/src/folder/folder_migration.rs similarity index 93% rename from collab-folder/src/folder_migration.rs rename to collab/src/folder/folder_migration.rs index 745247b4a..f00dc93f7 100644 --- a/collab-folder/src/folder_migration.rs +++ b/collab/src/folder/folder_migration.rs @@ -1,9 +1,9 @@ +use crate::preclude::{Any, Array, ArrayRef, Map, MapExt, MapRef, ReadTxn, YrsValue}; use anyhow::bail; -use collab::preclude::{Any, Array, ArrayRef, Map, MapExt, MapRef, ReadTxn, YrsValue}; use serde::{Deserialize, Serialize}; -use crate::folder::FAVORITES_V1; -use crate::{Folder, ParentChildRelations, SectionItem, ViewId, Workspace}; +use super::FAVORITES_V1; +use super::{Folder, ParentChildRelations, SectionItem, ViewId, Workspace}; const WORKSPACE_ID: &str = "id"; const WORKSPACE_NAME: &str = "name"; @@ -122,7 +122,7 @@ impl TryFrom<&YrsValue> for FavoriteId { #[derive(Debug, Serialize, Deserialize)] struct TrashRecord { pub id: ViewId, - #[serde(deserialize_with = "collab::preclude::deserialize_i64_from_numeric")] + #[serde(deserialize_with = "crate::preclude::deserialize_i64_from_numeric")] pub created_at: i64, #[serde(default)] pub workspace_id: String, diff --git a/collab-folder/src/folder_observe.rs b/collab/src/folder/folder_observe.rs similarity index 95% rename from collab-folder/src/folder_observe.rs rename to collab/src/folder/folder_observe.rs index 1c8dbfb92..ab1b19496 100644 --- a/collab-folder/src/folder_observe.rs +++ b/collab/src/folder/folder_observe.rs @@ -1,15 +1,15 @@ use dashmap::DashMap; use std::sync::Arc; -use collab::preclude::{ +use crate::preclude::{ DeepObservable, EntryChange, Event, Map, MapExt, MapRef, Subscription, YrsValue, }; use tokio::sync::broadcast; -use crate::revision::RevisionMapping; -use crate::section::SectionMap; -use crate::view::FOLDER_VIEW_ID; -use crate::{ParentChildRelations, View, ViewId, view_from_map_ref}; +use super::revision::RevisionMapping; +use super::section::SectionMap; +use super::view::FOLDER_VIEW_ID; +use super::{ParentChildRelations, View, ViewId, view_from_map_ref}; #[derive(Debug, Clone)] pub enum ViewChange { diff --git a/collab-folder/src/hierarchy_builder.rs b/collab/src/folder/hierarchy_builder.rs similarity index 99% rename from collab-folder/src/hierarchy_builder.rs rename to collab/src/folder/hierarchy_builder.rs index 2f2443fbe..92f3d7181 100644 --- a/collab-folder/src/hierarchy_builder.rs +++ b/collab/src/folder/hierarchy_builder.rs @@ -1,5 +1,5 @@ -use crate::space_info::SpacePermission; -use crate::{ +use super::space_info::SpacePermission; +use super::{ IconType, RepeatedViewIdentifier, SPACE_CREATED_AT_KEY, SPACE_ICON_COLOR_KEY, SPACE_ICON_KEY, SPACE_IS_SPACE_KEY, SPACE_PERMISSION_KEY, SpaceInfo, View, ViewIcon, ViewId, ViewIdentifier, ViewLayout, timestamp, @@ -356,8 +356,8 @@ impl FlattedViews { #[cfg(test)] mod tests { - use crate::ViewId; - use crate::hierarchy_builder::{FlattedViews, NestedViewBuilder}; + use super::super::ViewId; + use super::{FlattedViews, NestedViewBuilder}; #[tokio::test] async fn create_first_level_views_test() { diff --git a/collab-folder/src/lib.rs b/collab/src/folder/mod.rs similarity index 77% rename from collab-folder/src/lib.rs rename to collab/src/folder/mod.rs index a1ee3c7bc..e8631a0d9 100644 --- a/collab-folder/src/lib.rs +++ b/collab/src/folder/mod.rs @@ -1,29 +1,25 @@ +#![allow(clippy::module_inception)] + +pub use crate::entity::define::ViewId; pub use entities::*; pub use folder::*; pub use folder_migration::*; pub use folder_observe::*; pub use relation::*; pub use section::*; -// pub use trash::*; -pub use collab_entity::define::ViewId; pub use space_info::*; pub use view::*; pub use workspace::*; mod entities; mod folder; -mod relation; -mod section; -// mod trash; -mod view; -mod workspace; - -#[macro_use] -mod macros; -pub mod error; pub mod folder_diff; mod folder_migration; mod folder_observe; pub mod hierarchy_builder; +mod relation; mod revision; +mod section; pub mod space_info; +mod view; +mod workspace; diff --git a/collab-folder/src/relation.rs b/collab/src/folder/relation.rs similarity index 96% rename from collab-folder/src/relation.rs rename to collab/src/folder/relation.rs index 0f57ba8f7..1292282e5 100644 --- a/collab-folder/src/relation.rs +++ b/collab/src/folder/relation.rs @@ -2,9 +2,9 @@ use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use std::sync::Arc; -use collab::preclude::{Any, MapExt, MapRef, YrsValue}; -use collab::preclude::{Array, ArrayRef, ReadTxn, TransactionMut}; -use collab_entity::define::ViewId; +use crate::entity::define::ViewId; +use crate::preclude::{Any, MapExt, MapRef, YrsValue}; +use crate::preclude::{Array, ArrayRef, ReadTxn, TransactionMut}; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -333,11 +333,11 @@ impl From for Vec { #[repr(transparent)] #[derive(Serialize, Deserialize, Default, Clone, Eq, PartialEq, Debug)] pub struct ViewIdentifier { - pub id: collab_entity::uuid_validation::ViewId, + pub id: crate::entity::uuid_validation::ViewId, } impl Deref for ViewIdentifier { - type Target = collab_entity::uuid_validation::ViewId; + type Target = crate::entity::uuid_validation::ViewId; fn deref(&self) -> &Self::Target { &self.id @@ -345,7 +345,7 @@ impl Deref for ViewIdentifier { } impl ViewIdentifier { - pub fn new(id: collab_entity::uuid_validation::ViewId) -> Self { + pub fn new(id: crate::entity::uuid_validation::ViewId) -> Self { Self { id } } diff --git a/collab-folder/src/revision.rs b/collab/src/folder/revision.rs similarity index 95% rename from collab-folder/src/revision.rs rename to collab/src/folder/revision.rs index 66b2bce3b..3d4e110e3 100644 --- a/collab-folder/src/revision.rs +++ b/collab/src/folder/revision.rs @@ -1,5 +1,5 @@ -use crate::ViewId; -use collab::preclude::{Any, Map, MapRef, Out, ReadTxn, TransactionMut}; +use super::ViewId; +use crate::preclude::{Any, Map, MapRef, Out, ReadTxn, TransactionMut}; pub struct RevisionMapping { container: MapRef, diff --git a/collab-folder/src/section.rs b/collab/src/folder/section.rs similarity index 97% rename from collab-folder/src/section.rs rename to collab/src/folder/section.rs index 0fd2166b9..30ae5d4cb 100644 --- a/collab-folder/src/section.rs +++ b/collab/src/folder/section.rs @@ -1,13 +1,13 @@ use std::collections::HashMap; use std::sync::Arc; -use crate::{UserId, ViewId, timestamp}; -use anyhow::bail; -use collab::preclude::encoding::serde::{from_any, to_any}; -use collab::preclude::{ +use super::{UserId, ViewId, timestamp}; +use crate::preclude::encoding::serde::{from_any, to_any}; +use crate::preclude::{ Any, AnyMut, Array, Map, MapRef, ReadTxn, Subscription, TransactionMut, YrsValue, }; -use collab::preclude::{ArrayRef, MapExt, deserialize_i64_from_numeric}; +use crate::preclude::{ArrayRef, MapExt, deserialize_i64_from_numeric}; +use anyhow::bail; use serde::{Deserialize, Serialize}; use tokio::sync::broadcast; use uuid::Uuid; diff --git a/collab-folder/src/space_info.rs b/collab/src/folder/space_info.rs similarity index 98% rename from collab-folder/src/space_info.rs rename to collab/src/folder/space_info.rs index 18d74ffe5..3c5c0f8bd 100644 --- a/collab-folder/src/space_info.rs +++ b/collab/src/folder/space_info.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::timestamp; +use super::timestamp; pub const SPACE_IS_SPACE_KEY: &str = "is_space"; pub const SPACE_PERMISSION_KEY: &str = "space_permission"; diff --git a/collab-folder/src/view.rs b/collab/src/folder/view.rs similarity index 88% rename from collab-folder/src/view.rs rename to collab/src/folder/view.rs index ab547cecc..ae47bf57f 100644 --- a/collab-folder/src/view.rs +++ b/collab/src/folder/view.rs @@ -1,10 +1,8 @@ use std::collections::{HashMap, HashSet}; use std::sync::Arc; +use crate::preclude::{Any, Map, MapExt, MapPrelim, MapRef, ReadTxn, Subscription, TransactionMut}; use anyhow::bail; -use collab::preclude::{ - Any, Map, MapExt, MapPrelim, MapRef, ReadTxn, Subscription, TransactionMut, -}; use dashmap::DashMap; use serde::{Deserialize, Serialize}; use serde_repr::*; @@ -12,14 +10,14 @@ use tokio::sync::Mutex; use tracing::{instrument, trace}; use uuid::Uuid; -use crate::folder_observe::ViewChangeSender; +use super::folder_observe::ViewChangeSender; -use crate::revision::RevisionMapping; -use crate::section::{Section, SectionItem, SectionMap}; -use crate::space_info::SpaceInfo; -use crate::{ParentChildRelations, RepeatedViewIdentifier, ViewIdentifier, subscribe_view_change}; -use crate::{UserId, impl_any_update, impl_i64_update, impl_option_i64_update, impl_str_update}; -use collab_entity::define::ViewId; +use super::UserId; +use super::revision::RevisionMapping; +use super::section::{Section, SectionItem, SectionMap}; +use super::space_info::SpaceInfo; +use super::{ParentChildRelations, RepeatedViewIdentifier, ViewIdentifier, subscribe_view_change}; +use crate::entity::define::ViewId; pub(crate) const FOLDER_VIEW_ID: &str = "id"; pub(crate) const FOLDER_VIEW_NAME: &str = "name"; @@ -651,19 +649,123 @@ pub struct ViewUpdate<'a, 'b, 'c> { } impl<'a, 'b, 'c> ViewUpdate<'a, 'b, 'c> { - impl_str_update!(set_name, set_name_if_not_none, FOLDER_VIEW_NAME); - impl_str_update!(set_bid, set_bid_if_not_none, VIEW_PARENT_ID); - impl_str_update!(set_desc, set_desc_if_not_none, VIEW_DESC); - impl_any_update!(set_layout, set_layout_if_not_none, VIEW_LAYOUT, ViewLayout); - impl_i64_update!(set_created_at, set_created_at_if_not_none, VIEW_CREATE_AT); - impl_option_i64_update!(set_created_by, VIEW_CREATED_BY); - impl_i64_update!( - set_last_edited_time, - set_last_edited_time_if_not_none, - VIEW_LAST_EDITED_TIME - ); - impl_option_i64_update!(set_last_edited_by, VIEW_LAST_EDITED_BY); - impl_str_update!(set_extra, set_extra_if_not_none, VIEW_EXTRA); + pub fn set_name>(self, value: T) -> Self { + self + .map_ref + .insert(self.txn, FOLDER_VIEW_NAME, value.as_ref()); + self + } + + pub fn set_name_if_not_none>(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, FOLDER_VIEW_NAME, value.as_ref()); + } + self + } + + pub fn set_bid>(self, value: T) -> Self { + self + .map_ref + .insert(self.txn, VIEW_PARENT_ID, value.as_ref()); + self + } + + pub fn set_bid_if_not_none>(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, VIEW_PARENT_ID, value.as_ref()); + } + self + } + + pub fn set_desc>(self, value: T) -> Self { + self.map_ref.insert(self.txn, VIEW_DESC, value.as_ref()); + self + } + + pub fn set_desc_if_not_none>(self, value: Option) -> Self { + if let Some(value) = value { + self.map_ref.insert(self.txn, VIEW_DESC, value.as_ref()); + } + self + } + + pub fn set_layout(self, value: ViewLayout) -> Self { + self.map_ref.insert(self.txn, VIEW_LAYOUT, value); + self + } + + pub fn set_layout_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self.map_ref.insert(self.txn, VIEW_LAYOUT, value); + } + self + } + + pub fn set_created_at(self, value: i64) -> Self { + self + .map_ref + .insert(self.txn, VIEW_CREATE_AT, Any::BigInt(value)); + self + } + + pub fn set_created_at_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, VIEW_CREATE_AT, Any::BigInt(value)); + } + self + } + + pub fn set_created_by(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, VIEW_CREATED_BY, Any::BigInt(value)); + } + self + } + + pub fn set_last_edited_time(self, value: i64) -> Self { + self + .map_ref + .insert(self.txn, VIEW_LAST_EDITED_TIME, Any::BigInt(value)); + self + } + + pub fn set_last_edited_time_if_not_none(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, VIEW_LAST_EDITED_TIME, Any::BigInt(value)); + } + self + } + + pub fn set_last_edited_by(self, value: Option) -> Self { + if let Some(value) = value { + self + .map_ref + .insert(self.txn, VIEW_LAST_EDITED_BY, Any::BigInt(value)); + } + self + } + + pub fn set_extra>(self, value: T) -> Self { + self.map_ref.insert(self.txn, VIEW_EXTRA, value.as_ref()); + self + } + + pub fn set_extra_if_not_none>(self, value: Option) -> Self { + if let Some(value) = value { + self.map_ref.insert(self.txn, VIEW_EXTRA, value.as_ref()); + } + self + } pub fn new( uid: UserId, @@ -788,7 +890,7 @@ impl<'a, 'b, 'c> ViewUpdate<'a, 'b, 'c> { } } -// Use ViewId from collab_entity instead +// Use ViewId from entity module instead // pub type ViewId = Arc; #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] @@ -796,7 +898,7 @@ pub struct View { /// The id of the view pub id: ViewId, /// The id for given parent view - #[serde(with = "collab::preclude::serde_option_uuid")] + #[serde(with = "crate::preclude::serde_option_uuid")] pub parent_view_id: Option, /// The name that display on the left sidebar pub name: String, @@ -884,7 +986,7 @@ impl From for IconType { /// /// # Example /// ```no_run -/// use collab_folder::{IconType, ViewIcon}; +/// use collab::folder::{IconType, ViewIcon}; /// let view_icon = ViewIcon { /// ty: IconType::Url, /// value: String::from("https://example.com/icon.png"), diff --git a/collab-folder/src/workspace.rs b/collab/src/folder/workspace.rs similarity index 89% rename from collab-folder/src/workspace.rs rename to collab/src/folder/workspace.rs index 0d6a30493..511c76aa8 100644 --- a/collab-folder/src/workspace.rs +++ b/collab/src/folder/workspace.rs @@ -1,10 +1,10 @@ use serde::{Deserialize, Serialize}; -use crate::{RepeatedViewIdentifier, View, ViewLayout, timestamp}; +use super::{RepeatedViewIdentifier, View, ViewLayout, timestamp}; #[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] pub struct Workspace { - pub id: collab_entity::uuid_validation::WorkspaceId, + pub id: crate::entity::uuid_validation::WorkspaceId, pub name: String, pub child_views: RepeatedViewIdentifier, pub created_at: i64, @@ -14,7 +14,7 @@ pub struct Workspace { } impl Workspace { - pub fn new(id: collab_entity::uuid_validation::WorkspaceId, name: String, uid: i64) -> Self { + pub fn new(id: crate::entity::uuid_validation::WorkspaceId, name: String, uid: i64) -> Self { let time = timestamp(); Self { id, diff --git a/collab-importer/src/imported_collab.rs b/collab/src/importer/imported_collab.rs similarity index 90% rename from collab-importer/src/imported_collab.rs rename to collab/src/importer/imported_collab.rs index 66cc861e4..26abb11e1 100644 --- a/collab-importer/src/imported_collab.rs +++ b/collab/src/importer/imported_collab.rs @@ -1,9 +1,9 @@ -use crate::error::ImporterError; -use crate::notion::NotionImporter; -use crate::notion::page::CollabResource; -use crate::util::{Either, unzip_from_path_or_memory}; -use collab::entity::EncodedCollab; -use collab_entity::CollabType; +use crate::entity::CollabType; +use crate::entity::EncodedCollab; +use crate::error::CollabError; +use crate::importer::notion::NotionImporter; +use crate::importer::notion::page::CollabResource; +use crate::importer::util::{Either, unzip_from_path_or_memory}; use std::fmt; use futures::StreamExt; @@ -17,9 +17,9 @@ pub async fn import_notion_zip_file( workspace_id: &str, zip_file: PathBuf, output_dir: PathBuf, -) -> Result { +) -> Result { if !zip_file.exists() { - return Err(ImporterError::FileNotFound); + return Err(CollabError::ImporterFileNotFound); } let unzip_file = unzip_from_path_or_memory(Either::Left(zip_file), output_dir).await?; diff --git a/collab-importer/src/lib.rs b/collab/src/importer/mod.rs similarity index 87% rename from collab-importer/src/lib.rs rename to collab/src/importer/mod.rs index 5729ff837..e30d24d75 100644 --- a/collab-importer/src/lib.rs +++ b/collab/src/importer/mod.rs @@ -1,4 +1,3 @@ -pub mod error; pub mod imported_collab; pub mod notion; mod space_view; diff --git a/collab-importer/src/notion/file.rs b/collab/src/importer/notion/file.rs similarity index 98% rename from collab-importer/src/notion/file.rs rename to collab/src/importer/notion/file.rs index 216290a70..204b0e2c0 100644 --- a/collab-importer/src/notion/file.rs +++ b/collab/src/importer/notion/file.rs @@ -1,4 +1,4 @@ -use crate::notion::page::ImportedRowDocument; +use crate::importer::notion::page::ImportedRowDocument; use markdown::mdast::Node; use markdown::{ParseOptions, to_mdast}; use serde::Serialize; diff --git a/collab-importer/src/notion/importer.rs b/collab/src/importer/notion/importer.rs similarity index 94% rename from collab-importer/src/notion/importer.rs rename to collab/src/importer/notion/importer.rs index 7f7e8de63..7bba41d2c 100644 --- a/collab-importer/src/notion/importer.rs +++ b/collab/src/importer/notion/importer.rs @@ -1,21 +1,23 @@ -use crate::error::ImporterError; -use crate::imported_collab::{ImportType, ImportedCollab, ImportedCollabInfo}; -use crate::notion::file::NotionFile; -use crate::notion::page::{CollabResource, NotionPage, build_imported_collab_recursively}; -use crate::notion::walk_dir::{file_name_from_path, process_entry, walk_sub_dir}; -use collab_folder::hierarchy_builder::{ +use crate::error::CollabError; +use crate::folder::hierarchy_builder::{ NestedChildViewBuilder, NestedViews, ParentChildViews, ViewExtraBuilder, }; -use collab_folder::{SpaceInfo, SpacePermission, ViewLayout}; +use crate::folder::{SpaceInfo, SpacePermission, ViewLayout}; +use crate::importer::imported_collab::{ImportType, ImportedCollab, ImportedCollabInfo}; +use crate::importer::notion::file::NotionFile; +use crate::importer::notion::page::{ + CollabResource, NotionPage, build_imported_collab_recursively, +}; +use crate::importer::notion::walk_dir::{file_name_from_path, process_entry, walk_sub_dir}; use futures::stream; use futures::stream::{Stream, StreamExt}; use std::collections::{HashMap, HashSet}; use std::ops::Deref; -use crate::space_view::create_space_view; +use crate::entity::CollabType; +use crate::importer::space_view::create_space_view; +use crate::preclude::Collab; use anyhow::{Error, anyhow}; -use collab::preclude::Collab; -use collab_entity::CollabType; use csv::Reader; use fancy_regex::Regex; use std::path::PathBuf; @@ -39,10 +41,10 @@ impl NotionImporter { file_path: P, workspace_id: S, host: String, - ) -> Result { + ) -> Result { let path = file_path.into(); if !path.exists() { - return Err(ImporterError::InvalidPath(format!( + return Err(CollabError::ImporterInvalidPath(format!( "Path: does not exist: {:?}", path ))); @@ -64,14 +66,14 @@ impl NotionImporter { } /// Return a ImportedInfo struct that contains all the views and their children recursively. - pub async fn import(mut self) -> Result { + pub async fn import(mut self) -> Result { let views = self.collect_pages().await?; if views.is_empty() { - return Err(ImporterError::CannotImport); + return Err(CollabError::ImporterCannotImport); } let workspace_uuid = uuid::Uuid::parse_str(&self.workspace_id).map_err(|e| { - ImporterError::Internal(anyhow!( + CollabError::Internal(anyhow!( "Invalid workspace ID format '{}': {}", self.workspace_id, e @@ -87,7 +89,7 @@ impl NotionImporter { ) } - async fn collect_pages(&mut self) -> Result, ImporterError> { + async fn collect_pages(&mut self) -> Result, CollabError> { let mut has_spaces = false; let mut has_pages = false; @@ -135,10 +137,10 @@ impl NotionImporter { }); } - Ok::<_, ImporterError>(notion_pages) + Ok::<_, CollabError>(notion_pages) }) .await - .map_err(|err| ImporterError::Internal(err.into()))??; + .map_err(|err| CollabError::Internal(err.into()))??; Ok(pages) } @@ -163,7 +165,7 @@ impl ImportedInfo { host: String, name: String, views: Vec, - ) -> Result { + ) -> Result { let view_uuid = uuid::Uuid::new_v4(); let (space_view, space_collab) = create_space_view( uid, @@ -221,7 +223,7 @@ impl ImportedInfo { collab_type: CollabType::Document, encoded_collab: self .space_collab - .encode_collab_v1(|_collab| Ok::<_, ImporterError>(())) + .encode_collab_v1(|_collab| Ok::<_, CollabError>(())) .unwrap(), }; diff --git a/collab-importer/src/notion/mod.rs b/collab/src/importer/notion/mod.rs similarity index 100% rename from collab-importer/src/notion/mod.rs rename to collab/src/importer/notion/mod.rs diff --git a/collab-importer/src/notion/page.rs b/collab/src/importer/notion/page.rs similarity index 93% rename from collab-importer/src/notion/page.rs rename to collab/src/importer/notion/page.rs index 008001507..517b90c48 100644 --- a/collab-importer/src/notion/page.rs +++ b/collab/src/importer/notion/page.rs @@ -1,25 +1,25 @@ -use crate::error::ImporterError; -use crate::imported_collab::{ImportType, ImportedCollab, ImportedCollabInfo}; - -use collab_database::database::{Database, get_row_document_id}; -use collab_database::template::csv::{CSVResource, CSVTemplate}; -use collab_document::blocks::{BlockType, TextDelta, mention_block_data, mention_block_delta}; -use collab_document::document::Document; -use collab_document::importer::define::URL_FIELD; -use collab_document::importer::md_importer::{MDImporter, create_image_block}; -use collab_entity::CollabType; -use collab_entity::uuid_validation::DatabaseId; +use crate::error::CollabError; +use crate::importer::imported_collab::{ImportType, ImportedCollab, ImportedCollabInfo}; + +use crate::database::database::{Database, get_row_document_id}; +use crate::database::template::csv::{CSVResource, CSVTemplate}; +use crate::document::blocks::{BlockType, TextDelta, mention_block_data, mention_block_delta}; +use crate::document::document::Document; +use crate::document::importer::define::URL_FIELD; +use crate::document::importer::md_importer::{MDImporter, create_image_block}; +use crate::entity::CollabType; +use crate::entity::uuid_validation::DatabaseId; use futures::stream::{self, StreamExt}; -use crate::notion::file::NotionFile; -use crate::notion::walk_dir::{extract_delta_link, extract_external_links}; -use crate::notion::{CSVRelation, ImportedCollabInfoStream}; -use crate::util::{FileId, upload_file_url}; -use collab::core::collab::default_client_id; -use collab_database::database_trait::NoPersistenceDatabaseCollabService; -use collab_database::template::builder::FileUrlBuilder; -use collab_document::document_data::default_document_data; -use collab_entity::uuid_validation::RowId; +use crate::core::collab::default_client_id; +use crate::database::database_trait::NoPersistenceDatabaseCollabService; +use crate::database::template::builder::FileUrlBuilder; +use crate::document::document_data::default_document_data; +use crate::entity::uuid_validation::RowId; +use crate::importer::notion::file::NotionFile; +use crate::importer::notion::walk_dir::{extract_delta_link, extract_external_links}; +use crate::importer::notion::{CSVRelation, ImportedCollabInfoStream}; +use crate::importer::util::{FileId, upload_file_url}; use percent_encoding::percent_decode_str; use serde::Serialize; use serde_json::json; @@ -134,7 +134,7 @@ impl NotionPage { search_view(&self.children, id) } - pub async fn as_document(&self) -> Result<(Document, CollabResource), ImporterError> { + pub async fn as_document(&self) -> Result<(Document, CollabResource), CollabError> { let external_link_views = self.get_external_link_notion_view(); match &self.notion_file { NotionFile::Markdown { file_path, .. } => { @@ -184,7 +184,7 @@ impl NotionPage { let resource = CollabResource { object_id: Uuid::parse_str(&self.view_id).map_err(|_| { - ImporterError::Internal(anyhow::anyhow!( + CollabError::Internal(anyhow::anyhow!( "Invalid UUID format for view_id: {}", self.view_id )) @@ -194,7 +194,7 @@ impl NotionPage { Ok((document, resource)) }, - _ => Err(ImporterError::InvalidFileType(format!( + _ => Err(CollabError::ImporterInvalidFileType(format!( "File type is not supported for document: {:?}", self.notion_file ))), @@ -362,7 +362,7 @@ impl NotionPage { // Insert new image blocks if any are created for image_url in block_deltas_result.new_delta_image_blocks { - let new_block_id = collab_document::document_data::generate_id(); + let new_block_id = crate::document::document_data::generate_id(); let image_block = create_image_block(&new_block_id, image_url, block_id); if let Err(err) = document.insert_block(image_block, Some(block_id.to_string())) { error!( @@ -496,7 +496,7 @@ impl NotionPage { } } - pub async fn as_database(&self) -> Result { + pub async fn as_database(&self) -> Result { match &self.notion_file { NotionFile::CSV { file_path, @@ -520,8 +520,8 @@ impl NotionPage { // create csv template, we need to set the view id as csv template view id let mut csv_template = CSVTemplate::try_from_reader(content.as_bytes(), true, Some(csv_resource))?; - let view_uuid = uuid::Uuid::parse_str(&self.view_id) - .map_err(|err| ImporterError::Internal(err.into()))?; + let view_uuid = + uuid::Uuid::parse_str(&self.view_id).map_err(|err| CollabError::Internal(err.into()))?; csv_template.reset_view_id(view_uuid); let database_id = csv_template.database_id; @@ -571,7 +571,7 @@ impl NotionPage { resource, }) }, - _ => Err(ImporterError::InvalidFileType(format!( + _ => Err(CollabError::ImporterInvalidFileType(format!( "File type is not supported for database: {:?}", self.notion_file ))), @@ -579,7 +579,7 @@ impl NotionPage { } #[async_recursion::async_recursion(?Send)] - pub async fn build_imported_collab(&self) -> Result, ImporterError> { + pub async fn build_imported_collab(&self) -> Result, CollabError> { let name = self.notion_name.clone(); match &self.notion_file { NotionFile::CSV { .. } => { @@ -587,7 +587,7 @@ impl NotionPage { let database_id = content .database .get_database_id() - .map_err(|e| ImporterError::Internal(e.into()))?; + .map_err(|e| CollabError::Internal(e.into()))?; let mut resources = vec![content.resource]; let view_ids = content .database @@ -672,7 +672,7 @@ impl NotionPage { imported_collabs: vec![imported_collab], resources: vec![CollabResource { object_id: Uuid::parse_str(&self.view_id).map_err(|_| { - ImporterError::Internal(anyhow::anyhow!( + CollabError::Internal(anyhow::anyhow!( "Invalid UUID format for view_id: {}", self.view_id )) diff --git a/collab-importer/src/notion/walk_dir.rs b/collab/src/importer/notion/walk_dir.rs similarity index 96% rename from collab-importer/src/notion/walk_dir.rs rename to collab/src/importer/notion/walk_dir.rs index b32e7fbcd..98ca2101c 100644 --- a/collab-importer/src/notion/walk_dir.rs +++ b/collab/src/importer/notion/walk_dir.rs @@ -1,4 +1,4 @@ -use crate::error::ImporterError; +use crate::error::CollabError; use std::fmt::Display; use fancy_regex::Regex; @@ -6,10 +6,12 @@ use markdown::mdast::Node; use markdown::{ParseOptions, to_mdast}; use percent_encoding::percent_decode_str; -use crate::notion::NotionExportContext; -use crate::notion::file::{NotionFile, Resource, process_row_md_content}; -use crate::notion::page::{ExternalLink, ExternalLinkType, ImportedRowDocument, NotionPage}; -use crate::util::parse_csv; +use crate::importer::notion::NotionExportContext; +use crate::importer::notion::file::{NotionFile, Resource, process_row_md_content}; +use crate::importer::notion::page::{ + ExternalLink, ExternalLinkType, ImportedRowDocument, NotionPage, +}; +use crate::importer::util::parse_csv; use std::fs; use std::path::{Component, Path, PathBuf}; @@ -462,10 +464,10 @@ fn process_md_file( } // Main function to get all links from a markdown file -pub(crate) fn get_md_links(md_file_path: &Path) -> Result>, ImporterError> { +pub(crate) fn get_md_links(md_file_path: &Path) -> Result>, CollabError> { let content = std::fs::read_to_string(md_file_path)?; let ast = - to_mdast(&content, &ParseOptions::default()).map_err(ImporterError::ParseMarkdownError)?; + to_mdast(&content, &ParseOptions::default()).map_err(CollabError::ImporterParseMarkdown)?; let mut links = Vec::new(); collect_links_from_node(&ast, &mut links); Ok( @@ -511,7 +513,7 @@ fn link_type_from_extension(extension: Option<&str>) -> ExternalLinkType { } } -pub(crate) fn extract_external_links(path_str: &str) -> Result, ImporterError> { +pub(crate) fn extract_external_links(path_str: &str) -> Result, CollabError> { let path_str = percent_decode_str(path_str).decode_utf8()?.to_string(); let mut result = Vec::new(); let re = Regex::new(r"^(.*?)\s*([a-f0-9]{32})(?:\.(\w+))?$").unwrap(); @@ -540,7 +542,7 @@ pub(crate) fn extract_external_links(path_str: &str) -> Result }); } } else { - return Err(ImporterError::Internal(anyhow::anyhow!( + return Err(CollabError::Internal(anyhow::anyhow!( "Non-UTF8 path component" ))); } @@ -612,28 +614,28 @@ fn get_file_extension(path: &Path, include_partial_csv: bool) -> FileExtension { _ => FileExtension::Unknown, }) } -fn name_and_id_from_path(path: &Path) -> Result<(String, Option), ImporterError> { +fn name_and_id_from_path(path: &Path) -> Result<(String, Option), CollabError> { let re = Regex::new(r"^(.*?)(?:\s+([a-f0-9]{32}))?(?:_[a-zA-Z0-9]+)?(?:\.[a-zA-Z0-9]+)?\s*$").unwrap(); let input = path .file_name() .and_then(|name| name.to_str()) - .ok_or(ImporterError::InvalidPathFormat)?; + .ok_or(CollabError::ImporterInvalidPathFormat)?; if let Ok(Some(captures)) = re.captures(input) { let file_name = captures .get(1) .map(|m| m.as_str().trim().to_string()) .filter(|s| !s.is_empty()) - .ok_or(ImporterError::InvalidPathFormat)?; + .ok_or(CollabError::ImporterInvalidPathFormat)?; let file_id = captures.get(2).map(|m| m.as_str().to_string()); return Ok((file_name, file_id)); } // Fallback for cases where no ID is present but a valid name exists - Err(ImporterError::InvalidPathFormat) + Err(CollabError::ImporterInvalidPathFormat) } /// - If the file is a `.csv` and contains `_all`, it's considered a `CSV`. @@ -678,12 +680,12 @@ fn notion_file_from_path(path: &Path, no_subpages: bool) -> Option { } } -pub(crate) fn file_name_from_path(path: &Path) -> Result { +pub(crate) fn file_name_from_path(path: &Path) -> Result { path .file_name() - .ok_or_else(|| ImporterError::InvalidPath("can't get file name".to_string()))? + .ok_or_else(|| CollabError::ImporterInvalidPath("can't get file name".to_string()))? .to_str() - .ok_or_else(|| ImporterError::InvalidPath("file name is not a valid string".to_string())) + .ok_or_else(|| CollabError::ImporterInvalidPath("file name is not a valid string".to_string())) .map(|s| s.to_string()) } diff --git a/collab-importer/src/space_view.rs b/collab/src/importer/space_view.rs similarity index 62% rename from collab-importer/src/space_view.rs rename to collab/src/importer/space_view.rs index 667b98beb..6dfa3ef1b 100644 --- a/collab-importer/src/space_view.rs +++ b/collab/src/importer/space_view.rs @@ -1,10 +1,10 @@ -use crate::error::ImporterError; -use collab::core::collab::{CollabOptions, DataSource, default_client_id}; -use collab::core::origin::CollabOrigin; -use collab::preclude::Collab; -use collab_document::document_data::default_document_collab_data; -use collab_folder::hierarchy_builder::{NestedChildViewBuilder, ParentChildViews}; -use collab_folder::{SpaceInfo, ViewLayout}; +use crate::core::collab::{CollabOptions, DataSource, default_client_id}; +use crate::core::origin::CollabOrigin; +use crate::document::document_data::default_document_collab_data; +use crate::error::CollabError; +use crate::folder::hierarchy_builder::{NestedChildViewBuilder, ParentChildViews}; +use crate::folder::{SpaceInfo, ViewLayout}; +use crate::preclude::Collab; use uuid::Uuid; #[allow(dead_code)] @@ -15,17 +15,17 @@ pub fn create_space_view( view_id: &Uuid, child_views: Vec, space_info: SpaceInfo, -) -> Result<(ParentChildViews, Collab), ImporterError> { +) -> Result<(ParentChildViews, Collab), CollabError> { let client_id = default_client_id(); let import_container_doc_state = default_document_collab_data(&view_id.to_string(), client_id) - .map_err(|err| ImporterError::Internal(err.into()))? + .map_err(|err| CollabError::Internal(err.into()))? .doc_state .to_vec(); let options = CollabOptions::new(*view_id, client_id) .with_data_source(DataSource::DocStateV1(import_container_doc_state)); let collab = Collab::new_with_options(CollabOrigin::Empty, options) - .map_err(|err| ImporterError::Internal(err.into()))?; + .map_err(|err| CollabError::Internal(err.into()))?; let view = NestedChildViewBuilder::new(uid, *workspace_id) .with_view_id(*view_id) diff --git a/collab-importer/src/util.rs b/collab/src/importer/util.rs similarity index 94% rename from collab-importer/src/util.rs rename to collab/src/importer/util.rs index a46ad34a5..cc7b1ddeb 100644 --- a/collab-importer/src/util.rs +++ b/collab/src/importer/util.rs @@ -1,4 +1,4 @@ -use crate::zip_tool::async_zip::{async_unzip, unzip_single_file}; +use crate::importer::zip_tool::async_zip::{async_unzip, unzip_single_file}; use anyhow::Error; use anyhow::Result; use async_zip::base::read::stream::ZipFileReader; @@ -10,8 +10,8 @@ use std::ops::Deref; use std::path::PathBuf; use tokio::io::{AsyncReadExt, BufReader}; -use crate::error::ImporterError; -use crate::zip_tool::util::{is_multi_part_zip, is_multi_part_zip_file}; +use crate::error::CollabError; +use crate::importer::zip_tool::util::{is_multi_part_zip, is_multi_part_zip_file}; use tracing::warn; pub fn upload_file_url(host: &str, workspace_id: &str, object_id: &str, file_id: &str) -> String { @@ -58,7 +58,7 @@ async fn async_calculate_file_id(file_path: &PathBuf) -> Result { pub async fn unzip_from_path_or_memory( input: Either>, out: PathBuf, -) -> Result { +) -> Result { match input { Either::Left(path) => { if is_multi_part_zip(&path).await.unwrap_or(false) { diff --git a/collab-importer/src/workspace/database_collab_remapper.rs b/collab/src/importer/workspace/database_collab_remapper.rs similarity index 83% rename from collab-importer/src/workspace/database_collab_remapper.rs rename to collab/src/importer/workspace/database_collab_remapper.rs index 797bdc01c..6d86ee886 100644 --- a/collab-importer/src/workspace/database_collab_remapper.rs +++ b/collab/src/importer/workspace/database_collab_remapper.rs @@ -1,14 +1,14 @@ +use crate::core::collab::default_client_id; +use crate::database::database::{Database, DatabaseContext, DatabaseData}; +use crate::database::database_remapper::DatabaseCollabRemapper as DatabaseRemapper; +use crate::database::database_trait::NoPersistenceDatabaseCollabService; +use crate::database::entity::CreateDatabaseParams; use anyhow::Result; -use collab::core::collab::default_client_id; -use collab_database::database::{Database, DatabaseContext, DatabaseData}; -use collab_database::database_remapper::DatabaseCollabRemapper as DatabaseRemapper; -use collab_database::database_trait::NoPersistenceDatabaseCollabService; -use collab_database::entity::CreateDatabaseParams; use serde_json; use std::collections::HashMap; use std::sync::Arc; -use crate::workspace::id_remapper::JsonIdRemapper; +use crate::importer::workspace::id_remapper::JsonIdRemapper; pub struct DatabaseCollabRemapper { id_mapping: HashMap, diff --git a/collab-importer/src/workspace/document_collab_remapper.rs b/collab/src/importer/workspace/document_collab_remapper.rs similarity index 85% rename from collab-importer/src/workspace/document_collab_remapper.rs rename to collab/src/importer/workspace/document_collab_remapper.rs index 03931b6fc..79b0d7cab 100644 --- a/collab-importer/src/workspace/document_collab_remapper.rs +++ b/collab/src/importer/workspace/document_collab_remapper.rs @@ -1,12 +1,12 @@ +use crate::core::collab::default_client_id; +use crate::document::blocks::DocumentData; +use crate::document::document::Document; use anyhow::Result; -use collab::core::collab::default_client_id; -use collab_document::blocks::DocumentData; -use collab_document::document::Document; use serde_json; use std::collections::HashMap; use uuid::Uuid; -use crate::workspace::id_remapper::JsonIdRemapper; +use crate::importer::workspace::id_remapper::JsonIdRemapper; pub struct DocumentCollabRemapper { id_mapping: HashMap, diff --git a/collab-importer/src/workspace/entities.rs b/collab/src/importer/workspace/entities.rs similarity index 97% rename from collab-importer/src/workspace/entities.rs rename to collab/src/importer/workspace/entities.rs index fbe872c07..00a730f1f 100644 --- a/collab-importer/src/workspace/entities.rs +++ b/collab/src/importer/workspace/entities.rs @@ -1,5 +1,5 @@ -use collab_entity::CollabType; -use collab_folder::{ViewIcon, ViewLayout}; +use crate::entity::CollabType; +use crate::folder::{ViewIcon, ViewLayout}; use indexmap::IndexMap; use serde::{Deserialize, Serialize}; use std::collections::HashMap; diff --git a/collab-importer/src/workspace/folder_collab_remapper.rs b/collab/src/importer/workspace/folder_collab_remapper.rs similarity index 92% rename from collab-importer/src/workspace/folder_collab_remapper.rs rename to collab/src/importer/workspace/folder_collab_remapper.rs index 5895c00c6..55cc09b5a 100644 --- a/collab-importer/src/workspace/folder_collab_remapper.rs +++ b/collab/src/importer/workspace/folder_collab_remapper.rs @@ -1,13 +1,13 @@ -use anyhow::{Result, anyhow}; -use collab::core::collab::{CollabOptions, default_client_id}; -use collab::preclude::Collab; -use collab_folder::{ +use crate::core::collab::{CollabOptions, default_client_id}; +use crate::folder::{ CollabOrigin, Folder, RepeatedViewIdentifier, View, ViewIdentifier, Workspace, default_folder_data, timestamp, }; +use crate::preclude::Collab; +use anyhow::{Result, anyhow}; -use crate::workspace::entities::WorkspaceRelationMap; -use crate::workspace::id_mapper::IdMapper; +use crate::importer::workspace::entities::WorkspaceRelationMap; +use crate::importer::workspace::id_mapper::IdMapper; pub struct FolderCollabRemapper; diff --git a/collab-importer/src/workspace/id_mapper.rs b/collab/src/importer/workspace/id_mapper.rs similarity index 96% rename from collab-importer/src/workspace/id_mapper.rs rename to collab/src/importer/workspace/id_mapper.rs index 50b66a463..3032bc996 100644 --- a/collab-importer/src/workspace/id_mapper.rs +++ b/collab/src/importer/workspace/id_mapper.rs @@ -1,6 +1,6 @@ -use crate::workspace::entities::{DependencyType, WorkspaceRelationMap}; +use crate::database::database::get_row_document_id; +use crate::importer::workspace::entities::{DependencyType, WorkspaceRelationMap}; use anyhow::{Result, anyhow}; -use collab_database::database::get_row_document_id; use std::collections::HashMap; use uuid::Uuid; diff --git a/collab-importer/src/workspace/id_remapper.rs b/collab/src/importer/workspace/id_remapper.rs similarity index 100% rename from collab-importer/src/workspace/id_remapper.rs rename to collab/src/importer/workspace/id_remapper.rs diff --git a/collab-importer/src/workspace/mod.rs b/collab/src/importer/workspace/mod.rs similarity index 100% rename from collab-importer/src/workspace/mod.rs rename to collab/src/importer/workspace/mod.rs diff --git a/collab-importer/src/workspace/relation_map_parser.rs b/collab/src/importer/workspace/relation_map_parser.rs similarity index 97% rename from collab-importer/src/workspace/relation_map_parser.rs rename to collab/src/importer/workspace/relation_map_parser.rs index eeeff89da..34baff46d 100644 --- a/collab-importer/src/workspace/relation_map_parser.rs +++ b/collab/src/importer/workspace/relation_map_parser.rs @@ -1,6 +1,6 @@ use std::fs::read_to_string; -use crate::workspace::entities::WorkspaceRelationMap; +use crate::importer::workspace::entities::WorkspaceRelationMap; use anyhow::{Result, anyhow}; pub struct RelationMapParser {} diff --git a/collab-importer/src/workspace/space_view_edge_case_handler.rs b/collab/src/importer/workspace/space_view_edge_case_handler.rs similarity index 94% rename from collab-importer/src/workspace/space_view_edge_case_handler.rs rename to collab/src/importer/workspace/space_view_edge_case_handler.rs index 3d843a224..732f41720 100644 --- a/collab-importer/src/workspace/space_view_edge_case_handler.rs +++ b/collab/src/importer/workspace/space_view_edge_case_handler.rs @@ -1,8 +1,8 @@ -use crate::workspace::entities::{ViewMetadata, WorkspaceRelationMap}; -use crate::workspace::id_mapper::IdMapper; +use crate::database::database::timestamp; +use crate::folder::ViewLayout; +use crate::importer::workspace::entities::{ViewMetadata, WorkspaceRelationMap}; +use crate::importer::workspace::id_mapper::IdMapper; use anyhow::Result; -use collab_database::database::timestamp; -use collab_folder::ViewLayout; use serde_json; use std::fs; use std::path::Path; diff --git a/collab-importer/src/workspace/workspace_database_remapper.rs b/collab/src/importer/workspace/workspace_database_remapper.rs similarity index 89% rename from collab-importer/src/workspace/workspace_database_remapper.rs rename to collab/src/importer/workspace/workspace_database_remapper.rs index 0ebe17192..6f395a3ef 100644 --- a/collab-importer/src/workspace/workspace_database_remapper.rs +++ b/collab/src/importer/workspace/workspace_database_remapper.rs @@ -1,15 +1,15 @@ +use crate::core::collab::CollabOptions; +use crate::core::collab::default_client_id; +use crate::core::origin::CollabOrigin; +use crate::database::workspace_database::WorkspaceDatabase; +use crate::preclude::Collab; use anyhow::{Result, anyhow}; -use collab::core::collab::CollabOptions; -use collab::core::collab::default_client_id; -use collab::core::origin::CollabOrigin; -use collab::preclude::Collab; -use collab_database::workspace_database::WorkspaceDatabase; use serde::{Deserialize, Serialize}; use serde_json; use std::collections::HashMap; use uuid::Uuid; -use crate::workspace::id_remapper::JsonIdRemapper; +use crate::importer::workspace::id_remapper::JsonIdRemapper; #[derive(Debug, Clone, Deserialize, Serialize)] pub struct DatabaseMetaData { diff --git a/collab-importer/src/workspace/workspace_remapper.rs b/collab/src/importer/workspace/workspace_remapper.rs similarity index 90% rename from collab-importer/src/workspace/workspace_remapper.rs rename to collab/src/importer/workspace/workspace_remapper.rs index c722ec701..207d7d4bf 100644 --- a/collab-importer/src/workspace/workspace_remapper.rs +++ b/collab/src/importer/workspace/workspace_remapper.rs @@ -1,9 +1,9 @@ +use crate::database::database::Database; +use crate::database::workspace_database::WorkspaceDatabase; +use crate::document::document::Document; +use crate::entity::CollabType; +use crate::folder::Folder; use anyhow::{Result, anyhow}; -use collab_database::database::Database; -use collab_database::workspace_database::WorkspaceDatabase; -use collab_document::document::Document; -use collab_entity::CollabType; -use collab_folder::Folder; use serde_json; use std::collections::HashMap; use std::fs; @@ -11,14 +11,14 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use uuid::Uuid; -use crate::workspace::database_collab_remapper::DatabaseCollabRemapper; -use crate::workspace::document_collab_remapper::DocumentCollabRemapper; -use crate::workspace::entities::{DependencyType, WorkspaceRelationMap}; -use crate::workspace::folder_collab_remapper::FolderCollabRemapper; -use crate::workspace::id_mapper::IdMapper; -use crate::workspace::relation_map_parser::RelationMapParser; -use crate::workspace::space_view_edge_case_handler::SpaceViewEdgeCaseHandler; -use crate::workspace::workspace_database_remapper::WorkspaceDatabaseRemapper; +use crate::importer::workspace::database_collab_remapper::DatabaseCollabRemapper; +use crate::importer::workspace::document_collab_remapper::DocumentCollabRemapper; +use crate::importer::workspace::entities::{DependencyType, WorkspaceRelationMap}; +use crate::importer::workspace::folder_collab_remapper::FolderCollabRemapper; +use crate::importer::workspace::id_mapper::IdMapper; +use crate::importer::workspace::relation_map_parser::RelationMapParser; +use crate::importer::workspace::space_view_edge_case_handler::SpaceViewEdgeCaseHandler; +use crate::importer::workspace::workspace_database_remapper::WorkspaceDatabaseRemapper; pub struct WorkspaceRemapper { #[allow(dead_code)] diff --git a/collab-importer/src/zip_tool/async_zip.rs b/collab/src/importer/zip_tool/async_zip.rs similarity index 92% rename from collab-importer/src/zip_tool/async_zip.rs rename to collab/src/importer/zip_tool/async_zip.rs index 383f72549..b6a1061ab 100644 --- a/collab-importer/src/zip_tool/async_zip.rs +++ b/collab/src/importer/zip_tool/async_zip.rs @@ -4,6 +4,7 @@ use async_zip::base::read::stream::{Ready, ZipFileReader}; use async_zip::{StringEncoding, ZipString}; use futures::AsyncReadExt as FuturesAsyncReadExt; use futures::io::AsyncBufRead; +use futures_lite::io; use std::ffi::OsString; use std::str; @@ -18,8 +19,8 @@ use tokio::fs::{OpenOptions, create_dir_all}; use tokio_util::compat::TokioAsyncReadCompatExt; use tokio_util::compat::TokioAsyncWriteCompatExt; -use crate::error::ImporterError; -use crate::zip_tool::util::{ +use crate::error::CollabError; +use crate::importer::zip_tool::util::{ has_multi_part_extension, has_multi_part_suffix, is_multi_part_zip_signature, remove_part_suffix, sanitize_file_path, }; @@ -36,7 +37,7 @@ pub async fn async_unzip( mut zip_reader: ZipFileReader>, out_dir: PathBuf, default_file_name: Option, -) -> Result +) -> Result where R: AsyncBufRead + Unpin, { @@ -105,7 +106,7 @@ where entry_reader.entry(), err, ); - return Err(ImporterError::Internal(anyhow!( + return Err(CollabError::Internal(anyhow!( "Unexpected EOF while reading: {}", filename ))); @@ -139,7 +140,7 @@ where // move all unzip file content into parent match root_dir { None => match default_file_name { - None => Err(ImporterError::FileNotFound), + None => Err(CollabError::ImporterFileNotFound), Some(default_file_name) => { if fs::metadata(&out_dir).await.is_err() { fs::create_dir_all(&out_dir) @@ -197,18 +198,18 @@ pub async fn unzip_single_file( archive: File, out_dir: &Path, mut root_dir: Option, -) -> Result { +) -> Result { let archive = BufReader::new(archive).compat(); let mut reader = SeekZipFileReader::new(archive) .await - .map_err(|err| ImporterError::Internal(err.into()))?; + .map_err(|err| CollabError::Internal(err.into()))?; for index in 0..reader.file().entries().len() { let entry = reader.file().entries().get(index).unwrap(); let file_name = entry .filename() .as_str() - .map_err(|err| ImporterError::Internal(err.into()))?; + .map_err(|err| CollabError::Internal(err.into()))?; if root_dir.is_none() && file_name.ends_with('/') { root_dir = Some(file_name.split('/').next().unwrap_or(file_name).to_string()); } @@ -220,11 +221,11 @@ pub async fn unzip_single_file( // https://github.com/python/cpython/blob/820ef62833bd2d84a141adedd9a05998595d6b6d/Lib/zipfile.py#L528 let entry_is_dir = entry .dir() - .map_err(|err| ImporterError::Internal(err.into()))?; + .map_err(|err| CollabError::Internal(err.into()))?; let mut entry_reader = reader .reader_without_entry(index) .await - .map_err(|err| ImporterError::Internal(err.into()))?; + .map_err(|err| CollabError::Internal(err.into()))?; if entry_is_dir { if !path.exists() { @@ -243,11 +244,11 @@ pub async fn unzip_single_file( .create_new(true) .open(&path) .await?; - futures_lite::io::copy(&mut entry_reader, &mut writer.compat_write()).await?; + io::copy(&mut entry_reader, &mut writer.compat_write()).await?; } } match root_dir { - None => Err(ImporterError::FileNotFound), + None => Err(CollabError::ImporterFileNotFound), Some(root_dir) => Ok(UnzipFile { file_name: root_dir.clone(), unzip_dir_path: out_dir.join(root_dir), diff --git a/collab-importer/src/zip_tool/mod.rs b/collab/src/importer/zip_tool/mod.rs similarity index 100% rename from collab-importer/src/zip_tool/mod.rs rename to collab/src/importer/zip_tool/mod.rs diff --git a/collab-importer/src/zip_tool/sync_zip.rs b/collab/src/importer/zip_tool/sync_zip.rs similarity index 73% rename from collab-importer/src/zip_tool/sync_zip.rs rename to collab/src/importer/zip_tool/sync_zip.rs index 79660ad10..38b0b97de 100644 --- a/collab-importer/src/zip_tool/sync_zip.rs +++ b/collab/src/importer/zip_tool/sync_zip.rs @@ -1,5 +1,5 @@ -use crate::error::ImporterError; -use crate::zip_tool::util::{ +use crate::error::CollabError; +use crate::importer::zip_tool::util::{ has_multi_part_extension, has_multi_part_suffix, is_multi_part_zip_signature, remove_part_suffix, sanitize_file_path, }; @@ -22,12 +22,12 @@ pub fn sync_unzip( file_path: PathBuf, out_dir: PathBuf, default_file_name: Option, -) -> Result { +) -> Result { let file = File::open(file_path) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to open zip file: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to open zip file: {:?}", e)))?; let mut archive = ZipArchive::new(file) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to read zip archive: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to read zip archive: {:?}", e)))?; let mut root_dir = None; let mut parts = vec![]; @@ -42,14 +42,14 @@ pub fn sync_unzip( if !out_dir.exists() { fs::create_dir_all(&out_dir) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to create dir: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to create dir: {:?}", e)))?; } // Iterate through each file in the archive for i in 0..archive.len() { let mut entry = archive .by_index(i) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to read entry: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to read entry: {:?}", e)))?; let filename = entry.name().to_string(); // Skip zip files within subdirectories @@ -61,11 +61,11 @@ pub fn sync_unzip( let output_path = out_dir.join(&filename); if entry.is_dir() { fs::create_dir_all(&output_path) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to create dir: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to create dir: {:?}", e)))?; } else { if let Some(parent) = output_path.parent() { fs::create_dir_all(parent) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to create parent dir: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to create parent dir: {:?}", e)))?; } // Create and write the file @@ -74,7 +74,7 @@ pub fn sync_unzip( .create_new(true) .open(&output_path) .map_err(|e| { - ImporterError::Internal(anyhow!( + CollabError::Internal(anyhow!( "Failed to create or open file with path: {:?}, error: {:?}", output_path, e @@ -82,9 +82,9 @@ pub fn sync_unzip( }) { Ok(mut outfile) => { let mut buffer = vec![]; - entry.read_to_end(&mut buffer).map_err(|e| { - ImporterError::Internal(anyhow!("Failed to read entry content: {:?}", e)) - })?; + entry + .read_to_end(&mut buffer) + .map_err(|e| CollabError::Internal(anyhow!("Failed to read entry content: {:?}", e)))?; // Check if it's a multipart zip file if buffer.len() >= 4 { @@ -107,7 +107,7 @@ pub fn sync_unzip( outfile .write_all(&buffer) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to write file: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to write file: {:?}", e)))?; }, Err(err) => { warn!("{}", err); @@ -129,7 +129,7 @@ pub fn sync_unzip( // Move all unzipped file content into parent match root_dir { None => match default_file_name { - None => Err(ImporterError::FileNotFound), + None => Err(CollabError::ImporterFileNotFound), Some(root_dir) => Ok(UnzipFile { dir_name: root_dir, unzip_dir: out_dir, @@ -163,15 +163,15 @@ fn unzip_single_file( archive_file: File, out_dir: &Path, mut root_dir: Option, -) -> Result { +) -> Result { let mut archive = ZipArchive::new(archive_file) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to read zip archive: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to read zip archive: {:?}", e)))?; // Iterate through each file in the archive for i in 0..archive.len() { let mut entry = archive .by_index(i) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to read entry: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to read entry: {:?}", e)))?; let entry_name = entry.name(); if entry_name == ".DS_Store" || entry_name.starts_with("__MACOSX") { @@ -194,14 +194,14 @@ fn unzip_single_file( if entry.is_dir() { if !path.exists() { fs::create_dir_all(&path) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to create directory: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to create directory: {:?}", e)))?; } } else { // Ensure parent directories exist if let Some(parent) = path.parent() { if !parent.exists() { fs::create_dir_all(parent).map_err(|e| { - ImporterError::Internal(anyhow!("Failed to create parent directory: {:?}", e)) + CollabError::Internal(anyhow!("Failed to create parent directory: {:?}", e)) })?; } } @@ -212,7 +212,7 @@ fn unzip_single_file( .create_new(true) .open(&path) .map_err(|e| { - ImporterError::Internal(anyhow!( + CollabError::Internal(anyhow!( "Failed to create part file: {:?}, path:{:?}", e, path @@ -220,13 +220,13 @@ fn unzip_single_file( })?; io::copy(&mut entry, &mut outfile) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to write file: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to write file: {:?}", e)))?; } } // Return result with root directory info match root_dir { - None => Err(ImporterError::FileNotFound), + None => Err(CollabError::ImporterFileNotFound), Some(root_dir) => Ok(UnzipFile { dir_name: root_dir.clone(), unzip_dir: out_dir.join(root_dir), @@ -240,12 +240,12 @@ pub fn sync_simple_unzip( zip_path: PathBuf, output_dir: PathBuf, workspace_name: Option, -) -> Result { +) -> Result { let file = File::open(&zip_path) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to open zip file: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to open zip file: {:?}", e)))?; let mut archive = ZipArchive::new(file) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to read zip archive: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to read zip archive: {:?}", e)))?; let output_dir = if let Some(name) = workspace_name { output_dir.join(name) @@ -254,15 +254,14 @@ pub fn sync_simple_unzip( }; if !output_dir.exists() { - std::fs::create_dir_all(&output_dir).map_err(|e| { - ImporterError::Internal(anyhow!("Failed to create output directory: {:?}", e)) - })?; + std::fs::create_dir_all(&output_dir) + .map_err(|e| CollabError::Internal(anyhow!("Failed to create output directory: {:?}", e)))?; } for i in 0..archive.len() { let mut file = archive .by_index(i) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to read entry: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to read entry: {:?}", e)))?; let output_path = match file.enclosed_name() { Some(path) => output_dir.join(path), @@ -271,12 +270,12 @@ pub fn sync_simple_unzip( if file.is_dir() { std::fs::create_dir_all(&output_path) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to create directory: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to create directory: {:?}", e)))?; } else { if let Some(p) = output_path.parent() { if !p.exists() { std::fs::create_dir_all(p).map_err(|e| { - ImporterError::Internal(anyhow!("Failed to create parent directory: {:?}", e)) + CollabError::Internal(anyhow!("Failed to create parent directory: {:?}", e)) })?; } } @@ -285,10 +284,10 @@ pub fn sync_simple_unzip( .write(true) .create_new(true) .open(&output_path) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to create file: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to create file: {:?}", e)))?; std::io::copy(&mut file, &mut outfile) - .map_err(|e| ImporterError::Internal(anyhow!("Failed to extract file: {:?}", e)))?; + .map_err(|e| CollabError::Internal(anyhow!("Failed to extract file: {:?}", e)))?; } } diff --git a/collab-importer/src/zip_tool/util.rs b/collab/src/importer/zip_tool/util.rs similarity index 100% rename from collab-importer/src/zip_tool/util.rs rename to collab/src/importer/zip_tool/util.rs diff --git a/collab/src/lib.rs b/collab/src/lib.rs index 60b764c79..46e649bf4 100644 --- a/collab/src/lib.rs +++ b/collab/src/lib.rs @@ -1,24 +1,15 @@ -#[macro_export] -macro_rules! if_native { - ($($item:item)*) => {$( - #[cfg(not(target_arch = "wasm32"))] - $item - )*} -} - -#[macro_export] -macro_rules! if_wasm { - ($($item:item)*) => {$( - #[cfg(target_arch = "wasm32")] - $item - )*} -} - mod any_mut; pub mod core; +pub mod database; +pub mod document; pub mod entity; pub mod error; +pub mod folder; +pub mod importer; pub mod lock; +#[cfg(feature = "plugins")] +pub mod plugins; +pub mod user; pub mod util; pub mod preclude { @@ -35,7 +26,7 @@ pub mod preclude { pub use crate::any_mut::AnyMut; pub use crate::core::collab::Collab; pub use crate::core::collab_plugin::CollabPlugin; - pub use crate::core::fill::{FillError, FillRef}; + pub use crate::core::fill::FillRef; pub use crate::core::user_data::PermanentUserData; pub use crate::util::MapExt; pub use crate::util::deserialize_i32_from_numeric; diff --git a/collab/src/lock/lock_timeout.rs b/collab/src/lock/lock_timeout.rs index d3356095d..9c58badb2 100644 --- a/collab/src/lock/lock_timeout.rs +++ b/collab/src/lock/lock_timeout.rs @@ -1,6 +1,8 @@ use std::ops::Deref; use std::time::Duration; +use crate::error::CollabError; + pub const DEFAULT_RWLOCK_TIMEOUT: Duration = Duration::from_secs(15); #[derive(Debug)] @@ -39,17 +41,17 @@ impl RwLock { } } - pub async fn read_err(&self) -> Result, RwLockError> { + pub async fn read_err(&self) -> Result, CollabError> { match tokio::time::timeout(DEFAULT_RWLOCK_TIMEOUT, self.inner.read()).await { Ok(guard) => Ok(guard), - Err(_) => Err(RwLockError::ReadTimeout(DEFAULT_RWLOCK_TIMEOUT)), + Err(_) => Err(CollabError::RwLockReadTimeout(DEFAULT_RWLOCK_TIMEOUT)), } } - pub async fn write_err(&self) -> Result, RwLockError> { + pub async fn write_err(&self) -> Result, CollabError> { match tokio::time::timeout(DEFAULT_RWLOCK_TIMEOUT, self.inner.write()).await { Ok(guard) => Ok(guard), - Err(_) => Err(RwLockError::WriteTimeout(DEFAULT_RWLOCK_TIMEOUT)), + Err(_) => Err(CollabError::RwLockWriteTimeout(DEFAULT_RWLOCK_TIMEOUT)), } } } @@ -75,14 +77,6 @@ impl Default for RwLock { } } -#[derive(Debug, thiserror::Error)] -pub enum RwLockError { - #[error("Read lock timeout: {0:?}")] - ReadTimeout(Duration), - #[error("Write lock timeout: {0:?}")] - WriteTimeout(Duration), -} - #[derive(Debug)] pub struct Mutex { inner: tokio::sync::Mutex, @@ -108,10 +102,10 @@ impl Mutex { } } - pub async fn lock_err(&self) -> Result, MutexError> { + pub async fn lock_err(&self) -> Result, CollabError> { match tokio::time::timeout(DEFAULT_RWLOCK_TIMEOUT, self.inner.lock()).await { Ok(guard) => Ok(guard), - Err(_) => Err(MutexError::LockTimeout(DEFAULT_RWLOCK_TIMEOUT)), + Err(_) => Err(CollabError::MutexLockTimeout(DEFAULT_RWLOCK_TIMEOUT)), } } } @@ -137,12 +131,6 @@ impl Default for Mutex { } } -#[derive(Debug, thiserror::Error)] -pub enum MutexError { - #[error("Lock timeout: {0:?}")] - LockTimeout(Duration), -} - #[cfg(test)] mod test { use crate::lock::RwLock; diff --git a/collab-plugins/src/connect_state.rs b/collab/src/plugins/connect_state.rs similarity index 100% rename from collab-plugins/src/connect_state.rs rename to collab/src/plugins/connect_state.rs diff --git a/collab-plugins/src/local_storage/kv/db.rs b/collab/src/plugins/local_storage/kv/db.rs similarity index 83% rename from collab-plugins/src/local_storage/kv/db.rs rename to collab/src/plugins/local_storage/kv/db.rs index 6f4b58376..08abc24d7 100644 --- a/collab-plugins/src/local_storage/kv/db.rs +++ b/collab/src/plugins/local_storage/kv/db.rs @@ -3,10 +3,10 @@ use std::io::Write; use std::ops::RangeBounds; use std::sync::Arc; -use crate::local_storage::kv::PersistenceError; -use crate::local_storage::kv::keys::*; -use crate::local_storage::kv::oid::{DocIDGen, OID}; -use crate::local_storage::kv::snapshot::CollabSnapshot; +use crate::error::CollabError; +use crate::plugins::local_storage::kv::keys::*; +use crate::plugins::local_storage::kv::oid::{DocIDGen, OID}; +use crate::plugins::local_storage::kv::snapshot::CollabSnapshot; use smallvec::SmallVec; use yrs::{TransactionMut, Update}; @@ -23,19 +23,19 @@ pub trait KVTransactionDB: Send + Sync + 'static { fn with_write_txn<'a, 'b, Output>( &'b self, - f: impl FnOnce(&Self::TransactionAction<'a>) -> Result, - ) -> Result + f: impl FnOnce(&Self::TransactionAction<'a>) -> Result, + ) -> Result where 'b: 'a; - fn flush(&self) -> Result<(), PersistenceError>; + fn flush(&self) -> Result<(), CollabError>; } pub trait KVStore<'a> { type Range: Iterator; type Entry: KVEntry; type Value: AsRef<[u8]>; - type Error: Into + Debug; + type Error: Into + Debug; /// Get a value by key fn get>(&self, key: K) -> Result, Self::Error>; @@ -96,11 +96,11 @@ pub fn insert_snapshot_update<'a, K, S>( snapshot_id: SnapshotID, object_id: &K, data: Vec, -) -> Result<(), PersistenceError> +) -> Result<(), CollabError> where K: AsRef<[u8]> + ?Sized + Debug, S: KVStore<'a>, - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { let snapshot = CollabSnapshot::new(data).to_vec(); let update_key = create_update_key(snapshot_id, store, object_id, make_snapshot_update_key)?; @@ -113,17 +113,17 @@ pub fn insert_doc_update<'a, K, S>( doc_id: DocID, object_id: &K, value: Vec, -) -> Result, PersistenceError> +) -> Result, CollabError> where K: AsRef<[u8]> + ?Sized + Debug, S: KVStore<'a>, - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { let update_key = create_update_key(doc_id, db, object_id, make_doc_update_key)?; if let Ok(Some(_)) = db.get(update_key.as_ref()) { // The duplicate key might corrupt the document data when restoring from the disk, // So we return an error here. - return Err(PersistenceError::DuplicateUpdateKey); + return Err(CollabError::PersistenceDuplicateUpdateKey); } db.insert(update_key.as_ref(), value)?; Ok(update_key.to_vec()) @@ -133,11 +133,11 @@ pub fn get_last_update_key<'a, S, F>( store: &S, id: OID, make_update_key: F, -) -> Result, PersistenceError> +) -> Result, CollabError> where F: Fn(OID, Clock) -> Key<16>, S: KVStore<'a>, - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { let last_clock = get_last_update_clock(store, id, &make_update_key)?; Ok(make_update_key(id, last_clock)) @@ -148,12 +148,12 @@ fn create_update_key<'a, F, K, S>( store: &S, _object_id: &K, make_update_key: F, -) -> Result, PersistenceError> +) -> Result, CollabError> where F: Fn(OID, Clock) -> Key<16>, K: AsRef<[u8]> + ?Sized + Debug, S: KVStore<'a>, - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { let last_clock = get_last_update_clock(store, id, &make_update_key)?; let clock = last_clock + 1; @@ -166,11 +166,11 @@ fn get_last_update_clock<'a, S, F>( store: &S, id: OID, make_update_key: &F, -) -> Result +) -> Result where F: Fn(OID, Clock) -> Key<16>, S: KVStore<'a>, - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { let max_key = make_update_key(id, Clock::MAX); if let Ok(Some(entry)) = store.next_back_entry(max_key.as_ref()) { @@ -191,10 +191,10 @@ where Some(OID::from_be_bytes(bytes)) } -pub fn insert_doc_id_for_key<'a, S>(store: &S, key: Key<20>) -> Result +pub fn insert_doc_id_for_key<'a, S>(store: &S, key: Key<20>) -> Result where S: KVStore<'a>, - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { let new_id = DocIDGen::next_id(); store.insert(key.as_ref(), new_id.to_be_bytes())?; @@ -211,11 +211,11 @@ pub fn make_update_key_prefix(prefix: &[u8], oid: OID) -> Key<12> { pub trait TransactionMutExt<'doc> { /// Applies an update to the document. If the update is invalid, it will return an error. /// It allows to catch panics from `apply_update`. - fn try_apply_update(&mut self, update: Update) -> Result<(), PersistenceError>; + fn try_apply_update(&mut self, update: Update) -> Result<(), CollabError>; } impl<'doc> TransactionMutExt<'doc> for TransactionMut<'doc> { - fn try_apply_update(&mut self, update: Update) -> Result<(), PersistenceError> { + fn try_apply_update(&mut self, update: Update) -> Result<(), CollabError> { self.apply_update(update)?; Ok(()) } @@ -225,7 +225,7 @@ impl<'doc> TransactionMutExt<'doc> for TransactionMut<'doc> { pub trait KVRange<'a> { type Range: Iterator; type Entry: KVEntry; - type Error: Into; + type Error: Into; fn kv_range(self) -> Result; } diff --git a/collab-plugins/src/local_storage/kv/doc.rs b/collab/src/plugins/local_storage/kv/doc.rs similarity index 90% rename from collab-plugins/src/local_storage/kv/doc.rs rename to collab/src/plugins/local_storage/kv/doc.rs index 008ba4929..f810d4a0d 100644 --- a/collab-plugins/src/local_storage/kv/doc.rs +++ b/collab/src/plugins/local_storage/kv/doc.rs @@ -1,6 +1,7 @@ -use crate::local_storage::kv::keys::*; -use crate::local_storage::kv::snapshot::SnapshotAction; -use crate::local_storage::kv::*; +use crate::error::CollabError; +use crate::plugins::local_storage::kv::keys::*; +use crate::plugins::local_storage::kv::snapshot::SnapshotAction; +use crate::plugins::local_storage::kv::*; use smallvec::{SmallVec, smallvec}; use std::collections::HashSet; use tracing::error; @@ -11,7 +12,7 @@ use yrs::{Doc, ReadTxn, StateVector, Transact, TransactionMut, Update}; pub trait CollabKVAction<'a>: KVStore<'a> + Sized + 'a where - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { /// Create a new document with the given object id. fn create_new_doc( @@ -20,10 +21,10 @@ where workspace_id: &str, object_id: &str, txn: &T, - ) -> Result<(), PersistenceError> { + ) -> Result<(), CollabError> { if self.is_exist(uid, workspace_id, object_id) { tracing::warn!("🟡{:?} already exist", object_id); - return Err(PersistenceError::DocumentAlreadyExist); + return Err(CollabError::PersistenceDocumentAlreadyExist); } let doc_id = get_or_create_did(uid, self, workspace_id, object_id)?; let doc_state = txn.encode_diff_v1(&StateVector::default()); @@ -44,7 +45,7 @@ where object_id: &str, state_vector: Vec, doc_state: Vec, - ) -> Result<(), PersistenceError> { + ) -> Result<(), CollabError> { let doc_id = get_or_create_did(uid, self, workspace_id, object_id)?; let start = make_doc_start_key(doc_id); let end = make_doc_end_key(doc_id); @@ -73,7 +74,7 @@ where object_id: &str, state_vector: Vec, doc_state: Vec, - ) -> Result<(), PersistenceError> { + ) -> Result<(), CollabError> { let doc_id = get_or_create_did(uid, self, workspace_id, object_id)?; // Remove the updates @@ -105,7 +106,7 @@ where workspace_id: &str, object_id: &str, txn: &mut TransactionMut, - ) -> Result { + ) -> Result { let mut update_count = 0; if let Some(doc_id) = get_doc_id(uid, self, workspace_id, object_id) { @@ -119,7 +120,7 @@ where }, Err(err) => { error!("🔴{:?} decode doc state error: {}", object_id, err); - return Err(PersistenceError::Yrs(err)); + return Err(CollabError::DecodeUpdate(err)); }, } @@ -133,7 +134,7 @@ where // Decode the update and apply it to the transaction. If the update is invalid, we will // remove the update and the following updates. if let Err(e) = Update::decode_v1(encoded_update.value()) - .map_err(PersistenceError::Yrs) + .map_err(CollabError::DecodeUpdate) .and_then(|update| { // trace!("apply update: {:#?}", update); txn.try_apply_update(update) @@ -156,7 +157,7 @@ where Ok(update_count) } else { tracing::trace!("[Client] => {:?} not exist", object_id); - Err(PersistenceError::RecordNotFound(format!( + Err(CollabError::PersistenceRecordNotFound(format!( "doc with given object id: {:?} is not found", object_id ))) @@ -169,7 +170,7 @@ where workspace_id: &str, object_id: &str, doc: &Doc, - ) -> Result { + ) -> Result { let mut txn = doc.transact_mut(); self.load_doc_with_txn(uid, workspace_id, object_id, &mut txn) } @@ -181,7 +182,7 @@ where workspace_id: &str, object_id: &str, update: &[u8], - ) -> Result, PersistenceError> { + ) -> Result, CollabError> { match get_doc_id(uid, self, workspace_id, object_id) { None => { tracing::error!( @@ -189,7 +190,7 @@ where uid, object_id ); - Err(PersistenceError::RecordNotFound(format!( + Err(CollabError::PersistenceRecordNotFound(format!( "doc with given object id: {:?} is not found", object_id ))) @@ -205,7 +206,7 @@ where workspace_id: &str, object_id: &str, end: &[u8], - ) -> Result<(), PersistenceError> { + ) -> Result<(), CollabError> { if let Some(doc_id) = get_doc_id(uid, self, workspace_id, object_id) { let start = make_doc_update_key(doc_id, 0); self.remove_range(start.as_ref(), end.as_ref())?; @@ -218,7 +219,7 @@ where uid: i64, workspace_id: &str, object_id: &str, - ) -> Result<(), PersistenceError> { + ) -> Result<(), CollabError> { if let Some(doc_id) = get_doc_id(uid, self, workspace_id, object_id) { let start = make_doc_update_key(doc_id, 0); let end = make_doc_update_key(doc_id, Clock::MAX); @@ -234,7 +235,7 @@ where object_id: &str, doc_state: &[u8], sv: &[u8], - ) -> Result<(), PersistenceError> { + ) -> Result<(), CollabError> { let doc_id = get_or_create_did(uid, self, workspace_id, object_id)?; let start = make_doc_start_key(doc_id); let end = make_doc_end_key(doc_id); @@ -254,7 +255,7 @@ where uid: i64, workspace_id: &str, object_id: &str, - ) -> Result>, PersistenceError> { + ) -> Result>, CollabError> { if let Some(doc_id) = get_doc_id(uid, self, workspace_id, object_id) { let start = make_doc_update_key(doc_id, 0); let end = make_doc_update_key(doc_id, Clock::MAX); @@ -271,12 +272,7 @@ where /// Delete the document from the persistence /// This will remove all the updates and the document state - fn delete_doc( - &self, - uid: i64, - workspace_id: &str, - object_id: &str, - ) -> Result<(), PersistenceError> { + fn delete_doc(&self, uid: i64, workspace_id: &str, object_id: &str) -> Result<(), CollabError> { if let Some(did) = get_doc_id(uid, self, workspace_id, object_id) { tracing::trace!("[Client {}] => [{}] delete {:?} doc", uid, did, object_id); let key = make_doc_id_key_v1( @@ -305,8 +301,7 @@ where fn get_all_docs( &self, - ) -> Result>::Range, >::Entry>, PersistenceError> - { + ) -> Result>::Range, >::Entry>, CollabError> { let from = Key::from_const([DOC_SPACE, DOC_SPACE_OBJECT]); let to = Key::from_const([DOC_SPACE, DOC_SPACE_OBJECT_KEY]); let iter = self.range(from.as_ref()..to.as_ref())?; @@ -317,7 +312,7 @@ where &self, uid: i64, workspace_id: &str, - ) -> Result, PersistenceError> { + ) -> Result, CollabError> { let uid_bytes = uid.to_be_bytes(); let workspace_bytes = workspace_id.as_bytes(); @@ -339,7 +334,7 @@ where })) } - fn get_all_workspace_ids(&self) -> Result, PersistenceError> { + fn get_all_workspace_ids(&self) -> Result, CollabError> { let from = Key::from_const([DOC_SPACE, DOC_SPACE_OBJECT]); let to = Key::from_const([DOC_SPACE, DOC_SPACE_OBJECT_KEY]); let iter = self.range(from.as_ref()..to.as_ref())?; @@ -362,7 +357,7 @@ where uid: i64, workspace_id: &str, object_id: &str, - ) -> Result, PersistenceError> { + ) -> Result, CollabError> { if let Some(doc_id) = get_doc_id(uid, self, workspace_id, object_id) { let start = make_doc_update_key(doc_id, 0); let end = make_doc_update_key(doc_id, Clock::MAX); @@ -375,7 +370,7 @@ where } Ok(updates) } else { - Err(PersistenceError::RecordNotFound(format!( + Err(CollabError::PersistenceRecordNotFound(format!( "The document with given object id: {:?} is not found", object_id, ))) @@ -410,7 +405,7 @@ where impl<'a, T> CollabKVAction<'a> for T where T: KVStore<'a> + 'a, - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { } @@ -420,10 +415,10 @@ fn get_or_create_did<'a, S>( store: &S, workspace_id: &str, object_id: &str, -) -> Result +) -> Result where S: KVStore<'a>, - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { if let Some(did) = get_doc_id(uid, store, workspace_id, object_id) { Ok(did) @@ -490,10 +485,10 @@ fn extract_uuid_from_key(key: &[u8]) -> Option<[u8; 16]> { } } -pub fn migrate_old_keys<'a, S>(store: &'a S, workspace_id: &str) -> Result<(), PersistenceError> +pub fn migrate_old_keys<'a, S>(store: &'a S, workspace_id: &str) -> Result<(), CollabError> where S: KVStore<'a>, - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { let from = Key::from_const([DOC_SPACE, DOC_SPACE_OBJECT]); let to = Key::from_const([DOC_SPACE, DOC_SPACE_OBJECT_KEY]); diff --git a/collab-plugins/src/local_storage/kv/keys.rs b/collab/src/plugins/local_storage/kv/keys.rs similarity index 100% rename from collab-plugins/src/local_storage/kv/keys.rs rename to collab/src/plugins/local_storage/kv/keys.rs diff --git a/collab-plugins/src/local_storage/kv/mod.rs b/collab/src/plugins/local_storage/kv/mod.rs similarity index 77% rename from collab-plugins/src/local_storage/kv/mod.rs rename to collab/src/plugins/local_storage/kv/mod.rs index a4aecf66b..8ef9c82eb 100644 --- a/collab-plugins/src/local_storage/kv/mod.rs +++ b/collab/src/plugins/local_storage/kv/mod.rs @@ -1,10 +1,8 @@ pub use db::*; -pub use error::*; pub use range::*; mod db; pub mod doc; -pub mod error; pub mod keys; pub mod oid; mod range; diff --git a/collab-plugins/src/local_storage/kv/oid.rs b/collab/src/plugins/local_storage/kv/oid.rs similarity index 92% rename from collab-plugins/src/local_storage/kv/oid.rs rename to collab/src/plugins/local_storage/kv/oid.rs index 6888fe8b8..c0e1d44bd 100644 --- a/collab-plugins/src/local_storage/kv/oid.rs +++ b/collab/src/plugins/local_storage/kv/oid.rs @@ -4,8 +4,6 @@ use lazy_static::lazy_static; use std::cmp; use std::sync::{Arc, atomic}; -use crate::{if_native, if_wasm}; - // scope system time since epoch node id sequence number // |<-2->| <-----------------41--------------->| <--8--> |<----12---->| // 101010100000011010101111101100101000 @@ -93,25 +91,18 @@ impl DocIDGen { } } - if_wasm! { - fn timestamp() -> u64 { - js_sys::Date::now() as u64 - Self::EPOCH - } - } - - if_native! { - fn timestamp() -> u64 { - std::time::SystemTime::now() + fn timestamp() -> u64 { + std::time::SystemTime::now() .duration_since(std::time::SystemTime::UNIX_EPOCH) .expect("Clock moved backwards!") - .as_millis() as u64 - Self::EPOCH - } + .as_millis() as u64 + - Self::EPOCH } } #[cfg(test)] mod tests { - use crate::local_storage::kv::oid::DocIDGen; + use crate::plugins::local_storage::kv::oid::DocIDGen; use std::collections::HashMap; use std::sync::{Arc, RwLock}; use std::thread; diff --git a/collab-plugins/src/local_storage/kv/range.rs b/collab/src/plugins/local_storage/kv/range.rs similarity index 100% rename from collab-plugins/src/local_storage/kv/range.rs rename to collab/src/plugins/local_storage/kv/range.rs diff --git a/collab-plugins/src/local_storage/kv/snapshot.rs b/collab/src/plugins/local_storage/kv/snapshot.rs similarity index 91% rename from collab-plugins/src/local_storage/kv/snapshot.rs rename to collab/src/plugins/local_storage/kv/snapshot.rs index cc0055a3d..d99c38aaa 100644 --- a/collab-plugins/src/local_storage/kv/snapshot.rs +++ b/collab/src/plugins/local_storage/kv/snapshot.rs @@ -2,9 +2,10 @@ use std::fmt::Debug; use std::panic; use std::panic::AssertUnwindSafe; -use crate::local_storage::kv::keys::*; -use crate::local_storage::kv::*; -use collab_entity::CollabType; +use crate::entity::CollabType; +use crate::error::CollabError; +use crate::plugins::local_storage::kv::keys::*; +use crate::plugins::local_storage::kv::*; use serde::{Deserialize, Serialize}; use yrs::updates::encoder::{Encoder, EncoderV1}; use yrs::{ReadTxn, Snapshot}; @@ -12,13 +13,13 @@ use yrs::{ReadTxn, Snapshot}; impl<'a, T> SnapshotAction<'a> for T where T: KVStore<'a>, - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { } pub trait SnapshotAction<'a>: KVStore<'a> + Sized where - PersistenceError: From<>::Error>, + CollabError: From<>::Error>, { /// Create a snapshot for the given object id. /// The snapshot contains the updates prior to the given update_key. For example, @@ -30,7 +31,7 @@ where object_id: &K, txn: &T, snapshot: Snapshot, - ) -> Result<(), PersistenceError> + ) -> Result<(), CollabError> where K: AsRef<[u8]> + ?Sized + Debug, T: ReadTxn, @@ -61,7 +62,7 @@ where uid: i64, object_id: &K, snapshot_data: Vec, - ) -> Result<(), PersistenceError> + ) -> Result<(), CollabError> where K: AsRef<[u8]> + ?Sized + Debug, { @@ -124,7 +125,7 @@ where &self, uid: i64, object_id: &K, - ) -> Result<(), PersistenceError> { + ) -> Result<(), CollabError> { if let Some(snapshot_id) = get_snapshot_id(uid, self, object_id) { let start = make_snapshot_update_key(snapshot_id, 0); let end = make_snapshot_update_key(snapshot_id, Clock::MAX); @@ -138,7 +139,7 @@ where &self, uid: i64, object_id: &K, - ) -> Result { + ) -> Result { if let Some(snapshot_id) = get_snapshot_id(uid, self, object_id.as_ref()) { Ok(snapshot_id) } else { @@ -165,7 +166,7 @@ where pub fn try_encode_snapshot( txn: &T, snapshot: Snapshot, -) -> Result, PersistenceError> { +) -> Result, CollabError> { let mut encoded_data = vec![]; let result = { let mut wrapper = AssertUnwindSafe(&mut encoded_data); @@ -180,7 +181,7 @@ pub fn try_encode_snapshot( }; match result { Ok(_) => Ok(encoded_data), - Err(e) => Err(PersistenceError::InvalidData(format!("{:?}", e))), + Err(e) => Err(CollabError::PersistenceInvalidData(format!("{:?}", e))), } } @@ -191,7 +192,7 @@ pub trait SnapshotPersistence: Send + Sync { object_id: &str, collab_type: &CollabType, encoded_v1: Vec, - ) -> Result<(), PersistenceError>; + ) -> Result<(), CollabError>; } #[derive(Serialize, Deserialize)] @@ -212,7 +213,7 @@ impl CollabSnapshot { } impl TryFrom<&[u8]> for CollabSnapshot { - type Error = PersistenceError; + type Error = CollabError; fn try_from(value: &[u8]) -> Result { Ok(bincode::deserialize(value)?) diff --git a/collab/src/plugins/local_storage/mod.rs b/collab/src/plugins/local_storage/mod.rs new file mode 100644 index 000000000..b2be08028 --- /dev/null +++ b/collab/src/plugins/local_storage/mod.rs @@ -0,0 +1,6 @@ +pub mod kv; +pub mod rocksdb; + +mod storage_config; + +pub use storage_config::*; diff --git a/collab-plugins/src/local_storage/rocksdb/kv_impl.rs b/collab/src/plugins/local_storage/rocksdb/kv_impl.rs similarity index 93% rename from collab-plugins/src/local_storage/rocksdb/kv_impl.rs rename to collab/src/plugins/local_storage/rocksdb/kv_impl.rs index f70ca8537..ee0cc223c 100644 --- a/collab-plugins/src/local_storage/rocksdb/kv_impl.rs +++ b/collab/src/plugins/local_storage/rocksdb/kv_impl.rs @@ -3,9 +3,9 @@ use std::ops::RangeBounds; use std::path::Path; use std::sync::Arc; -use crate::local_storage::kv::doc::CollabKVAction; - -use crate::local_storage::kv::{KVEntry, KVStore, KVTransactionDB, PersistenceError}; +use crate::error::CollabError; +use crate::plugins::local_storage::kv::doc::CollabKVAction; +use crate::plugins::local_storage::kv::{KVEntry, KVStore, KVTransactionDB}; use rocksdb::Direction::Forward; use rocksdb::{ DBIteratorWithThreadMode, Direction, ErrorKind, IteratorMode, Options, ReadOptions, @@ -21,7 +21,7 @@ pub struct KVTransactionDBRocksdbImpl { impl KVTransactionDBRocksdbImpl { /// Open a new RocksDB database at the given path. /// If the database is corrupted, try to repair it. If it cannot be repaired, return an error. - pub fn open(path: impl AsRef) -> Result { + pub fn open(path: impl AsRef) -> Result { let auto_repair = false; let txn_db_opts = TransactionDBOptions::default(); let mut db_opts = Options::default(); @@ -89,19 +89,19 @@ impl KVTransactionDBRocksdbImpl { // If the database is corrupted, try to repair it // tracing::info!("Trying to repair collab database"); TransactionDB::::repair(&db_opts, &path).map_err(|err| { - PersistenceError::RocksdbRepairFail(format!( + CollabError::PersistenceRocksdbRepairFail(format!( "Failed to repair collab database: {:?}", err )) })?; TransactionDB::::open(&db_opts, &txn_db_opts, &path).map_err(|err| { - PersistenceError::RocksdbRepairFail(format!( + CollabError::PersistenceRocksdbRepairFail(format!( "Failed to repair collab database: {:?}", err )) }) } else { - Err(PersistenceError::RocksdbCorruption(e.to_string())) + Err(CollabError::PersistenceRocksdbCorruption(e.to_string())) } }, _ => Err(e.into()), @@ -117,7 +117,7 @@ impl KVTransactionDBRocksdbImpl { uid: i64, workspace_id: &str, object_id: &str, - ) -> Result { + ) -> Result { let read_txn = self.read_txn(); Ok(read_txn.is_exist(uid, workspace_id, object_id)) } @@ -127,7 +127,7 @@ impl KVTransactionDBRocksdbImpl { uid: i64, workspace_id: &str, doc_id: &str, - ) -> Result<(), PersistenceError> { + ) -> Result<(), CollabError> { self.with_write_txn(|txn| txn.delete_doc(uid, workspace_id, doc_id))?; Ok(()) } @@ -165,8 +165,8 @@ impl KVTransactionDB for KVTransactionDBRocksdbImpl { fn with_write_txn<'a, 'b, Output>( &'b self, - f: impl FnOnce(&Self::TransactionAction<'a>) -> Result, - ) -> Result + f: impl FnOnce(&Self::TransactionAction<'a>) -> Result, + ) -> Result where 'b: 'a, { @@ -180,7 +180,7 @@ impl KVTransactionDB for KVTransactionDBRocksdbImpl { Ok(result) } - fn flush(&self) -> Result<(), PersistenceError> { + fn flush(&self) -> Result<(), CollabError> { Ok(()) } } @@ -196,7 +196,7 @@ impl<'a, DB: Send + Sync> RocksdbKVStoreImpl<'a, DB> { Self(txn) } - pub fn commit_transaction(self) -> Result<(), PersistenceError> { + pub fn commit_transaction(self) -> Result<(), CollabError> { self.0.commit()?; Ok(()) } @@ -206,7 +206,7 @@ impl<'a, DB: Send + Sync> KVStore<'a> for RocksdbKVStoreImpl<'a, DB> { type Range = RocksdbRange<'a, DB>; type Entry = RocksdbEntry; type Value = Vec; - type Error = PersistenceError; + type Error = CollabError; fn get>(&self, key: K) -> Result, Self::Error> { if let Some(value) = self.0.get(key)? { diff --git a/collab-plugins/src/local_storage/rocksdb/mod.rs b/collab/src/plugins/local_storage/rocksdb/mod.rs similarity index 100% rename from collab-plugins/src/local_storage/rocksdb/mod.rs rename to collab/src/plugins/local_storage/rocksdb/mod.rs diff --git a/collab-plugins/src/local_storage/rocksdb/rocksdb_plugin.rs b/collab/src/plugins/local_storage/rocksdb/rocksdb_plugin.rs similarity index 92% rename from collab-plugins/src/local_storage/rocksdb/rocksdb_plugin.rs rename to collab/src/plugins/local_storage/rocksdb/rocksdb_plugin.rs index bb0573f21..5c17e20b9 100644 --- a/collab-plugins/src/local_storage/rocksdb/rocksdb_plugin.rs +++ b/collab/src/plugins/local_storage/rocksdb/rocksdb_plugin.rs @@ -1,19 +1,18 @@ -use crate::CollabKVDB; -use crate::local_storage::CollabPersistenceConfig; -use crate::local_storage::kv::KVTransactionDB; -use crate::local_storage::kv::doc::CollabKVAction; +use crate::plugins::CollabKVDB; +use crate::plugins::local_storage::CollabPersistenceConfig; +use crate::plugins::local_storage::kv::KVTransactionDB; +use crate::plugins::local_storage::kv::doc::CollabKVAction; use std::ops::Deref; use std::sync::atomic::Ordering::SeqCst; use std::sync::atomic::{AtomicBool, AtomicU32}; use std::sync::{Arc, Weak}; -use collab::entity::EncodedCollab; -use collab::preclude::{Collab, CollabPlugin}; -use collab_entity::CollabType; +use crate::entity::{CollabType, EncodedCollab}; +use crate::preclude::{Collab, CollabPlugin}; use tracing::{error, info, warn}; -use collab::core::collab_plugin::CollabPluginType; +use crate::core::collab_plugin::CollabPluginType; use yrs::TransactionMut; pub trait RocksdbBackup: Send + Sync { diff --git a/collab-plugins/src/local_storage/rocksdb/snapshot_plugin.rs b/collab/src/plugins/local_storage/rocksdb/snapshot_plugin.rs similarity index 87% rename from collab-plugins/src/local_storage/rocksdb/snapshot_plugin.rs rename to collab/src/plugins/local_storage/rocksdb/snapshot_plugin.rs index 1b0e351d5..739abab5f 100644 --- a/collab-plugins/src/local_storage/rocksdb/snapshot_plugin.rs +++ b/collab/src/plugins/local_storage/rocksdb/snapshot_plugin.rs @@ -1,12 +1,13 @@ use std::sync::atomic::{AtomicU8, Ordering}; use std::sync::{Arc, Weak}; -use crate::local_storage::kv::doc::CollabKVAction; -use crate::local_storage::kv::snapshot::SnapshotPersistence; -use crate::local_storage::kv::{KVTransactionDB, PersistenceError}; -use crate::CollabKVDB; -use collab::preclude::Collab; -use collab_entity::CollabType; +use crate::error::CollabError; +use crate::plugins::local_storage::kv::doc::CollabKVAction; +use crate::plugins::local_storage::kv::snapshot::SnapshotPersistence; +use crate::plugins::local_storage::kv::KVTransactionDB; +use crate::plugins::CollabKVDB; +use crate::preclude::Collab; +use crate::entity::CollabType; use yrs::{ReadTxn, StateVector}; @@ -99,8 +100,8 @@ impl CollabSnapshot { object_id: String, collab_type: CollabType, state: Arc, - ) -> Result<(), PersistenceError> { - let result: Result<(), PersistenceError> = tokio::task::spawn_blocking(move || { + ) -> Result<(), CollabError> { + let result: Result<(), CollabError> = tokio::task::spawn_blocking(move || { let mut collab = Collab::new(uid, object_id.clone(), "1", vec![], false); db.read_txn() .load_doc_with_txn(uid, &object_id, &mut collab.transact_mut())?; diff --git a/collab-plugins/src/local_storage/rocksdb/util.rs b/collab/src/plugins/local_storage/rocksdb/util.rs similarity index 82% rename from collab-plugins/src/local_storage/rocksdb/util.rs rename to collab/src/plugins/local_storage/rocksdb/util.rs index a887eb557..4f8cdf9b3 100644 --- a/collab-plugins/src/local_storage/rocksdb/util.rs +++ b/collab/src/plugins/local_storage/rocksdb/util.rs @@ -1,11 +1,11 @@ -use crate::CollabKVDB; -use crate::local_storage::kv::KVTransactionDB; -use crate::local_storage::kv::doc::CollabKVAction; +use crate::core::collab::DataSource; +use crate::core::collab_plugin::CollabPersistence; +use crate::error::CollabError; +use crate::plugins::CollabKVDB; +use crate::plugins::local_storage::kv::KVTransactionDB; +use crate::plugins::local_storage::kv::doc::CollabKVAction; +use crate::preclude::Collab; use anyhow::anyhow; -use collab::core::collab::DataSource; -use collab::core::collab_plugin::CollabPersistence; -use collab::error::CollabError; -use collab::preclude::Collab; use std::sync::Weak; use tracing::error; diff --git a/collab-plugins/src/local_storage/storage_config.rs b/collab/src/plugins/local_storage/storage_config.rs similarity index 100% rename from collab-plugins/src/local_storage/storage_config.rs rename to collab/src/plugins/local_storage/storage_config.rs diff --git a/collab/src/plugins/mod.rs b/collab/src/plugins/mod.rs new file mode 100644 index 000000000..2e26ea30b --- /dev/null +++ b/collab/src/plugins/mod.rs @@ -0,0 +1,6 @@ +pub mod local_storage; + +pub mod connect_state; + +#[cfg(feature = "plugins")] +pub type CollabKVDB = local_storage::rocksdb::kv_impl::KVTransactionDBRocksdbImpl; diff --git a/collab/src/user/mod.rs b/collab/src/user/mod.rs new file mode 100644 index 000000000..c4cbf1607 --- /dev/null +++ b/collab/src/user/mod.rs @@ -0,0 +1,7 @@ +mod reminder; +mod user_awareness; + +pub mod core { + pub use super::reminder::*; + pub use super::user_awareness::*; +} diff --git a/collab-user/src/reminder.rs b/collab/src/user/reminder.rs similarity index 98% rename from collab-user/src/reminder.rs rename to collab/src/user/reminder.rs index 3e1502b9f..a827d9700 100644 --- a/collab-user/src/reminder.rs +++ b/collab/src/user/reminder.rs @@ -1,14 +1,14 @@ use std::collections::HashMap; -use collab::preclude::encoding::serde::from_any; -use collab::preclude::{ - Any, Array, ArrayRef, Change, DeepObservable, Event, Map, MapPrelim, MapRef, Out, ReadTxn, - Subscription, ToJson, TransactionMut, YrsValue, -}; -use collab_entity::reminder::{ +use crate::entity::reminder::{ REMINDER_ID, REMINDER_IS_ACK, REMINDER_IS_READ, REMINDER_MESSAGE, REMINDER_META, REMINDER_OBJECT_ID, REMINDER_SCHEDULED_AT, REMINDER_TITLE, REMINDER_TY, Reminder, }; +use crate::preclude::encoding::serde::from_any; +use crate::preclude::{ + Any, Array, ArrayRef, Change, DeepObservable, Event, Map, MapPrelim, MapRef, Out, ReadTxn, + Subscription, ToJson, TransactionMut, YrsValue, +}; use tokio::sync::broadcast; pub type RemindersChangeSender = broadcast::Sender; diff --git a/collab-user/src/user_awareness.rs b/collab/src/user/user_awareness.rs similarity index 94% rename from collab-user/src/user_awareness.rs rename to collab/src/user/user_awareness.rs index e0d41c0e0..7370151b9 100644 --- a/collab-user/src/user_awareness.rs +++ b/collab/src/user/user_awareness.rs @@ -2,17 +2,16 @@ use std::borrow::{Borrow, BorrowMut}; use std::collections::HashMap; use std::ops::{Deref, DerefMut}; -use crate::core::ReminderUpdate; -use crate::reminder::{Reminders, RemindersChangeSender}; +use super::reminder::{Reminders, RemindersChangeSender}; +use crate::core::collab::CollabOptions; +use crate::core::origin::CollabOrigin; +use crate::entity::define::USER_AWARENESS; +use crate::entity::reminder::Reminder; +use crate::entity::{CollabType, EncodedCollab}; +use crate::preclude::block::ClientID; +use crate::preclude::{ArrayRef, Collab, Map, MapExt, MapRef}; +use crate::user::core::ReminderUpdate; use anyhow::{Error, Result}; -use collab::core::collab::CollabOptions; -use collab::core::origin::CollabOrigin; -use collab::entity::EncodedCollab; -use collab::preclude::block::ClientID; -use collab::preclude::{ArrayRef, Collab, Map, MapExt, MapRef}; -use collab_entity::CollabType; -use collab_entity::define::USER_AWARENESS; -use collab_entity::reminder::Reminder; use serde::{Deserialize, Serialize}; use uuid::Uuid; diff --git a/collab-database/tests/asset/selected-services-march-2024-quarter-csv.csv b/collab/tests/database/asset/selected-services-march-2024-quarter-csv.csv similarity index 100% rename from collab-database/tests/asset/selected-services-march-2024-quarter-csv.csv rename to collab/tests/database/asset/selected-services-march-2024-quarter-csv.csv diff --git a/collab-database/tests/assets/database_remapper/d5db7722-8919-4e9b-ac2d-8d054015dcb2.collab b/collab/tests/database/assets/database_remapper/d5db7722-8919-4e9b-ac2d-8d054015dcb2.collab similarity index 100% rename from collab-database/tests/assets/database_remapper/d5db7722-8919-4e9b-ac2d-8d054015dcb2.collab rename to collab/tests/database/assets/database_remapper/d5db7722-8919-4e9b-ac2d-8d054015dcb2.collab diff --git a/collab-database/tests/assets/database_remapper/database_row_1.collab b/collab/tests/database/assets/database_remapper/database_row_1.collab similarity index 100% rename from collab-database/tests/assets/database_remapper/database_row_1.collab rename to collab/tests/database/assets/database_remapper/database_row_1.collab diff --git a/collab-database/tests/assets/database_remapper/relation_map.json b/collab/tests/database/assets/database_remapper/relation_map.json similarity index 100% rename from collab-database/tests/assets/database_remapper/relation_map.json rename to collab/tests/database/assets/database_remapper/relation_map.json diff --git a/collab-database/tests/assets/row_meta/50dfa70a-d53c-4b7d-8b49-6194aadbac2a.json b/collab/tests/database/assets/row_meta/50dfa70a-d53c-4b7d-8b49-6194aadbac2a.json similarity index 100% rename from collab-database/tests/assets/row_meta/50dfa70a-d53c-4b7d-8b49-6194aadbac2a.json rename to collab/tests/database/assets/row_meta/50dfa70a-d53c-4b7d-8b49-6194aadbac2a.json diff --git a/collab-database/tests/database_test/block_test.rs b/collab/tests/database/database_test/block_test.rs similarity index 95% rename from collab-database/tests/database_test/block_test.rs rename to collab/tests/database/database_test/block_test.rs index 5f7fbb4c8..9fd80d634 100644 --- a/collab-database/tests/database_test/block_test.rs +++ b/collab/tests/database/database_test/block_test.rs @@ -1,4 +1,4 @@ -use collab_database::rows::CreateRowParams; +use collab::database::rows::CreateRowParams; use uuid::Uuid; use crate::database_test::helper::{TEST_VIEW_ID_V1, create_database}; diff --git a/collab-database/tests/database_test/cell_test.rs b/collab/tests/database/database_test/cell_test.rs similarity index 98% rename from collab-database/tests/database_test/cell_test.rs rename to collab/tests/database/database_test/cell_test.rs index c84296307..5ae2abc63 100644 --- a/collab-database/tests/database_test/cell_test.rs +++ b/collab/tests/database/database_test/cell_test.rs @@ -1,4 +1,4 @@ -use collab_database::rows::Cells; +use collab::database::rows::Cells; use crate::database_test::helper::{TEST_VIEW_ID_V1, create_database_with_default_data}; use crate::helper::{TestNumberCell, TestTextCell}; diff --git a/collab-database/tests/database_test/cell_type_option_test.rs b/collab/tests/database/database_test/cell_type_option_test.rs similarity index 100% rename from collab-database/tests/database_test/cell_type_option_test.rs rename to collab/tests/database/database_test/cell_type_option_test.rs diff --git a/collab-database/tests/database_test/encode_collab_test.rs b/collab/tests/database/database_test/encode_collab_test.rs similarity index 100% rename from collab-database/tests/database_test/encode_collab_test.rs rename to collab/tests/database/database_test/encode_collab_test.rs diff --git a/collab-database/tests/database_test/field_observe_test.rs b/collab/tests/database/database_test/field_observe_test.rs similarity index 97% rename from collab-database/tests/database_test/field_observe_test.rs rename to collab/tests/database/database_test/field_observe_test.rs index 241970f2d..16b035513 100644 --- a/collab-database/tests/database_test/field_observe_test.rs +++ b/collab/tests/database/database_test/field_observe_test.rs @@ -1,6 +1,6 @@ use crate::database_test::helper::{create_database_with_default_data, wait_for_specific_event}; use crate::helper::setup_log; -use collab_database::fields::FieldChange; +use collab::database::fields::FieldChange; use collab::lock::Mutex; use std::sync::Arc; diff --git a/collab-database/tests/database_test/field_setting_test.rs b/collab/tests/database/database_test/field_setting_test.rs similarity index 97% rename from collab-database/tests/database_test/field_setting_test.rs rename to collab/tests/database/database_test/field_setting_test.rs index d381a4fb6..11ac32aa8 100644 --- a/collab-database/tests/database_test/field_setting_test.rs +++ b/collab/tests/database/database_test/field_setting_test.rs @@ -3,9 +3,9 @@ use crate::database_test::helper::{ default_field_settings_by_layout, field_settings_for_default_database, }; use crate::helper::TestFieldSetting; -use collab_database::entity::CreateViewParams; -use collab_database::fields::Field; -use collab_database::views::{DatabaseLayout, OrderObjectPosition}; +use collab::database::entity::CreateViewParams; +use collab::database::fields::Field; +use collab::database::views::{DatabaseLayout, OrderObjectPosition}; use std::collections::HashMap; use uuid::Uuid; diff --git a/collab-database/tests/database_test/field_test.rs b/collab/tests/database/database_test/field_test.rs similarity index 98% rename from collab-database/tests/database_test/field_test.rs rename to collab/tests/database/database_test/field_test.rs index ca5faa5a7..a530f2ceb 100644 --- a/collab-database/tests/database_test/field_test.rs +++ b/collab/tests/database/database_test/field_test.rs @@ -2,8 +2,8 @@ use crate::database_test::helper::{ TEST_VIEW_ID_V1, TEST_VIEW_ID_V2, create_database, create_database_with_default_data, default_field_settings_by_layout, }; -use collab_database::entity::CreateViewParams; -use collab_database::{fields::Field, views::OrderObjectPosition}; +use collab::database::entity::CreateViewParams; +use collab::database::{fields::Field, views::OrderObjectPosition}; use uuid::Uuid; #[tokio::test] diff --git a/collab-database/tests/database_test/filter_test.rs b/collab/tests/database/database_test/filter_test.rs similarity index 100% rename from collab-database/tests/database_test/filter_test.rs rename to collab/tests/database/database_test/filter_test.rs diff --git a/collab-database/tests/database_test/group_test.rs b/collab/tests/database/database_test/group_test.rs similarity index 98% rename from collab-database/tests/database_test/group_test.rs rename to collab/tests/database/database_test/group_test.rs index 441d3b593..4b04e24fb 100644 --- a/collab-database/tests/database_test/group_test.rs +++ b/collab/tests/database/database_test/group_test.rs @@ -1,7 +1,7 @@ +use collab::database::entity::CreateViewParams; +use collab::database::views::{DatabaseLayout, GroupMap}; use collab::preclude::Any; use collab::util::{AnyExt, AnyMapExt}; -use collab_database::entity::CreateViewParams; -use collab_database::views::{DatabaseLayout, GroupMap}; use uuid::Uuid; use crate::database_test::helper::{ diff --git a/collab-database/tests/database_test/helper.rs b/collab/tests/database/database_test/helper.rs similarity index 97% rename from collab-database/tests/database_test/helper.rs rename to collab/tests/database/database_test/helper.rs index 9e769e914..1fdcdc80b 100644 --- a/collab-database/tests/database_test/helper.rs +++ b/collab/tests/database/database_test/helper.rs @@ -1,14 +1,14 @@ use collab::core::collab::{CollabOptions, default_client_id}; use collab::core::origin::CollabOrigin; -use collab::preclude::Collab; -use collab_database::database::{Database, DatabaseContext}; -use collab_database::fields::Field; -use collab_database::rows::{Cells, CreateRowParams, DatabaseRow, Row}; -use collab_database::views::{ +use collab::database::database::{Database, DatabaseContext}; +use collab::database::fields::Field; +use collab::database::rows::{Cells, CreateRowParams, DatabaseRow, Row}; +use collab::database::views::{ DatabaseLayout, FieldSettingsByFieldIdMap, FieldSettingsMap, LayoutSetting, LayoutSettings, OrderObjectPosition, }; -use collab_entity::uuid_validation::RowId; +use collab::entity::uuid_validation::RowId; +use collab::preclude::Collab; use futures::StreamExt; use std::collections::HashMap; use std::ops::{Deref, DerefMut}; @@ -18,9 +18,9 @@ use std::time::Duration; use crate::helper::{TestFieldSetting, TestTextCell, make_rocks_db, setup_log}; use crate::user_test::helper::TestUserDatabaseServiceImpl; -use collab_database::entity::{CreateDatabaseParams, CreateViewParams}; +use collab::database::entity::{CreateDatabaseParams, CreateViewParams}; -use collab_plugins::CollabKVDB; +use collab::plugins::CollabKVDB; use tempfile::TempDir; use tokio::time::timeout; use uuid::Uuid; diff --git a/collab-database/tests/database_test/layout_test.rs b/collab/tests/database/database_test/layout_test.rs similarity index 97% rename from collab-database/tests/database_test/layout_test.rs rename to collab/tests/database/database_test/layout_test.rs index 1ad7d4f93..3ad91dd6f 100644 --- a/collab-database/tests/database_test/layout_test.rs +++ b/collab/tests/database/database_test/layout_test.rs @@ -1,5 +1,5 @@ -use collab_database::fields::Field; -use collab_database::views::DatabaseLayout; +use collab::database::fields::Field; +use collab::database::views::DatabaseLayout; use crate::database_test::helper::{ DatabaseTest, DatabaseTestBuilder, TEST_VIEW_ID_V1, create_database_with_default_data, diff --git a/collab-database/tests/database_test/mod.rs b/collab/tests/database/database_test/mod.rs similarity index 100% rename from collab-database/tests/database_test/mod.rs rename to collab/tests/database/database_test/mod.rs diff --git a/collab-database/tests/database_test/restore_test.rs b/collab/tests/database/database_test/restore_test.rs similarity index 98% rename from collab-database/tests/database_test/restore_test.rs rename to collab/tests/database/database_test/restore_test.rs index c9524b231..db3b53e92 100644 --- a/collab-database/tests/database_test/restore_test.rs +++ b/collab/tests/database/database_test/restore_test.rs @@ -8,8 +8,8 @@ use collab::core::collab::{CollabOptions, default_client_id}; use collab::core::origin::CollabOrigin; use collab::entity::EncodedCollab; use collab::preclude::Collab; -use collab_database::rows::CreateRowParams; -use collab_plugins::CollabKVDB; +use collab::database::rows::CreateRowParams; +use collab::plugins::CollabKVDB; use serde_json::{Value, json}; use uuid::Uuid; @@ -107,7 +107,7 @@ async fn open_020_history_database_test() { let actual_1 = database_test.to_json_value().await.unwrap(); assert_json_include!(expected: expected_json(), actual: actual_1); - let bytes = std::fs::read("./tests/history_database/database_020_encode_collab").unwrap(); + let bytes = std::fs::read("./tests/database/history_database/database_020_encode_collab").unwrap(); let encode_collab = EncodedCollab::decode_from_bytes(&bytes).unwrap(); let options = CollabOptions::new( "c0e69740-49f0-4790-a488-702e2750ba8d".to_string(), diff --git a/collab-database/tests/database_test/row_observe_test.rs b/collab/tests/database/database_test/row_observe_test.rs similarity index 95% rename from collab-database/tests/database_test/row_observe_test.rs rename to collab/tests/database/database_test/row_observe_test.rs index 84b7fac30..ccca60e92 100644 --- a/collab-database/tests/database_test/row_observe_test.rs +++ b/collab/tests/database/database_test/row_observe_test.rs @@ -4,10 +4,10 @@ use std::time::Duration; use collab::lock::Mutex; use tokio::time::sleep; +use collab::database::database::gen_row_id; +use collab::database::rows::{Cell, CreateRowParams, RowChange, new_cell_builder}; +use collab::database::views::DatabaseViewChange; use collab::util::AnyMapExt; -use collab_database::database::gen_row_id; -use collab_database::rows::{Cell, CreateRowParams, RowChange, new_cell_builder}; -use collab_database::views::DatabaseViewChange; use uuid::Uuid; use crate::database_test::helper::{create_database, wait_for_specific_event}; diff --git a/collab-database/tests/database_test/row_test.rs b/collab/tests/database/database_test/row_test.rs similarity index 98% rename from collab-database/tests/database_test/row_test.rs rename to collab/tests/database/database_test/row_test.rs index 7022c50dd..2d31c58ce 100644 --- a/collab-database/tests/database_test/row_test.rs +++ b/collab/tests/database/database_test/row_test.rs @@ -2,12 +2,12 @@ use crate::database_test::helper::{ TEST_VIEW_ID_V1, TEST_VIEW_ID_V2, create_database, create_database_with_default_data, create_row, }; use collab::core::collab::default_client_id; -use collab_database::database::gen_row_id; -use collab_database::entity::{CreateViewParams, FileUploadType}; -use collab_database::rows::{ +use collab::database::database::gen_row_id; +use collab::database::entity::{CreateViewParams, FileUploadType}; +use collab::database::rows::{ CoverType, CreateRowParams, RowCover, RowMetaKey, meta_id_from_row_id, }; -use collab_database::views::OrderObjectPosition; +use collab::database::views::OrderObjectPosition; use uuid::Uuid; #[tokio::test] diff --git a/collab-database/tests/database_test/sort_test.rs b/collab/tests/database/database_test/sort_test.rs similarity index 97% rename from collab-database/tests/database_test/sort_test.rs rename to collab/tests/database/database_test/sort_test.rs index 9eb920c31..91462ecd2 100644 --- a/collab-database/tests/database_test/sort_test.rs +++ b/collab/tests/database/database_test/sort_test.rs @@ -2,8 +2,8 @@ use crate::database_test::helper::{ DatabaseTest, TEST_VIEW_ID_V1, create_database_with_default_data, }; use crate::helper::{SortCondition, TestSort}; -use collab_database::entity::CreateViewParams; -use collab_database::views::DatabaseLayout; +use collab::database::entity::CreateViewParams; +use collab::database::views::DatabaseLayout; #[tokio::test] async fn create_database_view_with_sort_test() { diff --git a/collab-database/tests/database_test/type_option_test.rs b/collab/tests/database/database_test/type_option_test.rs similarity index 97% rename from collab-database/tests/database_test/type_option_test.rs rename to collab/tests/database/database_test/type_option_test.rs index 8a8d9b293..f6f8fb286 100644 --- a/collab-database/tests/database_test/type_option_test.rs +++ b/collab/tests/database/database_test/type_option_test.rs @@ -2,9 +2,9 @@ use crate::database_test::helper::{ DatabaseTest, create_database, default_field_settings_by_layout, }; use crate::helper::{TestCheckboxTypeOption, TestDateFormat, TestDateTypeOption, TestTimeFormat}; +use collab::database::fields::{Field, TypeOptionDataBuilder, TypeOptions}; +use collab::database::views::OrderObjectPosition; use collab::util::AnyMapExt; -use collab_database::fields::{Field, TypeOptionDataBuilder, TypeOptions}; -use collab_database::views::OrderObjectPosition; use std::ops::DerefMut; use uuid::Uuid; diff --git a/collab-database/tests/database_test/view_observe_test.rs b/collab/tests/database/database_test/view_observe_test.rs similarity index 98% rename from collab-database/tests/database_test/view_observe_test.rs rename to collab/tests/database/database_test/view_observe_test.rs index 9919ca2a2..a89bc7956 100644 --- a/collab-database/tests/database_test/view_observe_test.rs +++ b/collab/tests/database/database_test/view_observe_test.rs @@ -1,15 +1,15 @@ use crate::database_test::helper::{TEST_VIEW_ID_V1, create_database, wait_for_specific_event}; use crate::helper::setup_log; -use collab_database::database::{DatabaseBody, gen_row_id}; +use collab::database::database::{DatabaseBody, gen_row_id}; use uuid::Uuid; -use collab::lock::Mutex; -use collab_database::database_trait::NoPersistenceDatabaseCollabService; -use collab_database::entity::CreateViewParams; -use collab_database::rows::CreateRowParams; -use collab_database::views::{ +use collab::database::database_trait::NoPersistenceDatabaseCollabService; +use collab::database::entity::CreateViewParams; +use collab::database::rows::CreateRowParams; +use collab::database::views::{ DatabaseLayout, DatabaseViewChange, FilterMapBuilder, GroupSettingBuilder, SortMapBuilder, }; +use collab::lock::Mutex; use std::sync::Arc; use std::time::Duration; use tokio::time::sleep; @@ -394,7 +394,7 @@ async fn observe_move_database_view_row_test() { let txn = collab.transact(); let second_view_uuid = - collab_entity::uuid_validation::try_parse_database_view_id(&second_view_id).unwrap(); + collab::entity::uuid_validation::try_parse_database_view_id(&second_view_id).unwrap(); let body_row_orders = db_body.views.get_row_orders(&txn, &second_view_uuid); assert_eq!(body_row_orders.len(), 4); assert_eq!(body_row_orders[0].id, row_id_1); diff --git a/collab-database/tests/database_test/view_test.rs b/collab/tests/database/database_test/view_test.rs similarity index 96% rename from collab-database/tests/database_test/view_test.rs rename to collab/tests/database/database_test/view_test.rs index d3feb54df..e68f0c753 100644 --- a/collab-database/tests/database_test/view_test.rs +++ b/collab/tests/database/database_test/view_test.rs @@ -4,13 +4,13 @@ use uuid::Uuid; use assert_json_diff::assert_json_eq; use collab::core::collab::{CollabOptions, default_client_id}; use collab::core::origin::CollabOrigin; +use collab::database::database::{DatabaseBody, DatabaseData, gen_row_id}; +use collab::database::entity::CreateViewParams; +use collab::database::fields::Field; +use collab::database::rows::{CreateRowParams, Row}; +use collab::database::views::{DatabaseLayout, LayoutSetting, OrderObjectPosition}; use collab::preclude::{Any, Collab}; use collab::util::AnyMapExt; -use collab_database::database::{DatabaseBody, DatabaseData, gen_row_id}; -use collab_database::entity::CreateViewParams; -use collab_database::fields::Field; -use collab_database::rows::{CreateRowParams, Row}; -use collab_database::views::{DatabaseLayout, LayoutSetting, OrderObjectPosition}; use futures::StreamExt; use nanoid::nanoid; @@ -99,7 +99,7 @@ async fn create_database_row_test() { database_test .create_row(CreateRowParams::new( row_id, - collab_entity::uuid_validation::try_parse_database_id(&database_id).unwrap(), + collab::entity::uuid_validation::try_parse_database_id(&database_id).unwrap(), )) .await .unwrap(); diff --git a/collab-database/tests/helper/mod.rs b/collab/tests/database/helper/mod.rs similarity index 100% rename from collab-database/tests/helper/mod.rs rename to collab/tests/database/helper/mod.rs diff --git a/collab-database/tests/helper/util.rs b/collab/tests/database/helper/util.rs similarity index 97% rename from collab-database/tests/helper/util.rs rename to collab/tests/database/helper/util.rs index 0aff1a975..43dfee91f 100644 --- a/collab-database/tests/helper/util.rs +++ b/collab/tests/database/helper/util.rs @@ -6,16 +6,16 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, Once}; use anyhow::bail; -use collab::preclude::encoding::serde::from_any; -use collab::preclude::{Any, any}; -use collab::util::AnyMapExt; -use collab_database::fields::{TypeOptionData, TypeOptionDataBuilder}; -use collab_database::rows::Cell; -use collab_database::views::{ +use collab::database::fields::{TypeOptionData, TypeOptionDataBuilder}; +use collab::database::rows::Cell; +use collab::database::views::{ FieldSettingsMap, FilterMap, FilterMapBuilder, GroupMap, GroupMapBuilder, GroupSettingBuilder, GroupSettingMap, LayoutSetting, SortMap, SortMapBuilder, }; -use collab_plugins::CollabKVDB; +use collab::plugins::CollabKVDB; +use collab::preclude::encoding::serde::from_any; +use collab::preclude::{Any, any}; +use collab::util::AnyMapExt; use nanoid::nanoid; use serde::Deserialize; use serde_repr::{Deserialize_repr, Serialize_repr}; @@ -566,9 +566,9 @@ pub fn setup_log() { pub fn unzip_history_database_db(folder_name: &str) -> std::io::Result<(Cleaner, PathBuf)> { // Open the zip file - let zip_file_path = format!("./tests/history_database/{}.zip", folder_name); + let zip_file_path = format!("./tests/database/history_database/{}.zip", folder_name); let reader = File::open(zip_file_path)?; - let output_folder_path = format!("./tests/history_document/unit_test_{}", nanoid!(6)); + let output_folder_path = format!("./tests/database/history_document/unit_test_{}", nanoid!(6)); // Create a ZipArchive from the file let mut archive = ZipArchive::new(reader)?; diff --git a/collab-database/tests/history_database/020_database.zip b/collab/tests/database/history_database/020_database.zip similarity index 100% rename from collab-database/tests/history_database/020_database.zip rename to collab/tests/database/history_database/020_database.zip diff --git a/collab-database/tests/history_database/database_020_encode_collab b/collab/tests/database/history_database/database_020_encode_collab similarity index 100% rename from collab-database/tests/history_database/database_020_encode_collab rename to collab/tests/database/history_database/database_020_encode_collab diff --git a/collab-database/tests/main.rs b/collab/tests/database/main.rs similarity index 76% rename from collab-database/tests/main.rs rename to collab/tests/database/main.rs index 750ac7f04..f85e02237 100644 --- a/collab-database/tests/main.rs +++ b/collab/tests/database/main.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "plugins")] + pub mod database_test; pub mod helper; pub mod remapper; diff --git a/collab-database/tests/remapper/database_remapper_test.rs b/collab/tests/database/remapper/database_remapper_test.rs similarity index 94% rename from collab-database/tests/remapper/database_remapper_test.rs rename to collab/tests/database/remapper/database_remapper_test.rs index 019e43832..5de637b7f 100644 --- a/collab-database/tests/remapper/database_remapper_test.rs +++ b/collab/tests/database/remapper/database_remapper_test.rs @@ -1,12 +1,13 @@ -use collab_database::database::DatabaseData; -use collab_database::database_remapper::DatabaseCollabRemapper; +use collab::database::database::DatabaseData; +use collab::database::database_remapper::DatabaseCollabRemapper; use std::collections::HashMap; use std::fs; use uuid::Uuid; #[tokio::test] async fn test_remap_database_with_database_id() { - let test_db_path = "tests/assets/database_remapper/d5db7722-8919-4e9b-ac2d-8d054015dcb2.collab"; + let test_db_path = + "tests/database/assets/database_remapper/d5db7722-8919-4e9b-ac2d-8d054015dcb2.collab"; let db_state = fs::read(test_db_path).expect("Failed to read test database file"); let mut id_mapping: HashMap = HashMap::new(); @@ -130,7 +131,7 @@ async fn test_remap_database_with_database_id() { #[tokio::test] async fn test_database_remapper_with_row_meta() { - let test_json_path = "tests/assets/row_meta/50dfa70a-d53c-4b7d-8b49-6194aadbac2a.json"; + let test_json_path = "tests/database/assets/row_meta/50dfa70a-d53c-4b7d-8b49-6194aadbac2a.json"; let json_content = fs::read_to_string(test_json_path).unwrap(); let database_data = serde_json::from_str::(&json_content).unwrap(); diff --git a/collab-database/tests/remapper/mod.rs b/collab/tests/database/remapper/mod.rs similarity index 100% rename from collab-database/tests/remapper/mod.rs rename to collab/tests/database/remapper/mod.rs diff --git a/collab-database/tests/template_test/create_template_test.rs b/collab/tests/database/template_test/create_template_test.rs similarity index 93% rename from collab-database/tests/template_test/create_template_test.rs rename to collab/tests/database/template_test/create_template_test.rs index 77e3cca63..d3536a38f 100644 --- a/collab-database/tests/template_test/create_template_test.rs +++ b/collab/tests/database/template_test/create_template_test.rs @@ -1,11 +1,11 @@ use crate::helper::make_rocks_db; use crate::user_test::helper::TestUserDatabaseServiceImpl; use collab::core::collab::default_client_id; -use collab_database::database::{Database, gen_database_id, gen_database_view_id}; -use collab_database::entity::FieldType; -use collab_database::rows::Row; -use collab_database::template::builder::DatabaseTemplateBuilder; -use collab_database::template::entity::CELL_DATA; +use collab::database::database::{Database, gen_database_id, gen_database_view_id}; +use collab::database::entity::FieldType; +use collab::database::rows::Row; +use collab::database::template::builder::DatabaseTemplateBuilder; +use collab::database::template::entity::CELL_DATA; use futures::StreamExt; use std::sync::Arc; use uuid::Uuid; diff --git a/collab-database/tests/template_test/import_csv_test.rs b/collab/tests/database/template_test/import_csv_test.rs similarity index 92% rename from collab-database/tests/template_test/import_csv_test.rs rename to collab/tests/database/template_test/import_csv_test.rs index 8c5b47d43..2574d4ef2 100644 --- a/collab-database/tests/template_test/import_csv_test.rs +++ b/collab/tests/database/template_test/import_csv_test.rs @@ -1,10 +1,10 @@ use crate::helper::make_rocks_db; use crate::user_test::helper::TestUserDatabaseServiceImpl; use collab::core::collab::default_client_id; -use collab_database::database::Database; -use collab_database::rows::Row; -use collab_database::template::csv::CSVTemplate; -use collab_database::template::entity::CELL_DATA; +use collab::database::database::Database; +use collab::database::rows::Row; +use collab::database::template::csv::CSVTemplate; +use collab::database::template::entity::CELL_DATA; use futures::StreamExt; use std::sync::Arc; use uuid::Uuid; diff --git a/collab-database/tests/template_test/mod.rs b/collab/tests/database/template_test/mod.rs similarity index 100% rename from collab-database/tests/template_test/mod.rs rename to collab/tests/database/template_test/mod.rs diff --git a/collab-database/tests/user_test/async_test/flush_test.rs b/collab/tests/database/user_test/async_test/flush_test.rs similarity index 98% rename from collab-database/tests/user_test/async_test/flush_test.rs rename to collab/tests/database/user_test/async_test/flush_test.rs index f7a037bd6..89a652acf 100644 --- a/collab-database/tests/user_test/async_test/flush_test.rs +++ b/collab/tests/database/user_test/async_test/flush_test.rs @@ -1,4 +1,4 @@ -use collab_plugins::local_storage::CollabPersistenceConfig; +use collab::plugins::local_storage::CollabPersistenceConfig; use serde_json::{json, Value}; use crate::user_test::async_test::script::{create_database, database_test, DatabaseScript::*}; diff --git a/collab-database/tests/user_test/async_test/mod.rs b/collab/tests/database/user_test/async_test/mod.rs similarity index 100% rename from collab-database/tests/user_test/async_test/mod.rs rename to collab/tests/database/user_test/async_test/mod.rs diff --git a/collab-database/tests/user_test/async_test/row_test.rs b/collab/tests/database/user_test/async_test/row_test.rs similarity index 97% rename from collab-database/tests/user_test/async_test/row_test.rs rename to collab/tests/database/user_test/async_test/row_test.rs index 35814781d..a71090f22 100644 --- a/collab-database/tests/user_test/async_test/row_test.rs +++ b/collab/tests/database/user_test/async_test/row_test.rs @@ -1,9 +1,9 @@ -use collab_database::database::timestamp; -use collab_database::rows::CreateRowParams; -use collab_database::rows::RowId; +use collab::database::database::timestamp; +use collab::database::rows::CreateRowParams; +use collab::database::rows::RowId; use serde_json::{json, Value}; -use collab_plugins::local_storage::CollabPersistenceConfig; +use collab::plugins::local_storage::CollabPersistenceConfig; use futures::stream::FuturesUnordered; use futures::StreamExt; diff --git a/collab-database/tests/user_test/async_test/script.rs b/collab/tests/database/user_test/async_test/script.rs similarity index 93% rename from collab-database/tests/user_test/async_test/script.rs rename to collab/tests/database/user_test/async_test/script.rs index 5dfeea43c..d010fb206 100644 --- a/collab-database/tests/user_test/async_test/script.rs +++ b/collab/tests/database/user_test/async_test/script.rs @@ -2,16 +2,16 @@ use std::path::PathBuf; use std::sync::Arc; use assert_json_diff::assert_json_include; -use collab_database::fields::Field; -use collab_database::rows::CreateRowParams; -use collab_database::rows::{Cells, CellsBuilder, RowId}; -use collab_database::user::WorkspaceDatabase; -use collab_database::views::{CreateDatabaseParams, CreateViewParams}; -use collab_plugins::local_storage::kv::doc::CollabKVAction; +use collab::database::fields::Field; +use collab::database::rows::CreateRowParams; +use collab::database::rows::{Cells, CellsBuilder, RowId}; +use collab::database::user::WorkspaceDatabase; +use collab::database::views::{CreateDatabaseParams, CreateViewParams}; +use collab::plugins::local_storage::kv::doc::CollabKVAction; use crate::user_test::helper::TEST_VIEW_ID_V1; -use collab_plugins::local_storage::kv::KVTransactionDB; -use collab_plugins::local_storage::CollabPersistenceConfig; -use collab_plugins::CollabKVDB; +use collab::plugins::local_storage::kv::KVTransactionDB; +use collab::plugins::local_storage::CollabPersistenceConfig; +use collab::plugins::CollabKVDB; use serde_json::Value; use tempfile::TempDir; diff --git a/collab-database/tests/user_test/cell_test.rs b/collab/tests/database/user_test/cell_test.rs similarity index 94% rename from collab-database/tests/user_test/cell_test.rs rename to collab/tests/database/user_test/cell_test.rs index a4d472a28..565b2d2c4 100644 --- a/collab-database/tests/user_test/cell_test.rs +++ b/collab/tests/database/user_test/cell_test.rs @@ -1,8 +1,8 @@ use crate::database_test::helper::{DatabaseTest, create_database_with_params}; +use collab::database::entity::{CreateDatabaseParams, CreateViewParams}; +use collab::database::rows::{CREATED_AT, new_cell_builder}; +use collab::database::rows::{CreateRowParams, LAST_MODIFIED}; use collab::util::AnyMapExt; -use collab_database::entity::{CreateDatabaseParams, CreateViewParams}; -use collab_database::rows::{CREATED_AT, new_cell_builder}; -use collab_database::rows::{CreateRowParams, LAST_MODIFIED}; use uuid::Uuid; #[tokio::test] diff --git a/collab-database/tests/user_test/database_test.rs b/collab/tests/database/user_test/database_test.rs similarity index 93% rename from collab-database/tests/user_test/database_test.rs rename to collab/tests/database/user_test/database_test.rs index afa6a2af3..3dde14d3d 100644 --- a/collab-database/tests/user_test/database_test.rs +++ b/collab/tests/database/user_test/database_test.rs @@ -1,6 +1,6 @@ use crate::database_test::helper::{TEST_VIEW_ID_V1, TEST_VIEW_ID_V2, create_database_with_params}; -use collab_database::entity::{CreateDatabaseParams, CreateViewParams}; -use collab_database::rows::CreateRowParams; +use collab::database::entity::{CreateDatabaseParams, CreateViewParams}; +use collab::database::rows::CreateRowParams; use uuid::Uuid; #[tokio::test] @@ -68,9 +68,9 @@ async fn create_database_test() { // let database_id = Uuid::new_v4(); // let database = test // .create_database(CreateDatabaseParams { -// database_id: collab_entity::uuid_validation::database_id_from_string(&database_id.to_string()).unwrap_or_else(|_| collab_entity::uuid_validation::generate_database_id()), +// database_id: collab::entity::uuid_validation::database_id_from_string(&database_id.to_string()).unwrap_or_else(|_| collab::entity::uuid_validation::generate_database_id()), // views: vec![CreateViewParams { -// database_id: collab_entity::uuid_validation::database_id_from_string(&database_id.to_string()).unwrap_or_else(|_| collab_entity::uuid_validation::generate_database_id()), +// database_id: collab::entity::uuid_validation::database_id_from_string(&database_id.to_string()).unwrap_or_else(|_| collab::entity::uuid_validation::generate_database_id()), // view_id: uuid::Uuid::new_v5(&uuid::Uuid::NAMESPACE_OID, "v1".as_bytes()), // ..Default::default() // }], diff --git a/collab-database/tests/user_test/helper.rs b/collab/tests/database/user_test/helper.rs similarity index 80% rename from collab-database/tests/user_test/helper.rs rename to collab/tests/database/user_test/helper.rs index 977c074dc..1f133aadd 100644 --- a/collab-database/tests/user_test/helper.rs +++ b/collab/tests/database/user_test/helper.rs @@ -5,15 +5,15 @@ use std::time::Duration; use async_trait::async_trait; use collab::core::collab::CollabOptions; use collab::core::origin::CollabOrigin; +use collab::database::database::{gen_database_id, gen_field_id}; +use collab::database::fields::Field; +use collab::database::rows::{CreateRowParams, DatabaseRow}; +use collab::database::views::DatabaseLayout; +use collab::database::workspace_database::{RowRelationChange, RowRelationUpdateReceiver}; +use collab::entity::CollabType; +use collab::entity::uuid_validation::{ObjectId, RowId}; +use collab::error::CollabError; use collab::preclude::Collab; -use collab_database::database::{gen_database_id, gen_field_id}; -use collab_database::error::DatabaseError; -use collab_database::fields::Field; -use collab_database::rows::{CreateRowParams, DatabaseRow}; -use collab_database::views::DatabaseLayout; -use collab_database::workspace_database::{RowRelationChange, RowRelationUpdateReceiver}; -use collab_entity::CollabType; -use collab_entity::uuid_validation::{ObjectId, RowId}; use dashmap::DashMap; use tokio::sync::mpsc::{Receiver, channel}; @@ -22,15 +22,15 @@ use crate::database_test::helper::field_settings_for_default_database; pub const TEST_VIEW_ID_V1: &str = "00000000-0000-0000-0000-000000000001"; pub const TEST_VIEW_ID_V2: &str = "00000000-0000-0000-0000-000000000002"; -use collab::entity::EncodedCollab; -use collab::lock::RwLock; -use collab_database::database_trait::{ +use collab::database::database_trait::{ DatabaseCollabPersistenceService, DatabaseCollabReader, EncodeCollabByOid, }; -use collab_database::entity::{CreateDatabaseParams, CreateViewParams}; -use collab_plugins::CollabKVDB; -use collab_plugins::local_storage::kv::KVTransactionDB; -use collab_plugins::local_storage::kv::doc::CollabKVAction; +use collab::database::entity::{CreateDatabaseParams, CreateViewParams}; +use collab::entity::EncodedCollab; +use collab::lock::RwLock; +use collab::plugins::CollabKVDB; +use collab::plugins::local_storage::kv::KVTransactionDB; +use collab::plugins::local_storage::kv::doc::CollabKVAction; use rand::Rng; use uuid::Uuid; use yrs::block::ClientID; @@ -76,9 +76,9 @@ impl DatabaseCollabPersistenceService for TestUserDatabasePersistenceImpl { fn upsert_collab( &self, - object_id: &collab_entity::uuid_validation::ObjectId, + object_id: &collab::entity::uuid_validation::ObjectId, encoded_collab: EncodedCollab, - ) -> Result<(), DatabaseError> { + ) -> Result<(), CollabError> { let db_write = self.db.write_txn(); let _ = db_write.upsert_doc_with_doc_state( self.uid, @@ -89,13 +89,13 @@ impl DatabaseCollabPersistenceService for TestUserDatabasePersistenceImpl { ); db_write .commit_transaction() - .map_err(|err| DatabaseError::Internal(err.into()))?; + .map_err(|err| CollabError::Internal(err.into()))?; Ok(()) } fn get_encoded_collab( &self, - object_id: &collab_entity::uuid_validation::ObjectId, + object_id: &collab::entity::uuid_validation::ObjectId, collab_type: CollabType, ) -> Option { let options = CollabOptions::new(*object_id, self.client_id); @@ -108,8 +108,8 @@ impl DatabaseCollabPersistenceService for TestUserDatabasePersistenceImpl { fn delete_collab( &self, - object_id: &collab_entity::uuid_validation::ObjectId, - ) -> Result<(), DatabaseError> { + object_id: &collab::entity::uuid_validation::ObjectId, + ) -> Result<(), CollabError> { let write_txn = self.db.write_txn(); write_txn .delete_doc(self.uid, self.workspace_id.as_str(), &object_id.to_string()) @@ -118,7 +118,7 @@ impl DatabaseCollabPersistenceService for TestUserDatabasePersistenceImpl { Ok(()) } - fn is_collab_exist(&self, object_id: &collab_entity::uuid_validation::ObjectId) -> bool { + fn is_collab_exist(&self, object_id: &collab::entity::uuid_validation::ObjectId) -> bool { let read_txn = self.db.read_txn(); read_txn.is_exist(self.uid, self.workspace_id.as_str(), &object_id.to_string()) } @@ -134,7 +134,7 @@ impl DatabaseCollabReader for TestUserDatabaseServiceImpl { &self, object_id: &ObjectId, collab_type: CollabType, - ) -> Result { + ) -> Result { let options = CollabOptions::new(*object_id, self.client_id); let mut collab = Collab::new_with_options(CollabOrigin::Empty, options).unwrap(); let object_id_str = collab.object_id().to_string(); @@ -143,16 +143,14 @@ impl DatabaseCollabReader for TestUserDatabaseServiceImpl { let _ = db_read.load_doc_with_txn(self.uid, &self.workspace_id, &object_id_str, &mut txn); drop(txn); - collab - .encode_collab_v1(|collab| collab_type.validate_require_data(collab)) - .map_err(|e| e.into()) + collab.encode_collab_v1(|collab| collab_type.validate_require_data(collab)) } async fn reader_batch_get_collabs( &self, object_ids: Vec, collab_type: CollabType, - ) -> Result { + ) -> Result { let mut map = EncodeCollabByOid::new(); for object_id in object_ids { let options = CollabOptions::new(object_id, self.client_id); @@ -163,9 +161,8 @@ impl DatabaseCollabReader for TestUserDatabaseServiceImpl { let _ = db_read.load_doc_with_txn(self.uid, &self.workspace_id, &object_id_str, &mut txn); drop(txn); - let encoded_collab = collab - .encode_collab_v1(|collab| collab_type.validate_require_data(collab)) - .unwrap(); + let encoded_collab = + collab.encode_collab_v1(|collab| collab_type.validate_require_data(collab))?; map.insert(object_id, encoded_collab); } Ok(map) diff --git a/collab-database/tests/user_test/mod.rs b/collab/tests/database/user_test/mod.rs similarity index 100% rename from collab-database/tests/user_test/mod.rs rename to collab/tests/database/user_test/mod.rs diff --git a/collab-database/tests/user_test/relation_test.rs b/collab/tests/database/user_test/relation_test.rs similarity index 97% rename from collab-database/tests/user_test/relation_test.rs rename to collab/tests/database/user_test/relation_test.rs index a0fc478de..54396d0b9 100644 --- a/collab-database/tests/user_test/relation_test.rs +++ b/collab/tests/database/user_test/relation_test.rs @@ -1,5 +1,5 @@ use collab::preclude::MapRefExtension; -use collab_database::user::{RowRelation, RowRelationChange}; +use collab::database::user::{RowRelation, RowRelationChange}; use crate::user_test::helper::{poll_row_relation_rx, test_timeout, user_database_test}; diff --git a/collab-database/tests/user_test/snapshot_test.rs b/collab/tests/database/user_test/snapshot_test.rs similarity index 90% rename from collab-database/tests/user_test/snapshot_test.rs rename to collab/tests/database/user_test/snapshot_test.rs index 59fc53ebd..cf613c41a 100644 --- a/collab-database/tests/user_test/snapshot_test.rs +++ b/collab/tests/database/user_test/snapshot_test.rs @@ -1,6 +1,6 @@ -use collab_database::rows::CreateRowParams; -use collab_database::views::CreateDatabaseParams; -use collab_plugins::disk::rocksdb::CollabPersistenceConfig; +use collab::database::rows::CreateRowParams; +use collab::database::views::CreateDatabaseParams; +use collab::plugins::disk::rocksdb::CollabPersistenceConfig; use crate::user_test::helper::{user_database_test, user_database_test_with_config, TEST_VIEW_ID_V1}; diff --git a/collab-database/tests/user_test/type_option_test.rs b/collab/tests/database/user_test/type_option_test.rs similarity index 92% rename from collab-database/tests/user_test/type_option_test.rs rename to collab/tests/database/user_test/type_option_test.rs index 7d0ffdd21..4dba828f6 100644 --- a/collab-database/tests/user_test/type_option_test.rs +++ b/collab/tests/database/user_test/type_option_test.rs @@ -1,7 +1,7 @@ +use collab::database::entity::{CreateDatabaseParams, CreateViewParams}; +use collab::database::fields::{Field, TypeOptionDataBuilder, TypeOptions}; +use collab::database::views::OrderObjectPosition; use collab::util::AnyMapExt; -use collab_database::entity::{CreateDatabaseParams, CreateViewParams}; -use collab_database::fields::{Field, TypeOptionDataBuilder, TypeOptions}; -use collab_database::views::OrderObjectPosition; use uuid::Uuid; use crate::database_test::helper::{ diff --git a/collab-document/tests/assets/inline_database/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab b/collab/tests/document/assets/inline_database/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab similarity index 100% rename from collab-document/tests/assets/inline_database/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab rename to collab/tests/document/assets/inline_database/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab diff --git a/collab-document/tests/assets/inline_database/relation_map.json b/collab/tests/document/assets/inline_database/relation_map.json similarity index 100% rename from collab-document/tests/assets/inline_database/relation_map.json rename to collab/tests/document/assets/inline_database/relation_map.json diff --git a/collab-document/tests/assets/mention_page/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab b/collab/tests/document/assets/mention_page/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab similarity index 100% rename from collab-document/tests/assets/mention_page/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab rename to collab/tests/document/assets/mention_page/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab diff --git a/collab-document/tests/assets/mention_page/relation_map.json b/collab/tests/document/assets/mention_page/relation_map.json similarity index 100% rename from collab-document/tests/assets/mention_page/relation_map.json rename to collab/tests/document/assets/mention_page/relation_map.json diff --git a/collab-document/tests/block_parser/bulleted_list_test.rs b/collab/tests/document/block_parser/bulleted_list_test.rs similarity index 93% rename from collab-document/tests/block_parser/bulleted_list_test.rs rename to collab/tests/document/block_parser/bulleted_list_test.rs index 6f79fb34b..a95abeb6f 100644 --- a/collab-document/tests/block_parser/bulleted_list_test.rs +++ b/collab/tests/document/block_parser/bulleted_list_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::bulleted_list::BulletedListParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::bulleted_list::BulletedListParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::json; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/callout_test.rs b/collab/tests/document/block_parser/callout_test.rs similarity index 92% rename from collab-document/tests/block_parser/callout_test.rs rename to collab/tests/document/block_parser/callout_test.rs index 48dc7bf4b..868873f77 100644 --- a/collab-document/tests/block_parser/callout_test.rs +++ b/collab/tests/document/block_parser/callout_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::callout::CalloutParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::callout::CalloutParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::{Value, json}; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/code_block_test.rs b/collab/tests/document/block_parser/code_block_test.rs similarity index 92% rename from collab-document/tests/block_parser/code_block_test.rs rename to collab/tests/document/block_parser/code_block_test.rs index 882c4750a..d9e5e6133 100644 --- a/collab-document/tests/block_parser/code_block_test.rs +++ b/collab/tests/document/block_parser/code_block_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::code_block::CodeBlockParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::code_block::CodeBlockParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::{Value, json}; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/divider_test.rs b/collab/tests/document/block_parser/divider_test.rs similarity index 90% rename from collab-document/tests/block_parser/divider_test.rs rename to collab/tests/document/block_parser/divider_test.rs index a58d68759..1a987730b 100644 --- a/collab-document/tests/block_parser/divider_test.rs +++ b/collab/tests/document/block_parser/divider_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::divider::DividerParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::divider::DividerParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/document_parser_test.rs b/collab/tests/document/block_parser/document_parser_test.rs similarity index 94% rename from collab-document/tests/block_parser/document_parser_test.rs rename to collab/tests/document/block_parser/document_parser_test.rs index 83af0c5c7..8b87074b2 100644 --- a/collab-document/tests/block_parser/document_parser_test.rs +++ b/collab/tests/document/block_parser/document_parser_test.rs @@ -1,7 +1,7 @@ -use collab_document::block_parser::{ +use collab::document::block_parser::{ DocumentParser, DocumentParserDelegate, OutputFormat, ParseContext, }; -use collab_document::blocks::{Block, BlockType, mention_block_delta}; +use collab::document::blocks::{Block, BlockType, mention_block_delta}; use serde_json::json; use std::collections::HashMap; use std::sync::Arc; diff --git a/collab-document/tests/block_parser/file_block_test.rs b/collab/tests/document/block_parser/file_block_test.rs similarity index 92% rename from collab-document/tests/block_parser/file_block_test.rs rename to collab/tests/document/block_parser/file_block_test.rs index 940c3c9af..e34b3c117 100644 --- a/collab-document/tests/block_parser/file_block_test.rs +++ b/collab/tests/document/block_parser/file_block_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::file_block::FileBlockParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::file_block::FileBlockParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::Value; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/heading_test.rs b/collab/tests/document/block_parser/heading_test.rs similarity index 94% rename from collab-document/tests/block_parser/heading_test.rs rename to collab/tests/document/block_parser/heading_test.rs index caba7c6be..27e1a3e4b 100644 --- a/collab-document/tests/block_parser/heading_test.rs +++ b/collab/tests/document/block_parser/heading_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::heading::HeadingParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::heading::HeadingParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::{Value, json}; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/image_test.rs b/collab/tests/document/block_parser/image_test.rs similarity index 94% rename from collab-document/tests/block_parser/image_test.rs rename to collab/tests/document/block_parser/image_test.rs index 96c48d898..0cc1d5bce 100644 --- a/collab-document/tests/block_parser/image_test.rs +++ b/collab/tests/document/block_parser/image_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::image::ImageParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::image::ImageParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::Value; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/link_preview_test.rs b/collab/tests/document/block_parser/link_preview_test.rs similarity index 91% rename from collab-document/tests/block_parser/link_preview_test.rs rename to collab/tests/document/block_parser/link_preview_test.rs index 36eb0a0ef..b7c9544b6 100644 --- a/collab-document/tests/block_parser/link_preview_test.rs +++ b/collab/tests/document/block_parser/link_preview_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::link_preview::LinkPreviewParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::link_preview::LinkPreviewParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::Value; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/math_equation_test.rs b/collab/tests/document/block_parser/math_equation_test.rs similarity index 91% rename from collab-document/tests/block_parser/math_equation_test.rs rename to collab/tests/document/block_parser/math_equation_test.rs index d02953779..a61eebae0 100644 --- a/collab-document/tests/block_parser/math_equation_test.rs +++ b/collab/tests/document/block_parser/math_equation_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::math_equation::MathEquationParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::math_equation::MathEquationParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::Value; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/mod.rs b/collab/tests/document/block_parser/mod.rs similarity index 100% rename from collab-document/tests/block_parser/mod.rs rename to collab/tests/document/block_parser/mod.rs diff --git a/collab-document/tests/block_parser/numbered_list_test.rs b/collab/tests/document/block_parser/numbered_list_test.rs similarity index 97% rename from collab-document/tests/block_parser/numbered_list_test.rs rename to collab/tests/document/block_parser/numbered_list_test.rs index 71f7150aa..0cbc35310 100644 --- a/collab-document/tests/block_parser/numbered_list_test.rs +++ b/collab/tests/document/block_parser/numbered_list_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::numbered_list::NumberedListParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::numbered_list::NumberedListParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::{Value, json}; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/paragraph_test.rs b/collab/tests/document/block_parser/paragraph_test.rs similarity index 89% rename from collab-document/tests/block_parser/paragraph_test.rs rename to collab/tests/document/block_parser/paragraph_test.rs index 3c2b6e827..8ce5829c7 100644 --- a/collab-document/tests/block_parser/paragraph_test.rs +++ b/collab/tests/document/block_parser/paragraph_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::paragraph::ParagraphParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::paragraph::ParagraphParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::json; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/parser_test.rs b/collab/tests/document/block_parser/parser_test.rs similarity index 98% rename from collab-document/tests/block_parser/parser_test.rs rename to collab/tests/document/block_parser/parser_test.rs index 0a3af58b8..94e23342e 100644 --- a/collab-document/tests/block_parser/parser_test.rs +++ b/collab/tests/document/block_parser/parser_test.rs @@ -1,5 +1,5 @@ use crate::importer::util::markdown_to_document_data; -use collab_document::block_parser::{DocumentParser, OutputFormat}; +use collab::document::block_parser::{DocumentParser, OutputFormat}; #[test] fn test_desktop_guide_markdown_parser() { diff --git a/collab-document/tests/block_parser/quote_list_test.rs b/collab/tests/document/block_parser/quote_list_test.rs similarity index 96% rename from collab-document/tests/block_parser/quote_list_test.rs rename to collab/tests/document/block_parser/quote_list_test.rs index 5951c113d..163a365a8 100644 --- a/collab-document/tests/block_parser/quote_list_test.rs +++ b/collab/tests/document/block_parser/quote_list_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::quote_list::QuoteListParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::quote_list::QuoteListParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::json; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/simple_columns_test.rs b/collab/tests/document/block_parser/simple_columns_test.rs similarity index 96% rename from collab-document/tests/block_parser/simple_columns_test.rs rename to collab/tests/document/block_parser/simple_columns_test.rs index 567ac0c2b..d705f5842 100644 --- a/collab-document/tests/block_parser/simple_columns_test.rs +++ b/collab/tests/document/block_parser/simple_columns_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::document_parser::DocumentParser; -use collab_document::block_parser::{OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::document_parser::DocumentParser; +use collab::document::block_parser::{OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::json; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/simple_table_test.rs b/collab/tests/document/block_parser/simple_table_test.rs similarity index 97% rename from collab-document/tests/block_parser/simple_table_test.rs rename to collab/tests/document/block_parser/simple_table_test.rs index 96e68af33..76390f80a 100644 --- a/collab-document/tests/block_parser/simple_table_test.rs +++ b/collab/tests/document/block_parser/simple_table_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::document_parser::DocumentParser; -use collab_document::block_parser::{OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::document_parser::DocumentParser; +use collab::document::block_parser::{OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::json; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/subpage_test.rs b/collab/tests/document/block_parser/subpage_test.rs similarity index 91% rename from collab-document/tests/block_parser/subpage_test.rs rename to collab/tests/document/block_parser/subpage_test.rs index afe254925..988f605f2 100644 --- a/collab-document/tests/block_parser/subpage_test.rs +++ b/collab/tests/document/block_parser/subpage_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::subpage::SubpageParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::subpage::SubpageParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::Value; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/text_utils_test.rs b/collab/tests/document/block_parser/text_utils_test.rs similarity index 98% rename from collab-document/tests/block_parser/text_utils_test.rs rename to collab/tests/document/block_parser/text_utils_test.rs index 2f4677982..ffb0f8258 100644 --- a/collab-document/tests/block_parser/text_utils_test.rs +++ b/collab/tests/document/block_parser/text_utils_test.rs @@ -1,5 +1,5 @@ +use collab::document::block_parser::*; use collab::preclude::{Any, Attrs}; -use collab_document::block_parser::*; use std::sync::Arc; #[test] diff --git a/collab-document/tests/block_parser/todo_list_test.rs b/collab/tests/document/block_parser/todo_list_test.rs similarity index 96% rename from collab-document/tests/block_parser/todo_list_test.rs rename to collab/tests/document/block_parser/todo_list_test.rs index 2f77934b9..c820803e5 100644 --- a/collab-document/tests/block_parser/todo_list_test.rs +++ b/collab/tests/document/block_parser/todo_list_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::todo_list::TodoListParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::todo_list::TodoListParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::{Value, json}; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/block_parser/toggle_list_test.rs b/collab/tests/document/block_parser/toggle_list_test.rs similarity index 91% rename from collab-document/tests/block_parser/toggle_list_test.rs rename to collab/tests/document/block_parser/toggle_list_test.rs index 862109094..487566618 100644 --- a/collab-document/tests/block_parser/toggle_list_test.rs +++ b/collab/tests/document/block_parser/toggle_list_test.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use collab_document::block_parser::parsers::toggle_list::ToggleListParser; -use collab_document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; -use collab_document::blocks::{Block, BlockType}; +use collab::document::block_parser::parsers::toggle_list::ToggleListParser; +use collab::document::block_parser::{BlockParser, DocumentParser, OutputFormat, ParseContext}; +use collab::document::blocks::{Block, BlockType}; use serde_json::json; use crate::blocks::block_test_core::{BlockTestCore, generate_id}; diff --git a/collab-document/tests/blocks/block_test.rs b/collab/tests/document/blocks/block_test.rs similarity index 99% rename from collab-document/tests/blocks/block_test.rs rename to collab/tests/document/blocks/block_test.rs index 147f2289e..07bb88de1 100644 --- a/collab-document/tests/blocks/block_test.rs +++ b/collab/tests/document/blocks/block_test.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use collab_document::blocks::{Block, BlockAction, BlockActionPayload, BlockActionType}; +use collab::document::blocks::{Block, BlockAction, BlockActionPayload, BlockActionType}; use serde_json::json; use crate::blocks::block_test_core::{BlockTestCore, TEXT_BLOCK_TYPE, generate_id}; diff --git a/collab-document/tests/blocks/block_test_core.rs b/collab/tests/document/blocks/block_test_core.rs similarity index 96% rename from collab-document/tests/blocks/block_test_core.rs rename to collab/tests/document/blocks/block_test_core.rs index 3ee497765..a7baef323 100644 --- a/collab-document/tests/blocks/block_test_core.rs +++ b/collab/tests/document/blocks/block_test_core.rs @@ -5,15 +5,15 @@ use crate::util::document_storage; use collab::core::collab::{CollabOptions, default_client_id}; use collab::core::origin::{CollabClient, CollabOrigin}; -use collab::preclude::Collab; -use collab_document::blocks::{ +use collab::document::blocks::{ Block, BlockAction, BlockActionPayload, BlockActionType, BlockEvent, DocumentData, DocumentMeta, }; -use collab_document::document::Document; -use collab_entity::CollabType; -use collab_plugins::CollabKVDB; -use collab_plugins::local_storage::rocksdb::rocksdb_plugin::RocksdbDiskPlugin; -use collab_plugins::local_storage::rocksdb::util::KVDBCollabPersistenceImpl; +use collab::document::document::Document; +use collab::entity::CollabType; +use collab::plugins::CollabKVDB; +use collab::plugins::local_storage::rocksdb::rocksdb_plugin::RocksdbDiskPlugin; +use collab::plugins::local_storage::rocksdb::util::KVDBCollabPersistenceImpl; +use collab::preclude::Collab; use nanoid::nanoid; use serde_json::{Value, json}; use uuid::Uuid; diff --git a/collab-document/tests/blocks/mod.rs b/collab/tests/document/blocks/mod.rs similarity index 100% rename from collab-document/tests/blocks/mod.rs rename to collab/tests/document/blocks/mod.rs diff --git a/collab-document/tests/blocks/text_test.rs b/collab/tests/document/blocks/text_test.rs similarity index 99% rename from collab-document/tests/blocks/text_test.rs rename to collab/tests/document/blocks/text_test.rs index a183bb846..86ad1f399 100644 --- a/collab-document/tests/blocks/text_test.rs +++ b/collab/tests/document/blocks/text_test.rs @@ -1,8 +1,8 @@ use crate::blocks::block_test_core::{BlockTestCore, generate_id}; -use collab::preclude::{Attrs, Delta, YrsValue}; -use collab_document::blocks::{ +use collab::document::blocks::{ BlockAction, BlockActionPayload, BlockActionType, TextDelta, deserialize_text_delta, }; +use collab::preclude::{Attrs, Delta, YrsValue}; use crate::util::try_decode_from_encode_collab; use serde_json::json; diff --git a/collab-document/tests/conversions/mod.rs b/collab/tests/document/conversions/mod.rs similarity index 100% rename from collab-document/tests/conversions/mod.rs rename to collab/tests/document/conversions/mod.rs diff --git a/collab-document/tests/conversions/plain_text_test.rs b/collab/tests/document/conversions/plain_text_test.rs similarity index 97% rename from collab-document/tests/conversions/plain_text_test.rs rename to collab/tests/document/conversions/plain_text_test.rs index ec9137e5f..1d715d311 100644 --- a/collab-document/tests/conversions/plain_text_test.rs +++ b/collab/tests/document/conversions/plain_text_test.rs @@ -1,4 +1,4 @@ -use collab_document::{blocks::Block, document::Document}; +use collab::document::{blocks::Block, document::Document}; use nanoid::nanoid; use crate::util::DocumentTest; diff --git a/collab-document/tests/document/awareness_test.rs b/collab/tests/document/document/awareness_test.rs similarity index 98% rename from collab-document/tests/document/awareness_test.rs rename to collab/tests/document/document/awareness_test.rs index bdb4a47aa..80053a1e2 100644 --- a/collab-document/tests/document/awareness_test.rs +++ b/collab/tests/document/document/awareness_test.rs @@ -1,9 +1,9 @@ use crate::util::DocumentTest; use collab::core::awareness::AwarenessUpdate; +use collab::document::document_awareness::{DocumentAwarenessState, DocumentAwarenessUser}; use collab::preclude::block::ClientID; use collab::preclude::updates::decoder::{Decode, Decoder}; -use collab_document::document_awareness::{DocumentAwarenessState, DocumentAwarenessUser}; use arc_swap::ArcSwapOption; use serde_json::Value; diff --git a/collab-document/tests/document/document_data_test.rs b/collab/tests/document/document/document_data_test.rs similarity index 93% rename from collab-document/tests/document/document_data_test.rs rename to collab/tests/document/document/document_data_test.rs index ca34a4f52..e92ae33cf 100644 --- a/collab-document/tests/document/document_data_test.rs +++ b/collab/tests/document/document/document_data_test.rs @@ -1,8 +1,8 @@ use collab::core::collab::{CollabOptions, default_client_id}; use collab::core::origin::CollabOrigin; +use collab::document::document::Document; +use collab::document::document_data::default_document_data; use collab::preclude::Collab; -use collab_document::document::Document; -use collab_document::document_data::default_document_data; use uuid::Uuid; #[test] diff --git a/collab-document/tests/document/document_test.rs b/collab/tests/document/document/document_test.rs similarity index 99% rename from collab-document/tests/document/document_test.rs rename to collab/tests/document/document/document_test.rs index 85287bec6..93e424659 100644 --- a/collab-document/tests/document/document_test.rs +++ b/collab/tests/document/document/document_test.rs @@ -1,5 +1,5 @@ use crate::util::{DocumentTest, apply_actions, get_document_data, open_document_with_db}; -use collab_document::{ +use collab::document::{ blocks::{Block, BlockAction, BlockActionPayload, BlockActionType}, document::DocumentIndexContent, }; diff --git a/collab-document/tests/document/mod.rs b/collab/tests/document/document/mod.rs similarity index 100% rename from collab-document/tests/document/mod.rs rename to collab/tests/document/document/mod.rs diff --git a/collab-document/tests/document/redo_undo_test.rs b/collab/tests/document/document/redo_undo_test.rs similarity index 100% rename from collab-document/tests/document/redo_undo_test.rs rename to collab/tests/document/document/redo_undo_test.rs diff --git a/collab-document/tests/document/restore_test.rs b/collab/tests/document/document/restore_test.rs similarity index 97% rename from collab-document/tests/document/restore_test.rs rename to collab/tests/document/document/restore_test.rs index b9012c66d..16481e868 100644 --- a/collab-document/tests/document/restore_test.rs +++ b/collab/tests/document/document/restore_test.rs @@ -1,7 +1,7 @@ -use collab_document::blocks::Block; +use collab::document::blocks::Block; use uuid::Uuid; -use collab_plugins::CollabKVDB; +use collab::plugins::CollabKVDB; use crate::util::{ DocumentTest, document_storage, get_document_data, open_document_with_db, diff --git a/collab-document/tests/history_document/020_document.zip b/collab/tests/document/history_document/020_document.zip similarity index 100% rename from collab-document/tests/history_document/020_document.zip rename to collab/tests/document/history_document/020_document.zip diff --git a/collab-document/tests/importer/md_importer_customer_test.rs b/collab/tests/document/importer/md_importer_customer_test.rs similarity index 99% rename from collab-document/tests/importer/md_importer_customer_test.rs rename to collab/tests/document/importer/md_importer_customer_test.rs index ae3d396a9..9ff26eeef 100644 --- a/collab-document/tests/importer/md_importer_customer_test.rs +++ b/collab/tests/document/importer/md_importer_customer_test.rs @@ -1,5 +1,5 @@ -use collab_document::blocks::BlockType; -use collab_document::importer::define::URL_FIELD; +use collab::document::blocks::BlockType; +use collab::document::importer::define::URL_FIELD; use serde_json::json; use crate::importer::util::{ diff --git a/collab-document/tests/importer/md_importer_test.rs b/collab/tests/document/importer/md_importer_test.rs similarity index 98% rename from collab-document/tests/importer/md_importer_test.rs rename to collab/tests/document/importer/md_importer_test.rs index e944d8803..c93c9a5f6 100644 --- a/collab-document/tests/importer/md_importer_test.rs +++ b/collab/tests/document/importer/md_importer_test.rs @@ -4,8 +4,8 @@ use crate::importer::util::{ }; use assert_json_diff::assert_json_eq; use collab::core::collab::default_client_id; -use collab_document::document::Document; -use collab_document::importer::md_importer::MDImporter; +use collab::document::document::Document; +use collab::document::importer::md_importer::MDImporter; use serde_json::json; #[test] @@ -13,7 +13,7 @@ fn test_override_document() { let markdown_1 = "hello world"; let doc_data_1 = markdown_to_document_data(markdown_1); - let doc_id = collab_entity::uuid_validation::generate_document_id().to_string(); + let doc_id = collab::entity::uuid_validation::generate_document_id().to_string(); let doc = Document::create(&doc_id, doc_data_1, default_client_id()).unwrap(); { let plain_txt = doc.to_plain_text().join(""); diff --git a/collab-document/tests/importer/mod.rs b/collab/tests/document/importer/mod.rs similarity index 100% rename from collab-document/tests/importer/mod.rs rename to collab/tests/document/importer/mod.rs diff --git a/collab-document/tests/importer/util.rs b/collab/tests/document/importer/util.rs similarity index 94% rename from collab-document/tests/importer/util.rs rename to collab/tests/document/importer/util.rs index 71458746a..76ffe2c0a 100644 --- a/collab-document/tests/importer/util.rs +++ b/collab/tests/document/importer/util.rs @@ -1,5 +1,5 @@ -use collab_document::blocks::{Block, DocumentData}; -use collab_document::importer::md_importer::MDImporter; +use collab::document::blocks::{Block, DocumentData}; +use collab::document::importer::md_importer::MDImporter; use serde_json::Value; pub(crate) fn markdown_to_document_data(md: T) -> DocumentData { diff --git a/collab/tests/document/main.rs b/collab/tests/document/main.rs new file mode 100644 index 000000000..0ecf003c8 --- /dev/null +++ b/collab/tests/document/main.rs @@ -0,0 +1,12 @@ +#![cfg(feature = "plugins")] + +mod block_parser; +mod blocks; +mod document; +mod util; + +mod conversions; + +mod importer; + +mod remapper; diff --git a/collab-document/tests/remapper/document_remapper_test.rs b/collab/tests/document/remapper/document_remapper_test.rs similarity index 93% rename from collab-document/tests/remapper/document_remapper_test.rs rename to collab/tests/document/remapper/document_remapper_test.rs index ee5973ab7..65be9fcd4 100644 --- a/collab-document/tests/remapper/document_remapper_test.rs +++ b/collab/tests/document/remapper/document_remapper_test.rs @@ -1,8 +1,8 @@ use collab::core::collab::{CollabOptions, DataSource}; use collab::core::origin::CollabOrigin; +use collab::document::document::Document; +use collab::document::document_remapper::DocumentCollabRemapper; use collab::preclude::*; -use collab_document::document::Document; -use collab_document::document_remapper::DocumentCollabRemapper; use std::collections::HashMap; use std::fs; use uuid::Uuid; @@ -21,7 +21,8 @@ fn doc_state_to_document(doc_state: &[u8], doc_id: &str, user_id: &str) -> Docum #[test] fn test_remap_collab_with_mentioned_page_ids() { - let test_collab_path = "tests/assets/mention_page/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab"; + let test_collab_path = + "tests/document/assets/mention_page/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab"; let doc_state = fs::read(test_collab_path).expect("Failed to read test collab file"); let mut id_mapping: HashMap = HashMap::new(); @@ -97,7 +98,8 @@ fn test_remap_collab_with_mentioned_page_ids() { #[test] fn test_remap_collab_with_inline_database() { - let test_collab_path = "tests/assets/inline_database/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab"; + let test_collab_path = + "tests/document/assets/inline_database/b29ee07f-c7b2-4b24-a8c6-5cd6d8ba1213.collab"; let doc_state = fs::read(test_collab_path).expect("Failed to read test collab file"); let mut id_mapping: HashMap = HashMap::new(); diff --git a/collab-document/tests/remapper/mod.rs b/collab/tests/document/remapper/mod.rs similarity index 100% rename from collab-document/tests/remapper/mod.rs rename to collab/tests/document/remapper/mod.rs diff --git a/collab-document/tests/util.rs b/collab/tests/document/util.rs similarity index 93% rename from collab-document/tests/util.rs rename to collab/tests/document/util.rs index d92c3724e..d1995a9a4 100644 --- a/collab-document/tests/util.rs +++ b/collab/tests/document/util.rs @@ -9,13 +9,13 @@ use std::sync::{Arc, Once}; use collab::core::collab::{CollabOptions, default_client_id}; use collab::core::origin::{CollabClient, CollabOrigin}; +use collab::document::blocks::{Block, BlockAction, DocumentData, DocumentMeta}; +use collab::document::document::Document; +use collab::entity::CollabType; +use collab::plugins::CollabKVDB; +use collab::plugins::local_storage::rocksdb::rocksdb_plugin::RocksdbDiskPlugin; +use collab::plugins::local_storage::rocksdb::util::KVDBCollabPersistenceImpl; use collab::preclude::Collab; -use collab_document::blocks::{Block, BlockAction, DocumentData, DocumentMeta}; -use collab_document::document::Document; -use collab_entity::CollabType; -use collab_plugins::CollabKVDB; -use collab_plugins::local_storage::rocksdb::rocksdb_plugin::RocksdbDiskPlugin; -use collab_plugins::local_storage::rocksdb::util::KVDBCollabPersistenceImpl; use nanoid::nanoid; use serde_json::json; use tempfile::TempDir; @@ -242,9 +242,9 @@ impl Drop for Cleaner { pub fn unzip_history_document_db(folder_name: &str) -> std::io::Result<(Cleaner, PathBuf)> { // Open the zip file - let zip_file_path = format!("./tests/history_document/{}.zip", folder_name); + let zip_file_path = format!("./tests/document/history_document/{}.zip", folder_name); let reader = File::open(zip_file_path)?; - let output_folder_path = format!("./tests/history_document/unit_test_{}", nanoid!(6)); + let output_folder_path = format!("./tests/document/history_document/unit_test_{}", nanoid!(6)); // Create a ZipArchive from the file let mut archive = ZipArchive::new(reader)?; diff --git a/collab-folder/tests/folder_test/child_views_test.rs b/collab/tests/folder/child_views_test.rs similarity index 99% rename from collab-folder/tests/folder_test/child_views_test.rs rename to collab/tests/folder/child_views_test.rs index 450017fcf..13a29da0f 100644 --- a/collab-folder/tests/folder_test/child_views_test.rs +++ b/collab/tests/folder/child_views_test.rs @@ -1,7 +1,7 @@ use crate::util::{create_folder_with_workspace, make_test_view, parse_view_id}; use assert_json_diff::assert_json_include; -use collab_entity::uuid_validation::view_id_from_any_string; -use collab_folder::{UserId, timestamp}; +use collab::entity::uuid_validation::view_id_from_any_string; +use collab::folder::{UserId, timestamp}; use serde_json::json; #[test] diff --git a/collab-folder/tests/folder_test/custom_section.rs b/collab/tests/folder/custom_section.rs similarity index 94% rename from collab-folder/tests/folder_test/custom_section.rs rename to collab/tests/folder/custom_section.rs index 1011405b7..5f54ec16c 100644 --- a/collab-folder/tests/folder_test/custom_section.rs +++ b/collab/tests/folder/custom_section.rs @@ -1,8 +1,8 @@ use crate::util::create_folder_with_workspace; use assert_json_diff::assert_json_include; +use collab::entity::uuid_validation::view_id_from_any_string; +use collab::folder::{Section, SectionItem, UserId, timestamp}; use collab::preclude::Any; -use collab_entity::uuid_validation::view_id_from_any_string; -use collab_folder::{Section, SectionItem, UserId, timestamp}; use serde_json::json; use std::collections::HashMap; use std::sync::Arc; diff --git a/collab-folder/tests/folder_test/favorite_test.rs b/collab/tests/folder/favorite_test.rs similarity index 98% rename from collab-folder/tests/folder_test/favorite_test.rs rename to collab/tests/folder/favorite_test.rs index 3f340fd24..fd96d318e 100644 --- a/collab-folder/tests/folder_test/favorite_test.rs +++ b/collab/tests/folder/favorite_test.rs @@ -2,8 +2,8 @@ use crate::util::{ create_folder_with_data, create_folder_with_workspace, make_test_view, parse_view_id, }; use assert_json_diff::assert_json_include; -use collab_entity::uuid_validation::view_id_from_any_string; -use collab_folder::{FolderData, UserId}; +use collab::entity::uuid_validation::view_id_from_any_string; +use collab::folder::{FolderData, UserId}; use serde_json::json; #[test] diff --git a/collab-folder/tests/folder_test/history_folder/folder_data.json b/collab/tests/folder/history_folder/folder_data.json similarity index 100% rename from collab-folder/tests/folder_test/history_folder/folder_data.json rename to collab/tests/folder/history_folder/folder_data.json diff --git a/collab-folder/tests/folder_test/history_folder/folder_with_fav_v1.zip b/collab/tests/folder/history_folder/folder_with_fav_v1.zip similarity index 100% rename from collab-folder/tests/folder_test/history_folder/folder_with_fav_v1.zip rename to collab/tests/folder/history_folder/folder_with_fav_v1.zip diff --git a/collab-folder/tests/folder_test/history_folder/folder_without_fav.zip b/collab/tests/folder/history_folder/folder_without_fav.zip similarity index 100% rename from collab-folder/tests/folder_test/history_folder/folder_without_fav.zip rename to collab/tests/folder/history_folder/folder_without_fav.zip diff --git a/collab-folder/tests/folder_test/load_disk.rs b/collab/tests/folder/load_disk.rs similarity index 100% rename from collab-folder/tests/folder_test/load_disk.rs rename to collab/tests/folder/load_disk.rs diff --git a/collab-folder/tests/folder_test/main.rs b/collab/tests/folder/main.rs similarity index 88% rename from collab-folder/tests/folder_test/main.rs rename to collab/tests/folder/main.rs index 132153707..76b5cbeb2 100644 --- a/collab-folder/tests/folder_test/main.rs +++ b/collab/tests/folder/main.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "plugins")] + mod child_views_test; mod custom_section; mod favorite_test; diff --git a/collab-folder/tests/folder_test/recent_views_test.rs b/collab/tests/folder/recent_views_test.rs similarity index 98% rename from collab-folder/tests/folder_test/recent_views_test.rs rename to collab/tests/folder/recent_views_test.rs index 37243e56d..96fa6895a 100644 --- a/collab-folder/tests/folder_test/recent_views_test.rs +++ b/collab/tests/folder/recent_views_test.rs @@ -1,5 +1,5 @@ use assert_json_diff::assert_json_include; -use collab_folder::{FolderData, Section, UserId, timestamp}; +use collab::folder::{FolderData, Section, UserId, timestamp}; use serde_json::json; use crate::util::{create_folder_with_data, create_folder_with_workspace, make_test_view}; diff --git a/collab-folder/tests/folder_test/replace_view_test.rs b/collab/tests/folder/replace_view_test.rs similarity index 95% rename from collab-folder/tests/folder_test/replace_view_test.rs rename to collab/tests/folder/replace_view_test.rs index d9efa4c37..2e0e80a43 100644 --- a/collab-folder/tests/folder_test/replace_view_test.rs +++ b/collab/tests/folder/replace_view_test.rs @@ -1,8 +1,8 @@ use crate::util::{create_folder, make_test_view, parse_view_id}; +use collab::entity::uuid_validation::view_id_from_any_string; +use collab::folder::{Folder, UserId}; use collab::preclude::updates::decoder::Decode; use collab::preclude::{Collab, Update}; -use collab_entity::uuid_validation::view_id_from_any_string; -use collab_folder::{Folder, UserId}; use uuid::Uuid; #[test] @@ -96,7 +96,7 @@ fn replace_view_get_view_concurrent_update() { ); let mut v23 = make_test_view("v2.3", workspace_id, vec![]); - v23.parent_view_id = Some(collab_entity::uuid_validation::view_id_from_any_string( + v23.parent_view_id = Some(collab::entity::uuid_validation::view_id_from_any_string( "v2", )); f2.insert_view(v23, None, uid2); @@ -171,7 +171,7 @@ fn replace_view_all_views_concurrent_update() { ); let mut v23 = make_test_view("v2.3", workspace_id, vec![]); - v23.parent_view_id = Some(collab_entity::uuid_validation::view_id_from_any_string( + v23.parent_view_id = Some(collab::entity::uuid_validation::view_id_from_any_string( "v2", )); f2.insert_view(v23, None, uid2); diff --git a/collab-folder/tests/folder_test/serde_test.rs b/collab/tests/folder/serde_test.rs similarity index 97% rename from collab-folder/tests/folder_test/serde_test.rs rename to collab/tests/folder/serde_test.rs index d1bfcd8b4..3a54d0e51 100644 --- a/collab-folder/tests/folder_test/serde_test.rs +++ b/collab/tests/folder/serde_test.rs @@ -1,9 +1,9 @@ use crate::util::{create_folder, make_test_view, parse_view_id}; use collab::core::collab::{CollabOptions, default_client_id}; use collab::core::origin::CollabOrigin; +use collab::entity::uuid_validation::view_id_from_any_string; +use collab::folder::{Folder, FolderData, UserId, ViewId, timestamp}; use collab::preclude::{Collab, ReadTxn}; -use collab_entity::uuid_validation::view_id_from_any_string; -use collab_folder::{Folder, FolderData, UserId, ViewId, timestamp}; use serde_json::json; use std::sync::Arc; use std::time::{Duration, Instant}; @@ -242,7 +242,7 @@ fn child_view_json_serde() { #[tokio::test] async fn deserialize_folder_data() { - let json = include_str!("../folder_test/history_folder/folder_data.json"); + let json = include_str!("history_folder/folder_data.json"); let folder_data: FolderData = serde_json::from_str(json).unwrap(); let options = CollabOptions::new(Uuid::new_v4(), default_client_id()); let collab = Collab::new_with_options(CollabOrigin::Empty, options).unwrap(); diff --git a/collab-folder/tests/folder_test/space_info_test.rs b/collab/tests/folder/space_info_test.rs similarity index 99% rename from collab-folder/tests/folder_test/space_info_test.rs rename to collab/tests/folder/space_info_test.rs index bacb3596b..4ab778daa 100644 --- a/collab-folder/tests/folder_test/space_info_test.rs +++ b/collab/tests/folder/space_info_test.rs @@ -1,4 +1,4 @@ -use collab_folder::{ +use collab::folder::{ SPACE_CREATED_AT_KEY, SPACE_ICON_COLOR_KEY, SPACE_ICON_KEY, SPACE_IS_SPACE_KEY, SPACE_PERMISSION_KEY, SpacePermission, hierarchy_builder::ViewExtraBuilder, timestamp, }; diff --git a/collab-folder/tests/folder_test/trash_test.rs b/collab/tests/folder/trash_test.rs similarity index 96% rename from collab-folder/tests/folder_test/trash_test.rs rename to collab/tests/folder/trash_test.rs index f632c5007..f29ac0542 100644 --- a/collab-folder/tests/folder_test/trash_test.rs +++ b/collab/tests/folder/trash_test.rs @@ -1,5 +1,5 @@ -use collab_entity::uuid_validation::view_id_from_any_string; -use collab_folder::{SectionChange, SectionChangeReceiver, TrashSectionChange, UserId}; +use collab::entity::uuid_validation::view_id_from_any_string; +use collab::folder::{SectionChange, SectionChangeReceiver, TrashSectionChange, UserId}; use std::future::Future; use std::time::Duration; diff --git a/collab-folder/tests/folder_test/util.rs b/collab/tests/folder/util.rs similarity index 94% rename from collab-folder/tests/folder_test/util.rs rename to collab/tests/folder/util.rs index 8bb262d52..25d83ed5b 100644 --- a/collab-folder/tests/folder_test/util.rs +++ b/collab/tests/folder/util.rs @@ -5,11 +5,11 @@ use uuid::Uuid; use collab::core::collab::{CollabOptions, DataSource, default_client_id}; use collab::core::origin::{CollabClient, CollabOrigin}; +use collab::entity::CollabType; +use collab::folder::*; +use collab::plugins::CollabKVDB; +use collab::plugins::local_storage::rocksdb::rocksdb_plugin::RocksdbDiskPlugin; use collab::preclude::Collab; -use collab_entity::CollabType; -use collab_folder::*; -use collab_plugins::CollabKVDB; -use collab_plugins::local_storage::rocksdb::rocksdb_plugin::RocksdbDiskPlugin; use tempfile::TempDir; use tracing_subscriber::EnvFilter; use tracing_subscriber::fmt::Subscriber; @@ -90,7 +90,7 @@ pub fn make_test_view(view_id: &str, parent_view_id: Uuid, belongings: Vec>(); View { - id: collab_entity::uuid_validation::view_id_from_any_string(view_id), + id: collab::entity::uuid_validation::view_id_from_any_string(view_id), parent_view_id: Some(parent_view_id), name: "".to_string(), children: RepeatedViewIdentifier::new(belongings), diff --git a/collab-folder/tests/folder_test/view_test.rs b/collab/tests/folder/view_test.rs similarity index 98% rename from collab-folder/tests/folder_test/view_test.rs rename to collab/tests/folder/view_test.rs index 4ef313a88..4fa1fa55b 100644 --- a/collab-folder/tests/folder_test/view_test.rs +++ b/collab/tests/folder/view_test.rs @@ -1,8 +1,8 @@ use crate::util::{create_folder_with_workspace, make_test_view, parse_view_id, setup_log}; use collab::core::collab::default_client_id; -use collab_entity::uuid_validation::view_id_from_any_string; -use collab_folder::folder_diff::FolderViewChange; -use collab_folder::{IconType, UserId, ViewChange, ViewIcon, timestamp}; +use collab::entity::uuid_validation::view_id_from_any_string; +use collab::folder::folder_diff::FolderViewChange; +use collab::folder::{IconType, UserId, ViewChange, ViewIcon, timestamp}; #[test] fn create_view_test() { @@ -104,15 +104,15 @@ fn delete_view_test() { .get_views(&txn, &[v1_id, v2_id, v3_id], uid.as_i64()); assert_eq!( views[0].id.to_string(), - collab_entity::uuid_validation::view_id_from_any_string("v1").to_string() + collab::entity::uuid_validation::view_id_from_any_string("v1").to_string() ); assert_eq!( views[1].id.to_string(), - collab_entity::uuid_validation::view_id_from_any_string("v2").to_string() + collab::entity::uuid_validation::view_id_from_any_string("v2").to_string() ); assert_eq!( views[2].id.to_string(), - collab_entity::uuid_validation::view_id_from_any_string("v3").to_string() + collab::entity::uuid_validation::view_id_from_any_string("v3").to_string() ); folder diff --git a/collab-folder/tests/folder_test/workspace_test.rs b/collab/tests/folder/workspace_test.rs similarity index 93% rename from collab-folder/tests/folder_test/workspace_test.rs rename to collab/tests/folder/workspace_test.rs index d7ee49e86..b0a5d2b7b 100644 --- a/collab-folder/tests/folder_test/workspace_test.rs +++ b/collab/tests/folder/workspace_test.rs @@ -1,7 +1,7 @@ use collab::core::collab::{CollabOptions, default_client_id}; use collab::core::origin::CollabOrigin; +use collab::folder::{Folder, FolderData, UserId, Workspace, check_folder_is_valid}; use collab::preclude::Collab; -use collab_folder::{Folder, FolderData, UserId, Workspace, check_folder_is_valid}; use uuid::Uuid; #[test] diff --git a/collab-importer/tests/asset/2025-07-16_22-15-54.zip b/collab/tests/importer/asset/2025-07-16_22-15-54.zip similarity index 100% rename from collab-importer/tests/asset/2025-07-16_22-15-54.zip rename to collab/tests/importer/asset/2025-07-16_22-15-54.zip diff --git a/collab-importer/tests/asset/2025-07-17_16-37-11.zip b/collab/tests/importer/asset/2025-07-17_16-37-11.zip similarity index 100% rename from collab-importer/tests/asset/2025-07-17_16-37-11.zip rename to collab/tests/importer/asset/2025-07-17_16-37-11.zip diff --git a/collab-importer/tests/asset/2025-07-18_15-31-18.zip b/collab/tests/importer/asset/2025-07-18_15-31-18.zip similarity index 100% rename from collab-importer/tests/asset/2025-07-18_15-31-18.zip rename to collab/tests/importer/asset/2025-07-18_15-31-18.zip diff --git a/collab-importer/tests/asset/My Workspace_2025-07-23_21-52-13.zip b/collab/tests/importer/asset/My Workspace_2025-07-23_21-52-13.zip similarity index 100% rename from collab-importer/tests/asset/My Workspace_2025-07-23_21-52-13.zip rename to collab/tests/importer/asset/My Workspace_2025-07-23_21-52-13.zip diff --git a/collab-importer/tests/asset/VWspace_2025-07-29_15-58-31.zip b/collab/tests/importer/asset/VWspace_2025-07-29_15-58-31.zip similarity index 100% rename from collab-importer/tests/asset/VWspace_2025-07-29_15-58-31.zip rename to collab/tests/importer/asset/VWspace_2025-07-29_15-58-31.zip diff --git a/collab-importer/tests/asset/all_md_files.zip b/collab/tests/importer/asset/all_md_files.zip similarity index 100% rename from collab-importer/tests/asset/all_md_files.zip rename to collab/tests/importer/asset/all_md_files.zip diff --git a/collab-importer/tests/asset/blog_post.zip b/collab/tests/importer/asset/blog_post.zip similarity index 100% rename from collab-importer/tests/asset/blog_post.zip rename to collab/tests/importer/asset/blog_post.zip diff --git a/collab-importer/tests/asset/blog_post_duplicate_name.zip b/collab/tests/importer/asset/blog_post_duplicate_name.zip similarity index 100% rename from collab-importer/tests/asset/blog_post_duplicate_name.zip rename to collab/tests/importer/asset/blog_post_duplicate_name.zip diff --git a/collab-importer/tests/asset/blog_post_no_subpages.zip b/collab/tests/importer/asset/blog_post_no_subpages.zip similarity index 100% rename from collab-importer/tests/asset/blog_post_no_subpages.zip rename to collab/tests/importer/asset/blog_post_no_subpages.zip diff --git a/collab-importer/tests/asset/csv_relation.zip b/collab/tests/importer/asset/csv_relation.zip similarity index 100% rename from collab-importer/tests/asset/csv_relation.zip rename to collab/tests/importer/asset/csv_relation.zip diff --git a/collab-importer/tests/asset/design.zip b/collab/tests/importer/asset/design.zip similarity index 100% rename from collab-importer/tests/asset/design.zip rename to collab/tests/importer/asset/design.zip diff --git a/collab-importer/tests/asset/empty_spaces.zip b/collab/tests/importer/asset/empty_spaces.zip similarity index 100% rename from collab-importer/tests/asset/empty_spaces.zip rename to collab/tests/importer/asset/empty_spaces.zip diff --git a/collab-importer/tests/asset/empty_zip.zip b/collab/tests/importer/asset/empty_zip.zip similarity index 100% rename from collab-importer/tests/asset/empty_zip.zip rename to collab/tests/importer/asset/empty_zip.zip diff --git a/collab-importer/tests/asset/import_test.zip b/collab/tests/importer/asset/import_test.zip similarity index 100% rename from collab-importer/tests/asset/import_test.zip rename to collab/tests/importer/asset/import_test.zip diff --git a/collab-importer/tests/asset/multi_part_zip.zip b/collab/tests/importer/asset/multi_part_zip.zip similarity index 100% rename from collab-importer/tests/asset/multi_part_zip.zip rename to collab/tests/importer/asset/multi_part_zip.zip diff --git a/collab-importer/tests/asset/project&task.zip b/collab/tests/importer/asset/project&task.zip similarity index 100% rename from collab-importer/tests/asset/project&task.zip rename to collab/tests/importer/asset/project&task.zip diff --git a/collab-importer/tests/asset/project&task_contain_zip_attachment.zip b/collab/tests/importer/asset/project&task_contain_zip_attachment.zip similarity index 100% rename from collab-importer/tests/asset/project&task_contain_zip_attachment.zip rename to collab/tests/importer/asset/project&task_contain_zip_attachment.zip diff --git a/collab-importer/tests/asset/project&task_no_subpages.zip b/collab/tests/importer/asset/project&task_no_subpages.zip similarity index 100% rename from collab-importer/tests/asset/project&task_no_subpages.zip rename to collab/tests/importer/asset/project&task_no_subpages.zip diff --git a/collab-importer/tests/asset/project.zip b/collab/tests/importer/asset/project.zip similarity index 100% rename from collab-importer/tests/asset/project.zip rename to collab/tests/importer/asset/project.zip diff --git a/collab-importer/tests/asset/row_page_with_headings.zip b/collab/tests/importer/asset/row_page_with_headings.zip similarity index 100% rename from collab-importer/tests/asset/row_page_with_headings.zip rename to collab/tests/importer/asset/row_page_with_headings.zip diff --git a/collab-importer/tests/asset/two_spaces.zip b/collab/tests/importer/asset/two_spaces.zip similarity index 100% rename from collab-importer/tests/asset/two_spaces.zip rename to collab/tests/importer/asset/two_spaces.zip diff --git a/collab-importer/tests/asset/two_spaces_with_other_files.zip b/collab/tests/importer/asset/two_spaces_with_other_files.zip similarity index 100% rename from collab-importer/tests/asset/two_spaces_with_other_files.zip rename to collab/tests/importer/asset/two_spaces_with_other_files.zip diff --git a/collab-importer/tests/main.rs b/collab/tests/importer/main.rs similarity index 100% rename from collab-importer/tests/main.rs rename to collab/tests/importer/main.rs diff --git a/collab-importer/tests/notion_test/customer_import_test.rs b/collab/tests/importer/notion_test/customer_import_test.rs similarity index 97% rename from collab-importer/tests/notion_test/customer_import_test.rs rename to collab/tests/importer/notion_test/customer_import_test.rs index 69e86814a..b1da41b44 100644 --- a/collab-importer/tests/notion_test/customer_import_test.rs +++ b/collab/tests/importer/notion_test/customer_import_test.rs @@ -1,6 +1,6 @@ use crate::util::sync_unzip_asset; -use collab_document::blocks::BlockType; -use collab_importer::notion::NotionImporter; +use collab::document::blocks::BlockType; +use collab::importer::notion::NotionImporter; /// Customer import test 1 /// diff --git a/collab-importer/tests/notion_test/import_test.rs b/collab/tests/importer/notion_test/import_test.rs similarity index 96% rename from collab-importer/tests/notion_test/import_test.rs rename to collab/tests/importer/notion_test/import_test.rs index 591efd0ea..acb0cecdc 100644 --- a/collab-importer/tests/notion_test/import_test.rs +++ b/collab/tests/importer/notion_test/import_test.rs @@ -1,29 +1,28 @@ use crate::util::{async_unzip_asset, setup_log, sync_unzip_asset}; -use collab::preclude::Collab; -use collab_database::database::Database; -use collab_database::entity::FieldType; -use collab_database::entity::FieldType::*; -use collab_database::error::DatabaseError; -use collab_database::fields::media_type_option::MediaCellData; -use collab_database::fields::{Field, TypeOptionCellReader}; -use collab_database::rows::Row; -use collab_document::blocks::{ +use collab::database::database::Database; +use collab::database::entity::FieldType; +use collab::database::entity::FieldType::*; +use collab::database::fields::media_type_option::MediaCellData; +use collab::database::fields::{Field, TypeOptionCellReader}; +use collab::database::rows::Row; +use collab::document::blocks::{ BlockType, extract_page_id_from_block_delta, extract_view_id_from_block_data, mention_block_content_from_delta, }; +use collab::preclude::Collab; -use collab_document::importer::define::URL_FIELD; -use collab_entity::CollabType; -use collab_folder::hierarchy_builder::ParentChildViews; -use collab_folder::{Folder, View, default_folder_data}; -use collab_importer::error::ImporterError; -use collab_importer::imported_collab::{ImportType, ImportedCollabInfo, import_notion_zip_file}; -use collab_importer::notion::page::NotionPage; -use collab_importer::notion::{CSVContentCache, NotionImporter, is_csv_contained_cached}; -use collab_importer::util::{CSVRow, parse_csv}; +use collab::document::importer::define::URL_FIELD; +use collab::entity::CollabType; +use collab::error::CollabError; +use collab::folder::hierarchy_builder::ParentChildViews; +use collab::folder::{Folder, View, default_folder_data}; +use collab::importer::imported_collab::{ImportType, ImportedCollabInfo, import_notion_zip_file}; +use collab::importer::notion::page::NotionPage; +use collab::importer::notion::{CSVContentCache, NotionImporter, is_csv_contained_cached}; +use collab::importer::util::{CSVRow, parse_csv}; use collab::core::collab::default_client_id; -use collab_document::document::Document; +use collab::document::document::Document; use futures::stream::StreamExt; use percent_encoding::percent_decode_str; use std::collections::{HashMap, HashSet}; @@ -359,7 +358,7 @@ async fn import_project_and_task_test() { async fn import_project_and_task_collab_test() { let workspace_id = uuid::Uuid::new_v4().to_string(); let host = "http://test.appflowy.cloud"; - let zip_file_path = PathBuf::from("./tests/asset/project&task.zip"); + let zip_file_path = PathBuf::from("./tests/importer/asset/project&task.zip"); let temp_dir = temp_dir().join(uuid::Uuid::new_v4().to_string()); std::fs::create_dir_all(&temp_dir).unwrap(); let info = import_notion_zip_file(1, host, &workspace_id, zip_file_path, temp_dir.clone()) @@ -399,7 +398,7 @@ async fn import_empty_zip_test() { ) .unwrap(); let err = importer.import().await.unwrap_err(); - assert!(matches!(err, ImporterError::CannotImport)); + assert!(matches!(err, CollabError::ImporterCannotImport)); } #[tokio::test] @@ -680,7 +679,7 @@ fn assert_database_rows_with_csv_rows( csv_rows: Vec, database: Database, fields: Vec, - rows: Vec>, + rows: Vec>, mut expected_files: HashMap<&str, &str>, ) { let type_option_by_field_id = fields diff --git a/collab-importer/tests/notion_test/mod.rs b/collab/tests/importer/notion_test/mod.rs similarity index 100% rename from collab-importer/tests/notion_test/mod.rs rename to collab/tests/importer/notion_test/mod.rs diff --git a/collab-importer/tests/util.rs b/collab/tests/importer/util.rs similarity index 89% rename from collab-importer/tests/util.rs rename to collab/tests/importer/util.rs index b601764b3..ab4651b94 100644 --- a/collab-importer/tests/util.rs +++ b/collab/tests/importer/util.rs @@ -1,8 +1,8 @@ use std::env::temp_dir; use async_zip::base::read::stream::ZipFileReader; -use collab_importer::zip_tool::async_zip::async_unzip; -use collab_importer::zip_tool::sync_zip::sync_unzip; +use collab::importer::zip_tool::async_zip::async_unzip; +use collab::importer::zip_tool::sync_zip::sync_unzip; use std::path::PathBuf; use std::sync::Once; use tokio::io::BufReader; @@ -30,7 +30,7 @@ impl Drop for Cleaner { } pub async fn sync_unzip_asset(file_name: &str) -> std::io::Result<(Cleaner, PathBuf)> { - let zip_file_path = PathBuf::from(format!("./tests/asset/{}.zip", file_name)); + let zip_file_path = PathBuf::from(format!("./tests/importer/asset/{}.zip", file_name)); if !zip_file_path.exists() { panic!("File not found: {:?}", zip_file_path); } @@ -60,7 +60,7 @@ pub async fn sync_unzip_asset(file_name: &str) -> std::io::Result<(Cleaner, Path pub async fn async_unzip_asset(file_name: &str) -> std::io::Result<(Cleaner, PathBuf)> { setup_log(); - let zip_file_path = PathBuf::from(format!("./tests/asset/{}.zip", file_name)); + let zip_file_path = PathBuf::from(format!("./tests/importer/asset/{}.zip", file_name)); let output_folder_path = temp_dir().join(uuid::Uuid::new_v4().to_string()); tokio::fs::create_dir_all(&output_folder_path).await?; diff --git a/collab-importer/tests/workspace/database_collab_remapper.rs b/collab/tests/importer/workspace/database_collab_remapper.rs similarity index 94% rename from collab-importer/tests/workspace/database_collab_remapper.rs rename to collab/tests/importer/workspace/database_collab_remapper.rs index c7ad9be6d..e981993f6 100644 --- a/collab-importer/tests/workspace/database_collab_remapper.rs +++ b/collab/tests/importer/workspace/database_collab_remapper.rs @@ -1,7 +1,7 @@ use crate::util::sync_unzip_asset; -use collab_importer::workspace::database_collab_remapper::DatabaseCollabRemapper; -use collab_importer::workspace::id_mapper::IdMapper; -use collab_importer::workspace::relation_map_parser::RelationMapParser; +use collab::importer::workspace::database_collab_remapper::DatabaseCollabRemapper; +use collab::importer::workspace::id_mapper::IdMapper; +use collab::importer::workspace::relation_map_parser::RelationMapParser; #[tokio::test] async fn test_parse_real_database_json() { diff --git a/collab-importer/tests/workspace/document_collab_remapper.rs b/collab/tests/importer/workspace/document_collab_remapper.rs similarity index 92% rename from collab-importer/tests/workspace/document_collab_remapper.rs rename to collab/tests/importer/workspace/document_collab_remapper.rs index 777764135..53c2f340c 100644 --- a/collab-importer/tests/workspace/document_collab_remapper.rs +++ b/collab/tests/importer/workspace/document_collab_remapper.rs @@ -1,7 +1,7 @@ use crate::util::sync_unzip_asset; -use collab_importer::workspace::document_collab_remapper::DocumentCollabRemapper; -use collab_importer::workspace::id_mapper::IdMapper; -use collab_importer::workspace::relation_map_parser::RelationMapParser; +use collab::importer::workspace::document_collab_remapper::DocumentCollabRemapper; +use collab::importer::workspace::id_mapper::IdMapper; +use collab::importer::workspace::relation_map_parser::RelationMapParser; #[tokio::test] async fn test_parse_real_document_json() { diff --git a/collab-importer/tests/workspace/folder_collab_remapper.rs b/collab/tests/importer/workspace/folder_collab_remapper.rs similarity index 93% rename from collab-importer/tests/workspace/folder_collab_remapper.rs rename to collab/tests/importer/workspace/folder_collab_remapper.rs index 37ef5b55d..b8eb2df28 100644 --- a/collab-importer/tests/workspace/folder_collab_remapper.rs +++ b/collab/tests/importer/workspace/folder_collab_remapper.rs @@ -1,8 +1,8 @@ use crate::util::sync_unzip_asset; -use collab_folder::{Folder, ViewLayout}; -use collab_importer::workspace::folder_collab_remapper::FolderCollabRemapper; -use collab_importer::workspace::id_mapper::IdMapper; -use collab_importer::workspace::relation_map_parser::RelationMapParser; +use collab::folder::{Folder, ViewLayout}; +use collab::importer::workspace::folder_collab_remapper::FolderCollabRemapper; +use collab::importer::workspace::id_mapper::IdMapper; +use collab::importer::workspace::relation_map_parser::RelationMapParser; #[allow(clippy::too_many_arguments)] fn verify_view( @@ -21,7 +21,7 @@ fn verify_view( assert_eq!(view.name, expected_name); assert_eq!( view.parent_view_id, - Some(collab_entity::uuid_validation::view_id_from_any_string( + Some(collab::entity::uuid_validation::view_id_from_any_string( expected_parent_id )) ); @@ -115,7 +115,7 @@ async fn test_folder_collab_remapper() { .unwrap(); assert_eq!( child.id, - collab_entity::uuid_validation::view_id_from_any_string(&expected_child_id.to_string()) + collab::entity::uuid_validation::view_id_from_any_string(&expected_child_id.to_string()) ); } } diff --git a/collab-importer/tests/workspace/id_mapper.rs b/collab/tests/importer/workspace/id_mapper.rs similarity index 96% rename from collab-importer/tests/workspace/id_mapper.rs rename to collab/tests/importer/workspace/id_mapper.rs index 7c465dcf0..c9a7a2c93 100644 --- a/collab-importer/tests/workspace/id_mapper.rs +++ b/collab/tests/importer/workspace/id_mapper.rs @@ -1,6 +1,6 @@ use crate::util::sync_unzip_asset; -use collab_importer::workspace::id_mapper::IdMapper; -use collab_importer::workspace::relation_map_parser::RelationMapParser; +use collab::importer::workspace::id_mapper::IdMapper; +use collab::importer::workspace::relation_map_parser::RelationMapParser; use std::collections::HashSet; use uuid::Uuid; diff --git a/collab-importer/tests/workspace/mod.rs b/collab/tests/importer/workspace/mod.rs similarity index 100% rename from collab-importer/tests/workspace/mod.rs rename to collab/tests/importer/workspace/mod.rs diff --git a/collab-importer/tests/workspace/relation_map_parser.rs b/collab/tests/importer/workspace/relation_map_parser.rs similarity index 91% rename from collab-importer/tests/workspace/relation_map_parser.rs rename to collab/tests/importer/workspace/relation_map_parser.rs index 5d1453124..3fcdc9653 100644 --- a/collab-importer/tests/workspace/relation_map_parser.rs +++ b/collab/tests/importer/workspace/relation_map_parser.rs @@ -1,5 +1,5 @@ use crate::util::sync_unzip_asset; -use collab_importer::workspace::relation_map_parser::RelationMapParser; +use collab::importer::workspace::relation_map_parser::RelationMapParser; use uuid::Uuid; #[tokio::test] diff --git a/collab-importer/tests/workspace/space_view_edge_case_handler.rs b/collab/tests/importer/workspace/space_view_edge_case_handler.rs similarity index 98% rename from collab-importer/tests/workspace/space_view_edge_case_handler.rs rename to collab/tests/importer/workspace/space_view_edge_case_handler.rs index e09f76544..6769d5ba2 100644 --- a/collab-importer/tests/workspace/space_view_edge_case_handler.rs +++ b/collab/tests/importer/workspace/space_view_edge_case_handler.rs @@ -1,5 +1,5 @@ use crate::util::sync_unzip_asset; -use collab_importer::workspace::WorkspaceRemapper; +use collab::importer::workspace::WorkspaceRemapper; #[tokio::test] async fn test_space_view_edge_case_handler() { diff --git a/collab-importer/tests/workspace/workspace_database_remapper.rs b/collab/tests/importer/workspace/workspace_database_remapper.rs similarity index 90% rename from collab-importer/tests/workspace/workspace_database_remapper.rs rename to collab/tests/importer/workspace/workspace_database_remapper.rs index 25fef3871..70d8e5fb7 100644 --- a/collab-importer/tests/workspace/workspace_database_remapper.rs +++ b/collab/tests/importer/workspace/workspace_database_remapper.rs @@ -1,7 +1,7 @@ use crate::util::sync_unzip_asset; -use collab_importer::workspace::id_mapper::IdMapper; -use collab_importer::workspace::relation_map_parser::RelationMapParser; -use collab_importer::workspace::workspace_database_remapper::WorkspaceDatabaseRemapper; +use collab::importer::workspace::id_mapper::IdMapper; +use collab::importer::workspace::relation_map_parser::RelationMapParser; +use collab::importer::workspace::workspace_database_remapper::WorkspaceDatabaseRemapper; #[tokio::test] async fn test_workspace_database_remapper() { diff --git a/collab-importer/tests/workspace/workspace_remapper_test.rs b/collab/tests/importer/workspace/workspace_remapper_test.rs similarity index 98% rename from collab-importer/tests/workspace/workspace_remapper_test.rs rename to collab/tests/importer/workspace/workspace_remapper_test.rs index e5f17f3fa..fa0e29907 100644 --- a/collab-importer/tests/workspace/workspace_remapper_test.rs +++ b/collab/tests/importer/workspace/workspace_remapper_test.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use crate::util::sync_unzip_asset; -use collab_importer::workspace::WorkspaceRemapper; +use collab::importer::workspace::WorkspaceRemapper; #[tokio::test] async fn test_workspace_remapper_creation() { diff --git a/collab-importer/tests/zip_tool.rs b/collab/tests/importer/zip_tool.rs similarity index 97% rename from collab-importer/tests/zip_tool.rs rename to collab/tests/importer/zip_tool.rs index 8cc441282..73007641a 100644 --- a/collab-importer/tests/zip_tool.rs +++ b/collab/tests/importer/zip_tool.rs @@ -2,8 +2,8 @@ use anyhow::Result; use std::io::{Cursor, Write}; use std::path::Path; -use collab_importer::zip_tool::async_zip::async_unzip; -use collab_importer::zip_tool::sync_zip::sync_unzip; +use collab::importer::zip_tool::async_zip::async_unzip; +use collab::importer::zip_tool::sync_zip::sync_unzip; use tempfile::tempdir; use tokio_util::compat::TokioAsyncReadCompatExt; use zip::CompressionMethod; diff --git a/collab-plugins/tests/disk/delete_test.rs b/collab/tests/plugins/disk/delete_test.rs similarity index 94% rename from collab-plugins/tests/disk/delete_test.rs rename to collab/tests/plugins/disk/delete_test.rs index 6f2d2d4e4..7bff9ebcb 100644 --- a/collab-plugins/tests/disk/delete_test.rs +++ b/collab/tests/plugins/disk/delete_test.rs @@ -1,5 +1,5 @@ use crate::disk::script::CollabPersistenceTest; -use collab_plugins::local_storage::CollabPersistenceConfig; +use collab::plugins::local_storage::CollabPersistenceConfig; #[tokio::test] async fn delete_single_doc_test() { diff --git a/collab-plugins/tests/disk/insert_test.rs b/collab/tests/plugins/disk/insert_test.rs similarity index 94% rename from collab-plugins/tests/disk/insert_test.rs rename to collab/tests/plugins/disk/insert_test.rs index 1f6fa5fd7..f852cd74a 100644 --- a/collab-plugins/tests/disk/insert_test.rs +++ b/collab/tests/plugins/disk/insert_test.rs @@ -5,12 +5,12 @@ use uuid::Uuid; use anyhow::Error; use collab::core::collab::{CollabOptions, default_client_id}; use collab::core::origin::CollabOrigin; +use collab::entity::CollabType; +use collab::plugins::local_storage::CollabPersistenceConfig; +use collab::plugins::local_storage::kv::KVTransactionDB; +use collab::plugins::local_storage::kv::doc::CollabKVAction; +use collab::plugins::local_storage::rocksdb::util::KVDBCollabPersistenceImpl; use collab::preclude::Collab; -use collab_entity::CollabType; -use collab_plugins::local_storage::CollabPersistenceConfig; -use collab_plugins::local_storage::kv::KVTransactionDB; -use collab_plugins::local_storage::kv::doc::CollabKVAction; -use collab_plugins::local_storage::rocksdb::util::KVDBCollabPersistenceImpl; use std::sync::Arc; #[tokio::test] diff --git a/collab-plugins/tests/disk/mod.rs b/collab/tests/plugins/disk/mod.rs similarity index 100% rename from collab-plugins/tests/disk/mod.rs rename to collab/tests/plugins/disk/mod.rs diff --git a/collab-plugins/tests/disk/range_test.rs b/collab/tests/plugins/disk/range_test.rs similarity index 97% rename from collab-plugins/tests/disk/range_test.rs rename to collab/tests/plugins/disk/range_test.rs index 064d92787..28f1d4d0d 100644 --- a/collab-plugins/tests/disk/range_test.rs +++ b/collab/tests/plugins/disk/range_test.rs @@ -3,8 +3,8 @@ use std::sync::Arc; use std::thread; use crate::disk::util::rocks_db; -use collab_plugins::local_storage::kv::keys::{Clock, clock_from_key, make_doc_update_key}; -use collab_plugins::local_storage::kv::{KVEntry, KVStore, KVTransactionDB}; +use collab::plugins::local_storage::kv::keys::{Clock, clock_from_key, make_doc_update_key}; +use collab::plugins::local_storage::kv::{KVEntry, KVStore, KVTransactionDB}; use smallvec::SmallVec; #[tokio::test] diff --git a/collab-plugins/tests/disk/restore_test.rs b/collab/tests/plugins/disk/restore_test.rs similarity index 96% rename from collab-plugins/tests/disk/restore_test.rs rename to collab/tests/plugins/disk/restore_test.rs index 6c98fecd6..19f83170f 100644 --- a/collab-plugins/tests/disk/restore_test.rs +++ b/collab/tests/plugins/disk/restore_test.rs @@ -1,10 +1,10 @@ use crate::disk::util::rocks_db; -use collab_plugins::CollabKVDB; -use collab_plugins::local_storage::kv::doc::{ +use collab::plugins::CollabKVDB; +use collab::plugins::local_storage::kv::doc::{ CollabKVAction, extract_object_id_from_key_v1, migrate_old_keys, }; -use collab_plugins::local_storage::kv::keys::{make_doc_id_key_v0, make_doc_id_key_v1}; -use collab_plugins::local_storage::kv::{KVStore, KVTransactionDB}; +use collab::plugins::local_storage::kv::keys::{make_doc_id_key_v0, make_doc_id_key_v1}; +use collab::plugins::local_storage::kv::{KVStore, KVTransactionDB}; use std::thread; use uuid::Uuid; use yrs::{Doc, GetString, Text, Transact}; diff --git a/collab-plugins/tests/disk/script.rs b/collab/tests/plugins/disk/script.rs similarity index 95% rename from collab-plugins/tests/disk/script.rs rename to collab/tests/plugins/disk/script.rs index d33fec741..76cdeaff5 100644 --- a/collab-plugins/tests/disk/script.rs +++ b/collab/tests/plugins/disk/script.rs @@ -5,15 +5,15 @@ use std::sync::Arc; use crate::setup_log; use collab::core::collab::{CollabOptions, default_client_id}; use collab::core::origin::CollabOrigin; +use collab::entity::CollabType; use collab::lock::RwLock; +use collab::plugins::CollabKVDB; +use collab::plugins::local_storage::CollabPersistenceConfig; +use collab::plugins::local_storage::kv::KVTransactionDB; +use collab::plugins::local_storage::kv::doc::CollabKVAction; +use collab::plugins::local_storage::rocksdb::rocksdb_plugin::RocksdbDiskPlugin; +use collab::plugins::local_storage::rocksdb::util::KVDBCollabPersistenceImpl; use collab::preclude::*; -use collab_entity::CollabType; -use collab_plugins::CollabKVDB; -use collab_plugins::local_storage::CollabPersistenceConfig; -use collab_plugins::local_storage::kv::KVTransactionDB; -use collab_plugins::local_storage::kv::doc::CollabKVAction; -use collab_plugins::local_storage::rocksdb::rocksdb_plugin::RocksdbDiskPlugin; -use collab_plugins::local_storage::rocksdb::util::KVDBCollabPersistenceImpl; use tempfile::TempDir; use uuid::Uuid; diff --git a/collab-plugins/tests/disk/undo_test.rs b/collab/tests/plugins/disk/undo_test.rs similarity index 97% rename from collab-plugins/tests/disk/undo_test.rs rename to collab/tests/plugins/disk/undo_test.rs index ac5889a6e..6eb25a186 100644 --- a/collab-plugins/tests/disk/undo_test.rs +++ b/collab/tests/plugins/disk/undo_test.rs @@ -1,5 +1,5 @@ use crate::disk::script::CollabPersistenceTest; -use collab_plugins::local_storage::CollabPersistenceConfig; +use collab::plugins::local_storage::CollabPersistenceConfig; use serde_json::json; use std::time::Duration; diff --git a/collab-plugins/tests/disk/util.rs b/collab/tests/plugins/disk/util.rs similarity index 88% rename from collab-plugins/tests/disk/util.rs rename to collab/tests/plugins/disk/util.rs index b913252f7..bfb6c34ca 100644 --- a/collab-plugins/tests/disk/util.rs +++ b/collab/tests/plugins/disk/util.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use collab_plugins::CollabKVDB; +use collab::plugins::CollabKVDB; use tempfile::TempDir; pub fn rocks_db() -> (PathBuf, CollabKVDB) { diff --git a/collab-plugins/tests/main.rs b/collab/tests/plugins/main.rs similarity index 80% rename from collab-plugins/tests/main.rs rename to collab/tests/plugins/main.rs index c9d82d344..045a28460 100644 --- a/collab-plugins/tests/main.rs +++ b/collab/tests/plugins/main.rs @@ -1,10 +1,7 @@ -#[cfg(not(target_arch = "wasm32"))] -mod disk; +#![cfg(feature = "plugins")] -#[cfg(target_arch = "wasm32")] -mod web; +mod disk; -#[cfg(not(target_arch = "wasm32"))] pub fn setup_log() { use tracing_subscriber::util::SubscriberInitExt; static START: std::sync::Once = std::sync::Once::new(); @@ -14,7 +11,7 @@ pub fn setup_log() { filters.push(format!("collab_persistence={}", level)); filters.push(format!("collab={}", level)); filters.push(format!("collab_sync={}", level)); - filters.push(format!("collab_plugins={}", level)); + filters.push(format!("collab::plugins={}", level)); unsafe { std::env::set_var("RUST_LOG", filters.join(",")); } diff --git a/collab/tests/user/main.rs b/collab/tests/user/main.rs new file mode 100644 index 000000000..8bc5bd704 --- /dev/null +++ b/collab/tests/user/main.rs @@ -0,0 +1,4 @@ +#![cfg(feature = "plugins")] + +mod reminder_test; +mod util; diff --git a/collab-user/tests/reminder_test/mod.rs b/collab/tests/user/reminder_test/mod.rs similarity index 100% rename from collab-user/tests/reminder_test/mod.rs rename to collab/tests/user/reminder_test/mod.rs diff --git a/collab-user/tests/reminder_test/subscribe_test.rs b/collab/tests/user/reminder_test/subscribe_test.rs similarity index 94% rename from collab-user/tests/reminder_test/subscribe_test.rs rename to collab/tests/user/reminder_test/subscribe_test.rs index ecc695eb5..4ca54da64 100644 --- a/collab-user/tests/reminder_test/subscribe_test.rs +++ b/collab/tests/user/reminder_test/subscribe_test.rs @@ -1,6 +1,6 @@ +use collab::entity::reminder::{ObjectType, Reminder}; use collab::lock::Mutex; -use collab_entity::reminder::{ObjectType, Reminder}; -use collab_user::core::ReminderChange; +use collab::user::core::ReminderChange; use std::sync::Arc; use crate::util::{UserAwarenessTest, receive_with_timeout}; diff --git a/collab-user/tests/reminder_test/test.rs b/collab/tests/user/reminder_test/test.rs similarity index 98% rename from collab-user/tests/reminder_test/test.rs rename to collab/tests/user/reminder_test/test.rs index 1f184c601..3fdae1e83 100644 --- a/collab-user/tests/reminder_test/test.rs +++ b/collab/tests/user/reminder_test/test.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use collab_entity::reminder::{ObjectType, Reminder}; +use collab::entity::reminder::{ObjectType, Reminder}; use crate::util::UserAwarenessTest; use assert_json_diff::assert_json_eq; diff --git a/collab-user/tests/util.rs b/collab/tests/user/util.rs similarity index 89% rename from collab-user/tests/util.rs rename to collab/tests/user/util.rs index b21f16468..530a332d9 100644 --- a/collab-user/tests/util.rs +++ b/collab/tests/user/util.rs @@ -5,11 +5,11 @@ use std::time::Duration; use anyhow::Result; use collab::core::collab::{CollabOptions, DataSource, default_client_id}; use collab::core::origin::{CollabClient, CollabOrigin}; +use collab::entity::CollabType; +use collab::plugins::CollabKVDB; +use collab::plugins::local_storage::rocksdb::rocksdb_plugin::RocksdbDiskPlugin; use collab::preclude::Collab; -use collab_entity::CollabType; -use collab_plugins::CollabKVDB; -use collab_plugins::local_storage::rocksdb::rocksdb_plugin::RocksdbDiskPlugin; -use collab_user::core::{RemindersChangeSender, UserAwareness, UserAwarenessNotifier}; +use collab::user::core::{RemindersChangeSender, UserAwareness, UserAwarenessNotifier}; use tempfile::TempDir; use tokio::sync::broadcast::Receiver; use tokio::time::timeout;