db: Create a new Model class

This inherits from the Table, but also implements the Gio.ListModel
interface with sorting for use in the sidebar Gtk.ListView

Implements: Issue #1 (Have SQLite sort our sidebar tables)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2021-10-07 19:16:13 -04:00
parent 427b9fb925
commit feeee8809d
2 changed files with 107 additions and 1 deletions

View File

@ -1,4 +1,6 @@
# Copyright 2021 (c) Anna Schumaker.
from gi.repository import GObject
from gi.repository import Gio
from . import sql
class Table:
@ -44,3 +46,44 @@ class Table:
self.do_drop()
self.cache.clear()
self.do_create()
class Model(GObject.GObject, Gio.ListModel, Table):
def __init__(self, table, order):
GObject.GObject.__init__(self)
Table.__init__(self, table)
self.order = order
def do_get_item_type(self):
return GObject.TYPE_PYOBJECT
def do_get_n_items(self):
return sql.execute(f"SELECT COUNT(*) FROM {self.table}").fetchone()[0]
def do_get_item(self, n):
cur = sql.execute(f"SELECT * FROM {self.table} ORDER BY {self.order} "
"LIMIT 1 OFFSET ?", [ n ])
return self.factory(cur.fetchone())
def get_item_index(self, item):
cur = sql.execute("SELECT * FROM (SELECT rowid,ROW_NUMBER() "
f"OVER (ORDER BY {self.order}) "
f"FROM {self.table}) "
"WHERE rowid=?", [ item.rowid ])
return cur.fetchone()[1] - 1
def delete(self, item):
pos = self.get_item_index(item)
super().delete(item)
self.emit("items-changed", pos, 1, 0)
def insert(self, *args):
row = super().insert(*args)
pos = self.get_item_index(row)
self.emit("items-changed", pos, 0, 1)
return row
def reset(self):
n = self.get_n_items()
super().reset()
self.emit("items-changed", 0, n, self.get_n_items())

View File

@ -1,10 +1,13 @@
# Copyright 2021 (c) Anna Schumaker.
import unittest
from gi.repository import GObject
from gi.repository import Gio
from . import sql
from . import table
class FakeRow:
class FakeRow(GObject.GObject):
def __init__(self, data):
GObject.GObject.__init__(self)
self.rowid = data["fakeid"]
self.name = data["name"]
@ -26,6 +29,13 @@ class FakeTable(table.Table):
def do_lookup(self, name):
return sql.execute("SELECT * FROM fake_table WHERE name=?", [ name ])
class FakeModel(table.Model, FakeTable):
def __init__(self):
table.Model.__init__(self, "fake_table", "lower(name)")
self.reset()
class TestTable(unittest.TestCase):
def test_init(self):
fake = FakeTable()
@ -76,3 +86,56 @@ class TestTable(unittest.TestCase):
fake.reset()
self.assertEqual(fake.cache, { })
class TestModel(unittest.TestCase):
def items_changed(self, table, pos, rm, add):
self.changed = (pos, rm, add)
def setUp(self):
self.changed = None
def test_init(self):
fake = FakeModel()
self.assertIsInstance(fake, GObject.GObject)
self.assertIsInstance(fake, Gio.ListModel)
self.assertIsInstance(fake, table.Table)
self.assertEqual(fake.order, "lower(name)")
def test_insert_delete(self):
fake = FakeModel()
fake.connect("items-changed", self.items_changed)
row = fake.insert("Test Row")
self.assertEqual(self.changed, (0, 0, 1))
fake.delete(row)
self.assertEqual(self.changed, (0, 1, 0))
def test_model(self):
fake = FakeModel()
self.assertEqual(fake.get_item_type(), GObject.TYPE_PYOBJECT)
self.assertEqual(fake.get_n_items(), 0)
c = fake.insert("C")
self.assertEqual(fake.get_n_items(), 1)
self.assertEqual(fake.get_item(0), c)
b = fake.insert("B")
self.assertEqual(fake.get_n_items(), 2)
self.assertEqual(fake.get_item(0), b)
self.assertEqual(fake.get_item(1), c)
a = fake.insert("A")
self.assertEqual(fake.get_n_items(), 3)
self.assertEqual(fake.get_item(0), a)
self.assertEqual(fake.get_item(1), b)
self.assertEqual(fake.get_item(2), c)
def test_reset(self):
fake = FakeModel()
fake.insert("Test Row")
fake.insert("Test Row 2")
fake.connect("items-changed", self.items_changed)
fake.reset()
self.assertEqual(self.changed, (0, 2, 0))