# 12 - Search File and folder search with multi-criteria filtering, recursive traversal, pagination, and in-memory result caching. Two modes: a simple `GET` with query parameters, or an advanced `POST` with a full criteria body. Controlled by the feature flag **OXICLOUD_ENABLE_SEARCH** (default: `true`). ## Architecture | Layer | Component | File | |---|---|---| | Application Port | **SearchUseCase** trait | `src/application/ports/inbound.rs` | | Application Service | **SearchService** | `src/application/services/search_service.rs` | | Application DTOs | **SearchCriteriaDto**, **SearchResultsDto** | `src/application/dtos/search_dto.rs` | | Interfaces | **SearchHandler** | `src/interfaces/api/handlers/search_handler.rs` | ## Search Criteria ```rust pub struct SearchCriteriaDto { pub name_contains: Option, // text to search in file/folder names pub file_types: Option>, // extensions, e.g. ["pdf", "jpg"] pub created_after: Option, // epoch seconds pub created_before: Option, pub modified_after: Option, pub modified_before: Option, pub min_size: Option, // bytes pub max_size: Option, pub folder_id: Option, // scope to a specific folder pub recursive: bool, // default: true pub limit: usize, // default: 100 pub offset: usize, // default: 0 } ``` ## Search Results ```rust pub struct SearchResultsDto { pub files: Vec, pub folders: Vec, pub total_count: Option, pub limit: usize, pub offset: usize, pub has_more: bool, } ``` ## REST API Endpoints All routes under `/api/search`, require authentication. | Method | Path | Handler | Description | |---|---|---|---| | `GET` | `/api/search/` | `SearchHandler::search_files_get` | Simple search via query params | | `POST` | `/api/search/advanced` | `SearchHandler::search_files_post` | Advanced search via JSON body | | `DELETE` | `/api/search/cache` | `SearchHandler::clear_search_cache` | Clear the result cache | ### GET Query Parameters | Parameter | Type | Description | |---|---|---| | `query` | `String` | Text to search in names | | `type` | `String` | File extension filter (comma-separated) | | `created_after` | `u64` | Epoch seconds | | `created_before` | `u64` | Epoch seconds | | `modified_after` | `u64` | Epoch seconds | | `modified_before` | `u64` | Epoch seconds | | `min_size` | `u64` | Minimum size in bytes | | `max_size` | `u64` | Maximum size in bytes | | `folder_id` | `String` | Scope to folder | | `recursive` | `bool` | Recursive search (default: true) | | `limit` | `usize` | Max results (default: 100) | | `offset` | `usize` | Pagination offset | ### Example ```bash # Simple search curl -H "Authorization: Bearer $TOKEN" \ "https://oxicloud.example.com/api/search/?query=report&type=pdf&limit=20" # Advanced search curl -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"name_contains":"report","file_types":["pdf","docx"],"min_size":1024,"recursive":true,"limit":50}' \ "https://oxicloud.example.com/api/search/advanced" ``` ## Implementation Details ### Search Algorithm 1. If `folder_id` is provided, start from that folder. Otherwise start from root. 2. When `recursive` is true, traverse all subfolders depth-first via `search_recursive()`. 3. Files are filtered by name match, extension, date range, and size range. 4. Folders are filtered by name match and date range. 5. Results are paginated with `offset`/`limit`. ### Caching Results are cached in-memory using a hash of the search criteria + user ID as the key. - **Cache TTL**: 5 minutes (300 seconds) - **Max entries**: 1000 - **Cleanup**: background `tokio` task runs periodically, evicts expired entries - **Manual clear**: `DELETE /api/search/cache` ## DI Wiring ```rust // In di.rs — SearchService creation let search_service = SearchService::new( repos.file_read_repository.clone(), repos.folder_repository.clone(), 300, // cache TTL seconds 1000, // max cache entries ); ``` Stored in `AppState.applications.search_service: Option>`.