Files
Oxicloud/src/application/dtos/search_dto.rs
T
2026-04-01 23:14:42 +02:00

257 lines
7.5 KiB
Rust

use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
/**
* Data Transfer Object for file search criteria.
*
* This structure represents all possible search parameters that can be used
* to filter files and folders in the system. It supports various filter types
* including name matching, file types, date ranges, and size constraints.
*/
#[derive(Debug, Clone, Hash, Serialize, Deserialize, ToSchema)]
pub struct SearchCriteriaDto {
/// Optional text to search in file/folder names
#[serde(skip_serializing_if = "Option::is_none")]
pub name_contains: Option<String>,
/// Optional list of file extensions to include (e.g., "pdf", "jpg")
#[serde(skip_serializing_if = "Option::is_none")]
pub file_types: Option<Vec<String>>,
/// Optional minimum creation date (seconds since epoch)
#[serde(skip_serializing_if = "Option::is_none")]
pub created_after: Option<u64>,
/// Optional maximum creation date (seconds since epoch)
#[serde(skip_serializing_if = "Option::is_none")]
pub created_before: Option<u64>,
/// Optional minimum modification date (seconds since epoch)
#[serde(skip_serializing_if = "Option::is_none")]
pub modified_after: Option<u64>,
/// Optional maximum modification date (seconds since epoch)
#[serde(skip_serializing_if = "Option::is_none")]
pub modified_before: Option<u64>,
/// Optional minimum file size in bytes
#[serde(skip_serializing_if = "Option::is_none")]
pub min_size: Option<u64>,
/// Optional maximum file size in bytes
#[serde(skip_serializing_if = "Option::is_none")]
pub max_size: Option<u64>,
/// Optional folder ID to limit search scope
#[serde(skip_serializing_if = "Option::is_none")]
pub folder_id: Option<String>,
/// Whether to search recursively within subfolders (default: true)
#[serde(default = "default_recursive")]
pub recursive: bool,
/// Maximum number of results to return
#[serde(default = "default_limit")]
pub limit: usize,
/// Offset for pagination
#[serde(default)]
pub offset: usize,
/// Sort order for results: "relevance", "name", "name_desc", "date", "date_desc", "size", "size_desc"
#[serde(default = "default_sort_by")]
pub sort_by: String,
}
/// Default value for recursive search (true)
fn default_recursive() -> bool {
true
}
/// Default limit for search results (100)
fn default_limit() -> usize {
100
}
/// Default sort_by value
fn default_sort_by() -> String {
"relevance".to_string()
}
impl Default for SearchCriteriaDto {
fn default() -> Self {
Self {
name_contains: None,
file_types: None,
created_after: None,
created_before: None,
modified_after: None,
modified_before: None,
min_size: None,
max_size: None,
folder_id: None,
recursive: default_recursive(),
limit: default_limit(),
offset: 0,
sort_by: default_sort_by(),
}
}
}
/// A file search result enriched with server-computed metadata
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct SearchFileResultDto {
/// File ID
pub id: String,
/// File name
pub name: String,
/// Path to the file (relative)
pub path: String,
/// Size in bytes
pub size: u64,
/// MIME type
pub mime_type: String,
/// Parent folder ID
pub folder_id: Option<String>,
/// Creation timestamp
pub created_at: u64,
/// Last modification timestamp
pub modified_at: u64,
/// Relevance score (0-100) computed server-side
pub relevance_score: u32,
/// Human-readable file size (e.g., "2.5 MB")
pub size_formatted: String,
/// CSS icon class for the file type (e.g., "fas fa-file-pdf")
pub icon_class: String,
/// Extra CSS class for icon styling (e.g., "pdf-icon", "code-icon js-icon")
pub icon_special_class: String,
/// Content category: "document", "image", "video", "audio", "archive", "code", "other"
pub category: String,
}
/// A folder search result enriched with server-computed metadata
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct SearchFolderResultDto {
/// Folder ID
pub id: String,
/// Folder name
pub name: String,
/// Path to the folder (relative)
pub path: String,
/// Parent folder ID
pub parent_id: Option<String>,
/// Creation timestamp
pub created_at: u64,
/// Last modification timestamp
pub modified_at: u64,
/// Whether it is a root folder
pub is_root: bool,
/// Relevance score (0-100) computed server-side
pub relevance_score: u32,
}
/**
* Data Transfer Object for search results.
*
* This structure encapsulates the results of a search operation, including
* both files and folders that match the search criteria, along with pagination
* information and server-computed metadata.
*/
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct SearchResultsDto {
/// Files matching the search criteria (enriched with metadata)
pub files: Vec<SearchFileResultDto>,
/// Folders matching the search criteria (enriched with metadata)
pub folders: Vec<SearchFolderResultDto>,
/// Total count of matching items (for pagination)
pub total_count: Option<usize>,
/// Limit used in the search
pub limit: usize,
/// Offset used in the search
pub offset: usize,
/// Whether there are more results available
pub has_more: bool,
/// Query execution time in milliseconds (server-side)
pub query_time_ms: u64,
/// Sort order used
pub sort_by: String,
}
impl SearchResultsDto {
/// Creates a new empty search results object
pub fn empty() -> Self {
Self {
files: Vec::new(),
folders: Vec::new(),
total_count: None,
limit: 0,
offset: 0,
has_more: false,
query_time_ms: 0,
sort_by: "relevance".to_string(),
}
}
/// Creates a new search results object from files and folders
pub fn new(
files: Vec<SearchFileResultDto>,
folders: Vec<SearchFolderResultDto>,
limit: usize,
offset: usize,
total_count: Option<usize>,
query_time_ms: u64,
sort_by: String,
) -> Self {
let has_more = match total_count {
Some(total) => (offset + files.len() + folders.len()) < total,
None => false,
};
Self {
files,
folders,
total_count,
limit,
offset,
has_more,
query_time_ms,
sort_by,
}
}
}
/// DTO for search suggestion results (quick prefix search)
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct SearchSuggestionsDto {
/// Suggested file/folder names matching the query prefix
pub suggestions: Vec<SearchSuggestionItem>,
/// Query execution time in milliseconds
pub query_time_ms: u64,
}
/// Individual search suggestion item
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct SearchSuggestionItem {
/// The suggested name
pub name: String,
/// Type: "file" or "folder"
pub item_type: String,
/// Item ID for navigation
pub id: String,
/// Path for context
pub path: String,
/// CSS icon class
pub icon_class: String,
/// Extra CSS class for icon styling
pub icon_special_class: String,
/// Relevance score
pub relevance_score: u32,
}