Skip to content

Commit

Permalink
Expand labels in row view as well
Browse files Browse the repository at this point in the history
  • Loading branch information
tmcl-it committed Mar 6, 2023
1 parent 1ad92a1 commit 98c7206
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 58 deletions.
7 changes: 6 additions & 1 deletion datasette/views/row.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
)
import json
import sqlite_utils
from .table import display_columns_and_rows
from .table import display_columns_and_rows, expand_labels


class RowView(DataView):
Expand Down Expand Up @@ -42,6 +42,11 @@ async def data(self, request, default_labels=False):
if not rows:
raise NotFound(f"Record not found: {pk_values}")

# Expand labeled columns if requested
rows, _, _ = await expand_labels(
self.ds, database, table, columns, rows, request.args, default_labels
)

async def template_data():
display_columns, display_rows = await display_columns_and_rows(
self.ds,
Expand Down
132 changes: 75 additions & 57 deletions datasette/views/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,6 @@ async def sortable_columns_for_table(self, database_name, table_name, use_rowid)
sortable_columns.add("rowid")
return sortable_columns

async def expandable_columns(self, database_name, table_name):
# Returns list of (fk_dict, label_column-or-None) pairs for that table
expandables = []
db = self.ds.databases[database_name]
for fk in await db.foreign_keys_for_table(table_name):
label_column = await db.label_column_for_table(fk["other_table"])
expandables.append((fk, label_column))
return expandables

async def post(self, request):
from datasette.app import TableNotFound

Expand Down Expand Up @@ -632,54 +623,15 @@ async def execute_suggested_facets():
rows = list(results.rows)

# Expand labeled columns if requested
expanded_columns = []
expandable_columns = await self.expandable_columns(database_name, table_name)
columns_to_expand = None
try:
all_labels = value_as_boolean(request.args.get("_labels", ""))
except ValueError:
all_labels = default_labels
# Check for explicit _label=
if "_label" in request.args:
columns_to_expand = request.args.getlist("_label")
if columns_to_expand is None and all_labels:
# expand all columns with foreign keys
columns_to_expand = [fk["column"] for fk, _ in expandable_columns]

if columns_to_expand:
expanded_labels = {}
for fk, _ in expandable_columns:
column = fk["column"]
if column not in columns_to_expand:
continue
if column not in columns:
continue
expanded_columns.append(column)
# Gather the values
column_index = columns.index(column)
values = [row[column_index] for row in rows]
# Expand them
expanded_labels.update(
await self.ds.expand_foreign_keys(
database_name, table_name, column, values
)
)
if expanded_labels:
# Rewrite the rows
new_rows = []
for row in rows:
new_row = CustomRow(columns)
for column in row.keys():
value = row[column]
if (column, value) in expanded_labels and value is not None:
new_row[column] = {
"value": value,
"label": expanded_labels[(column, value)],
}
else:
new_row[column] = value
new_rows.append(new_row)
rows = new_rows
rows, expanded_columns, expandable_columns = await expand_labels(
self.ds,
database_name,
table_name,
columns,
rows,
request.args,
default_labels,
)

# Pagination next link
next_value = None
Expand Down Expand Up @@ -1073,6 +1025,72 @@ async def display_columns_and_rows(
return columns, cell_rows


async def expand_labels(
datasette,
database_name,
table_name,
columns,
rows,
request_args,
default_labels,
):
"""Expands labeled columns if requested"""
db = datasette.databases[database_name]
expanded_columns = []
# List of (fk_dict, label_column-or-None) pairs for the table
expandable_columns = []
for fk in await db.foreign_keys_for_table(table_name):
label_column = await db.label_column_for_table(fk["other_table"])
expandable_columns.append((fk, label_column))
columns_to_expand = None
try:
all_labels = value_as_boolean(request_args.get("_labels", ""))
except ValueError:
all_labels = default_labels
# Check for explicit _label=
if "_label" in request_args:
columns_to_expand = request_args.getlist("_label")
if columns_to_expand is None and all_labels:
# expand all columns with foreign keys
columns_to_expand = [fk["column"] for fk, _ in expandable_columns]

if columns_to_expand:
expanded_labels = {}
for fk, _ in expandable_columns:
column = fk["column"]
if column not in columns_to_expand:
continue
if column not in columns:
continue
expanded_columns.append(column)
# Gather the values
column_index = columns.index(column)
values = [row[column_index] for row in rows]
# Expand them
expanded_labels.update(
await datasette.expand_foreign_keys(
database_name, table_name, column, values
)
)
if expanded_labels:
# Rewrite the rows
new_rows = []
for row in rows:
new_row = CustomRow(columns)
for column in row.keys():
value = row[column]
if (column, value) in expanded_labels and value is not None:
new_row[column] = {
"value": value,
"label": expanded_labels[(column, value)],
}
else:
new_row[column] = value
new_rows.append(new_row)
rows = new_rows
return rows, expanded_columns, expandable_columns


class TableInsertView(BaseView):
name = "table-insert"

Expand Down
32 changes: 32 additions & 0 deletions tests/test_table_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,38 @@ async def test_table_html_foreign_key_links(ds_client):
]


@pytest.mark.asyncio
async def test_row_html_foreign_key_links(ds_client):
response = await ds_client.get("/fixtures/foreign_key_references/1")
assert response.status_code == 200
table = Soup(response.text, "html.parser").find("table")
actual = [[str(td) for td in tr.select("td")] for tr in table.select("tbody tr")]
assert actual == [
[
'<td class="col-pk type-str">1</td>',
'<td class="col-foreign_key_with_label type-str"><a href="/fixtures/simple_primary_key/1">hello</a>\xa0<em>1</em></td>',
'<td class="col-foreign_key_with_blank_label type-str"><a href="/fixtures/simple_primary_key/3">-</a>\xa0<em>3</em></td>',
'<td class="col-foreign_key_with_no_label type-str"><a href="/fixtures/primary_key_multiple_columns/1">1</a></td>',
'<td class="col-foreign_key_compound_pk1 type-str">a</td>',
'<td class="col-foreign_key_compound_pk2 type-str">b</td>',
],
]
response = await ds_client.get("/fixtures/foreign_key_references/2")
assert response.status_code == 200
table = Soup(response.text, "html.parser").find("table")
actual = [[str(td) for td in tr.select("td")] for tr in table.select("tbody tr")]
assert actual == [
[
'<td class="col-pk type-str">2</td>',
'<td class="col-foreign_key_with_label type-none">\xa0</td>',
'<td class="col-foreign_key_with_blank_label type-none">\xa0</td>',
'<td class="col-foreign_key_with_no_label type-none">\xa0</td>',
'<td class="col-foreign_key_compound_pk1 type-none">\xa0</td>',
'<td class="col-foreign_key_compound_pk2 type-none">\xa0</td>',
],
]


@pytest.mark.asyncio
async def test_table_html_foreign_key_facets(ds_client):
response = await ds_client.get(
Expand Down

0 comments on commit 98c7206

Please sign in to comment.