max / audiofiles
1 file changed,
+28 insertions,
-2 deletions
| @@ -6,6 +6,12 @@ use crate::id_types::{NodeId, VfsId}; | |||
| 6 | 6 | use crate::vfs::{self as vfs_mod, VfsNodeWithAnalysis}; | |
| 7 | 7 | use tracing::instrument; | |
| 8 | 8 | ||
| 9 | + | /// Maximum rows any single search returns. Bounds the result Vec (and the egui | |
| 10 | + | /// table that renders it) so a broad query against a huge library can't | |
| 11 | + | /// materialize the whole table on the GUI thread. Applies to both folder and | |
| 12 | + | /// global scope. A user who needs to narrow further types a more specific query. | |
| 13 | + | pub const SEARCH_RESULT_LIMIT: usize = 500; | |
| 14 | + | ||
| 9 | 15 | /// Search scope: current folder or global across all VFS roots. | |
| 10 | 16 | #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] | |
| 11 | 17 | pub enum SearchScope { | |
| @@ -161,7 +167,9 @@ pub fn search_in_folder( | |||
| 161 | 167 | ||
| 162 | 168 | append_filter_clauses(&mut sql, &mut params, filter); | |
| 163 | 169 | ||
| 164 | - | sql.push_str(" ORDER BY n.node_type ASC, n.name ASC"); | |
| 170 | + | sql.push_str(&format!( | |
| 171 | + | " ORDER BY n.node_type ASC, n.name ASC LIMIT {SEARCH_RESULT_LIMIT}" | |
| 172 | + | )); | |
| 165 | 173 | ||
| 166 | 174 | let mut stmt = db.conn().prepare(&sql)?; | |
| 167 | 175 | let param_refs: Vec<&dyn rusqlite::types::ToSql> = params.iter().map(|p| p.as_ref()).collect(); | |
| @@ -188,7 +196,9 @@ pub fn search_global( | |||
| 188 | 196 | ||
| 189 | 197 | append_filter_clauses(&mut sql, &mut params, filter); | |
| 190 | 198 | ||
| 191 | - | sql.push_str(" ORDER BY n.node_type ASC, n.name ASC LIMIT 500"); | |
| 199 | + | sql.push_str(&format!( | |
| 200 | + | " ORDER BY n.node_type ASC, n.name ASC LIMIT {SEARCH_RESULT_LIMIT}" | |
| 201 | + | )); | |
| 192 | 202 | ||
| 193 | 203 | let mut stmt = db.conn().prepare(&sql)?; | |
| 194 | 204 | let param_refs: Vec<&dyn rusqlite::types::ToSql> = params.iter().map(|p| p.as_ref()).collect(); | |
| @@ -375,6 +385,22 @@ mod tests { | |||
| 375 | 385 | (db, vfs_id) | |
| 376 | 386 | } | |
| 377 | 387 | ||
| 388 | + | #[test] | |
| 389 | + | fn folder_search_caps_at_result_limit() { | |
| 390 | + | let db = Database::open_in_memory().unwrap(); | |
| 391 | + | let vfs_id = vfs::create_vfs(&db, "Big").unwrap(); | |
| 392 | + | // Insert more matches than the cap allows. | |
| 393 | + | for i in 0..(SEARCH_RESULT_LIMIT + 50) { | |
| 394 | + | let hash = format!("h{i}"); | |
| 395 | + | insert_fake_sample(&db, &hash); | |
| 396 | + | vfs::create_sample_link(&db, vfs_id, None, &format!("kick_{i}.wav"), &hash).unwrap(); | |
| 397 | + | } | |
| 398 | + | let mut filter = SearchFilter::default(); | |
| 399 | + | filter.text_query = "kick".to_string(); | |
| 400 | + | let results = search_in_folder(&db, &filter, vfs_id, None).unwrap(); | |
| 401 | + | assert_eq!(results.len(), SEARCH_RESULT_LIMIT); | |
| 402 | + | } | |
| 403 | + | ||
| 378 | 404 | /// Set up a VFS with two analysed samples for filter tests. | |
| 379 | 405 | fn setup_with_analysis() -> (Database, VfsId) { | |
| 380 | 406 | let db = Database::open_in_memory().unwrap(); |