perf: scale fixes for 1M+ photo libraries
Indexes: share_targets.target_id, duplicate_groups.status, GIN on stacks members + duplicate candidates JSONB, composite (owner_user_id, created_at DESC) on assets. N+1 elimination: batch metadata loading via find_by_assets(ids) using WHERE asset_id = ANY($1), used in timeline + sidecar export. Visibility: cache find_targets_for_user per request via OnceCell, extract filter_visible helper to reduce duplication. Streaming: FileStoragePort.open_file() returns (DataStream, u64), LocalFileStorage uses ReaderStream instead of loading full file. serve_file/serve_derivative use Body::from_stream(). Unbounded queries: sidecar full_export/import batched in 500-row chunks instead of u32::MAX. find_unresolved paginated with limit/offset. list_duplicates API accepts pagination params.
This commit is contained in:
@@ -5,6 +5,7 @@ use domain::catalog::entities::{Asset, AssetType, SourceReference};
|
||||
use domain::errors::DomainError;
|
||||
use domain::ports::{AssetRepository, FileStoragePort};
|
||||
use domain::value_objects::{Checksum, SystemId};
|
||||
use futures::StreamExt;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[tokio::test]
|
||||
@@ -36,7 +37,9 @@ async fn reads_file_successfully() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.data, file_data);
|
||||
let chunks: Vec<Bytes> = result.stream.map(|r| r.unwrap()).collect().await;
|
||||
let data: Bytes = chunks.into_iter().flatten().collect();
|
||||
assert_eq!(data, file_data);
|
||||
assert_eq!(result.mime_type, "image/jpeg");
|
||||
assert_eq!(result.filename, "cat.jpg");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user