pinakes/crates/pinakes-core/src/collections.rs
NotAShelf 3d9f8933d2
pinakes-core: update remaining modules and tests
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I9e0ff5ea33a5cf697473423e88f167ce6a6a6964
2026-03-08 00:43:30 +03:00

154 lines
3.5 KiB
Rust

use uuid::Uuid;
use crate::{
error::Result,
model::{
AuditAction,
Collection,
CollectionKind,
MediaId,
MediaItem,
Pagination,
},
storage::DynStorageBackend,
};
/// Creates a new collection.
///
/// # Arguments
///
/// * `storage` - Storage backend
/// * `name` - Collection name
/// * `kind` - Manual or virtual collection
/// * `description` - Optional description
/// * `filter_query` - For virtual collections, the search query
///
/// # Returns
///
/// The created collection
///
/// # Errors
///
/// Returns [`crate::error::PinakesError`] if the storage operation fails.
pub async fn create_collection(
storage: &DynStorageBackend,
name: &str,
kind: CollectionKind,
description: Option<&str>,
filter_query: Option<&str>,
) -> Result<Collection> {
storage
.create_collection(name, kind, description, filter_query)
.await
}
/// Adds a media item to a collection.
///
/// # Arguments
///
/// * `storage` - Storage backend
/// * `collection_id` - Target collection
/// * `media_id` - Media item to add
/// * `position` - Position in the collection order
///
/// # Returns
///
/// `Ok(())` on success
///
/// # Errors
///
/// Returns [`crate::error::PinakesError`] if the storage operation fails.
pub async fn add_member(
storage: &DynStorageBackend,
collection_id: Uuid,
media_id: MediaId,
position: i32,
) -> Result<()> {
storage
.add_to_collection(collection_id, media_id, position)
.await?;
crate::audit::record_action(
storage,
Some(media_id),
AuditAction::AddedToCollection,
Some(format!("collection_id={collection_id}")),
)
.await
}
/// Removes a media item from a collection.
///
/// # Arguments
///
/// * `storage` - Storage backend
/// * `collection_id` - Target collection
/// * `media_id` - Media item to remove
///
/// # Returns
///
/// `Ok(())` on success
///
/// # Errors
///
/// Returns [`crate::error::PinakesError`] if the storage operation fails.
pub async fn remove_member(
storage: &DynStorageBackend,
collection_id: Uuid,
media_id: MediaId,
) -> Result<()> {
storage
.remove_from_collection(collection_id, media_id)
.await?;
crate::audit::record_action(
storage,
Some(media_id),
AuditAction::RemovedFromCollection,
Some(format!("collection_id={collection_id}")),
)
.await
}
/// Returns all media items in a collection.
///
/// Virtual collections are evaluated dynamically using their filter query.
/// Manual collections return stored members.
///
/// # Arguments
///
/// * `storage` - Storage backend
/// * `collection_id` - Collection to query
///
/// # Returns
///
/// List of media items in the collection
///
/// # Errors
///
/// Returns [`crate::error::PinakesError`] if the storage operation fails.
pub async fn get_members(
storage: &DynStorageBackend,
collection_id: Uuid,
) -> Result<Vec<MediaItem>> {
let collection = storage.get_collection(collection_id).await?;
match collection.kind {
CollectionKind::Virtual => {
// Virtual collections evaluate their filter_query dynamically
if let Some(ref query_str) = collection.filter_query {
let query = crate::search::parse_search_query(query_str)?;
let request = crate::search::SearchRequest {
query,
sort: crate::search::SortOrder::DateDesc,
pagination: Pagination::new(0, 10000, None),
};
let results = storage.search(&request).await?;
Ok(results.items)
} else {
Ok(Vec::new())
}
},
CollectionKind::Manual => {
storage.get_collection_members(collection_id).await
},
}
}