diff --git a/src/wuttjamaican/db/util.py b/src/wuttjamaican/db/util.py index 0df0e68..643e267 100644 --- a/src/wuttjamaican/db/util.py +++ b/src/wuttjamaican/db/util.py @@ -27,6 +27,7 @@ Database Utilities import uuid as _uuid import sqlalchemy as sa +from sqlalchemy import orm from sqlalchemy.dialects.postgresql import UUID as PGUUID from wuttjamaican.util import make_uuid @@ -127,3 +128,26 @@ def uuid_fk_column(target_column, *args, **kwargs): if not args: args = (sa.String(length=32), sa.ForeignKey(target_column)) return sa.Column(*args, **kwargs) + + +def make_topo_sortkey(model): + """ + Returns a function suitable for use as a ``key`` kwarg to a + standard Python sorting call. This key function will expect a + single class mapper and return a sequence number associated with + that model. The sequence is determined by SQLAlchemy's + topological table sorting. + + :param model: Usually the :term:`app model`, but can be any module + containing model classes. + """ + metadata = model.Base.metadata + tables = dict([(table.name, i) + for i, table in enumerate(metadata.sorted_tables, 1)]) + + def sortkey(name): + cls = getattr(model, name) + mapper = orm.class_mapper(cls) + return tuple(tables[t.name] for t in mapper.tables) + + return sortkey diff --git a/tests/db/test_util.py b/tests/db/test_util.py index 2f0c9ed..8ffef76 100644 --- a/tests/db/test_util.py +++ b/tests/db/test_util.py @@ -11,6 +11,7 @@ try: from wuttjamaican.db import util as mod from wuttjamaican.db.model.base import Setting from wuttjamaican.util import make_true_uuid + from wuttjamaican.testing import DataTestCase except ImportError: pass else: @@ -124,3 +125,17 @@ else: self.assertIsInstance(column, sa.Column) self.assertIsInstance(column.type, sa.String) self.assertEqual(column.type.length, 32) + + + class TestMakeTopoSortkey(DataTestCase): + + def test_basic(self): + model = self.app.model + sortkey = mod.make_topo_sortkey(model) + original = ['User', 'Person', 'UserRole', 'Role'] + + # models are sorted so dependants come later + result = sorted(original, key=sortkey) + self.assertTrue(result.index('Role') < result.index('UserRole')) + self.assertTrue(result.index('User') < result.index('UserRole')) + self.assertTrue(result.index('Person') < result.index('User'))