Files
upstream-affine/packages/frontend/native/nbstore/src/blob.rs
upstream-mirror 702cc698a7
Some checks failed
Build & Test / Analyze (javascript, affine) (push) Failing after 4s
Build & Test / Analyze (typescript, affine) (push) Failing after 3s
Build & Test / Rust test filter (push) Failing after 4s
Build & Test / Check yarn binary (push) Failing after 3s
Build & Test / E2E BlockSuite Test (3) (push) Failing after 3s
Build & Test / Analyze (javascript, blocksuite) (push) Failing after 3s
Build & Test / Analyze (typescript, blocksuite) (push) Failing after 3s
Build & Test / Mobile native build filter (push) Failing after 3s
Build & Test / E2E BlockSuite Test (1) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (2) (push) Failing after 4s
Build & Test / E2E Mobile Test (1) (push) Failing after 3s
Build & Test / Unit Test (1) (push) Has been skipped
Build & Test / Unit Test (2) (push) Has been skipped
Build & Test / Unit Test (3) (push) Has been skipped
Build & Test / Unit Test (4) (push) Has been skipped
Build & Test / Unit Test (5) (push) Has been skipped
Build & Test / Native Unit Test (push) Has been skipped
Build & Test / E2E BlockSuite Test (4) (push) Failing after 3s
Build & Test / E2E BlockSuite Test (5) (push) Failing after 3s
Build & Test / E2E BlockSuite Cross Browser Test (push) Failing after 3s
Build & Test / E2E Mobile Test (2) (push) Failing after 3s
Build & Test / Build AFFiNE native (x86_64-unknown-linux-gnu) (push) Failing after 3s
Build & Test / Build Server native (push) Failing after 3s
Build & Test / Check Git Status (push) Has been skipped
Build & Test / Server Test (0, 4) (push) Has been skipped
Build & Test / Server Test (1, 4) (push) Has been skipped
Build & Test / Server Test (2, 4) (push) Has been skipped
Build & Test / Server Test (3, 4) (push) Has been skipped
Build & Test / Server Test with Elasticsearch (push) Has been skipped
Build & Test / Build @affine/electron renderer (push) Failing after 3s
Build & Test / Copilot test filter (push) Failing after 4s
Build & Test / Lint Rust (push) Has been skipped
Build & Test / Server Test with Embedded Search (push) Has been skipped
Build & Test / Server Test with Manticore Search (push) Has been skipped
Build & Test / Server E2E Test (push) Has been skipped
Build & Test / Cloud Desktop E2E Test (push) Has been skipped
Build & Test / Cloud E2E Test 1/2 (push) Has been skipped
Build & Test / Cloud E2E Test 2/2 (push) Has been skipped
Build & Test / Build Android app (push) Has been skipped
Build & Test / Test Android app (push) Has been skipped
Build & Test / Run native tests (push) Has been skipped
Build & Test / Server Copilot Api Test (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (1, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (2, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (3, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (4, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (5, 5) (push) Has been skipped
Release / Canary Gate (push) Has been skipped
Build & Test / Build AFFiNE native (aarch64-apple-darwin) (push) Has been cancelled
Build & Test / Lint (push) Has been cancelled
Build & Test / Typecheck (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-apple-darwin) (push) Has been cancelled
Build & Test / Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true) (push) Has been cancelled
Build & Test / Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true) (push) Has been cancelled
Build & Test / E2E Test (1) (push) Has been cancelled
Build & Test / E2E Test (2) (push) Has been cancelled
Build & Test / E2E Test (3) (push) Has been cancelled
Build & Test / E2E Test (4) (push) Has been cancelled
Build & Test / E2E Test (5) (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, x64, x86_64-apple-darwin, false) (push) Has been cancelled
Build & Test / 3, 2, 1 Launch (push) Has been cancelled
Build & Test / Build iOS app (push) Has been cancelled
Copilot Test Automatically / Setup Test (push) Failing after 1s
Release / Prepare (push) Failing after 2s
Release / Release Cloud (push) Has been skipped
Release / Release Desktop (push) Has been skipped
Release / Release Docker Image (push) Has been skipped
Release / Release Mobile (push) Has been skipped
snapshot of https://github.com/toeverything/AFFiNE.git (canary, 2026-09-16; blobs > 131072B omitted)
2026-09-16 04:01:20 +05:00

187 lines
4.4 KiB
Rust

use std::ops::Deref;
use super::{Blob, ListedBlob, SetBlob, error::Result, storage::SqliteDocStorage};
impl SqliteDocStorage {
pub async fn get_blob(&self, key: String) -> Result<Option<Blob>> {
let result = sqlx::query_as!(
Blob,
"SELECT key, data, size, mime, created_at FROM blobs WHERE key = ? AND deleted_at IS NULL",
key
)
.fetch_optional(&self.pool)
.await?;
Ok(result)
}
pub async fn set_blob(&self, blob: SetBlob) -> Result<()> {
sqlx::query(
r#"
INSERT INTO blobs (key, data, mime, size)
VALUES ($1, $2, $3, $4)
ON CONFLICT(key)
DO UPDATE SET data=$2, mime=$3, size=$4, deleted_at=NULL;"#,
)
.bind(blob.key)
.bind(blob.data.deref())
.bind(blob.mime)
.bind(blob.data.len() as i64)
.execute(&self.pool)
.await?;
Ok(())
}
pub async fn delete_blob(&self, key: String, permanently: bool) -> Result<()> {
if permanently {
sqlx::query("DELETE FROM blobs WHERE key = ?")
.bind(&key)
.execute(&self.pool)
.await?;
} else {
sqlx::query("UPDATE blobs SET deleted_at = CURRENT_TIMESTAMP WHERE key = ?")
.bind(&key)
.execute(&self.pool)
.await?;
}
Ok(())
}
pub async fn release_blobs(&self) -> Result<()> {
sqlx::query("DELETE FROM blobs WHERE deleted_at IS NOT NULL;")
.execute(&self.pool)
.await?;
Ok(())
}
pub async fn list_blobs(&self) -> Result<Vec<ListedBlob>> {
let result = sqlx::query_as!(
ListedBlob,
"SELECT key, size, mime, created_at FROM blobs WHERE deleted_at IS NULL ORDER BY created_at DESC;"
)
.fetch_all(&self.pool)
.await?;
Ok(result)
}
}
#[cfg(test)]
mod tests {
use sqlx::Row;
use super::{super::Data, *};
async fn get_storage() -> SqliteDocStorage {
let storage = SqliteDocStorage::new(":memory:".to_string());
storage.connect().await.unwrap();
storage
}
#[tokio::test]
async fn delete_blob() {
let storage = get_storage().await;
for i in 1..5u32 {
storage
.set_blob(SetBlob {
key: format!("test_{}", i),
data: Into::<Data>::into(vec![0, 0]),
mime: "text/plain".to_string(),
})
.await
.unwrap();
}
let result = storage.get_blob("test_1".to_string()).await.unwrap();
assert!(result.is_some());
storage.delete_blob("test_".to_string(), false).await.unwrap();
let result = storage.get_blob("test".to_string()).await.unwrap();
assert!(result.is_none());
storage.delete_blob("test_2".to_string(), true).await.unwrap();
let result = storage.get_blob("test".to_string()).await.unwrap();
assert!(result.is_none());
}
#[tokio::test]
async fn list_blobs() {
let storage = get_storage().await;
let blobs = storage.list_blobs().await.unwrap();
assert_eq!(blobs.len(), 0);
for i in 1..5u32 {
storage
.set_blob(SetBlob {
key: format!("test_{}", i),
data: Into::<Data>::into(vec![0, 0]),
mime: "text/plain".to_string(),
})
.await
.unwrap();
}
let blobs = storage.list_blobs().await.unwrap();
assert_eq!(blobs.len(), 4);
assert_eq!(
blobs.iter().map(|b| b.key.as_str()).collect::<Vec<_>>(),
vec!["test_1", "test_2", "test_3", "test_4"]
);
storage.delete_blob("test_2".to_string(), false).await.unwrap();
storage.delete_blob("test_3".to_string(), true).await.unwrap();
let query = sqlx::query("SELECT COUNT(*) as len FROM blobs;")
.fetch_one(&storage.pool)
.await
.unwrap();
assert_eq!(query.get::<i64, &str>("len"), 3);
let blobs = storage.list_blobs().await.unwrap();
assert_eq!(blobs.len(), 2);
assert_eq!(
blobs.iter().map(|b| b.key.as_str()).collect::<Vec<_>>(),
vec!["test_1", "test_4"]
);
}
#[tokio::test]
async fn release_blobs() {
let storage = get_storage().await;
for i in 1..5u32 {
storage
.set_blob(SetBlob {
key: format!("test_{}", i),
data: Into::<Data>::into(vec![0, 0]),
mime: "text/plain".to_string(),
})
.await
.unwrap();
}
storage.delete_blob("test_2".to_string(), false).await.unwrap();
storage.release_blobs().await.unwrap();
let query = sqlx::query("SELECT COUNT(*) as len FROM blobs;")
.fetch_one(&storage.pool)
.await
.unwrap();
assert_eq!(query.get::<i64, &str>("len"), 3);
}
}