pub struct Db<M = ReadWrite> { /* private fields */ }Expand description
A SQLite connection whose mode parameter says whether write APIs resolve.
Read methods are available in both modes; write methods only on
Db<ReadWrite> (the default, so Db spelled bare means writable):
let db = musefs_db::Db::open_in_memory().unwrap().into_read_only();
db.data_version().unwrap();let db = musefs_db::Db::open_in_memory().unwrap().into_read_only();
db.upsert_track(unimplemented!());Implementations§
Source§impl<M> Db<M>
impl<M> Db<M>
pub fn get_art(&self, id: i64) -> Result<Option<Art>>
Sourcepub fn get_art_meta(&self, id: i64) -> Result<Option<ArtMeta>>
pub fn get_art_meta(&self, id: i64) -> Result<Option<ArtMeta>>
Art row metadata without loading the image blob — used to build synthesis inputs at resolve time without materializing art in memory.
Sourcepub fn read_art_chunk_into(
&self,
art_id: i64,
offset: u64,
buf: &mut [u8],
) -> Result<()>
pub fn read_art_chunk_into( &self, art_id: i64, offset: u64, buf: &mut [u8], ) -> Result<()>
Stream art-blob bytes at offset directly into buf via SQLite incremental
blob I/O — no intermediate allocation (#70). A short read means the row no
longer matches the layout; read_at_exact surfaces that as an error rather
than silently zero-filling.
Sourcepub fn read_art_chunk(
&self,
art_id: i64,
offset: u64,
len: usize,
) -> Result<Vec<u8>>
pub fn read_art_chunk( &self, art_id: i64, offset: u64, len: usize, ) -> Result<Vec<u8>>
Allocating convenience form of read_art_chunk_into (non-hot-path callers).
pub fn get_track_art(&self, track_id: i64) -> Result<Vec<TrackArt>>
Sourcepub fn get_track_art_with_meta(
&self,
track_id: i64,
) -> Result<Vec<(TrackArt, Option<ArtMeta>)>>
pub fn get_track_art_with_meta( &self, track_id: i64, ) -> Result<Vec<(TrackArt, Option<ArtMeta>)>>
A track’s track_art links joined with their art row metadata (no
image blob), in one query — collapses the former N+1 (get_track_art
plus one get_art_meta per row) on the resolve hot path. The art side
is None for an orphaned link: SQLite FK enforcement is per-connection,
so an external writer can leave a track_art row dangling, and the
caller surfaces that rather than silently dropping the art.
Source§impl Db<ReadWrite>
impl Db<ReadWrite>
pub fn upsert_art(&self, a: &NewArt) -> Result<i64>
pub fn set_track_art(&self, track_id: i64, items: &[TrackArt]) -> Result<()>
Sourcepub fn gc_orphan_art(&self) -> Result<usize>
pub fn gc_orphan_art(&self) -> Result<usize>
Delete art rows no longer referenced by any track_art. Returns the
number of rows removed.
Uses NOT EXISTS rather than NOT IN (subquery): SQLite’s NOT IN
evaluates to UNKNOWN for the whole row if any subquery value is NULL,
which would silently delete nothing should a NULL art_id ever reach
track_art (#507). NOT EXISTS is NULL-safe.
Source§impl Db<ReadWrite>
impl Db<ReadWrite>
Sourcepub fn apply_bulk_pragmas_self(&self) -> Result<()>
pub fn apply_bulk_pragmas_self(&self) -> Result<()>
Apply bulk pragmas to this DB’s own connection.
Sourcepub fn bulk_writer(&self) -> Result<BulkWriter<'_>>
pub fn bulk_writer(&self) -> Result<BulkWriter<'_>>
Begin a batch transaction. All writes go through the returned handle and
land atomically on commit().
Source§impl Db<ReadWrite>
impl Db<ReadWrite>
Sourcepub fn vacuum(&self) -> Result<()>
pub fn vacuum(&self) -> Result<()>
Compact the store: reclaim free pages left by deletions, then truncate
the WAL. Runs a full VACUUM (rewrites the whole database — transiently
needs free disk roughly equal to the store size) followed by
PRAGMA wal_checkpoint(TRUNCATE). The TRUNCATE checkpoint after VACUUM
is what actually shrinks the main .db file on disk and zeroes the
-wal. A busy/locked store (e.g. a live mount) maps to
DbError::StoreInUse.
Source§impl<M> Db<M>
impl<M> Db<M>
Sourcepub fn track_ids_with_structural_blocks(&self) -> Result<HashSet<i64>>
pub fn track_ids_with_structural_blocks(&self) -> Result<HashSet<i64>>
Track ids that have at least one structural block row. Used by revalidate
to detect legacy FLAC tracks (scanned under V1) that still need a backfill.
Sourcepub fn get_structural_blocks(
&self,
track_id: i64,
) -> Result<Vec<StructuralBlock>>
pub fn get_structural_blocks( &self, track_id: i64, ) -> Result<Vec<StructuralBlock>>
Structural blocks for a track, ordered by (kind, ordinal). Empty when a FLAC track has not been (re)scanned under V2 — callers fall back to a front read in that case.
Source§impl Db<ReadWrite>
impl Db<ReadWrite>
Sourcepub fn set_structural_blocks(
&self,
track_id: i64,
blocks: &[StructuralBlock],
) -> Result<()>
pub fn set_structural_blocks( &self, track_id: i64, blocks: &[StructuralBlock], ) -> Result<()>
Replace the track’s structural blocks (FLAC STREAMINFO/SEEKTABLE).
Source§impl<M> Db<M>
impl<M> Db<M>
Binary tag rows for a track: streaming handle (rowid), key, and payload
length. Ordered by (key, ordinal) to match the layout builder’s emission
order. The blob bytes stream at read time; only key (materialized here)
is length-guarded, plus the per-track row count.
Sourcepub fn read_binary_tag_chunk_into(
&self,
payload_id: i64,
offset: u64,
buf: &mut [u8],
) -> Result<()>
pub fn read_binary_tag_chunk_into( &self, payload_id: i64, offset: u64, buf: &mut [u8], ) -> Result<()>
Stream binary-tag bytes at offset directly into buf via incremental blob
I/O — no intermediate allocation (#70). A short read means the row changed
underneath the resolved layout; read_at_exact surfaces it as an error rather
than zero-filling. (payload_id is the tags rowid; see the spec’s
“payload_id validity invariant”.)
Source§impl Db<ReadWrite>
impl Db<ReadWrite>
Replace the track’s binary tag rows (value_blob IS NOT NULL); text rows
(managed by replace_tags) are untouched. Binary rows store ‘’ in value.
Source§impl<M> Db<M>
impl<M> Db<M>
pub fn get_track(&self, id: i64) -> Result<Option<Track>>
pub fn get_track_by_path(&self, path: &str) -> Result<Option<Track>>
pub fn list_tracks(&self) -> Result<Vec<Track>>
pub fn track_content_version(&self, id: i64) -> Result<i64>
Sourcepub fn track_version_and_path(&self, id: i64) -> Result<Option<(i64, String)>>
pub fn track_version_and_path(&self, id: i64) -> Result<Option<(i64, String)>>
The two columns getattr needs to validate cached attrs — the freshness
stamp (content_version) and the path to re-stat (backing_path) —
without materializing a full Track (no format parse, no
TrackBounds) on the hottest metadata op. None if the id is unknown.
Sourcepub fn begin_read(&self) -> Result<()>
pub fn begin_read(&self) -> Result<()>
Begin a deferred (read) transaction: subsequent reads on this connection see
a single consistent snapshot until end_read. Used to make a binary-tag
read’s content_version check and its blob reads mutually consistent.
Sourcepub fn end_read(&self) -> Result<()>
pub fn end_read(&self) -> Result<()>
End the read transaction opened by begin_read (rollback — it is read-only).
Sourcepub fn list_render_keys(&self) -> Result<Vec<(i64, i64, Format)>>
pub fn list_render_keys(&self) -> Result<Vec<(i64, i64, Format)>>
Cheap render-key identity scan for incremental refresh: (id, content_version, format) for every track, ordered by id. No tags, no path columns — just the
two track-level inputs that determine a rendered path. See SP2 Component 1.
Sourcepub fn changelog_since(&self, last_seq: i64) -> Result<ChangelogRead>
pub fn changelog_since(&self, last_seq: i64) -> Result<ChangelogRead>
One read of the changelog ring past last_seq: the distinct changed track
ids (ascending) plus the table’s retained seq bounds (0/0 when empty). The
caller derives gap detection from min_seq (see musefs-core’s refresh).
Source§impl Db<ReadWrite>
impl Db<ReadWrite>
pub fn upsert_track(&self, t: &NewTrack) -> Result<i64>
Sourcepub fn delete_track(&self, id: i64) -> Result<()>
pub fn delete_track(&self, id: i64) -> Result<()>
Delete a track row. Foreign keys cascade to its tags and track_art
rows; the referenced art rows are left for gc_orphan_art.
Sourcepub fn tracks_by_fingerprint(&self, fp: &str) -> Result<Vec<Track>>
pub fn tracks_by_fingerprint(&self, fp: &str) -> Result<Vec<Track>>
All tracks whose stored fingerprint equals fp (rows with NULL
fingerprint never match). Used by the scan refind to find move candidates.
Sourcepub fn set_track_checksums(
&self,
id: i64,
fingerprint: Option<&str>,
content_hash: Option<&str>,
) -> Result<()>
pub fn set_track_checksums( &self, id: i64, fingerprint: Option<&str>, content_hash: Option<&str>, ) -> Result<()>
Set the scanner-owned checksums for a track. A None argument leaves the
existing column value intact (COALESCE), so a lower-tier pass never clears
a higher tier’s value.
Sourcepub fn retarget_track(
&self,
id: i64,
new_backing_path: &str,
backing_size: u64,
backing_mtime_ns: i64,
backing_ctime_ns: i64,
audio_offset: u64,
audio_length: u64,
fingerprint: Option<&str>,
content_hash: Option<&str>,
) -> Result<()>
pub fn retarget_track( &self, id: i64, new_backing_path: &str, backing_size: u64, backing_mtime_ns: i64, backing_ctime_ns: i64, audio_offset: u64, audio_length: u64, fingerprint: Option<&str>, content_hash: Option<&str>, ) -> Result<()>
Point an existing track at a relocated backing file: update its path,
validation stamp, and audio bounds in place, preserving its id (and
thus its tags/art/structural blocks). Checksum args COALESCE like
set_track_checksums. updated_at is refreshed; content_version is
left to the geometry trigger (it bumps only if backing_mtime_ns
actually changed — a pure move preserves mtime, so no bump).
Source§impl Db<ReadWrite>
impl Db<ReadWrite>
pub fn open<P: AsRef<Path>>(path: P) -> Result<Db>
pub fn open_in_memory() -> Result<Db>
Sourcepub fn into_read_only(self) -> Db<ReadOnly>
pub fn into_read_only(self) -> Db<ReadOnly>
Degrade to the read-only surface, keeping the same connection. The
change is type-level only — runtime behavior is unchanged. The only
intended caller is musefs_core’s DbPool::new, which strips write
access from the mount connection before the serve path can see it.
Source§impl Db<ReadOnly>
impl Db<ReadOnly>
Sourcepub fn open_readonly<P: AsRef<Path>>(path: P) -> Result<Db<ReadOnly>>
pub fn open_readonly<P: AsRef<Path>>(path: P) -> Result<Db<ReadOnly>>
Open an additional read-only connection to an existing file-backed DB.
WAL (set by the writer) lets these run concurrently without blocking.
No migration is run — the schema already exists and the connection is RO.
Note: even with SQLITE_OPEN_READ_ONLY, SQLite needs write access to the
directory (to create/use the -shm wal-index) when the DB is in WAL mode;
a strictly read-only DB directory will make this fail.