mirror of
https://github.com/simonw/datasette.git
synced 2026-06-23 09:14:34 +02:00
Expose foreign key data to alter table UI
Include current foreign key metadata in the alter table page data and allow the foreign-key-targets endpoint to be read by actors with alter-table permission for a specific table. Add API and HTML data tests for the new alter-table foreign key support.
This commit is contained in:
parent
dada4de172
commit
063b04ad83
4 changed files with 46 additions and 2 deletions
|
|
@ -382,6 +382,19 @@ async def _table_alter_ui(
|
|||
return None
|
||||
|
||||
column_types_map = await datasette.get_column_types(database_name, table_name)
|
||||
foreign_keys_by_column = {}
|
||||
for fk in await db.foreign_keys_for_table(table_name):
|
||||
other_column = fk["other_column"]
|
||||
if other_column is None and await db.table_exists(fk["other_table"]):
|
||||
other_pks = await db.primary_keys(fk["other_table"])
|
||||
if len(other_pks) == 1:
|
||||
other_column = other_pks[0]
|
||||
if other_column is None:
|
||||
continue
|
||||
foreign_keys_by_column[fk["column"]] = {
|
||||
"fk_table": fk["other_table"],
|
||||
"fk_column": other_column,
|
||||
}
|
||||
columns = []
|
||||
for column in await db.table_column_details(table_name):
|
||||
if column.hidden:
|
||||
|
|
@ -397,6 +410,7 @@ async def _table_alter_ui(
|
|||
"default": column.default_value,
|
||||
"has_default": column.default_value is not None,
|
||||
"is_pk": column.name in pks,
|
||||
"foreign_key": foreign_keys_by_column.get(column.name),
|
||||
"column_type": (
|
||||
{"type": column_type.name, "config": column_type.config}
|
||||
if column_type is not None
|
||||
|
|
@ -412,6 +426,10 @@ async def _table_alter_ui(
|
|||
"primaryKeys": pks,
|
||||
"columnTypes": ALTER_TABLE_COLUMN_TYPES,
|
||||
"defaultExpressions": list(DEFAULT_EXPR_SQL),
|
||||
"foreignKeyTargetsPath": "{}/-/foreign-key-targets?table={}".format(
|
||||
datasette.urls.database(database_name),
|
||||
urllib.parse.quote(table_name, safe=""),
|
||||
),
|
||||
}
|
||||
can_set_column_type = await datasette.allowed(
|
||||
action="set-column-type",
|
||||
|
|
|
|||
|
|
@ -867,11 +867,20 @@ class DatabaseForeignKeyTargetsView(BaseView):
|
|||
db = await self.ds.resolve_database(request)
|
||||
database_name = db.name
|
||||
|
||||
if not await self.ds.allowed(
|
||||
table_name = request.args.get("table")
|
||||
can_create_table = await self.ds.allowed(
|
||||
action="create-table",
|
||||
resource=DatabaseResource(database=database_name),
|
||||
actor=request.actor,
|
||||
):
|
||||
)
|
||||
can_alter_table = False
|
||||
if table_name and await db.table_exists(table_name):
|
||||
can_alter_table = await self.ds.allowed(
|
||||
action="alter-table",
|
||||
resource=TableResource(database=database_name, table=table_name),
|
||||
actor=request.actor,
|
||||
)
|
||||
if not (can_create_table or can_alter_table):
|
||||
return _error(["Permission denied: need create-table"], 403)
|
||||
|
||||
hidden_tables = await db.execute_fn(
|
||||
|
|
|
|||
|
|
@ -1252,6 +1252,17 @@ async def test_foreign_key_targets_permission_denied(ds_write):
|
|||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_foreign_key_targets_allowed_for_alter_table(ds_write):
|
||||
token = write_token(ds_write, permissions=["at"])
|
||||
response = await ds_write.client.get(
|
||||
"/data/-/foreign-key-targets?table=docs",
|
||||
headers=_headers(token),
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json()["ok"] is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_alter_table_permission_denied(ds_write):
|
||||
token = write_token(ds_write, permissions=["ir"])
|
||||
|
|
|
|||
|
|
@ -1137,6 +1137,9 @@ async def test_table_alter_action_button_and_data():
|
|||
assert alter_data["tableName"] == "items"
|
||||
assert alter_data["primaryKeys"] == ["id"]
|
||||
assert alter_data["columnTypes"] == ["text", "integer", "float", "blob"]
|
||||
assert alter_data["foreignKeyTargetsPath"] == (
|
||||
"/data/-/foreign-key-targets?table=items"
|
||||
)
|
||||
assert alter_data["defaultExpressions"] == [
|
||||
"current_timestamp",
|
||||
"current_date",
|
||||
|
|
@ -1158,6 +1161,7 @@ async def test_table_alter_action_button_and_data():
|
|||
"default": None,
|
||||
"has_default": False,
|
||||
"is_pk": True,
|
||||
"foreign_key": None,
|
||||
"column_type": None,
|
||||
},
|
||||
{
|
||||
|
|
@ -1168,6 +1172,7 @@ async def test_table_alter_action_button_and_data():
|
|||
"default": None,
|
||||
"has_default": False,
|
||||
"is_pk": False,
|
||||
"foreign_key": None,
|
||||
"column_type": {"type": "textarea", "config": None},
|
||||
},
|
||||
{
|
||||
|
|
@ -1178,6 +1183,7 @@ async def test_table_alter_action_button_and_data():
|
|||
"default": "5",
|
||||
"has_default": True,
|
||||
"is_pk": False,
|
||||
"foreign_key": None,
|
||||
"column_type": None,
|
||||
},
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue