db: Give Albums knowledge about their Media
We create a filter on the Media table for each Album object, but only match Media that have a name set. I also adjust filtering to display Albums that have a matching Medium. Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
51a13a8a04
commit
87606f8fac
|
@ -3,6 +3,8 @@
|
|||
import pathlib
|
||||
import sqlite3
|
||||
from gi.repository import GObject
|
||||
from gi.repository import Gtk
|
||||
from .media import Medium
|
||||
from .. import format
|
||||
from . import playlist
|
||||
|
||||
|
@ -16,10 +18,23 @@ class Album(playlist.Playlist):
|
|||
mbid = GObject.Property(type=str)
|
||||
cover = GObject.Property(type=GObject.TYPE_PYOBJECT)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Initialize an Album object."""
|
||||
super().__init__(**kwargs)
|
||||
self.add_children(self.table.sql.media,
|
||||
Gtk.CustomFilter.new(self.__match_medium))
|
||||
|
||||
def __match_medium(self, medium: Medium) -> bool:
|
||||
return medium.albumid == self.albumid and len(medium.name) > 0
|
||||
|
||||
def get_artists(self) -> list[playlist.Playlist]:
|
||||
"""Get a list of artists for this album."""
|
||||
return self.table.get_artists(self)
|
||||
|
||||
def get_media(self) -> list[Medium]:
|
||||
"""Get a list of media for this album."""
|
||||
return self.table.get_media(self)
|
||||
|
||||
@property
|
||||
def primary_key(self) -> int:
|
||||
"""Get the Album primary key."""
|
||||
|
@ -51,12 +66,15 @@ class Table(playlist.Table):
|
|||
"""Delete an album."""
|
||||
for artist in album.get_artists():
|
||||
artist.remove_album(album)
|
||||
for medium in album.get_media():
|
||||
medium.delete()
|
||||
return self.sql("DELETE FROM albums WHERE albumid=?", album.albumid)
|
||||
|
||||
def do_sql_glob(self, glob: str) -> sqlite3.Cursor:
|
||||
"""Search for albums matching the search text."""
|
||||
return self.sql("""SELECT albumid FROM albums
|
||||
WHERE CASEFOLD(name) GLOB ?""", glob)
|
||||
return self.sql("""SELECT albumid FROM album_artist_view
|
||||
WHERE CASEFOLD(album) GLOB :glob
|
||||
OR CASEFOLD(medium) GLOB :glob""", glob=glob)
|
||||
|
||||
def do_sql_insert(self, name: str, artist: str,
|
||||
release: str, *, mbid: str = "",
|
||||
|
@ -99,3 +117,9 @@ class Table(playlist.Table):
|
|||
WHERE albumid=?""", album.albumid).fetchall()
|
||||
artists = [self.sql.artists.rows.get(row["artistid"]) for row in rows]
|
||||
return list(filter(None, artists))
|
||||
|
||||
def get_media(self, album: Album) -> list[Medium]:
|
||||
"""Get the list of media for this album."""
|
||||
rows = self.sql("SELECT mediumid FROM media WHERE albumid=?",
|
||||
album.albumid)
|
||||
return [self.sql.media.rows.get(row["mediumid"]) for row in rows]
|
||||
|
|
|
@ -184,11 +184,11 @@ CREATE TRIGGER media_delete_trigger AFTER DELETE ON media
|
|||
END;
|
||||
|
||||
|
||||
/*******************************************
|
||||
* *
|
||||
* Artist <--> Album Linking *
|
||||
* *
|
||||
*******************************************/
|
||||
/*******************************************************
|
||||
* *
|
||||
* Artist <--> Album <--> Medium Linking *
|
||||
* *
|
||||
*******************************************************/
|
||||
|
||||
CREATE TABLE album_artist_link (
|
||||
artistid INTEGER NOT NULL REFERENCES artists (artistid)
|
||||
|
@ -202,10 +202,12 @@ CREATE TABLE album_artist_link (
|
|||
|
||||
CREATE VIEW album_artist_view AS
|
||||
SELECT artistid, artists.name as artist,
|
||||
albumid, COALESCE(albums.name, "") as album
|
||||
albumid, COALESCE(albums.name, "") as album,
|
||||
media.mediumid, COALESCE(media.name, "") as medium
|
||||
FROM artists
|
||||
LEFT JOIN album_artist_link USING (artistid)
|
||||
LEFT JOIN albums USING (albumid);
|
||||
LEFT JOIN albums USING (albumid)
|
||||
LEFT JOIN media USING (albumid);
|
||||
|
||||
|
||||
/******************************************
|
||||
|
|
|
@ -4,6 +4,7 @@ import pathlib
|
|||
import unittest.mock
|
||||
import emmental.db
|
||||
import tests.util
|
||||
from gi.repository import Gtk
|
||||
|
||||
|
||||
class TestAlbumObject(tests.util.TestCase):
|
||||
|
@ -48,6 +49,30 @@ class TestAlbumObject(tests.util.TestCase):
|
|||
mock.assert_called_with(self.album)
|
||||
self.assertEqual(self.album.parent, 1)
|
||||
|
||||
def test_get_media(self):
|
||||
"""Test getting the list of album media."""
|
||||
with unittest.mock.patch.object(self.table, "get_media",
|
||||
return_value=[1, 2, 3]) as mock:
|
||||
self.assertListEqual(self.album.get_media(), [1, 2, 3])
|
||||
mock.assert_called_with(self.album)
|
||||
|
||||
def test_media_model(self):
|
||||
"""Test getting a Gio.ListModel representing this Album's media."""
|
||||
self.assertIsInstance(self.album.children, Gtk.FilterListModel)
|
||||
self.assertIsInstance(self.album.children.get_filter(),
|
||||
Gtk.CustomFilter)
|
||||
self.assertEqual(self.album.children.get_model(), self.sql.media)
|
||||
|
||||
album = self.table.create("Test Album", "Album Artist", "2023-03")
|
||||
medium = self.sql.media.create(album, "Test Medium", number=1)
|
||||
self.assertTrue(album.children.get_filter().match(medium))
|
||||
|
||||
medium.albumid = album.albumid + 1
|
||||
self.assertFalse(album.children.get_filter().match(medium))
|
||||
|
||||
medium = self.sql.media.create(album, "", number=2)
|
||||
self.assertFalse(album.children.get_filter().match(medium))
|
||||
|
||||
|
||||
class TestAlbumTable(tests.util.TestCase):
|
||||
"""Tests our album table."""
|
||||
|
@ -117,11 +142,13 @@ class TestAlbumTable(tests.util.TestCase):
|
|||
"""Test deleting an album playlist."""
|
||||
artist = self.sql.artists.create("Test Artist")
|
||||
album = self.table.create("Test Album", "Album Artist", "2023-03")
|
||||
medium = self.sql.media.create(album, "Test Medium", number=1)
|
||||
artist.add_album(album)
|
||||
|
||||
self.assertTrue(album.delete())
|
||||
self.assertIsNone(self.table.index(album))
|
||||
self.assertFalse(artist.has_album(album))
|
||||
self.assertIsNone(self.sql.media.index(medium))
|
||||
|
||||
cur = self.sql("SELECT COUNT(name) FROM albums")
|
||||
self.assertEqual(cur.fetchone()["COUNT(name)"], 0)
|
||||
|
@ -139,14 +166,24 @@ class TestAlbumTable(tests.util.TestCase):
|
|||
|
||||
def test_filter(self):
|
||||
"""Test filtering an album playlist."""
|
||||
self.table.create("Album 1", "Album Artist", "2023-03")
|
||||
self.table.create("Album 2", "Album Artist", "2023-03")
|
||||
artist = self.sql.artists.create("Test Artist")
|
||||
|
||||
album1 = self.table.create("Album 1", "Album Artist", "2023-03")
|
||||
album2 = self.table.create("Album 2", "Album Artist", "2023-03")
|
||||
artist.add_album(album1)
|
||||
artist.add_album(album2)
|
||||
|
||||
self.sql.media.create(album2, "Medium 3", number=3)
|
||||
self.sql.media.create(album2, "", number=4)
|
||||
|
||||
self.table.filter("*1", now=True)
|
||||
self.assertSetEqual(self.table.get_filter().keys, {1})
|
||||
self.table.filter("album*", now=True)
|
||||
self.assertSetEqual(self.table.get_filter().keys, {1, 2})
|
||||
|
||||
self.table.filter("*3", now=True)
|
||||
self.assertSetEqual(self.table.get_filter().keys, {2})
|
||||
|
||||
def test_get_sort_key(self):
|
||||
"""Test the get_sort_key() function."""
|
||||
album1 = self.table.create("Album 1", "Album Artist", "2023-02")
|
||||
|
@ -233,3 +270,11 @@ class TestAlbumTable(tests.util.TestCase):
|
|||
|
||||
del self.sql.artists.rows[artist1.artistid]
|
||||
self.assertListEqual(self.table.get_artists(album), [artist2])
|
||||
|
||||
def test_get_media(self):
|
||||
"""Test getting the list of media for an album."""
|
||||
album = self.table.create("Test Album", "Album Artist", "2023-03")
|
||||
medium1 = self.sql.media.create(album, "", number=1)
|
||||
medium2 = self.sql.media.create(album, "", number=2)
|
||||
|
||||
self.assertListEqual(self.table.get_media(album), [medium1, medium2])
|
||||
|
|
Loading…
Reference in New Issue