aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-12-15 15:09:37 +0100
committermetamuffin <metamuffin@disroot.org>2025-12-15 15:09:37 +0100
commit0e48299889c3c2b81bf351ffe5da71e0bcd4c22a (patch)
tree8a7ff2bd2330c206070b2062723ba471b2d62544
parent7552a4ff0e027334398d28d5687a339ad77c0871 (diff)
downloadjellything-0e48299889c3c2b81bf351ffe5da71e0bcd4c22a.tar
jellything-0e48299889c3c2b81bf351ffe5da71e0bcd4c22a.tar.bz2
jellything-0e48299889c3c2b81bf351ffe5da71e0bcd4c22a.tar.zst
db
-rw-r--r--Cargo.lock412
-rw-r--r--database/Cargo.toml1
-rw-r--r--database/src/backends/memory.rs13
-rw-r--r--database/src/backends/mod.rs5
-rw-r--r--database/src/backends/redb.rs19
-rw-r--r--database/src/backends/rocksdb.rs19
-rw-r--r--database/src/indices/mod.rs19
-rw-r--r--database/src/indices/order.rs49
-rw-r--r--database/src/lib.rs513
-rw-r--r--database/src/search.rs64
-rw-r--r--server/Cargo.toml2
11 files changed, 151 insertions, 965 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ae64827..a31cc5c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -102,12 +102,6 @@ dependencies = [
]
[[package]]
-name = "allocator-api2"
-version = "0.2.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
-
-[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -188,12 +182,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
[[package]]
-name = "arc-swap"
-version = "1.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
-
-[[package]]
name = "arg_enum_proc_macro"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -420,15 +408,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
-name = "bitpacking"
-version = "0.9.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c1d3e2bfd8d06048a179f7b17afc3188effa10385e7b00dc65af6aae732ea92"
-dependencies = [
- "crunchy",
-]
-
-[[package]]
name = "bitstream-io"
version = "4.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -469,31 +448,6 @@ dependencies = [
]
[[package]]
-name = "bon"
-version = "3.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebeb9aaf9329dff6ceb65c689ca3db33dbf15f324909c60e4e5eef5701ce31b1"
-dependencies = [
- "bon-macros",
- "rustversion",
-]
-
-[[package]]
-name = "bon-macros"
-version = "3.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77e9d642a7e3a318e37c2c9427b5a6a48aa1ad55dcd986f3034ab2239045a645"
-dependencies = [
- "darling",
- "ident_case",
- "prettyplease",
- "proc-macro2",
- "quote",
- "rustversion",
- "syn",
-]
-
-[[package]]
name = "built"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -552,12 +506,6 @@ dependencies = [
]
[[package]]
-name = "census"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f4c707c6a209cbe82d10abd08e1ea8995e9ea937d2550646e02798948992be0"
-
-[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -870,7 +818,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
dependencies = [
"powerfmt",
- "serde_core",
]
[[package]]
@@ -942,12 +889,6 @@ dependencies = [
]
[[package]]
-name = "downcast-rs"
-version = "2.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc"
-
-[[package]]
name = "ebml"
version = "0.1.0"
source = "git+https://codeberg.org/metamuffin/ebml-rs#1535ae503f67b82d8a08d2c2787156f5bd4ffbba"
@@ -1069,12 +1010,6 @@ dependencies = [
]
[[package]]
-name = "fastdivide"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9afc2bd4d5a73106dd53d10d73d3401c2f32730ba2c0b93ddb888a8983680471"
-
-[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1146,12 +1081,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
-name = "foldhash"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
-
-[[package]]
name = "form_urlencoded"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1161,16 +1090,6 @@ dependencies = [
]
[[package]]
-name = "fs4"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8640e34b88f7652208ce9e88b1a37a2ae95227d84abec377ccd3c5cfeb141ed4"
-dependencies = [
- "rustix",
- "windows-sys 0.59.0",
-]
-
-[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1382,17 +1301,6 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.15.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
-dependencies = [
- "allocator-api2",
- "equivalent",
- "foldhash",
-]
-
-[[package]]
-name = "hashbrown"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
@@ -1434,12 +1342,6 @@ dependencies = [
]
[[package]]
-name = "htmlescape"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163"
-
-[[package]]
name = "http"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1602,15 +1504,6 @@ dependencies = [
]
[[package]]
-name = "hyperloglogplus"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "621debdf94dcac33e50475fdd76d34d5ea9c0362a834b9db08c3024696c1fbe3"
-dependencies = [
- "serde",
-]
-
-[[package]]
name = "iana-time-zone"
version = "0.1.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1807,7 +1700,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [
"equivalent",
- "hashbrown 0.16.1",
+ "hashbrown",
"serde",
"serde_core",
]
@@ -1947,7 +1840,6 @@ dependencies = [
"rocksdb",
"serde",
"serde_json",
- "tantivy",
]
[[package]]
@@ -2067,7 +1959,7 @@ dependencies = [
"rocket_ws",
"serde",
"serde_json",
- "serde_yml",
+ "serde_yaml_ng",
"tokio",
"tokio-util",
]
@@ -2186,12 +2078,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
[[package]]
-name = "levenshtein_automata"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25"
-
-[[package]]
name = "libavif"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2278,16 +2164,6 @@ dependencies = [
]
[[package]]
-name = "libyml"
-version = "0.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980"
-dependencies = [
- "anyhow",
- "version_check",
-]
-
-[[package]]
name = "libz-sys"
version = "1.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2350,15 +2226,6 @@ dependencies = [
]
[[package]]
-name = "lru"
-version = "0.12.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
-dependencies = [
- "hashbrown 0.15.5",
-]
-
-[[package]]
name = "lru-slab"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2375,12 +2242,6 @@ dependencies = [
]
[[package]]
-name = "lz4_flex"
-version = "0.11.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a"
-
-[[package]]
name = "markup"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2445,30 +2306,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
[[package]]
-name = "measure_time"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51c55d61e72fc3ab704396c5fa16f4c184db37978ae4e94ca8959693a235fc0e"
-dependencies = [
- "log",
-]
-
-[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
-name = "memmap2"
-version = "0.9.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490"
-dependencies = [
- "libc",
-]
-
-[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2531,12 +2374,6 @@ dependencies = [
]
[[package]]
-name = "murmurhash32"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b"
-
-[[package]]
name = "nalgebra"
version = "0.32.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2715,12 +2552,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
-name = "oneshot"
-version = "0.1.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4ce411919553d3f9fa53a0880544cda985a112117a0444d5ff1e870a893d6ea"
-
-[[package]]
name = "opaque-debug"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2736,15 +2567,6 @@ dependencies = [
]
[[package]]
-name = "ownedbytes"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fbd56f7631767e61784dc43f8580f403f4475bd4aaa4da003e6295e1bab4a7e"
-dependencies = [
- "stable_deref_trait",
-]
-
-[[package]]
name = "owning_ref"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2933,16 +2755,6 @@ dependencies = [
]
[[package]]
-name = "prettyplease"
-version = "0.2.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
-dependencies = [
- "proc-macro2",
- "syn",
-]
-
-[[package]]
name = "proc-macro2"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3494,16 +3306,6 @@ dependencies = [
]
[[package]]
-name = "rust-stemmers"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54"
-dependencies = [
- "serde",
- "serde_derive",
-]
-
-[[package]]
name = "rustc-hash"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3668,18 +3470,16 @@ dependencies = [
]
[[package]]
-name = "serde_yml"
-version = "0.0.12"
+name = "serde_yaml_ng"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd"
+checksum = "7b4db627b98b36d4203a7b458cf3573730f2bb591b28871d916dfa9efabfd41f"
dependencies = [
"indexmap",
"itoa",
- "libyml",
- "memchr",
"ryu",
"serde",
- "version_check",
+ "unsafe-libyaml",
]
[[package]]
@@ -3763,15 +3563,6 @@ dependencies = [
]
[[package]]
-name = "sketches-ddsketch"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1e9a774a6c28142ac54bb25d25562e6bcf957493a184f15ad4eebccb23e410a"
-dependencies = [
- "serde",
-]
-
-[[package]]
name = "slab"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3886,152 +3677,6 @@ dependencies = [
]
[[package]]
-name = "tantivy"
-version = "0.25.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "502915c7381c5cb2d2781503962610cb880ad8f1a0ca95df1bae645d5ebf2545"
-dependencies = [
- "aho-corasick",
- "arc-swap",
- "base64",
- "bitpacking",
- "bon",
- "byteorder",
- "census",
- "crc32fast",
- "crossbeam-channel",
- "downcast-rs",
- "fastdivide",
- "fnv",
- "fs4",
- "htmlescape",
- "hyperloglogplus",
- "itertools 0.14.0",
- "levenshtein_automata",
- "log",
- "lru",
- "lz4_flex",
- "measure_time",
- "memmap2",
- "once_cell",
- "oneshot",
- "rayon",
- "regex",
- "rust-stemmers",
- "rustc-hash",
- "serde",
- "serde_json",
- "sketches-ddsketch",
- "smallvec 1.15.1",
- "tantivy-bitpacker",
- "tantivy-columnar",
- "tantivy-common",
- "tantivy-fst",
- "tantivy-query-grammar",
- "tantivy-stacker",
- "tantivy-tokenizer-api",
- "tempfile",
- "thiserror 2.0.17",
- "time",
- "uuid",
- "winapi",
-]
-
-[[package]]
-name = "tantivy-bitpacker"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3b04eed5108d8283607da6710fe17a7663523440eaf7ea5a1a440d19a1448b6"
-dependencies = [
- "bitpacking",
-]
-
-[[package]]
-name = "tantivy-columnar"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b628488ae936c83e92b5c4056833054ca56f76c0e616aee8339e24ac89119cd"
-dependencies = [
- "downcast-rs",
- "fastdivide",
- "itertools 0.14.0",
- "serde",
- "tantivy-bitpacker",
- "tantivy-common",
- "tantivy-sstable",
- "tantivy-stacker",
-]
-
-[[package]]
-name = "tantivy-common"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f880aa7cab0c063a47b62596d10991cdd0b6e0e0575d9c5eeb298b307a25de55"
-dependencies = [
- "async-trait",
- "byteorder",
- "ownedbytes",
- "serde",
- "time",
-]
-
-[[package]]
-name = "tantivy-fst"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d60769b80ad7953d8a7b2c70cdfe722bbcdcac6bccc8ac934c40c034d866fc18"
-dependencies = [
- "byteorder",
- "regex-syntax",
- "utf8-ranges",
-]
-
-[[package]]
-name = "tantivy-query-grammar"
-version = "0.25.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "768fccdc84d60d86235d42d7e4c33acf43c418258ff5952abf07bd7837fcd26b"
-dependencies = [
- "nom 7.1.3",
- "serde",
- "serde_json",
-]
-
-[[package]]
-name = "tantivy-sstable"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8292095d1a8a2c2b36380ec455f910ab52dde516af36321af332c93f20ab7d5"
-dependencies = [
- "futures-util",
- "itertools 0.14.0",
- "tantivy-bitpacker",
- "tantivy-common",
- "tantivy-fst",
- "zstd",
-]
-
-[[package]]
-name = "tantivy-stacker"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d38a379411169f0b3002c9cba61cdfe315f757e9d4f239c00c282497a0749d"
-dependencies = [
- "murmurhash32",
- "rand_distr",
- "tantivy-common",
-]
-
-[[package]]
-name = "tantivy-tokenizer-api"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23024f6aeb25ceb1a0e27740c84bdb0fae52626737b7e9a9de6ad5aa25c7b038"
-dependencies = [
- "serde",
-]
-
-[[package]]
name = "tempfile"
version = "3.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4517,12 +4162,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
-name = "utf8-ranges"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba"
-
-[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4535,18 +4174,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
-name = "uuid"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
-dependencies = [
- "getrandom 0.3.4",
- "js-sys",
- "serde_core",
- "wasm-bindgen",
-]
-
-[[package]]
name = "v_frame"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4819,15 +4446,6 @@ dependencies = [
[[package]]
name = "windows-sys"
-version = "0.59.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
@@ -5170,24 +4788,6 @@ dependencies = [
]
[[package]]
-name = "zstd"
-version = "0.13.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
-dependencies = [
- "zstd-safe",
-]
-
-[[package]]
-name = "zstd-safe"
-version = "7.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
-dependencies = [
- "zstd-sys",
-]
-
-[[package]]
name = "zstd-sys"
version = "2.0.16+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/database/Cargo.toml b/database/Cargo.toml
index eeeee7f..7e79b92 100644
--- a/database/Cargo.toml
+++ b/database/Cargo.toml
@@ -4,7 +4,6 @@ version = "0.1.0"
edition = "2024"
[dependencies]
-tantivy = "0.25.0"
jellycommon = { path = "../common" }
serde = { version = "1.0.228", features = ["derive"] }
log = { workspace = true }
diff --git a/database/src/backends/memory.rs b/database/src/backends/memory.rs
index 97c8c2c..2f19ce6 100644
--- a/database/src/backends/memory.rs
+++ b/database/src/backends/memory.rs
@@ -4,13 +4,18 @@
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
-use crate::backends::DatabaseStorage;
+use crate::backends::KV;
use anyhow::Result;
use std::{collections::BTreeMap, sync::RwLock};
pub struct Memory(RwLock<BTreeMap<Vec<u8>, Vec<u8>>>);
-impl DatabaseStorage for Memory {
+impl Memory {
+ pub fn new() -> Self {
+ Self(RwLock::new(BTreeMap::new()))
+ }
+}
+impl KV for Memory {
fn set(&self, key: &[u8], value: &[u8]) -> Result<()> {
self.0.write().unwrap().insert(key.to_vec(), value.to_vec());
Ok(())
@@ -18,6 +23,10 @@ impl DatabaseStorage for Memory {
fn get<'a>(&'a self, key: &[u8]) -> Result<Option<Vec<u8>>> {
Ok(self.0.read().unwrap().get(key).cloned())
}
+ fn del(&self, key: &[u8]) -> Result<()> {
+ self.0.write().unwrap().remove(key);
+ Ok(())
+ }
fn next(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
let r = self.0.read().unwrap();
Ok(r.range(key.to_vec()..).next().map(|(k, _)| k.to_owned()))
diff --git a/database/src/backends/mod.rs b/database/src/backends/mod.rs
index 1240ac1..b6d3770 100644
--- a/database/src/backends/mod.rs
+++ b/database/src/backends/mod.rs
@@ -4,15 +4,16 @@
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
+pub mod memory;
pub mod redb;
pub mod rocksdb;
-pub mod memory;
use anyhow::Result;
-pub trait DatabaseStorage {
+pub trait KV {
fn set(&self, key: &[u8], value: &[u8]) -> Result<()>;
fn get<'a>(&'a self, key: &[u8]) -> Result<Option<Vec<u8>>>;
+ fn del(&self, key: &[u8]) -> Result<()>;
fn next(&self, key: &[u8]) -> Result<Option<Vec<u8>>>;
fn prev(&self, key: &[u8]) -> Result<Option<Vec<u8>>>;
}
diff --git a/database/src/backends/redb.rs b/database/src/backends/redb.rs
index 39fe532..1b672b6 100644
--- a/database/src/backends/redb.rs
+++ b/database/src/backends/redb.rs
@@ -4,7 +4,9 @@
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
-use crate::backends::DatabaseStorage;
+use std::path::Path;
+
+use crate::backends::KV;
use anyhow::Result;
use redb::{Database, ReadableDatabase, TableDefinition};
@@ -14,13 +16,26 @@ pub struct Redb {
const TABLE: TableDefinition<&[u8], &[u8]> = TableDefinition::new("kv");
-impl DatabaseStorage for Redb {
+impl Redb {
+ pub fn new(path: &Path) -> Result<Self> {
+ Ok(Self {
+ db: Database::create(path)?,
+ })
+ }
+}
+impl KV for Redb {
fn set(&self, key: &[u8], value: &[u8]) -> Result<()> {
let txn = self.db.begin_write()?;
txn.open_table(TABLE)?.insert(key, value)?;
txn.commit()?;
Ok(())
}
+ fn del(&self, key: &[u8]) -> Result<()> {
+ let txn = self.db.begin_write()?;
+ txn.open_table(TABLE)?.remove(key)?;
+ txn.commit()?;
+ Ok(())
+ }
fn get<'a>(&'a self, key: &[u8]) -> Result<Option<Vec<u8>>> {
let txn = self.db.begin_read()?;
match txn.open_table(TABLE)?.get(key)? {
diff --git a/database/src/backends/rocksdb.rs b/database/src/backends/rocksdb.rs
index 7c6f5f3..f4ed55b 100644
--- a/database/src/backends/rocksdb.rs
+++ b/database/src/backends/rocksdb.rs
@@ -4,7 +4,9 @@
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
-use crate::backends::DatabaseStorage;
+use std::path::Path;
+
+use crate::backends::KV;
use anyhow::Result;
use rocksdb::DB;
@@ -12,14 +14,23 @@ pub struct Rocksdb {
db: DB,
}
-impl DatabaseStorage for Rocksdb {
+impl Rocksdb {
+ pub fn new(path: &Path) -> Result<Self> {
+ Ok(Self {
+ db: DB::open_default(path)?,
+ })
+ }
+}
+impl KV for Rocksdb {
fn set(&self, key: &[u8], value: &[u8]) -> Result<()> {
- self.db.put(key, value)?;
- Ok(())
+ Ok(self.db.put(key, value)?)
}
fn get<'a>(&'a self, key: &[u8]) -> Result<Option<Vec<u8>>> {
Ok(self.db.get(key)?)
}
+ fn del(&self, key: &[u8]) -> Result<()> {
+ Ok(self.db.delete(key)?)
+ }
fn next(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
let mut it = self.db.raw_iterator();
it.seek_for_prev(key);
diff --git a/database/src/indices/mod.rs b/database/src/indices/mod.rs
new file mode 100644
index 0000000..48e91a9
--- /dev/null
+++ b/database/src/indices/mod.rs
@@ -0,0 +1,19 @@
+/*
+ This file is part of jellything (https://codeberg.org/metamuffin/jellything)
+ which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
+ Copyright (C) 2025 metamuffin <metamuffin.org>
+*/
+
+use crate::backends::KV;
+use anyhow::Result;
+
+pub mod order;
+
+pub trait Index<T> {
+ fn add(&self, db: &dyn KV, id: u64, val: &T) -> Result<()>;
+ fn remove(&self, db: &dyn KV, id: u64, val: &T) -> Result<()>;
+ fn compare(&self, before: &T, after: &T) -> bool {
+ let _ = (before, after);
+ true
+ }
+}
diff --git a/database/src/indices/order.rs b/database/src/indices/order.rs
new file mode 100644
index 0000000..852342d
--- /dev/null
+++ b/database/src/indices/order.rs
@@ -0,0 +1,49 @@
+/*
+ This file is part of jellything (https://codeberg.org/metamuffin/jellything)
+ which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
+ Copyright (C) 2025 metamuffin <metamuffin.org>
+*/
+
+use crate::{Table, backends::KV, indices::Index};
+use anyhow::Result;
+use std::sync::Arc;
+
+pub struct OrderIndex<T> {
+ id: u32,
+ value: fn(&T) -> [u8; 8],
+ db: Arc<dyn KV>,
+}
+impl<T: 'static> OrderIndex<T> {
+ pub fn new(table: &mut Table<T>, id: u32, value: fn(&T) -> [u8; 8]) -> Self {
+ table.indices.push(Box::new(Self {
+ id,
+ value,
+ db: table.db.clone(),
+ }));
+ Self {
+ id,
+ value,
+ db: table.db.clone(),
+ }
+ }
+ fn key(&self, id: u64, val: &T) -> Vec<u8> {
+ let mut key = Vec::new();
+ key.extend(self.id.to_be_bytes());
+ key.extend((self.value)(val));
+ key.extend(id.to_be_bytes());
+ key
+ }
+}
+impl<T: 'static> Index<T> for OrderIndex<T> {
+ fn add(&self, db: &dyn KV, id: u64, val: &T) -> Result<()> {
+ db.set(&self.key(id, val), &[])?;
+ Ok(())
+ }
+ fn remove(&self, db: &dyn KV, id: u64, val: &T) -> Result<()> {
+ db.del(&self.key(id, val))?;
+ Ok(())
+ }
+ fn compare(&self, before: &T, after: &T) -> bool {
+ (self.value)(before) == (self.value)(after)
+ }
+}
diff --git a/database/src/lib.rs b/database/src/lib.rs
index 0e89873..828761e 100644
--- a/database/src/lib.rs
+++ b/database/src/lib.rs
@@ -3,499 +3,46 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
-pub mod search;
-use anyhow::{Context, Result, anyhow, bail};
-use jellycommon::{
- IdentifierType, Node, NodeID,
- user::{NodeUserData, User},
-};
-use log::info;
-use redb::{Durability, ReadableDatabase, ReadableTable, StorageError, TableDefinition};
-use search::NodeTextSearchIndex;
-use serde::{Serialize, de::DeserializeOwned};
-use std::{
- fs::create_dir_all,
- path::{Path, PathBuf},
- str::FromStr,
- sync::Arc,
- time::SystemTime,
-};
-use tantivy::{
- DateTime, TantivyDocument,
- collector::{Count, TopDocs},
- doc,
- query::QueryParser,
- schema::Value,
+use anyhow::{Result, bail};
+
+use crate::{
+ backends::{KV, memory::Memory, redb::Redb, rocksdb::Rocksdb},
+ indices::Index,
};
+use std::{path::Path, sync::Arc};
-const T_USER: TableDefinition<&str, Ser<User>> = TableDefinition::new("user");
-const T_USER_NODE: TableDefinition<(&str, [u8; 32]), Ser<NodeUserData>> =
- TableDefinition::new("user_node");
-const T_INVITE: TableDefinition<&str, ()> = TableDefinition::new("invite");
-const T_NODE: TableDefinition<[u8; 32], Ser<Node>> = TableDefinition::new("node");
-const T_NODE_CHILDREN: TableDefinition<([u8; 32], [u8; 32]), ()> =
- TableDefinition::new("node_children");
-const T_TAG_NODE: TableDefinition<(&str, [u8; 32]), ()> = TableDefinition::new("tag_node");
-const T_NODE_IDENTIFIER: TableDefinition<(u8, &str), [u8; 32]> = TableDefinition::new("node_ids");
-const T_IMPORT_FILE_MTIME: TableDefinition<&[u8], u64> = TableDefinition::new("import_file_mtime");
-const T_NODE_MTIME: TableDefinition<[u8; 32], u64> = TableDefinition::new("node_mtime");
-const T_NODE_MEDIA_PATHS: TableDefinition<([u8; 32], &str), ()> =
- TableDefinition::new("node_media_paths");
+pub mod backends;
+pub mod indices;
-#[derive(Clone)]
pub struct Database {
- inner: Arc<redb::Database>,
- text_search: Arc<NodeTextSearchIndex>,
+ storage: Arc<dyn KV>,
}
impl Database {
- pub fn open(path: &Path) -> Result<Self, anyhow::Error> {
- create_dir_all(path).context("creating database directory")?;
- info!("opening kv store...");
- let db = redb::Database::create(path.join("data")).context("opening kv store")?;
- info!("opening node index...");
- let ft_node = NodeTextSearchIndex::new(path).context("in node index")?;
- let r = Self {
- inner: db.into(),
- text_search: ft_node.into(),
- };
-
- {
- // this creates all tables such that read operations on them do not fail.
- let txn = r.inner.begin_write()?;
- txn.open_table(T_INVITE)?;
- txn.open_table(T_USER)?;
- txn.open_table(T_USER_NODE)?;
- txn.open_table(T_NODE)?;
- txn.open_table(T_NODE_MTIME)?;
- txn.open_table(T_NODE_CHILDREN)?;
- txn.open_table(T_NODE_IDENTIFIER)?;
- txn.open_table(T_NODE_MEDIA_PATHS)?;
- txn.open_table(T_IMPORT_FILE_MTIME)?;
- txn.commit()?;
- }
-
- info!("ready");
- Ok(r)
- }
-
- pub fn get_node_slug(&self, slug: &str) -> Result<Option<Arc<Node>>> {
- self.get_node(NodeID::from_slug(slug))
- }
-
- pub fn get_node(&self, id: NodeID) -> Result<Option<Arc<Node>>> {
- let txn = self.inner.begin_read()?;
- let t_node = txn.open_table(T_NODE)?;
- if let Some(node) = t_node.get(id.0)? {
- Ok(Some(node.value().0.into()))
- } else {
- Ok(None)
- }
- }
- pub fn get_node_by_identifier(
- &self,
- ty: IdentifierType,
- value: &str,
- ) -> Result<Option<NodeID>> {
- let txn = self.inner.begin_read()?;
- let t_node_external_id = txn.open_table(T_NODE_IDENTIFIER)?;
- if let Some(id) = t_node_external_id.get((ty as u8, value))? {
- Ok(Some(NodeID(id.value())))
- } else {
- Ok(None)
- }
- }
- pub fn get_node_children(&self, id: NodeID) -> Result<Vec<NodeID>> {
- let txn = self.inner.begin_read()?;
- let t_node_children = txn.open_table(T_NODE_CHILDREN)?;
- Ok(t_node_children
- .range((id.0, NodeID::MIN.0)..(id.0, NodeID::MAX.0))?
- .map(|r| r.map(|r| NodeID(r.0.value().1)))
- .collect::<Result<Vec<_>, StorageError>>()?)
- }
- pub fn get_tag_nodes(&self, tag: &str) -> Result<Vec<NodeID>> {
- let txn = self.inner.begin_read()?;
- let t_tag_node = txn.open_table(T_TAG_NODE)?;
- Ok(t_tag_node
- .range((tag, NodeID::MIN.0)..(tag, NodeID::MAX.0))?
- .map(|r| r.map(|r| NodeID(r.0.value().1)))
- .collect::<Result<Vec<_>, StorageError>>()?)
- }
- pub fn get_nodes_modified_since(&self, since: u64) -> Result<Vec<NodeID>> {
- let txn = self.inner.begin_read()?;
- let t_node_mtime = txn.open_table(T_NODE_MTIME)?;
- Ok(t_node_mtime
- .iter()?
- .flat_map(|r| r.map(|r| (NodeID(r.0.value()), r.1.value())))
- .filter(|(_, mtime)| *mtime >= since)
- .map(|(id, _)| id)
- .collect())
- }
-
- pub fn clear_nodes(&self) -> Result<()> {
- let mut txn = self.inner.begin_write()?;
- let mut t_node = txn.open_table(T_NODE)?;
- let mut t_node_mtime = txn.open_table(T_NODE_MTIME)?;
- let mut t_node_children = txn.open_table(T_NODE_CHILDREN)?;
- let mut t_node_external_id = txn.open_table(T_NODE_IDENTIFIER)?;
- let mut t_import_file_mtime = txn.open_table(T_IMPORT_FILE_MTIME)?;
- let mut t_node_media_paths = txn.open_table(T_NODE_MEDIA_PATHS)?;
- t_node.retain(|_, _| false)?;
- t_node_mtime.retain(|_, _| false)?;
- t_node_children.retain(|_, _| false)?;
- t_node_external_id.retain(|_, _| false)?;
- t_import_file_mtime.retain(|_, _| false)?;
- t_node_media_paths.retain(|_, _| false)?;
- drop((
- t_node,
- t_node_mtime,
- t_node_children,
- t_node_external_id,
- t_import_file_mtime,
- t_node_media_paths,
- ));
- txn.set_durability(Durability::Immediate)?;
- txn.commit()?;
- Ok(())
- }
-
- pub fn get_node_udata(&self, id: NodeID, username: &str) -> Result<Option<NodeUserData>> {
- let txn = self.inner.begin_read()?;
- let t_node = txn.open_table(T_USER_NODE)?;
- if let Some(node) = t_node.get((username, id.0))? {
- Ok(Some(node.value().0))
- } else {
- Ok(None)
- }
- }
-
- pub fn update_node_init(&self, id: NodeID, update: impl FnOnce(&mut Node)) -> Result<()> {
- let time = SystemTime::now()
- .duration_since(SystemTime::UNIX_EPOCH)
- .unwrap()
- .as_secs();
- let mut txn = self.inner.begin_write()?;
- let mut t_node = txn.open_table(T_NODE)?;
- let mut t_node_mtime = txn.open_table(T_NODE_MTIME)?;
- let mut t_node_children = txn.open_table(T_NODE_CHILDREN)?;
- let mut t_node_external_id = txn.open_table(T_NODE_IDENTIFIER)?;
- let mut t_tag_node = txn.open_table(T_TAG_NODE)?;
- let mut node = t_node.get(id.0)?.map(|v| v.value().0).unwrap_or_default();
-
- let dh_before = serde_json::to_vec(&node).unwrap();
- update(&mut node);
- let dh_after = serde_json::to_vec(&node).unwrap();
-
- if dh_before == dh_after {
- return Ok(());
- }
-
- for parent in &node.parents {
- t_node_children.insert((parent.0, id.0), ())?;
- }
- for (pl, eid) in &node.identifiers {
- t_node_external_id.insert((*pl as u8, eid.as_str()), id.0)?;
- }
- for tag in &node.tags {
- t_tag_node.insert((tag.as_str(), id.0), ())?;
- }
- t_node.insert(&id.0, Ser(node))?;
- t_node_mtime.insert(&id.0, time)?;
- drop((
- t_node,
- t_node_mtime,
- t_node_children,
- t_node_external_id,
- t_tag_node,
- ));
- txn.set_durability(Durability::Immediate)?;
- txn.commit()?;
- Ok(())
- }
- pub fn get_node_media_paths(&self, id: NodeID) -> Result<Vec<PathBuf>> {
- let txn = self.inner.begin_read()?;
- let table = txn.open_table(T_NODE_MEDIA_PATHS)?;
- let mut paths = Vec::new();
- // TODO fix this
- for p in table.range((id.0, "\0")..(id.0, "\x7f"))? {
- paths.push(PathBuf::from_str(p?.0.value().1)?);
- }
- Ok(paths)
- }
- pub fn insert_node_media_path(&self, id: NodeID, path: &Path) -> Result<()> {
- let txn = self.inner.begin_write()?;
- let mut table = txn.open_table(T_NODE_MEDIA_PATHS)?;
- table.insert((id.0, path.to_str().unwrap()), ())?;
- drop(table);
- txn.commit()?;
- Ok(())
- }
-
- pub fn update_node_udata(
- &self,
- node: NodeID,
- username: &str,
- update: impl FnOnce(&mut NodeUserData) -> Result<()>,
- ) -> Result<()> {
- let txn = self.inner.begin_write()?;
- let mut user_nodes = txn.open_table(T_USER_NODE)?;
-
- let mut udata = user_nodes
- .get((username, node.0))?
- .map(|x| x.value().0)
- .unwrap_or_default();
-
- update(&mut udata)?;
-
- user_nodes.insert((username, node.0), Ser(udata))?;
- drop(user_nodes);
- txn.commit()?;
- Ok(())
- }
-
- pub fn get_user(&self, username: &str) -> Result<Option<User>> {
- let txn = self.inner.begin_read()?;
- let t_user = txn.open_table(T_USER)?;
- if let Some(user) = t_user.get(username)? {
- Ok(Some(user.value().0))
- } else {
- Ok(None)
- }
- }
- pub fn update_user(
- &self,
- username: &str,
- update: impl FnOnce(&mut User) -> Result<()>,
- ) -> Result<()> {
- let txn = self.inner.begin_write()?;
- let mut users = txn.open_table(T_USER)?;
- let mut user = users
- .get(username)?
- .ok_or(anyhow!("user does not exist"))?
- .value()
- .0;
- update(&mut user)?;
- users.insert(&username, Ser(user))?;
- drop(users);
- txn.commit()?;
-
- Ok(())
- }
- pub fn delete_user(&self, username: &str) -> Result<bool> {
- let txn = self.inner.begin_write()?;
- let mut table = txn.open_table(T_USER)?;
- let r = table.remove(username)?.is_some();
- drop(table);
- txn.commit()?;
- Ok(r)
- }
- pub fn list_users(&self) -> Result<Vec<User>> {
- let txn = self.inner.begin_read()?;
- let table = txn.open_table(T_USER)?;
- let i = table
- .iter()?
- .map(|a| {
- let (_, y) = a.unwrap(); // TODO
- y.value().0
- })
- .collect::<Vec<_>>();
- drop(table);
- Ok(i)
- }
- pub fn list_invites(&self) -> Result<Vec<String>> {
- let txn = self.inner.begin_read()?;
- let table = txn.open_table(T_INVITE)?;
- let i = table
- .iter()?
- .map(|a| {
- let (x, _) = a.unwrap();
- x.value().to_owned()
- })
- .collect::<Vec<_>>();
- drop(table);
- Ok(i)
- }
- pub fn create_invite(&self, inv: &str) -> Result<()> {
- let txn = self.inner.begin_write()?;
- let mut table = txn.open_table(T_INVITE)?;
- table.insert(inv, ())?;
- drop(table);
- txn.commit()?;
- Ok(())
- }
- pub fn delete_invite(&self, inv: &str) -> Result<bool> {
- let txn = self.inner.begin_write()?;
- let mut table = txn.open_table(T_INVITE)?;
- let r = table.remove(inv)?.is_some();
- drop(table);
- txn.commit()?;
- Ok(r)
- }
- pub fn register_user(&self, invite: &str, username: &str, user: User) -> Result<()> {
- let txn = self.inner.begin_write()?;
- let mut invites = txn.open_table(T_INVITE)?;
- let mut users = txn.open_table(T_USER)?;
-
- if invites.remove(invite)?.is_none() {
- bail!("invitation invalid");
- }
- let prev_user = users.insert(username, Ser(user))?.map(|x| x.value().0);
- if prev_user.is_some() {
- bail!("username taken");
- }
-
- drop(users);
- drop(invites);
- txn.commit()?;
- Ok(())
- }
- pub fn list_nodes_with_udata(&self, username: &str) -> Result<Vec<(Arc<Node>, NodeUserData)>> {
- let txn = self.inner.begin_read()?;
- let nodes = txn.open_table(T_NODE)?;
- let node_users = txn.open_table(T_USER_NODE)?;
- let i = nodes
- .iter()?
- .map(|a| {
- let (x, y) = a.unwrap();
- let (x, y) = (x.value().to_owned(), Arc::new(y.value().0));
- let z = node_users
- .get(&(username, x))
- .unwrap()
- .map(|z| z.value().0)
- .unwrap_or_default();
- (y, z)
- })
- .collect::<Vec<_>>();
- drop(nodes);
- Ok(i)
- }
- pub fn search(&self, query: &str, limit: usize, offset: usize) -> Result<(usize, Vec<NodeID>)> {
- let query = QueryParser::for_index(
- &self.text_search.index,
- vec![self.text_search.title, self.text_search.description],
- )
- .parse_query(query)
- .context("parsing query")?;
-
- let searcher = self.text_search.reader.searcher();
- let sres = searcher.search(&query, &TopDocs::with_limit(limit).and_offset(offset))?;
- let scount = searcher.search(&query, &Count)?;
-
- let mut results = Vec::new();
- for (_, daddr) in sres {
- let doc: TantivyDocument = searcher.doc(daddr)?;
- let id = doc
- .get_first(self.text_search.id)
- .unwrap()
- .as_bytes()
- .unwrap();
- let id = NodeID(id.try_into().unwrap());
- results.push(id);
- }
- Ok((scount, results))
- }
-
- pub fn search_create_index(&self) -> Result<()> {
- let mut w = self.text_search.writer.write().unwrap();
- w.delete_all_documents()?;
-
- let txn = self.inner.begin_read()?;
- let nodes = txn.open_table(T_NODE)?;
- for node in nodes.iter()? {
- let (x, y) = node?;
- let (id, node) = (x.value().to_owned(), y.value().0);
-
- w.add_document(doc!(
- self.text_search.id => id.to_vec(),
- self.text_search.title => node.title.unwrap_or_default(),
- self.text_search.description => node.description.unwrap_or_default(),
- self.text_search.releasedate => DateTime::from_timestamp_millis(node.release_date.unwrap_or_default()),
- self.text_search.f_index => node.index.unwrap_or_default() as u64,
- ))?;
- }
-
- w.commit()?;
- Ok(())
- }
-
- pub fn create_admin_user(&self, username: &str, password_hash: Vec<u8>) -> Result<()> {
- let txn = self.inner.begin_write().unwrap();
- let mut users = txn.open_table(T_USER).unwrap();
-
- let admin = users.get(username).unwrap().map(|x| x.value().0);
- users
- .insert(
- username,
- Ser(User {
- admin: true,
- name: username.to_owned(),
- password: password_hash,
- ..admin.unwrap_or_else(|| User {
- display_name: "Admin".to_string(),
- ..Default::default()
- })
- }),
- )
- .unwrap();
-
- drop(users);
- txn.commit().unwrap();
- Ok(())
- }
- pub fn get_import_file_mtime(&self, path: &Path) -> Result<Option<u64>> {
- let bytes = path.as_os_str().as_encoded_bytes();
- let txn = self.inner.begin_read()?;
- let table = txn.open_table(T_IMPORT_FILE_MTIME)?;
- if let Some(v) = table.get(bytes)? {
- Ok(Some(v.value()))
- } else {
- Ok(None)
- }
- }
- pub fn set_import_file_mtime(&self, path: &Path, mtime: u64) -> Result<()> {
- let bytes = path.as_os_str().as_encoded_bytes();
- let txn = self.inner.begin_write()?;
- let mut table = txn.open_table(T_IMPORT_FILE_MTIME)?;
- table.insert(bytes, mtime)?;
- drop(table);
- txn.commit()?;
- Ok(())
+ pub fn new(driver: &str, path: &Path) -> Result<Self> {
+ Ok(Self {
+ storage: match driver {
+ "rocksdb" => Arc::new(Rocksdb::new(path)?),
+ "redb" => Arc::new(Redb::new(path)?),
+ "memory" => Arc::new(Memory::new()),
+ _ => bail!("unknown db driver"),
+ },
+ })
}
}
-#[derive(Debug)]
-pub struct Ser<T>(pub T);
-impl<T: DeserializeOwned + Serialize + std::fmt::Debug> redb::Value for Ser<T> {
- type SelfType<'a>
- = Ser<T>
- where
- Self: 'a;
- type AsBytes<'a>
- = Vec<u8>
- where
- Self: 'a;
-
- fn fixed_width() -> Option<usize> {
- None
- }
-
- fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
- where
- Self: 'a,
- {
- Ser(serde_json::from_slice(data).unwrap())
- }
-
- fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
- where
- Self: 'a,
- Self: 'b,
- {
- serde_json::to_vec(&value.0).unwrap()
- }
-
- fn type_name() -> redb::TypeName {
- redb::TypeName::new("json")
+pub struct Table<T> {
+ id: u32,
+ indices: Vec<Box<dyn Index<T>>>,
+ db: Arc<dyn KV>,
+}
+impl<T> Table<T> {
+ pub fn new(db: &Database, id: u32) -> Self {
+ Self {
+ id,
+ indices: Vec::new(),
+ db: db.storage.clone(),
+ }
}
}
diff --git a/database/src/search.rs b/database/src/search.rs
deleted file mode 100644
index bbe39ab..0000000
--- a/database/src/search.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-use anyhow::Context;
-use std::{fs::create_dir_all, path::Path, sync::RwLock};
-use tantivy::{
- Index, IndexReader, IndexWriter, ReloadPolicy,
- directory::MmapDirectory,
- schema::{DateOptions, DateTimePrecision, FAST, Field, INDEXED, STORED, STRING, Schema, TEXT},
-};
-
-pub struct NodeTextSearchIndex {
- pub schema: Schema,
- pub reader: IndexReader,
- pub writer: RwLock<IndexWriter>,
- pub index: Index,
- pub id: Field,
- pub title: Field,
- pub releasedate: Field,
- pub description: Field,
- pub parent: Field,
- pub f_index: Field,
-}
-impl NodeTextSearchIndex {
- pub(crate) fn new(path: &Path) -> anyhow::Result<Self> {
- let mut schema = Schema::builder();
- let id = schema.add_text_field("id", TEXT | STORED | FAST);
- let title = schema.add_text_field("title", TEXT);
- let description = schema.add_text_field("description", TEXT);
- let parent = schema.add_text_field("parent", STRING | FAST);
- let f_index = schema.add_u64_field("index", FAST);
- let releasedate = schema.add_date_field(
- "releasedate",
- DateOptions::from(INDEXED)
- .set_fast()
- .set_precision(DateTimePrecision::Seconds),
- );
- let schema = schema.build();
- create_dir_all(path.join("node_index"))?;
- let directory =
- MmapDirectory::open(path.join("node_index")).context("opening index directory")?;
- let index = Index::open_or_create(directory, schema.clone()).context("creating index")?;
- let reader = index
- .reader_builder()
- .reload_policy(ReloadPolicy::OnCommitWithDelay)
- .try_into()
- .context("creating reader")?;
- let writer = index.writer(30_000_000).context("creating writer")?;
- Ok(Self {
- index,
- writer: writer.into(),
- reader,
- schema,
- parent,
- f_index,
- releasedate,
- id,
- description,
- title,
- })
- }
-}
diff --git a/server/Cargo.toml b/server/Cargo.toml
index a802b2d..84b978a 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -26,7 +26,7 @@ rocket = { workspace = true, features = ["secrets", "json"] }
rocket_ws = { workspace = true }
serde = { version = "1.0.228", features = ["derive", "rc"] }
serde_json = "1.0.145"
-serde_yml = "0.0.12"
+serde_yaml_ng = "0.10.0"
tokio = { workspace = true }
tokio-util = { version = "0.7.17", features = ["io", "io-util"] }