diff --git a/datasette/app.py b/datasette/app.py index 3e2cf42a..27f192e3 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -685,14 +685,19 @@ class RowView(BaseView): 'foreign_key_tables': await self.foreign_key_tables(name, table, pk_values), } - return { + data = { 'database': name, 'table': table, 'rows': rows, 'columns': columns, 'primary_keys': pks, 'primary_key_values': pk_values, - }, template_data + } + + if 'foreign_key_tables' in (request.raw_args.get('_extras') or '').split(','): + data['foreign_key_tables'] = await self.foreign_key_tables(name, table, pk_values) + + return data, template_data async def foreign_key_tables(self, name, table, pk_values): if len(pk_values) != 1: @@ -702,7 +707,7 @@ class RowView(BaseView): return [] foreign_keys = table_info['foreign_keys']['incoming'] sql = 'select ' + ', '.join([ - '(select count(*) from {table} where "{column}"= :id)'.format( + '(select count(*) from {table} where "{column}"=:id)'.format( table=escape_sqlite_table_name(fk['other_table']), column=fk['other_column'], ) @@ -713,12 +718,16 @@ class RowView(BaseView): except sqlite3.OperationalError: # Almost certainly hit the timeout return [] - foreign_table_counts = dict(zip([fk['other_table'] for fk in foreign_keys], rows[0])) + foreign_table_counts = dict( + zip( + [(fk['other_table'], fk['other_column']) for fk in foreign_keys], + list(rows[0]), + ) + ) foreign_key_tables = [] for fk in foreign_keys: - count = foreign_table_counts[fk['other_table']] - if count: - foreign_key_tables.append({**fk, **{'count': count}}) + count = foreign_table_counts.get((fk['other_table'], fk['other_column'])) or 0 + foreign_key_tables.append({**fk, **{'count': count}}) return foreign_key_tables diff --git a/tests/test_app.py b/tests/test_app.py index 2ea3b4a0..41a34c64 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -37,7 +37,7 @@ def test_homepage(app_client): assert response.json.keys() == {'test_tables': 0}.keys() d = response.json['test_tables'] assert d['name'] == 'test_tables' - assert d['tables_count'] == 6 + assert d['tables_count'] == 7 def test_database_page(app_client): @@ -63,6 +63,28 @@ def test_database_page(app_client): 'hidden': False, 'foreign_keys': {'incoming': [], 'outgoing': []}, 'label_column': None, + }, { + 'columns': ['pk', 'f1', 'f2', 'f3'], + 'name': 'complex_foreign_keys', + 'count': 1, + 'foreign_keys': { + 'incoming': [], + 'outgoing': [{ + 'column': 'f3', + 'other_column': 'id', + 'other_table': 'simple_primary_key' + }, { + 'column': 'f2', + 'other_column': 'id', + 'other_table': 'simple_primary_key' + }, { + 'column': 'f1', + 'other_column': 'id', + 'other_table': 'simple_primary_key' + }], + }, + 'hidden': False, + 'label_column': None, }, { 'columns': ['pk1', 'pk2', 'content'], 'name': 'compound_primary_key', @@ -82,7 +104,22 @@ def test_database_page(app_client): 'name': 'simple_primary_key', 'count': 3, 'hidden': False, - 'foreign_keys': {'incoming': [], 'outgoing': []}, + 'foreign_keys': { + 'incoming': [{ + 'column': 'id', + 'other_column': 'f3', + 'other_table': 'complex_foreign_keys' + }, { + 'column': 'id', + 'other_column': 'f2', + 'other_table': 'complex_foreign_keys' + }, { + 'column': 'id', + 'other_column': 'f1', + 'other_table': 'complex_foreign_keys' + }], + 'outgoing': [], + }, 'label_column': None, }, { 'columns': ['pk', 'content'], @@ -270,6 +307,27 @@ def test_row(app_client): assert [{'pk': '1', 'content': 'hello'}] == response.json['rows'] +def test_row_foreign_key_tables(app_client): + response = app_client.get('/test_tables/simple_primary_key/1.json?_extras=foreign_key_tables', gather_request=False) + assert response.status == 200 + assert [{ + 'column': 'id', + 'count': 1, + 'other_column': 'f3', + 'other_table': 'complex_foreign_keys' + }, { + 'column': 'id', + 'count': 0, + 'other_column': 'f2', + 'other_table': 'complex_foreign_keys' + }, { + 'column': 'id', + 'count': 1, + 'other_column': 'f1', + 'other_table': 'complex_foreign_keys' + }] == response.json['foreign_key_tables'] + + def test_add_filter_redirects(app_client): filter_args = urllib.parse.urlencode({ '_filter_column': 'content', @@ -379,10 +437,22 @@ CREATE TABLE "table/with/slashes.csv" ( content text ); +CREATE TABLE "complex_foreign_keys" ( + pk varchar(30) primary key, + f1 text, + f2 text, + f3 text, + FOREIGN KEY ("f1") REFERENCES [simple_primary_key](id), + FOREIGN KEY ("f2") REFERENCES [simple_primary_key](id), + FOREIGN KEY ("f3") REFERENCES [simple_primary_key](id) +); + INSERT INTO simple_primary_key VALUES (1, 'hello'); INSERT INTO simple_primary_key VALUES (2, 'world'); INSERT INTO simple_primary_key VALUES (3, ''); +INSERT INTO complex_foreign_keys VALUES (1, 1, 2, 1); + INSERT INTO [table/with/slashes.csv] VALUES (3, 'hey'); CREATE VIEW simple_view AS