From faf33515b2e6ef8b891e7c9693c66aba2a77dc54 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Wed, 15 May 2019 20:23:33 -0700 Subject: [PATCH] Sometimes sort tables by number of relationships, closes #460 --- datasette/app.py | 6 ++++++ datasette/views/database.py | 4 +--- datasette/views/index.py | 15 ++++++++++++++- tests/test_api.py | 15 +++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/datasette/app.py b/datasette/app.py index c2bf330f..db771e40 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -30,6 +30,7 @@ from .utils import ( detect_spatialite, escape_css_string, escape_sqlite, + get_all_foreign_keys, get_outbound_foreign_keys, get_plugins, module_from_path, @@ -261,6 +262,11 @@ class ConnectedDatabase: ) return [r[0] for r in results.rows] + async def get_all_foreign_keys(self): + return await self.ds.execute_against_connection_in_thread( + self.name, get_all_foreign_keys + ) + def __repr__(self): tags = [] if self.is_mutable: diff --git a/datasette/views/database.py b/datasette/views/database.py index 5fab04b0..5065b90f 100644 --- a/datasette/views/database.py +++ b/datasette/views/database.py @@ -29,9 +29,7 @@ class DatabaseView(BaseView): table_counts = await db.table_counts(5) views = await db.view_names() hidden_table_names = set(await db.hidden_table_names()) - all_foreign_keys = await self.ds.execute_against_connection_in_thread( - database, get_all_foreign_keys - ) + all_foreign_keys = await db.get_all_foreign_keys() metadata = (self.ds.metadata("databases") or {}).get(database, {}) self.ds.update_with_inherited_metadata(metadata) diff --git a/datasette/views/index.py b/datasette/views/index.py index bca901f5..d3d82bae 100644 --- a/datasette/views/index.py +++ b/datasette/views/index.py @@ -54,14 +54,27 @@ class IndexView(RenderMixin): "fts_table": await self.ds.execute_against_connection_in_thread( name, lambda conn: detect_fts(conn, table) ), + "num_relationships_for_sorting": 0, } + + if request.args.get("_sort") == "relationships" or not table_counts: + # We will be sorting by number of relationships, so populate that field + all_foreign_keys = await db.get_all_foreign_keys() + for table, foreign_keys in all_foreign_keys.items(): + count = len(foreign_keys["incoming"] + foreign_keys["outgoing"]) + tables[table]["num_relationships_for_sorting"] = count + hidden_tables = [t for t in tables.values() if t["hidden"]] visible_tables = [t for t in tables.values() if not t["hidden"]] tables_and_views_truncated = list( sorted( (t for t in tables.values() if t not in hidden_tables), - key=lambda t: t["count"] or 0, + key=lambda t: ( + t["num_relationships_for_sorting"], + t["count"] or 0, + t["name"], + ), reverse=True, )[:TRUNCATE_AT] ) diff --git a/tests/test_api.py b/tests/test_api.py index ea5d2a2d..b4599ab3 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -34,6 +34,21 @@ def test_homepage(app_client): assert d["views_count"] == 4 +def test_homepage_sort_by_relationships(app_client): + response = app_client.get("/.json?_sort=relationships") + assert response.status == 200 + tables = [ + t["name"] for t in response.json["fixtures"]["tables_and_views_truncated"] + ] + assert [ + "simple_primary_key", + "complex_foreign_keys", + "searchable_tags", + "foreign_key_references", + "facetable", + ] == tables + + def test_database_page(app_client): response = app_client.get("/fixtures.json") data = response.json