6.3 KiB
6.3 KiB
Database Structure
This document describes the database structure of the Music Library application.
Entity Relationship Diagram
erDiagram
RECORDS {
uuid id PK
enum type
enum format
string title
string cover_url
blob cover_data
string cover_hash
uuid musicbrainz_id
map musicbrainz_data
string[] genres
string release_date
datetime purchased_at
string selected_release_id
string[] release_ids
string[] included_release_group_ids
Artist[] artists
datetime inserted_at
datetime updated_at
}
RECORDS_SEARCH_INDEX {
uuid id PK
enum type
enum format
string title
string normalized_title
Artist[] artists
string normalized_artists
string[] genres
uuid musicbrainz_id
string[] release_ids
string[] included_release_group_ids
string cover_hash
datetime purchased_at
string release_date
}
ARTIST_INFOS {
uuid id PK
map musicbrainz_data
map discogs_data
blob image_data
string image_data_hash
integer image_data_width
datetime inserted_at
datetime updated_at
}
ARTIST_RECORDS {
uuid musicbrainz_id
uuid record_id
map artist
}
RECORDS ||--o{ RECORDS_SEARCH_INDEX : "syncs via triggers"
RECORDS ||--o{ ARTIST_INFOS : "references via musicbrainz_id"
RECORDS ||--o{ ARTIST_RECORDS : "extracted via view"
Tables Description
Records
The main table storing music records. Key features:
- Uses UUID as primary key
- Stores basic record information (title, type [album, ep, live, compilation, single, other], format [cd, backup, vinyl, blu_ray, dvd, multi])
- Includes MusicBrainz integration with IDs and additional data (musicbrainz_id, musicbrainz_data)
- Stores cover image data and URLs (cover_url, cover_data, cover_hash)
- Embeds artists data as an array of objects (each with musicbrainz_id, name, sort_name, disambiguation)
- Includes timestamps for record keeping
- Tracks purchase status via
purchased_atfield - Stores release information including multiple release IDs (
release_ids), included release group IDs (included_release_group_ids), and a selected release ID (selected_release_id) - Maintains release date information (
release_date)
Records Search Index
A virtual FTS5 (Full Text Search) table that mirrors the records table for efficient searching:
- Automatically synced with the records table via triggers
- Optimized for full-text search operations
- Contains most fields from the records table, including:
- id, type, format, title, normalized_title, artists, normalized_artists, genres, musicbrainz_id, release_ids, included_release_group_ids, cover_hash, purchased_at, release_date
normalized_titleandnormalized_artistsare unaccented versions for improved search- Some fields are marked as UNINDEXED for efficiency
Artist Infos
A table that stores additional artist information:
- Uses UUID as primary key
- Stores MusicBrainz and Discogs data for artists
- Maintains artist image data with dimensions and hash
- Includes timestamps for record keeping
Views
Artist Records View
A view that extracts artist information from the embedded JSON in the records table:
CREATE VIEW artist_records AS
SELECT json_extract(json_each.value, '$.musicbrainz_id') AS musicbrainz_id,
records.id AS record_id,
json_each.value as artist
FROM records,
json_each(records.artists)
This view is crucial for querying artist information as it:
- Extracts individual artists from the embedded JSON array in the records table
- Provides a normalized view of the artist-record relationships
- Makes it easier to query records by artist
- Maintains the relationship between records and their artists without requiring a separate join table
Triggers
The following triggers maintain the search index:
records_after_insert: Inserts new record data into search index after record creationrecords_after_update: Updates record data in search index after record updates
Indices
The following indices are maintained for performance:
- On
records:typeformattitlemusicbrainz_idpurchased_atincluded_release_group_idsrelease_ids
Notes
- The database uses SQLite as the primary database.
- Artists data is embedded directly in the records table as an array of objects, not a separate table.
- The search index is implemented using SQLite's FTS5 extension for efficient full-text search capabilities, with normalized (unaccented) fields for better search.
- Where needed, queries use SQLite's
unicodeextension to filter/sort over UTF-8 data. - The database supports both collection and wishlist functionality through the
purchased_atfield:- Records with
purchased_at IS NOT NULLare in the collection - Records with
purchased_at IS NULLare in the wishlist
- Records with
- The schema uses
release_datefor clarity - The
selected_release_idfield tracks the primary release for a record - The
artist_infostable stores additional artist metadata and images - The
artist_recordsview provides a normalized way to query artist-record relationships
WHY ONE TABLE?
In traditional relational database design, you would split out artists into a separate table, and associate them with records via a join table. So why sticking with one table?
- You only need to backup/export one table.
- Re-fetching data from MusicBrainz becomes trivial, as it just needs to update one field and everything else cascades accordingly.
- Traditional efficiency design constraints do not apply to SQLite, so it makes it easier to experiment with alternative database designs.