Add search/metadata API endpoint
- Add MetadataSearchRequest, SearchResponse, SearchAssetResult, SearchAlbumResult, SearchFacet, SearchFacetCount models - Create SearchApi with SearchMetadataBuilder supporting 35+ filters - Support filtering by location, dates, camera info, favorites, tags, people, albums, text search, and more - Integrate into Client with client.search().metadata() API
This commit is contained in:
@@ -344,6 +344,180 @@ pub struct TimeBucketAssetResponse {
|
||||
pub visibility: Vec<AssetVisibility>,
|
||||
}
|
||||
|
||||
/// Metadata search request for filtering assets
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MetadataSearchRequest {
|
||||
/// Filter by album IDs
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub album_ids: Option<Vec<AssetId>>,
|
||||
/// Filter by file checksum
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub checksum: Option<String>,
|
||||
/// Filter by city name
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub city: Option<String>,
|
||||
/// Filter by country name
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub country: Option<String>,
|
||||
/// Filter by creation date (after)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub created_after: Option<DateTime<Utc>>,
|
||||
/// Filter by creation date (before)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub created_before: Option<DateTime<Utc>>,
|
||||
/// Filter by description text
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
/// Filter by device asset ID
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub device_asset_id: Option<String>,
|
||||
/// Device ID to filter by
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub device_id: Option<String>,
|
||||
/// Filter by favorite status
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_favorite: Option<bool>,
|
||||
/// Filter by motion photo status
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_motion: Option<bool>,
|
||||
/// Filter assets not in any album
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_not_in_album: Option<bool>,
|
||||
/// Filter by offline status
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub is_offline: Option<bool>,
|
||||
/// Filter by lens model
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub lens_model: Option<String>,
|
||||
/// Library ID to filter by
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub library_id: Option<AssetId>,
|
||||
/// Filter by camera make
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub make: Option<String>,
|
||||
/// Filter by camera model
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub model: Option<String>,
|
||||
/// Filter by OCR text content
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ocr: Option<String>,
|
||||
/// Sort order
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub order: Option<AssetOrder>,
|
||||
/// Filter by original file name
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub original_file_name: Option<String>,
|
||||
/// Page number (default: 1)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub page: Option<u32>,
|
||||
/// Filter by person IDs
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub person_ids: Option<Vec<AssetId>>,
|
||||
/// Filter by rating [1-5], or null for unrated (-1 deprecated)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rating: Option<i32>,
|
||||
/// Number of results to return (default: 100)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub size: Option<u32>,
|
||||
/// Filter by state/province name
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub state: Option<String>,
|
||||
/// Filter by tag IDs
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tag_ids: Option<Vec<AssetId>>,
|
||||
/// Filter by taken date (after)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub taken_after: Option<DateTime<Utc>>,
|
||||
/// Filter by taken date (before)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub taken_before: Option<DateTime<Utc>>,
|
||||
/// Asset type filter
|
||||
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
|
||||
pub asset_type: Option<AssetType>,
|
||||
/// Filter by update date (after)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub updated_after: Option<DateTime<Utc>>,
|
||||
/// Filter by update date (before)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub updated_before: Option<DateTime<Utc>>,
|
||||
/// Filter by visibility
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub visibility: Option<AssetVisibility>,
|
||||
/// Include deleted assets
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub with_deleted: Option<bool>,
|
||||
/// Include EXIF data in response
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub with_exif: Option<bool>,
|
||||
/// Include people data in response
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub with_people: Option<bool>,
|
||||
/// Include stacked assets
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub with_stacked: Option<bool>,
|
||||
}
|
||||
|
||||
/// Represents a facet value count
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SearchFacetCount {
|
||||
/// Number of assets with this facet value
|
||||
pub count: i64,
|
||||
/// Facet value
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
/// Represents a search facet
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SearchFacet {
|
||||
/// Facet counts
|
||||
pub counts: Vec<SearchFacetCount>,
|
||||
/// Facet field name
|
||||
pub field_name: String,
|
||||
}
|
||||
|
||||
/// Paginated asset search results
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SearchAssetResult {
|
||||
/// Number of assets in this page
|
||||
pub count: i64,
|
||||
/// Facet information
|
||||
pub facets: Vec<SearchFacet>,
|
||||
/// The actual assets
|
||||
pub items: Vec<AssetResponse>,
|
||||
/// Next page token
|
||||
pub next_page: Option<String>,
|
||||
/// Total number of matching assets
|
||||
pub total: i64,
|
||||
}
|
||||
|
||||
/// Paginated album search results
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SearchAlbumResult {
|
||||
/// Number of albums in this page
|
||||
pub count: i64,
|
||||
/// Facet information
|
||||
pub facets: Vec<SearchFacet>,
|
||||
/// The actual albums
|
||||
pub items: Vec<AlbumResponse>,
|
||||
/// Total number of matching albums
|
||||
pub total: i64,
|
||||
}
|
||||
|
||||
/// Combined search response
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SearchResponse {
|
||||
/// Album results
|
||||
pub albums: SearchAlbumResult,
|
||||
/// Asset results
|
||||
pub assets: SearchAssetResult,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user