From 658be5bef1b5b5fddb48304c98f815ca30202580 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Thu, 7 Oct 2021 22:01:50 -0400 Subject: [PATCH] db: Create a new Child class This inherites from the Table, but takes a parent instance for some functions and calculates offsets for items that descend from this parent. Implements: Issue #1 (Have SQLite sort our sidebar tables) Signed-off-by: Anna Schumaker --- db/table.py | 28 ++++++++++++++++++++++++++++ db/test_table.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/db/table.py b/db/table.py index f4b30b2..dcbbfe4 100644 --- a/db/table.py +++ b/db/table.py @@ -87,3 +87,31 @@ class Model(GObject.GObject, Gio.ListModel, Table): n = self.get_n_items() super().reset() self.emit("items-changed", 0, n, self.get_n_items()) + + +class Child(Table): + def __init__(self, table, parent, order): + Table.__init__(self, table) + self.parent = parent + self.order = order + + def get_n_children(self, parent): + cur = sql.execute(f"SELECT COUNT(*) FROM {self.table} " + f"WHERE {self.parent}=?", [ parent.rowid ]) + return cur.fetchone()[0] + + def get_child(self, parent, n): + cur = sql.execute(f"SELECT * FROM {self.table} WHERE {self.parent}=? " + f"ORDER BY {self.order} LIMIT 1 OFFSET ?", + [ parent.rowid, n ]) + return self.factory(cur.fetchone()) + + def get_child_index(self, parent, child): + cur = sql.execute(f"SELECT * FROM (SELECT rowid,ROW_NUMBER() " + f"OVER (ORDER BY {self.order}) " + f"FROM {self.table} " + f"WHERE {self.parent}=?)" + f"WHERE rowid=?", [ parent.rowid, child.rowid ]) + return cur.fetchone()[1] - 1 + + def find(self, *args): raise NotImplementedError diff --git a/db/test_table.py b/db/test_table.py index 89f03f3..09538ef 100644 --- a/db/test_table.py +++ b/db/test_table.py @@ -34,6 +34,24 @@ class FakeModel(table.Model, FakeTable): table.Model.__init__(self, "fake_table", "lower(name)") self.reset() +class FakeChild(table.Child): + def __init__(self): + table.Child.__init__(self, "fake_child", "parentid", "lower(name)") + self.reset() + + def do_create(self): + sql.execute("CREATE TABLE IF NOT EXISTS fake_child " + "(fakeid INTEGER PRIMARY KEY, " + "parentid INTEGER, " + "name TEXT UNIQUE, " + "FOREIGN KEY(parentid) REFERENCES fake_table(fakeid))") + + def do_factory(self, row): + return FakeRow(row) + + def do_insert(self, parent, name): + return sql.execute("INSERT INTO fake_child (parentid, name) " + "VALUES (?,?)", [ parent.rowid, name ]) class TestTable(unittest.TestCase): @@ -139,3 +157,33 @@ class TestModel(unittest.TestCase): fake.connect("items-changed", self.items_changed) fake.reset() self.assertEqual(self.changed, (0, 2, 0)) + + +class TestChild(unittest.TestCase): + def test_init(self): + child = FakeChild() + + self.assertIsInstance(child, table.Table) + self.assertEqual(child.parent, "parentid") + self.assertEqual(child.order, "lower(name)") + + def test_children(self): + model = FakeModel() + child = FakeChild() + parent = model.insert("Fake Parent") + + self.assertEqual(child.get_n_children(parent), 0) + + c = child.insert(parent, "C") + b = child.insert(parent, "B") + a = child.insert(parent, "A") + + self.assertEqual(child.get_n_children(parent), 3) + + self.assertEqual(child.get_child(parent, 0), a) + self.assertEqual(child.get_child(parent, 1), b) + self.assertEqual(child.get_child(parent, 2), c) + + self.assertEqual(child.get_child_index(parent, a), 0) + self.assertEqual(child.get_child_index(parent, b), 1) + self.assertEqual(child.get_child_index(parent, c), 2)