diff --git a/datasette/renderer.py b/datasette/renderer.py
index 1d957b8d..757ba594 100644
--- a/datasette/renderer.py
+++ b/datasette/renderer.py
@@ -58,7 +58,8 @@ def json_renderer(request, args, data, error, truncated=None, view_name=None):
status_code = 400
data.update(error_body(error, status_code))
- if truncated is not None:
+ # A single row lookup cannot be truncated
+ if truncated is not None and not single_row:
data["truncated"] = truncated
if shape == "arrayfirst":
# Rows can be dicts, sqlite3.Row or lists (from remove_infinites)
@@ -78,6 +79,10 @@ def json_renderer(request, args, data, error, truncated=None, view_name=None):
("row", row) if key == "rows" else (key, value)
for key, value in data.items()
)
+ # Likewise the render_cell extra becomes a single object
+ if "render_cell" in data:
+ cells = data["render_cell"]
+ data["render_cell"] = cells[0] if cells else {}
if shape == "object":
shape_error = None
if "primary_keys" not in data:
diff --git a/datasette/views/table_extras.py b/datasette/views/table_extras.py
index 48eaa35f..bd56857b 100644
--- a/datasette/views/table_extras.py
+++ b/datasette/views/table_extras.py
@@ -648,12 +648,13 @@ class RenderCellExtra(Extra):
ExtraScope.ROW: ExtraExample(
value={
"row": {"id": 4, "content": "RENDER_CELL_DEMO"},
- "render_cell": [{"content": "Custom rendered HTML"}],
+ "render_cell": {"content": "Custom rendered HTML"},
},
note=(
- "The ``render_cell`` array has one item for the requested row. "
- "The object is keyed by column name. Only columns whose rendered "
- "value differs from the default are included."
+ "The ``render_cell`` object is keyed by column name. Only columns "
+ "whose rendered value differs from the default are included. If a "
+ "``?_shape=`` is specified ``render_cell`` is instead a list with "
+ "one item, matching the ``rows`` list."
),
),
ExtraScope.QUERY: ExtraExample(
diff --git a/docs/json_api.rst b/docs/json_api.rst
index 02bd6d9e..8627a974 100644
--- a/docs/json_api.rst
+++ b/docs/json_api.rst
@@ -960,7 +960,7 @@ The following extras are available for row JSON responses.
``render_cell``
Rendered HTML for each cell using the render_cell plugin hook (See the :ref:`render_cell() plugin hook ` documentation.)
- The ``render_cell`` array has one item for the requested row. The object is keyed by column name. Only columns whose rendered value differs from the default are included.
+ The ``render_cell`` object is keyed by column name. Only columns whose rendered value differs from the default are included. If a ``?_shape=`` is specified ``render_cell`` is instead a list with one item, matching the ``rows`` list.
.. code-block:: json
@@ -969,11 +969,9 @@ The following extras are available for row JSON responses.
"id": 4,
"content": "RENDER_CELL_DEMO"
},
- "render_cell": [
- {
- "content": "Custom rendered HTML"
- }
- ]
+ "render_cell": {
+ "content": "Custom rendered HTML"
+ }
}
``debug``
diff --git a/tests/test_api.py b/tests/test_api.py
index dd2365b6..8b02aeb9 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -369,6 +369,7 @@ async def test_row(ds_client):
assert data["ok"] is True
assert data["row"] == {"id": 1, "content": "hello"}
assert "rows" not in data
+ assert "truncated" not in data
@pytest.mark.asyncio
@@ -391,6 +392,7 @@ async def test_row_shape(ds_client, shape, expected):
data = response.json()
if shape in ("objects", "arrays"):
assert "row" not in data
+ assert data["truncated"] is False
data = data["rows"]
assert data == expected
@@ -650,20 +652,23 @@ async def test_row_extra_render_cell():
assert "render_cell" in data
assert "row" in data
- # render_cell should be a list with one row (since this is a row page)
+ # render_cell is a single object to match "row"
# Only columns modified by plugins are included (sparse output)
- render_cell = data["render_cell"]
- assert len(render_cell) == 1
-
- # The row: id=1, name='Alice'
# The 'name' column should be rendered by our plugin as Alice
- assert render_cell[0]["name"] == "Alice"
# The 'id' column is not included since no plugin modified it
- assert "id" not in render_cell[0]
+ assert data["render_cell"] == {"name": "Alice"}
# The regular row should still contain raw values
assert data["row"] == {"id": 1, "name": "Alice"}
+ # With a ?_shape= render_cell is a list, matching "rows"
+ response = await ds.client.get(
+ "/test_row_render/test_render/1.json?_extra=render_cell&_shape=objects"
+ )
+ data = response.json()
+ assert data["render_cell"] == [{"name": "Alice"}]
+ assert data["rows"] == [{"id": 1, "name": "Alice"}]
+
finally:
ds.pm.unregister(name="TestRenderCellPlugin")
diff --git a/tests/test_column_types.py b/tests/test_column_types.py
index d8dfc627..df20db00 100644
--- a/tests/test_column_types.py
+++ b/tests/test_column_types.py
@@ -748,7 +748,7 @@ async def test_row_endpoint_render_cell_with_column_types(ds_ct):
response = await ds_ct.client.get("/data/posts/1.json?_extra=render_cell")
assert response.status_code == 200
data = response.json()
- rendered = data["render_cell"][0]
+ rendered = data["render_cell"]
assert "mailto:" in rendered["author_email"]
assert "href" in rendered["website"]