diff --git a/Cargo.lock b/Cargo.lock index 99339c4..c4ce7e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -385,15 +385,14 @@ dependencies = [ "async-graphql", "async-graphql-axum", "axum", + "base64 0.22.1", "chrono", - "dotenv", - "lazy_static 1.5.0", "lindera-core 0.32.2", "lindera-dictionary 0.32.2", "lindera-tantivy 0.27.1 (git+https://github.com/ProjectAnni/lindera-tantivy)", + "rmp-serde", "sea-orm", "sea-orm-migration", - "seaography", "serde", "serde_json", "tantivy 0.22.0", @@ -1694,12 +1693,6 @@ dependencies = [ "syn 2.0.72", ] -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - [[package]] name = "dotenvy" version = "0.15.7" @@ -5246,6 +5239,28 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + [[package]] name = "rsa" version = "0.7.2" @@ -5738,20 +5753,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "seaography" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "892f0b05ebcb4a36a71a80b34cc43adb38b4650c1974ab2f53a4a006b427bc9d" -dependencies = [ - "async-graphql", - "fnv", - "heck 0.4.1", - "itertools 0.12.1", - "sea-orm", - "thiserror", -] - [[package]] name = "sec1" version = "0.7.3" diff --git a/annim/Cargo.toml b/annim/Cargo.toml index 2f4e157..cd31c5b 100644 --- a/annim/Cargo.toml +++ b/annim/Cargo.toml @@ -35,13 +35,11 @@ sea-orm-migration = { version = "1.0.0", features = [ anyhow.workspace = true thiserror.workspace = true -dotenv = "0.15.0" tracing = { version = "0.1.37" } tracing-subscriber = { version = "0.3.17" } -lazy_static = { version = "1.4.0" } serde_json = "1.0" chrono = "0.4.38" -serde = { workspace = true, features = ["derive"] } +serde.workspace = true # Search tantivy = "0.22.0" @@ -52,11 +50,8 @@ lindera-tantivy = { git = "https://github.com/ProjectAnni/lindera-tantivy", feat "compress", ] } -[dependencies.seaography] -version = "~1.0.0" - -[dev-dependencies] -serde_json = { version = "1.0.103" } +rmp-serde = "1.3.0" +base64 = "0.22.1" [features] default = ["postgres"] diff --git a/annim/Readme.md b/annim/Readme.md index 6881b0d..1935932 100644 --- a/annim/Readme.md +++ b/annim/Readme.md @@ -1,5 +1,13 @@ # Annim +## Debug + +```bash +export ANNIM_DATABASE_URL=postgres://postgres:password@localhost:5432/annim +export ANNIM_SEARCH_DIRECTORY=/tmp/tantivy +cargo run -p annim --release +``` + ## Installation ```bash @@ -10,6 +18,4 @@ cargo install seaography-cli ```bash sea-orm-cli generate entity --database-url 'sqlite:///tmp/annim.sqlite?mode=rwc' -# --seaography --model-extra-derives async_graphql::SimpleObject -seaography-cli -f=axum ./ src/entities 'sqlite:///tmp/annim.sqlite' annim ``` diff --git a/annim/src/graphql/cursor.rs b/annim/src/graphql/cursor.rs new file mode 100644 index 0000000..80449ef --- /dev/null +++ b/annim/src/graphql/cursor.rs @@ -0,0 +1,93 @@ +use base64::{prelude::BASE64_STANDARD, write::EncoderStringWriter, Engine}; +use sea_orm::sea_query::ValueTuple; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub(crate) struct Cursor(Vec); + +impl Cursor { + pub(crate) fn new(values: Vec) -> Self { + let values: Vec<_> = values.into_iter().map(Into::into).collect(); + Cursor(values) + } + + pub(crate) fn from_str(input: &str) -> anyhow::Result { + let bytes = BASE64_STANDARD.decode(input)?; + let cursor: Cursor = rmp_serde::from_slice(&bytes)?; + Ok(cursor) + } + + pub(crate) fn to_string(&self) -> String { + let mut writer = EncoderStringWriter::new(&BASE64_STANDARD); + rmp_serde::encode::write(&mut writer, self).unwrap(); + writer.into_inner() + } + + pub(crate) fn into_value_tuple(self) -> ValueTuple { + ValueTuple::Many(self.into_inner()) + } + + fn into_inner(self) -> Vec { + self.0.into_iter().map(Into::into).collect() + } +} + +#[derive(Serialize, Deserialize)] +pub(crate) enum CursorValue { + #[serde(rename = "t")] + /// t -> tiny + TinyInt(Option), + /// m -> mini + #[serde(rename = "m")] + SmallInt(Option), + /// n -> normal + #[serde(rename = "n")] + Int(Option), + /// b -> bigint + #[serde(rename = "b")] + BigInt(Option), + #[serde(rename = "T")] + TinyUnsigned(Option), + #[serde(rename = "M")] + SmallUnsigned(Option), + #[serde(rename = "N")] + Unsigned(Option), + #[serde(rename = "B")] + BigUnsigned(Option), + /// s -> string + #[serde(rename = "s")] + String(Option>), +} + +impl From for CursorValue { + fn from(value: sea_orm::Value) -> Self { + match value { + sea_orm::Value::TinyInt(value) => CursorValue::TinyInt(value), + sea_orm::Value::SmallInt(value) => CursorValue::SmallInt(value), + sea_orm::Value::Int(value) => CursorValue::Int(value), + sea_orm::Value::BigInt(value) => CursorValue::BigInt(value), + sea_orm::Value::TinyUnsigned(value) => CursorValue::TinyUnsigned(value), + sea_orm::Value::SmallUnsigned(value) => CursorValue::SmallUnsigned(value), + sea_orm::Value::Unsigned(value) => CursorValue::Unsigned(value), + sea_orm::Value::BigUnsigned(value) => CursorValue::BigUnsigned(value), + sea_orm::Value::String(value) => CursorValue::String(value), + _ => panic!("Unsupported value type"), + } + } +} + +impl From for sea_orm::Value { + fn from(value: CursorValue) -> Self { + match value { + CursorValue::TinyInt(value) => sea_orm::Value::TinyInt(value), + CursorValue::SmallInt(value) => sea_orm::Value::SmallInt(value), + CursorValue::Int(value) => sea_orm::Value::Int(value), + CursorValue::BigInt(value) => sea_orm::Value::BigInt(value), + CursorValue::TinyUnsigned(value) => sea_orm::Value::TinyUnsigned(value), + CursorValue::SmallUnsigned(value) => sea_orm::Value::SmallUnsigned(value), + CursorValue::Unsigned(value) => sea_orm::Value::Unsigned(value), + CursorValue::BigUnsigned(value) => sea_orm::Value::BigUnsigned(value), + CursorValue::String(value) => sea_orm::Value::String(value), + } + } +} diff --git a/annim/src/graphql/mod.rs b/annim/src/graphql/mod.rs index 1f2c8b7..cf25354 100644 --- a/annim/src/graphql/mod.rs +++ b/annim/src/graphql/mod.rs @@ -1,3 +1,4 @@ +mod cursor; mod input; pub mod types; @@ -8,6 +9,7 @@ use async_graphql::{ connection::{Connection, Edge}, Context, EmptySubscription, Object, Schema, ID, }; +use cursor::Cursor; use input::{AlbumsBy, MetadataIDInput}; use sea_orm::{ prelude::Uuid, @@ -15,7 +17,6 @@ use sea_orm::{ ActiveModelTrait, ActiveValue, ColumnTrait, DatabaseConnection, EntityTrait, Identity, ModelTrait, QueryFilter, QueryOrder, QuerySelect, Related, TransactionTrait, }; -use seaography::{decode_cursor, encode_cursor}; use tantivy::{ collector::TopDocs, indexer::NoMergePolicy, @@ -124,9 +125,8 @@ impl MetadataQuery { } if let Some(cursor) = after { - let values = decode_cursor(&cursor)?; - let cursor_values = ValueTuple::Many(values); - query.after(cursor_values); + let cursor = Cursor::from_str(&cursor)?; + query.after(cursor.into_value_tuple()); } let mut data = query.first(limit + 1).all(db).await.unwrap(); @@ -145,9 +145,8 @@ impl MetadataQuery { .map(|variant| model.get(variant.clone())) .collect(); - let cursor: String = encode_cursor(values); - - Edge::new(cursor, AlbumInfo(model)) + let cursor = Cursor::new(values); + Edge::new(cursor.to_string(), AlbumInfo(model)) }) .collect(); diff --git a/docker/Dockerfile.annim b/docker/Dockerfile.annim index d833b45..1fe8e8c 100644 --- a/docker/Dockerfile.annim +++ b/docker/Dockerfile.annim @@ -2,5 +2,6 @@ FROM alpine COPY annim /app/ +VOLUME /app/data ENTRYPOINT ["/app/annim"] EXPOSE 8000/tcp