db: Give Libraries knowledge about their Tracks & Properties
I expand on the libraries_view to include additional playlist properties, and configure the default sort order to sort by filepath. I then set up the library_tracks_view to make it easy to select tracks that belong to a specific Library. Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
e39d128488
commit
7920b3d5a8
|
@ -386,13 +386,15 @@ CREATE TABLE libraries (
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE VIEW libraries_view AS
|
CREATE VIEW libraries_view AS
|
||||||
SELECT libraryid, propertyid, path, path as name, enabled, active
|
SELECT libraryid, propertyid, path, path as name, enabled,
|
||||||
|
active, loop, shuffle, sort_order, current_trackid
|
||||||
FROM libraries
|
FROM libraries
|
||||||
JOIN playlist_properties USING (propertyid);
|
JOIN playlist_properties USING (propertyid);
|
||||||
|
|
||||||
CREATE TRIGGER libraries_insert_trigger AFTER INSERT ON libraries
|
CREATE TRIGGER libraries_insert_trigger AFTER INSERT ON libraries
|
||||||
BEGIN
|
BEGIN
|
||||||
INSERT INTO playlist_properties (active) VALUES (False);
|
INSERT INTO playlist_properties (active, sort_order)
|
||||||
|
VALUES (False, "filepath");
|
||||||
UPDATE libraries SET propertyid = last_insert_rowid()
|
UPDATE libraries SET propertyid = last_insert_rowid()
|
||||||
WHERE libraryid = NEW.libraryid;
|
WHERE libraryid = NEW.libraryid;
|
||||||
END;
|
END;
|
||||||
|
@ -573,6 +575,12 @@ CREATE VIEW year_tracks_view AS
|
||||||
JOIN libraries USING (libraryid)
|
JOIN libraries USING (libraryid)
|
||||||
WHERE libraries.deleting = False;
|
WHERE libraries.deleting = False;
|
||||||
|
|
||||||
|
CREATE VIEW library_tracks_view AS
|
||||||
|
SELECT tracks.trackid, libraries.libraryid
|
||||||
|
FROM tracks
|
||||||
|
JOIN libraries USING (libraryid)
|
||||||
|
WHERE libraries.deleting = False;
|
||||||
|
|
||||||
|
|
||||||
/****************************************************
|
/****************************************************
|
||||||
* *
|
* *
|
||||||
|
|
|
@ -7,6 +7,7 @@ from .. import path
|
||||||
from . import idle
|
from . import idle
|
||||||
from . import playlist
|
from . import playlist
|
||||||
from . import tagger
|
from . import tagger
|
||||||
|
from . import tracks
|
||||||
|
|
||||||
|
|
||||||
class Library(playlist.Playlist):
|
class Library(playlist.Playlist):
|
||||||
|
@ -100,10 +101,22 @@ class Library(playlist.Playlist):
|
||||||
class Table(playlist.Table):
|
class Table(playlist.Table):
|
||||||
"""Our Library ListModel."""
|
"""Our Library ListModel."""
|
||||||
|
|
||||||
|
def __init__(self, sql: GObject.TYPE_PYOBJECT, **kwargs):
|
||||||
|
"""Initialize the Libraries Table."""
|
||||||
|
super().__init__(sql=sql, system_tracks=False, **kwargs)
|
||||||
|
|
||||||
|
def do_add_track(self, library: Library, track: tracks.Track) -> bool:
|
||||||
|
"""Verify adding a Track to a Library playlist."""
|
||||||
|
return track.get_library() == library
|
||||||
|
|
||||||
def do_construct(self, **kwargs) -> Library:
|
def do_construct(self, **kwargs) -> Library:
|
||||||
"""Construct a new library."""
|
"""Construct a new library."""
|
||||||
return Library(**kwargs)
|
return Library(**kwargs)
|
||||||
|
|
||||||
|
def do_remove_track(self, library: Library, track: tracks.Track) -> bool:
|
||||||
|
"""Verify removing a Track from a Library playlist."""
|
||||||
|
return True
|
||||||
|
|
||||||
def do_sql_delete(self, library: Library) -> sqlite3.Cursor:
|
def do_sql_delete(self, library: Library) -> sqlite3.Cursor:
|
||||||
"""Delete a library."""
|
"""Delete a library."""
|
||||||
return self.sql("DELETE FROM libraries WHERE libraryid=?",
|
return self.sql("DELETE FROM libraries WHERE libraryid=?",
|
||||||
|
@ -128,6 +141,11 @@ class Table(playlist.Table):
|
||||||
"""Look up a library by path."""
|
"""Look up a library by path."""
|
||||||
return self.sql("SELECT libraryid FROM libraries WHERE path=?", path)
|
return self.sql("SELECT libraryid FROM libraries WHERE path=?", path)
|
||||||
|
|
||||||
|
def do_sql_select_trackids(self, library: Library) -> sqlite3.Cursor:
|
||||||
|
"""Load a Library's Tracks from the database."""
|
||||||
|
return self.sql("""SELECT trackid FROM library_tracks_view
|
||||||
|
WHERE libraryid=?""", library.libraryid)
|
||||||
|
|
||||||
def do_sql_update(self, library: Library, column: str, newval) -> bool:
|
def do_sql_update(self, library: Library, column: str, newval) -> bool:
|
||||||
"""Update a Library playlist."""
|
"""Update a Library playlist."""
|
||||||
if column == "enabled" and self.sql.playlists.collection:
|
if column == "enabled" and self.sql.playlists.collection:
|
||||||
|
|
|
@ -185,10 +185,25 @@ class TestLibraryTable(tests.util.TestCase):
|
||||||
tests.util.TestCase.setUp(self)
|
tests.util.TestCase.setUp(self)
|
||||||
self.table = self.sql.libraries
|
self.table = self.sql.libraries
|
||||||
|
|
||||||
|
self.album = self.sql.albums.create("Test Album", "Test Artist", "123")
|
||||||
|
self.medium = self.sql.media.create(self.album, "", number=1)
|
||||||
|
self.year = self.sql.years.create(2023)
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
"""Test that the library model is configured correctly."""
|
"""Test that the library model is configured correctly."""
|
||||||
self.assertIsInstance(self.table, emmental.db.playlist.Table)
|
self.assertIsInstance(self.table, emmental.db.playlist.Table)
|
||||||
self.assertEqual(len(self.table), 0)
|
self.assertEqual(len(self.table), 0)
|
||||||
|
self.assertFalse(self.table.autodelete)
|
||||||
|
self.assertFalse(self.table.system_tracks)
|
||||||
|
|
||||||
|
def test_add_track(self):
|
||||||
|
"""Test adding a Track to a Library playlist."""
|
||||||
|
library = self.table.create(pathlib.Path("/a/b"))
|
||||||
|
track = self.sql.tracks.create(library, pathlib.Path("/a/b/c.ogg"),
|
||||||
|
self.medium, self.year)
|
||||||
|
self.assertTrue(self.table.add_track(library, track))
|
||||||
|
library2 = self.table.create(pathlib.Path("/a/d"))
|
||||||
|
self.assertFalse(self.table.add_track(library2, track))
|
||||||
|
|
||||||
def test_construct(self):
|
def test_construct(self):
|
||||||
"""Test constructing a new library."""
|
"""Test constructing a new library."""
|
||||||
|
@ -202,12 +217,14 @@ class TestLibraryTable(tests.util.TestCase):
|
||||||
self.assertEqual(library.path, pathlib.Path("/a/b/c"))
|
self.assertEqual(library.path, pathlib.Path("/a/b/c"))
|
||||||
self.assertEqual(library.name, "/a/b/c")
|
self.assertEqual(library.name, "/a/b/c")
|
||||||
self.assertFalse(library.active)
|
self.assertFalse(library.active)
|
||||||
|
self.assertFalse(library.tracks_movable)
|
||||||
|
|
||||||
def test_create(self):
|
def test_create(self):
|
||||||
"""Test creating a library."""
|
"""Test creating a library."""
|
||||||
library = self.table.create(pathlib.Path("/a/b/c"))
|
library = self.table.create(pathlib.Path("/a/b/c"))
|
||||||
self.assertIsInstance(library, emmental.db.libraries.Library)
|
self.assertIsInstance(library, emmental.db.libraries.Library)
|
||||||
self.assertEqual(library.path, pathlib.Path("/a/b/c"))
|
self.assertEqual(library.path, pathlib.Path("/a/b/c"))
|
||||||
|
self.assertEqual(library.sort_order, "filepath")
|
||||||
|
|
||||||
cur = self.sql("SELECT COUNT(path) FROM libraries")
|
cur = self.sql("SELECT COUNT(path) FROM libraries")
|
||||||
self.assertEqual(cur.fetchone()["COUNT(path)"], 1)
|
self.assertEqual(cur.fetchone()["COUNT(path)"], 1)
|
||||||
|
@ -247,6 +264,16 @@ class TestLibraryTable(tests.util.TestCase):
|
||||||
self.table.filter("*a/b*", now=True)
|
self.table.filter("*a/b*", now=True)
|
||||||
self.assertSetEqual(self.table.get_filter().keys, {1, 2})
|
self.assertSetEqual(self.table.get_filter().keys, {1, 2})
|
||||||
|
|
||||||
|
def test_get_trackids(self):
|
||||||
|
"""Test loading library tracks from the database."""
|
||||||
|
library = self.table.create("/a/b/")
|
||||||
|
track1 = self.sql.tracks.create(library, pathlib.Path("/a/b/1.ogg"),
|
||||||
|
self.medium, self.year)
|
||||||
|
track2 = self.sql.tracks.create(library, pathlib.Path("/a/b/2.ogg"),
|
||||||
|
self.medium, self.year)
|
||||||
|
self.assertSetEqual(self.table.get_trackids(library),
|
||||||
|
{track1.trackid, track2.trackid})
|
||||||
|
|
||||||
def test_load(self):
|
def test_load(self):
|
||||||
"""Test loading libraries from the database."""
|
"""Test loading libraries from the database."""
|
||||||
self.table.create("/a/b/c")
|
self.table.create("/a/b/c")
|
||||||
|
@ -272,6 +299,11 @@ class TestLibraryTable(tests.util.TestCase):
|
||||||
self.assertEqual(self.table.lookup(pathlib.Path("/a/b/c/")), library)
|
self.assertEqual(self.table.lookup(pathlib.Path("/a/b/c/")), library)
|
||||||
self.assertIsNone(self.table.lookup(pathlib.Path("/no/library/path")))
|
self.assertIsNone(self.table.lookup(pathlib.Path("/no/library/path")))
|
||||||
|
|
||||||
|
def test_remove_track(self):
|
||||||
|
"""Test removing a Track from the Library."""
|
||||||
|
library = self.table.create("/a/b/")
|
||||||
|
self.assertTrue(self.table.remove_track(library, unittest.mock.Mock()))
|
||||||
|
|
||||||
def test_stop(self):
|
def test_stop(self):
|
||||||
"""Test stopping the library table."""
|
"""Test stopping the library table."""
|
||||||
library = self.table.create(pathlib.Path("/a/b/c"))
|
library = self.table.create(pathlib.Path("/a/b/c"))
|
||||||
|
@ -286,11 +318,20 @@ class TestLibraryTable(tests.util.TestCase):
|
||||||
library = self.table.create("/a/b/c")
|
library = self.table.create("/a/b/c")
|
||||||
library.active = True
|
library.active = True
|
||||||
library.enabled = False
|
library.enabled = False
|
||||||
|
library.loop = "Track"
|
||||||
|
library.shuffle = True
|
||||||
|
library.sort_order = "trackid"
|
||||||
|
|
||||||
row = self.sql("""SELECT active, enabled FROM libraries_view
|
row = self.sql("""SELECT active, enabled, loop, shuffle,
|
||||||
WHERE libraryid=?""", library.libraryid).fetchone()
|
sort_order, current_trackid
|
||||||
|
FROM libraries_view WHERE libraryid=?""",
|
||||||
|
library.libraryid).fetchone()
|
||||||
self.assertTrue(row["active"])
|
self.assertTrue(row["active"])
|
||||||
self.assertFalse(row["enabled"])
|
self.assertFalse(row["enabled"])
|
||||||
|
self.assertEqual(row["loop"], "Track")
|
||||||
|
self.assertTrue(row["shuffle"])
|
||||||
|
self.assertEqual(row["sort_order"], "trackid")
|
||||||
|
self.assertIsNone(row["current_trackid"])
|
||||||
|
|
||||||
def test_library_online(self):
|
def test_library_online(self):
|
||||||
"""Test the library-online signal."""
|
"""Test the library-online signal."""
|
||||||
|
|
Loading…
Reference in New Issue