db: Create a database Row base class

This will be shared between settings, playlists, and tracks so we have a
common interface for working with database rows.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2022-09-23 09:37:32 -04:00
parent 8c8135fc23
commit 2eef68f76f
3 changed files with 95 additions and 0 deletions

33
emmental/db/table.py Normal file
View File

@ -0,0 +1,33 @@
# Copyright 2022 (c) Anna Schumaker
"""Base classes for database objects."""
from gi.repository import GObject
from gi.repository import Gio
class Row(GObject.GObject):
"""A single row in a database table."""
table = GObject.Property(type=Gio.ListModel)
def __init__(self, table: Gio.ListModel, **kwargs):
"""Initialize a database Row."""
super().__init__(table=table, **kwargs)
self.connect("notify", self.__notify)
def __notify(self, row: GObject.GObject, param: GObject.ParamSpec) -> None:
match param.name:
case "table": pass
case _: self.do_update(param.name)
def do_update(self, column: str) -> bool:
"""Update a Row in the database."""
return self.table.update(self, column, self.get_property(column))
def delete(self) -> bool:
"""Delete this Row."""
return self.table.delete(self)
@property
def primary_key(self) -> None:
"""Get the primary key for this row."""
raise NotImplementedError

47
tests/db/test_table.py Normal file
View File

@ -0,0 +1,47 @@
# Copyright 2022 (c) Anna Schumaker
"""Tests our database object base classes."""
import unittest
import unittest.mock
import emmental.db.table
import tests.util.table
from gi.repository import GObject
from gi.repository import Gio
class TestRow(unittest.TestCase):
"""Tests our common database Row object."""
def setUp(self):
"""Set up common variables."""
self.table = Gio.ListStore()
self.table.delete = unittest.mock.Mock(return_value=True)
self.table.update = unittest.mock.Mock(return_value=True)
self.row = tests.util.table.MockRow(table=self.table)
def test_init(self):
"""Test that the database Row is configured correctly."""
self.assertIsInstance(self.row, emmental.db.table.Row)
self.assertIsInstance(self.row, GObject.GObject)
self.assertEqual(self.row.table, self.table)
def test_primary_key(self):
"""Test the primary_key property."""
with self.assertRaises(NotImplementedError):
emmental.db.table.Row(self.table).primary_key
self.row.number = 2
self.assertEqual(self.row.primary_key, 2)
def test_do_update(self):
"""Test updating a Row attribute."""
self.row.number = 1
self.table.update.assert_called_with(self.row, "number", 1)
self.table.update.reset_mock()
self.row.table = None
self.table.update.assert_not_called()
def test_delete(self):
"""Test deleting a Row."""
self.assertTrue(self.row.delete())
self.table.delete.assert_called_with(self.row)

15
tests/util/table.py Normal file
View File

@ -0,0 +1,15 @@
# Copyright 2023 (c) Anna Schumaker.
"""Mock Row and Table objects for testing."""
import emmental.db.table
from gi.repository import GObject
class MockRow(emmental.db.table.Row):
"""A fake Row customized for testing."""
number = GObject.Property(type=int)
@property
def primary_key(self) -> int:
"""Get the primary key for this MockRow."""
return self.number