Compound primary key support for /db/-/create - closes #1911

Needed for tests in #1864
pull/1912/head
Simon Willison 2022-11-29 10:47:46 -08:00
rodzic 484bef0d3b
commit 1154048f79
3 zmienionych plików z 69 dodań i 3 usunięć

Wyświetl plik

@ -701,7 +701,7 @@ async def _table_columns(datasette, database_name):
class TableCreateView(BaseView):
name = "table-create"
_valid_keys = {"table", "rows", "row", "columns", "pk"}
_valid_keys = {"table", "rows", "row", "columns", "pk", "pks"}
_supported_column_types = {
"text",
"integer",
@ -785,18 +785,28 @@ class TableCreateView(BaseView):
return _error(["rows must be a list of objects"])
pk = data.get("pk")
pks = data.get("pks")
if pk and pks:
return _error(["Cannot specify both pk and pks"])
if pk:
if not isinstance(pk, str):
return _error(["pk must be a string"])
if pks:
if not isinstance(pks, list):
return _error(["pks must be a list"])
for pk in pks:
if not isinstance(pk, str):
return _error(["pks must be a list of strings"])
def create_table(conn):
table = sqlite_utils.Database(conn)[table_name]
if rows:
table.insert_all(rows, pk=pk)
table.insert_all(rows, pk=pks or pk)
else:
table.create(
{c["name"]: c["type"] for c in columns},
pk=pk,
pk=pks or pk,
)
return table.schema

Wyświetl plik

@ -666,6 +666,8 @@ The JSON here describes the table that will be created:
If you set this to ``id`` without including an ``id`` column in the list of ``columns``, Datasette will create an integer ID column for you.
* ``pks`` can be used instead of ``pk`` to create a compound primary key. It should be a JSON list of column names to use in that primary key.
If the table is successfully created this will return a ``201`` status code and the following response:
.. code-block:: json

Wyświetl plik

@ -643,6 +643,27 @@ async def test_drop_table(ds_write, scenario):
"row_count": 1,
},
),
# Create table with compound primary key
(
{
"table": "five",
"row": {"type": "article", "key": 123, "title": "Article 1"},
"pks": ["type", "key"],
},
201,
{
"ok": True,
"database": "data",
"table": "five",
"table_url": "http://localhost/data/five",
"table_api_url": "http://localhost/data/five.json",
"schema": (
"CREATE TABLE [five] (\n [type] TEXT,\n [key] INTEGER,\n"
" [title] TEXT,\n PRIMARY KEY ([type], [key])\n)"
),
"row_count": 1,
},
),
# Error: Table is required
(
{
@ -799,6 +820,39 @@ async def test_drop_table(ds_write, scenario):
"errors": ["pk must be a string"],
},
),
# Error: Cannot specify both pk and pks
(
{
"table": "bad",
"row": {"id": 1, "name": "Row 1"},
"pk": "id",
"pks": ["id", "name"],
},
400,
{
"ok": False,
"errors": ["Cannot specify both pk and pks"],
},
),
# Error: pks must be a list
(
{
"table": "bad",
"row": {"id": 1, "name": "Row 1"},
"pks": "id",
},
400,
{
"ok": False,
"errors": ["pks must be a list"],
},
),
# Error: pks must be a list of strings
(
{"table": "bad", "row": {"id": 1, "name": "Row 1"}, "pks": [1, 2]},
400,
{"ok": False, "errors": ["pks must be a list of strings"]},
),
),
)
async def test_create_table(ds_write, input, expected_status, expected_response):