pub struct Database {
write: Mutex<Connection>,
read: Vec<Mutex<Connection>>,
read_deadlines: Vec<Arc<AtomicU64>>,
read_idx: AtomicUsize,
midi_library_total_cache: Mutex<Option<u64>>,
pdf_library_total_cache: Mutex<Option<u64>>,
audio_library_total_cache: Mutex<Option<u64>>,
preset_inventory_total_cache: Mutex<Option<u64>>,
daw_library_total_cache: Mutex<Option<u64>>,
plugin_library_total_cache: Mutex<Option<u64>>,
}Expand description
SQLite with WAL: multiple connections can serve read-heavy queries concurrently.
write is the only handle used for schema migrations and code paths that need the writer
mutex; never mix it into the read round-robin — doing so serialized every db_query_* IPC
with every other read/write on that mutex (spinners across tabs when one query held the slot).
read is a pool of read-only file handles; Database::read_conn round-robins only here
(always at least one after Database::open).
Fields§
§write: Mutex<Connection>§read: Vec<Mutex<Connection>>§read_deadlines: Vec<Arc<AtomicU64>>Per-slot query-start timestamp (epoch ms) for the progress-handler timeout.
read_idx: AtomicUsize§midi_library_total_cache: Mutex<Option<u64>>SELECT COUNT(*) FROM midi_library is O(rows); cache and invalidate on MIDI library writes.
pdf_library_total_cache: Mutex<Option<u64>>Same pattern as Self::midi_library_total_rows for pdf_library.
audio_library_total_cache: Mutex<Option<u64>>SELECT COUNT(*) FROM audio_library — invalidated on audio library writes.
preset_inventory_total_cache: Mutex<Option<u64>>Preset tab header: non-MIDI rows in library (query_presets / preset_filter_stats).
daw_library_total_cache: Mutex<Option<u64>>SELECT COUNT(*) FROM daw_library — invalidated on DAW library writes.
plugin_library_total_cache: Mutex<Option<u64>>SELECT COUNT(*) FROM plugin_library — invalidated on plugin library writes.
Implementations§
Source§impl Database
impl Database
Sourceconst SYNC_AUDIO_LIBRARY_PATHS_SQL: &'static str = r#"DELETE FROM audio_library WHERE path IN (SELECT path FROM _al_refresh_paths) AND path NOT IN (SELECT DISTINCT path FROM audio_samples);
INSERT OR REPLACE INTO audio_library (path, sample_id)
SELECT path, MAX(id) FROM audio_samples WHERE path IN (SELECT path FROM _al_refresh_paths) GROUP BY path;
DROP TABLE _al_refresh_paths;"#
const SYNC_AUDIO_LIBRARY_PATHS_SQL: &'static str = r#"DELETE FROM audio_library WHERE path IN (SELECT path FROM _al_refresh_paths) AND path NOT IN (SELECT DISTINCT path FROM audio_samples); INSERT OR REPLACE INTO audio_library (path, sample_id) SELECT path, MAX(id) FROM audio_samples WHERE path IN (SELECT path FROM _al_refresh_paths) GROUP BY path; DROP TABLE _al_refresh_paths;"#
SQL bodies for [sync_*_after_paths_refresh] (standalone: wrapped in BEGIN IMMEDIATE by
[exec_sync_paths_refresh]). For preset/midi/pdf flows already inside a
[Transaction], use [sync_preset_library_after_paths_refresh_tx] /
[sync_midi_library_after_paths_refresh_tx] /
[sync_pdf_library_after_paths_refresh_tx] via [exec_sync_paths_refresh_tx] — do not
nest another BEGIN (SQLite rejects it).
const SYNC_PDF_LIBRARY_PATHS_SQL: &'static str = r#"DELETE FROM pdf_library WHERE path IN (SELECT path FROM _pdf_lib_refresh_paths) AND path NOT IN (SELECT DISTINCT path FROM pdfs); INSERT OR REPLACE INTO pdf_library (path, pdf_id) SELECT path, MAX(id) FROM pdfs WHERE path IN (SELECT path FROM _pdf_lib_refresh_paths) GROUP BY path; DROP TABLE _pdf_lib_refresh_paths;"#
const SYNC_MIDI_LIBRARY_PATHS_SQL: &'static str = r#"DELETE FROM midi_library WHERE path IN (SELECT path FROM _midi_lib_refresh_paths) AND path NOT IN (SELECT DISTINCT path FROM midi_files); INSERT OR REPLACE INTO midi_library (path, midi_id) SELECT path, MAX(id) FROM midi_files WHERE path IN (SELECT path FROM _midi_lib_refresh_paths) GROUP BY path; DROP TABLE _midi_lib_refresh_paths;"#
const SYNC_PRESET_LIBRARY_PATHS_SQL: &'static str = r#"DELETE FROM preset_library WHERE path IN (SELECT path FROM _preset_lib_refresh_paths) AND path NOT IN (SELECT DISTINCT path FROM presets); INSERT OR REPLACE INTO preset_library (path, preset_id) SELECT path, MAX(id) FROM presets WHERE path IN (SELECT path FROM _preset_lib_refresh_paths) GROUP BY path; DROP TABLE _preset_lib_refresh_paths;"#
const SYNC_DAW_LIBRARY_PATHS_SQL: &'static str = r#"DELETE FROM daw_library WHERE path IN (SELECT path FROM _dl_refresh_paths) AND path NOT IN (SELECT DISTINCT path FROM daw_projects); INSERT OR REPLACE INTO daw_library (path, project_id) SELECT path, MAX(id) FROM daw_projects WHERE path IN (SELECT path FROM _dl_refresh_paths) GROUP BY path; DROP TABLE _dl_refresh_paths;"#
const SYNC_PLUGIN_LIBRARY_PATHS_SQL: &'static str = r#"DELETE FROM plugin_library WHERE path IN (SELECT path FROM _pl_refresh_paths) AND path NOT IN (SELECT DISTINCT path FROM plugins); INSERT OR REPLACE INTO plugin_library (path, plugin_id) SELECT path, MAX(id) FROM plugins WHERE path IN (SELECT path FROM _pl_refresh_paths) GROUP BY path; DROP TABLE _pl_refresh_paths;"#
Sourcefn read_pool_extra() -> usize
fn read_pool_extra() -> usize
User pref: additional read pool slots beyond the mandatory first reader (1 + this, min 1).
Sourcepub fn sqlite_read_pool_extra_slots(&self) -> usize
pub fn sqlite_read_pool_extra_slots(&self) -> usize
Count of read-pool connections (each participates in [read_conn] round-robin only).
Sourcepub fn sqlite_read_pool_total_handles(&self) -> usize
pub fn sqlite_read_pool_total_handles(&self) -> usize
Primary writer + read pool (1 + read.len() open file handles).
Sourcefn write_conn(&self) -> MutexGuard<'_, Connection>
fn write_conn(&self) -> MutexGuard<'_, Connection>
Exclusive writer — migrations, cache writes, and anything that should not compete with
Self::read_conn for the same Mutex.
Sourcefn read_conn(&self) -> MutexGuard<'_, Connection>
fn read_conn(&self) -> MutexGuard<'_, Connection>
Round-robin read pool only (never the primary write handle — see Database docs).
Resets the per-slot query-timeout deadline so the progress handler measures from now.
fn midi_library_total_rows(&self, conn: &Connection) -> Result<u64, String>
fn invalidate_midi_library_total_cache(&self)
fn pdf_library_total_rows(&self, conn: &Connection) -> Result<u64, String>
fn invalidate_pdf_library_total_cache(&self)
fn audio_library_total_rows(&self, conn: &Connection) -> Result<u64, String>
fn invalidate_audio_library_total_cache(&self)
fn preset_inventory_total_rows(&self, conn: &Connection) -> Result<u64, String>
fn invalidate_preset_inventory_total_cache(&self)
fn daw_library_total_rows(&self, conn: &Connection) -> Result<u64, String>
fn invalidate_daw_library_total_cache(&self)
fn plugin_library_total_rows(&self, conn: &Connection) -> Result<u64, String>
fn invalidate_plugin_library_total_cache(&self)
fn exec_sync_paths_refresh(conn: &Connection, sql: &str) -> Result<(), String>
fn exec_sync_paths_refresh_tx( tx: &Transaction<'_>, sql: &str, ) -> Result<(), String>
Sourcefn sync_audio_library_after_paths_refresh(
conn: &Connection,
) -> Result<(), String>
fn sync_audio_library_after_paths_refresh( conn: &Connection, ) -> Result<(), String>
_al_refresh_paths lists paths touched by removing audio_samples for a scan; those rows
must already be deleted. Reconciles audio_library with remaining audio_samples rows.
fn sync_pdf_library_after_paths_refresh(conn: &Connection) -> Result<(), String>
fn sync_pdf_library_after_paths_refresh_tx( tx: &Transaction<'_>, ) -> Result<(), String>
fn sync_midi_library_after_paths_refresh( conn: &Connection, ) -> Result<(), String>
fn sync_midi_library_after_paths_refresh_tx( tx: &Transaction<'_>, ) -> Result<(), String>
fn sync_preset_library_after_paths_refresh( conn: &Connection, ) -> Result<(), String>
fn sync_preset_library_after_paths_refresh_tx( tx: &Transaction<'_>, ) -> Result<(), String>
Sourcefn sync_daw_library_after_paths_refresh(conn: &Connection) -> Result<(), String>
fn sync_daw_library_after_paths_refresh(conn: &Connection) -> Result<(), String>
_dl_refresh_paths lists paths touched by removing daw_projects rows for a scan; those rows
must already be deleted. Reconciles daw_library with remaining daw_projects rows.
fn rebuild_daw_library(conn: &Connection) -> Result<(), String>
Sourcefn sync_plugin_library_after_paths_refresh(
conn: &Connection,
) -> Result<(), String>
fn sync_plugin_library_after_paths_refresh( conn: &Connection, ) -> Result<(), String>
_pl_refresh_paths lists paths touched by removing plugins rows for a scan; reconciles
plugin_library with remaining plugins rows (same pattern as sync_daw_library_after_paths_refresh).
fn rebuild_plugin_library(conn: &Connection) -> Result<(), String>
Sourcefn rebuild_pdf_midi_preset_daw_libraries(
conn: &mut Connection,
) -> Result<(), String>
fn rebuild_pdf_midi_preset_daw_libraries( conn: &mut Connection, ) -> Result<(), String>
Full rebuild after bulk deletes (e.g. prune_old_scans) where per-path sync is impractical.
One transaction: without it, each DELETE/INSERT autocommits separately — a crash or killed
process after DELETE FROM midi_library but before INSERT could leave *_library empty
while midi_files (etc.) still had rows.
Sourcepub fn housekeep_light(&self)
pub fn housekeep_light(&self)
Quick startup path: query planner refresh + cache touch. Safe from any thread; keep fast.
Sourcepub fn housekeep_heavy(&self)
pub fn housekeep_heavy(&self)
Expensive path: prune old scans (DELETE + full *_library rebuild) and optional VACUUM.
Run well after the window and setup() have finished so pooled read_conn() scopes are
not held across first-frame IPC (long prune batches still contend on SQLite + pool slots).
fn prune_old_scans_pref_enabled() -> bool
Sourcefn prune_old_scans_keep_pref() -> usize
fn prune_old_scans_keep_pref() -> usize
[performance] → pruneOldScansKeep (default 3, clamped 1..=100).
Sourcepub fn housekeep(&self)
pub fn housekeep(&self)
Full sequence (manual / tests). Startup uses Self::housekeep_light + delayed Self::housekeep_heavy.
Sourcepub fn prune_old_scans(&self, keep: usize)
pub fn prune_old_scans(&self, keep: usize)
Prune old scans — keep only the N most recent complete scans per type. Incomplete (user-stopped) runs are retained until superseded or cleared so library rows stay addressable.
Sourcepub fn set_audio_scan_complete(
&self,
id: &str,
complete: bool,
) -> Result<(), String>
pub fn set_audio_scan_complete( &self, id: &str, complete: bool, ) -> Result<(), String>
Mark whether a streaming scan finished normally (complete) or was user-stopped (partial).
pub fn set_plugin_scan_complete( &self, id: &str, complete: bool, ) -> Result<(), String>
pub fn set_daw_scan_complete( &self, id: &str, complete: bool, ) -> Result<(), String>
pub fn set_preset_scan_complete( &self, id: &str, complete: bool, ) -> Result<(), String>
pub fn set_midi_scan_complete( &self, id: &str, complete: bool, ) -> Result<(), String>
pub fn set_pdf_scan_complete( &self, id: &str, complete: bool, ) -> Result<(), String>
Sourcepub fn prewarm(&self)
pub fn prewarm(&self)
Checkpoint WAL to merge it into the main DB file. Keeps WAL small. Warm the page cache by touching each table + FTS index root. First real query returns ~1 ms instead of the 50-200 ms cold-cache penalty.
pub fn checkpoint(&self)
Sourcepub fn get_app_strings(
&self,
locale: &str,
) -> Result<HashMap<String, String>, String>
pub fn get_app_strings( &self, locale: &str, ) -> Result<HashMap<String, String>, String>
Resolved app UI strings for the given locale (merged with English fallback).
Sourcepub fn get_toast_strings(
&self,
locale: &str,
) -> Result<HashMap<String, String>, String>
pub fn get_toast_strings( &self, locale: &str, ) -> Result<HashMap<String, String>, String>
Alias for Self::get_app_strings (legacy command name).
Sourcepub fn vacuum_if_needed(&self)
pub fn vacuum_if_needed(&self)
VACUUM if >20% of pages are free (dead space from deleted rows).
Sourcefn migrate_plugin_paths_canonical(conn: &Connection) -> Result<(), String>
fn migrate_plugin_paths_canonical(conn: &Connection) -> Result<(), String>
One-time migration: normalize plugins.path and plugin_scans directories/roots JSON to
normalize_path_for_db form; remove duplicate (canonical path, scan_id) rows (keep max id).
Sourcepub fn audio_scan_parent_create(
&self,
id: &str,
timestamp: &str,
roots: &[String],
) -> Result<(), String>
pub fn audio_scan_parent_create( &self, id: &str, timestamp: &str, roots: &[String], ) -> Result<(), String>
Insert a batch of audio samples in a single transaction.
pub fn audio_scan_parent_finalize( &self, id: &str, _sample_count: u64, _total_bytes: u64, _format_counts: &HashMap<String, usize>, ) -> Result<(), String>
pub fn insert_audio_batch( &self, scan_id: &str, samples: &[AudioSample], ) -> Result<u64, String>
Sourcepub fn save_scan(
&self,
id: &str,
timestamp: &str,
sample_count: u64,
total_bytes: u64,
format_counts: &HashMap<String, usize>,
roots: &[String],
) -> Result<(), String>
pub fn save_scan( &self, id: &str, timestamp: &str, sample_count: u64, total_bytes: u64, format_counts: &HashMap<String, usize>, roots: &[String], ) -> Result<(), String>
Save scan metadata.
Sourcefn audio_fts_bounded_count_scan(
conn: &Connection,
fts_match: &str,
scan_id: &str,
) -> Result<(u64, bool), String>
fn audio_fts_bounded_count_scan( conn: &Connection, fts_match: &str, scan_id: &str, ) -> Result<(u64, bool), String>
Bounded FTS hit count for one scan (audio_samples_fts.scan_id).
Sourcefn audio_fts_bounded_count_library(
conn: &Connection,
fts_match: &str,
format_filter: Option<&str>,
) -> Result<(u64, bool), String>
fn audio_fts_bounded_count_library( conn: &Connection, fts_match: &str, format_filter: Option<&str>, ) -> Result<(u64, bool), String>
Bounded FTS hit count for library scope (same format_filter rules as Self::query_audio).
Sourcefn preset_fts_bounded_count_library(
conn: &Connection,
fts_match: &str,
format_filter: Option<&str>,
) -> Result<(u64, bool), String>
fn preset_fts_bounded_count_library( conn: &Connection, fts_match: &str, format_filter: Option<&str>, ) -> Result<(u64, bool), String>
Bounded FTS hit count for presets library (non-MIDI formats only; matches Self::query_presets).
Sourcefn midi_fts_bounded_count_library(
conn: &Connection,
fts_match: &str,
format_filter: Option<&str>,
) -> Result<(u64, bool), String>
fn midi_fts_bounded_count_library( conn: &Connection, fts_match: &str, format_filter: Option<&str>, ) -> Result<(u64, bool), String>
Bounded FTS hit count for MIDI library (same format_filter rules as Self::query_midi).
Sourcefn pdf_fts_bounded_count_library(
conn: &Connection,
fts_match: &str,
) -> Result<(u64, bool), String>
fn pdf_fts_bounded_count_library( conn: &Connection, fts_match: &str, ) -> Result<(u64, bool), String>
Bounded FTS hit count for PDF library (Self::query_pdfs has no format filter).
Sourcefn daw_fts_bounded_count_library(
conn: &Connection,
fts_match: &str,
daw_filter: Option<&str>,
) -> Result<(u64, bool), String>
fn daw_fts_bounded_count_library( conn: &Connection, fts_match: &str, daw_filter: Option<&str>, ) -> Result<(u64, bool), String>
Bounded FTS hit count for DAW project library (Self::query_daw daw_filter rules).
Sourcefn plugin_search_bounded_count_library(
conn: &Connection,
from_sql: &str,
where_cl: &str,
regex_pat: &Option<String>,
like_pat: &Option<String>,
type_filter: Option<&str>,
) -> Result<(u64, bool), String>
fn plugin_search_bounded_count_library( conn: &Connection, from_sql: &str, where_cl: &str, regex_pat: &Option<String>, like_pat: &Option<String>, type_filter: Option<&str>, ) -> Result<(u64, bool), String>
Bounded COUNT for plugin tab search (LIKE / REGEXP; no FTS). Same cap as inventory FTS paths.
Sourcepub fn query_audio(
&self,
params: &AudioQueryParams,
) -> Result<AudioQueryResult, String>
pub fn query_audio( &self, params: &AudioQueryParams, ) -> Result<AudioQueryResult, String>
Paginated, sortable, filterable query for audio samples.
scan_id Some(non-empty) → rows for that scan only (history detail).
scan_id None or empty → library mode: all rows across scans, deduped by path
(MAX(id) per path).
Sourcepub fn audio_stats(
&self,
scan_id: Option<&str>,
) -> Result<AudioStatsResult, String>
pub fn audio_stats( &self, scan_id: Option<&str>, ) -> Result<AudioStatsResult, String>
Get aggregate stats. scan_id None or empty → full library (deduped by path). Otherwise that scan only.
Sourcepub fn daw_stats(&self, scan_id: Option<&str>) -> Result<DawStatsResult, String>
pub fn daw_stats(&self, scan_id: Option<&str>) -> Result<DawStatsResult, String>
DAW aggregate stats. scan_id None or empty → full library (deduped by path).
Sourcepub fn preset_stats(
&self,
scan_id: Option<&str>,
) -> Result<PresetStatsResult, String>
pub fn preset_stats( &self, scan_id: Option<&str>, ) -> Result<PresetStatsResult, String>
Preset aggregate stats. scan_id None or empty → full library (deduped by path). MIDI excluded.
Sourcepub fn update_bpm(&self, path: &str, bpm: Option<f64>) -> Result<(), String>
pub fn update_bpm(&self, path: &str, bpm: Option<f64>) -> Result<(), String>
Update BPM for a sample (all rows for that path).
Sourcepub fn update_key(&self, path: &str, key: Option<&str>) -> Result<(), String>
pub fn update_key(&self, path: &str, key: Option<&str>) -> Result<(), String>
Update musical key for a sample.
Sourcepub fn update_audio_meta(
&self,
path: &str,
duration: Option<f64>,
channels: Option<u16>,
sample_rate: Option<u32>,
bits_per_sample: Option<u16>,
) -> Result<(), String>
pub fn update_audio_meta( &self, path: &str, duration: Option<f64>, channels: Option<u16>, sample_rate: Option<u32>, bits_per_sample: Option<u16>, ) -> Result<(), String>
Update core audio metadata (duration, channels, sample_rate, bits_per_sample) for a sample.
Sourcepub fn paths_missing_audio_meta(
&self,
paths: &[String],
) -> Result<Vec<String>, String>
pub fn paths_missing_audio_meta( &self, paths: &[String], ) -> Result<Vec<String>, String>
Get paths that are missing duration metadata (among the given paths).
Sourcepub fn update_lufs(&self, path: &str, lufs: Option<f64>) -> Result<(), String>
pub fn update_lufs(&self, path: &str, lufs: Option<f64>) -> Result<(), String>
Update LUFS for a sample (all rows for that path).
Sourcepub fn get_analysis(&self, path: &str) -> Result<Value, String>
pub fn get_analysis(&self, path: &str) -> Result<Value, String>
Get analysis data for a single sample.
Sourcepub fn unanalyzed_paths(&self, limit: u64) -> Result<Vec<String>, String>
pub fn unanalyzed_paths(&self, limit: u64) -> Result<Vec<String>, String>
Get paths of samples that still need BPM/Key/LUFS analysis (library rows).
Rows where key and LUFS are filled but BPM is still NULL after a batch run are marked
bpm_exhausted so we do not spin on the same paths forever
when tempo detection fails. Clearing the BPM cache resets bpm_exhausted so analysis can retry.
Sourcepub fn audio_library_paths(&self) -> Result<Vec<String>, String>
pub fn audio_library_paths(&self) -> Result<Vec<String>, String>
All canonical path values in the audio library (one row per path via audio_library).
pub fn query_plugins( &self, search: Option<&str>, type_filter: Option<&str>, status_filter: Option<&str>, sort_key: &str, sort_asc: bool, search_regex: bool, offset: u64, limit: u64, ) -> Result<PluginQueryResult, String>
Sourcepub fn query_daw(
&self,
search: Option<&str>,
daw_filter: Option<&str>,
sort_key: &str,
sort_asc: bool,
search_regex: bool,
offset: u64,
limit: u64,
) -> Result<DawQueryResult, String>
pub fn query_daw( &self, search: Option<&str>, daw_filter: Option<&str>, sort_key: &str, sort_asc: bool, search_regex: bool, offset: u64, limit: u64, ) -> Result<DawQueryResult, String>
Full library (deduped by path). Same pattern as query_audio without scan_id.
pub fn query_presets( &self, search: Option<&str>, format_filter: Option<&str>, sort_key: &str, sort_asc: bool, search_regex: bool, offset: u64, limit: u64, ) -> Result<PresetQueryResult, String>
pub fn save_plugin_scan(&self, snap: &ScanSnapshot) -> Result<(), String>
Sourcepub fn plugin_scan_parent_create(
&self,
id: &str,
timestamp: &str,
roots: &[String],
) -> Result<(), String>
pub fn plugin_scan_parent_create( &self, id: &str, timestamp: &str, roots: &[String], ) -> Result<(), String>
Begin a streaming plugin scan: parent row + clear prior rows for this id.
Sourcepub fn insert_plugin_batch(
&self,
scan_id: &str,
batch: &[PluginInfo],
) -> Result<u64, String>
pub fn insert_plugin_batch( &self, scan_id: &str, batch: &[PluginInfo], ) -> Result<u64, String>
Append plugins for a streaming scan; updates plugin_scans.plugin_count incrementally.
Sourcepub fn plugin_scan_parent_finalize(
&self,
id: &str,
_plugin_count: usize,
directories: &[String],
roots: &[String],
) -> Result<(), String>
pub fn plugin_scan_parent_finalize( &self, id: &str, _plugin_count: usize, directories: &[String], roots: &[String], ) -> Result<(), String>
Finalize directory list and counts after streaming inserts (matches non-streaming snapshot shape).
pub fn get_plugin_scans(&self) -> Result<Vec<Value>, String>
pub fn get_plugin_scan_detail(&self, id: &str) -> Result<ScanSnapshot, String>
pub fn get_latest_plugin_scan(&self) -> Result<Option<ScanSnapshot>, String>
pub fn delete_plugin_scan(&self, id: &str) -> Result<(), String>
pub fn clear_plugin_history(&self) -> Result<(), String>
pub fn save_audio_scan_full( &self, snap: &AudioScanSnapshot, ) -> Result<(), String>
pub fn get_audio_scans_list(&self) -> Result<Vec<Value>, String>
pub fn get_audio_scan_detail( &self, id: &str, ) -> Result<AudioScanSnapshot, String>
pub fn get_latest_audio_scan(&self) -> Result<Option<AudioScanSnapshot>, String>
pub fn delete_audio_scan(&self, id: &str) -> Result<(), String>
pub fn clear_audio_history(&self) -> Result<(), String>
Sourcepub fn daw_scan_parent_create(
&self,
id: &str,
timestamp: &str,
roots: &[String],
) -> Result<(), String>
pub fn daw_scan_parent_create( &self, id: &str, timestamp: &str, roots: &[String], ) -> Result<(), String>
Create (or re-create) a parent daw_scans row with zero counts. Used by streaming scans that don’t know totals up front.
Sourcepub fn daw_scan_parent_finalize(
&self,
id: &str,
_project_count: usize,
_total_bytes: u64,
_daw_counts: &HashMap<String, usize>,
) -> Result<(), String>
pub fn daw_scan_parent_finalize( &self, id: &str, _project_count: usize, _total_bytes: u64, _daw_counts: &HashMap<String, usize>, ) -> Result<(), String>
Finalize a parent daw_scans row with aggregate counts after streaming is complete.
Sourcepub fn insert_daw_batch(
&self,
scan_id: &str,
projects: &[DawProject],
) -> Result<Vec<usize>, String>
pub fn insert_daw_batch( &self, scan_id: &str, projects: &[DawProject], ) -> Result<Vec<usize>, String>
Stream-insert a batch of DawProject rows under an existing scan_id.
pub fn save_daw_scan(&self, snap: &DawScanSnapshot) -> Result<(), String>
pub fn get_daw_scans(&self) -> Result<Vec<Value>, String>
pub fn get_daw_scan_detail(&self, id: &str) -> Result<DawScanSnapshot, String>
pub fn get_latest_daw_scan(&self) -> Result<Option<DawScanSnapshot>, String>
pub fn delete_daw_scan(&self, id: &str) -> Result<(), String>
pub fn clear_daw_history(&self) -> Result<(), String>
pub fn preset_scan_parent_create( &self, id: &str, timestamp: &str, roots: &[String], ) -> Result<(), String>
pub fn preset_scan_parent_finalize( &self, id: &str, _preset_count: usize, _total_bytes: u64, _format_counts: &HashMap<String, usize>, ) -> Result<(), String>
pub fn insert_preset_batch( &self, scan_id: &str, presets: &[PresetFile], ) -> Result<u64, String>
pub fn save_preset_scan(&self, snap: &PresetScanSnapshot) -> Result<(), String>
pub fn get_preset_scans(&self) -> Result<Vec<Value>, String>
pub fn get_preset_scan_detail( &self, id: &str, ) -> Result<PresetScanSnapshot, String>
pub fn get_latest_preset_scan( &self, ) -> Result<Option<PresetScanSnapshot>, String>
pub fn delete_preset_scan(&self, id: &str) -> Result<(), String>
pub fn clear_preset_history(&self) -> Result<(), String>
pub fn midi_scan_parent_create( &self, id: &str, timestamp: &str, roots: &[String], ) -> Result<(), String>
pub fn midi_scan_parent_finalize( &self, id: &str, _midi_count: usize, _total_bytes: u64, _format_counts: &HashMap<String, usize>, ) -> Result<(), String>
pub fn insert_midi_batch( &self, scan_id: &str, midi_files: &[MidiFile], ) -> Result<(), String>
pub fn save_midi_scan(&self, snap: &MidiScanSnapshot) -> Result<(), String>
pub fn get_midi_scans(&self) -> Result<Vec<Value>, String>
pub fn get_midi_scan_detail(&self, id: &str) -> Result<MidiScanSnapshot, String>
pub fn get_latest_midi_scan(&self) -> Result<Option<MidiScanSnapshot>, String>
pub fn delete_midi_scan(&self, id: &str) -> Result<(), String>
pub fn clear_midi_history(&self) -> Result<(), String>
pub fn query_midi( &self, search: Option<&str>, format_filter: Option<&str>, sort_key: &str, sort_asc: bool, search_regex: bool, offset: u64, limit: u64, ) -> Result<MidiQueryResult, String>
pub fn midi_filter_stats( &self, search: Option<&str>, format_filter: Option<&str>, search_regex: bool, ) -> Result<FilterStatsResult, String>
pub fn pdf_scan_parent_create( &self, id: &str, timestamp: &str, roots: &[String], ) -> Result<(), String>
pub fn pdf_scan_parent_finalize( &self, id: &str, _pdf_count: usize, _total_bytes: u64, ) -> Result<(), String>
pub fn insert_pdf_batch( &self, scan_id: &str, pdfs: &[PdfFile], ) -> Result<u64, String>
Sourcepub fn load_directory_scan_snapshot(
&self,
domain: &str,
) -> Result<HashMap<String, i64>, String>
pub fn load_directory_scan_snapshot( &self, domain: &str, ) -> Result<HashMap<String, i64>, String>
Load stored directory mtimes for a domain (e.g. "unified").
pub fn upsert_directory_scan_batch( &self, domain: &str, rows: &[(String, i64)], last_scan_id: Option<&str>, ) -> Result<(), String>
Sourcepub fn delete_directory_scan_state_domain(
&self,
domain: &str,
) -> Result<u64, String>
pub fn delete_directory_scan_state_domain( &self, domain: &str, ) -> Result<u64, String>
Remove all incremental directory rows for a domain (e.g. "unified").
Sourcepub fn unified_scan_incremental_snapshot_is_trusted(
&self,
) -> Result<bool, String>
pub fn unified_scan_incremental_snapshot_is_trusted( &self, ) -> Result<bool, String>
True when the last persisted unified scan finished successfully; incremental mtime snapshots are only trusted in that case.
pub fn unified_scan_run_start( &self, run_id: &str, started_at: &str, audio_scan_id: &str, daw_scan_id: &str, preset_scan_id: &str, pdf_scan_id: &str, roots_json: &str, ) -> Result<(), String>
Sourcepub fn unified_scan_run_finish(
&self,
finished_at: &str,
outcome: &str,
error_message: Option<&str>,
last_directory_path: Option<&str>,
) -> Result<(), String>
pub fn unified_scan_run_finish( &self, finished_at: &str, outcome: &str, error_message: Option<&str>, last_directory_path: Option<&str>, ) -> Result<(), String>
Persists final unified scan outcome. When outcome is not complete, clears incremental
directory_scan_state rows for domain "unified" so partial walks are not reused.
pub fn get_unified_scan_run(&self) -> Result<UnifiedScanRunRow, String>
pub fn save_pdf_scan(&self, snap: &PdfScanSnapshot) -> Result<(), String>
pub fn get_pdf_scans(&self) -> Result<Vec<Value>, String>
pub fn get_pdf_scan_detail(&self, id: &str) -> Result<PdfScanSnapshot, String>
pub fn get_latest_pdf_scan(&self) -> Result<Option<PdfScanSnapshot>, String>
pub fn delete_pdf_scan(&self, id: &str) -> Result<(), String>
pub fn clear_pdf_history(&self) -> Result<(), String>
Sourcepub fn unindexed_pdf_paths(&self, limit: u64) -> Result<Vec<String>, String>
pub fn unindexed_pdf_paths(&self, limit: u64) -> Result<Vec<String>, String>
Paths in the materialized PDF library (newest row per filesystem path) that have no
pdf_metadata row yet. Uses pdf_library, not “latest scan only”, so PDFs whose
canonical pdfs row belongs to an older completed scan are still queued for page counts.
Sourcepub fn save_pdf_metadata(
&self,
batch: &[(String, Option<u32>)],
) -> Result<(), String>
pub fn save_pdf_metadata( &self, batch: &[(String, Option<u32>)], ) -> Result<(), String>
Batch upsert PDF page counts. Entries with None page count are still inserted (as a negative marker) so we don’t re-attempt broken files.
Sourcepub fn get_pdf_metadata(
&self,
paths: &[String],
) -> Result<HashMap<String, Option<u32>>, String>
pub fn get_pdf_metadata( &self, paths: &[String], ) -> Result<HashMap<String, Option<u32>>, String>
Get page counts for a set of paths (returns only entries that exist).
pub fn clear_pdf_metadata(&self) -> Result<(), String>
pub fn query_pdfs( &self, search: Option<&str>, sort_key: &str, sort_asc: bool, search_regex: bool, offset: u64, limit: u64, ) -> Result<PdfQueryResult, String>
Sourcepub fn pdf_stats(&self, scan_id: Option<&str>) -> Result<PdfStatsResult, String>
pub fn pdf_stats(&self, scan_id: Option<&str>) -> Result<PdfStatsResult, String>
PDF aggregate stats. scan_id None or empty → full library (deduped by path).
fn in_list_sql(values: &str) -> String
Sourcefn heatmap_audio_folder_key(dir: &str) -> String
fn heatmap_audio_folder_key(dir: &str) -> String
First three path segments of directory, matching heatmap-dashboard.js buildFolderCard.
Sourcefn audio_heatmap_aggregates(
conn: &Connection,
where_cl: &str,
fts_match: &Option<String>,
regex_pat: &Option<String>,
like_pat: &Option<String>,
format_filter: Option<&str>,
) -> Result<(Vec<u64>, u64, HashMap<String, u64>, u64, Vec<TopFolderRow>), String>
fn audio_heatmap_aggregates( conn: &Connection, where_cl: &str, fts_match: &Option<String>, regex_pat: &Option<String>, like_pat: &Option<String>, format_filter: Option<&str>, ) -> Result<(Vec<u64>, u64, HashMap<String, u64>, u64, Vec<TopFolderRow>), String>
BPM/key/folder aggregates for the heatmap dashboard (same where_cl as audio_filter_stats).
pub fn audio_filter_stats( &self, search: Option<&str>, format_filter: Option<&str>, search_regex: bool, ) -> Result<FilterStatsResult, String>
pub fn daw_filter_stats( &self, search: Option<&str>, daw_filter: Option<&str>, search_regex: bool, ) -> Result<FilterStatsResult, String>
pub fn preset_filter_stats( &self, search: Option<&str>, format_filter: Option<&str>, search_regex: bool, ) -> Result<FilterStatsResult, String>
pub fn plugin_filter_stats( &self, search: Option<&str>, type_filter: Option<&str>, search_regex: bool, ) -> Result<FilterStatsResult, String>
pub fn pdf_filter_stats( &self, search: Option<&str>, search_regex: bool, ) -> Result<FilterStatsResult, String>
pub fn load_kvr_cache(&self) -> Result<HashMap<String, KvrCacheEntry>, String>
pub fn update_kvr_cache( &self, entries: &[KvrCacheUpdateEntry], ) -> Result<(), String>
pub fn read_cache(&self, name: &str) -> Result<Value, String>
pub fn write_cache(&self, name: &str, data: &Value) -> Result<(), String>
fn read_analysis_as_cache(&self, field: &str) -> Result<Value, String>
fn write_analysis_from_cache( &self, data: &Value, field: &str, ) -> Result<(), String>
fn read_kv_cache(&self, name: &str) -> Result<Value, String>
fn write_kv_cache(&self, name: &str, data: &Value) -> Result<(), String>
Sourcepub fn table_counts(&self) -> Result<Value, String>
pub fn table_counts(&self) -> Result<Value, String>
Get row counts for all tables.
Sourcepub fn active_scan_inventory_counts(&self) -> Result<Value, String>
pub fn active_scan_inventory_counts(&self) -> Result<Value, String>
Row counts per inventory category for the library view: one canonical row per path.
Audio uses audio_library (v14); DAW uses daw_library (v16); PDF, MIDI, and presets use
pdf_library, midi_library, and preset_library (v15); plugins use plugin_library (v17).
Not scoped to a single scan_id. Presets exclude MID/MIDI (same tab rules as elsewhere).
Matches default scan_id handling on paginated queries and *_filter_stats, not raw
COUNT(*) on whole tables.
Sourcepub fn library_paths_for_content_hash(
&self,
) -> Result<Vec<(String, u64, String)>, String>
pub fn library_paths_for_content_hash( &self, ) -> Result<Vec<(String, u64, String)>, String>
All library paths with byte sizes for content-hash duplicate detection.
Uses the same per-domain library rules as Database::active_scan_inventory_counts.
Sourcepub fn cache_stats(&self) -> Result<Vec<CacheStat>, String>
pub fn cache_stats(&self) -> Result<Vec<CacheStat>, String>
Get stats for all caches: item count and estimated size.
Uses the primary write connection (not the read pool). Read-pool handles install a
SQLITE_QUERY_TIMEOUT_SECS progress-handler budget per acquisition; cache_stats runs
many sequential full-table COUNTs and dbstat passes — cumulative time exceeded 30s on
large libraries and surfaced as an empty/error cache table in Settings.
Sourcepub fn batch_update_analysis(
&self,
results: &[AnalysisBatchRow],
) -> Result<u32, String>
pub fn batch_update_analysis( &self, results: &[AnalysisBatchRow], ) -> Result<u32, String>
Batch update BPM/Key/LUFS for multiple files in a single transaction.
Returns the sum of sqlite3_changes() for each UPDATE (rows modified), not the
number of input paths — a path matching multiple audio_samples rows updates all of them.
Sourcepub fn clear_cache_table(&self, table: &str) -> Result<(), String>
pub fn clear_cache_table(&self, table: &str) -> Result<(), String>
Clear a specific cache table.
Sourcepub fn clear_all_caches(&self) -> Result<(), String>
pub fn clear_all_caches(&self) -> Result<(), String>
Clear all analysis and cache data from SQLite.
fn cache_table_for(&self, name: &str) -> (&str, &str, &str)
Sourcepub fn migrate_from_json(&self) -> Result<usize, String>
pub fn migrate_from_json(&self) -> Result<usize, String>
One-time migration of ALL JSON history/cache files to SQLite.
fn migrate_audio_json(&self, data_dir: &Path) -> Result<usize, String>
fn migrate_plugin_json(&self, data_dir: &Path) -> Result<usize, String>
fn migrate_daw_json(&self, data_dir: &Path) -> Result<usize, String>
fn migrate_preset_json(&self, data_dir: &Path) -> Result<usize, String>
fn migrate_kvr_json(&self, data_dir: &Path) -> Result<usize, String>
Sourcefn migrate_kv_cache(
&self,
data_dir: &Path,
filename: &str,
table: &str,
key_col: &str,
val_col: &str,
) -> Result<usize, String>
fn migrate_kv_cache( &self, data_dir: &Path, filename: &str, table: &str, key_col: &str, val_col: &str, ) -> Result<usize, String>
Generic key→value JSON cache migration (xref, waveform, spectrogram, fingerprint).
fn migrate_analysis_cache( &self, data_dir: &Path, filename: &str, field: &str, ) -> Result<(), String>
Auto Trait Implementations§
impl !Freeze for Database
impl RefUnwindSafe for Database
impl Send for Database
impl Sync for Database
impl Unpin for Database
impl UnwindSafe for Database
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more