mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Migrate /database view to use bulk allowed_resources()
Replace one-by-one permission checks with bulk allowed_resources() call: - DatabaseView and QueryView now fetch all allowed tables once - Filter views and tables using pre-fetched allowed_table_set - Update TableResource.resources_sql() to include views from catalog_views This improves performance by reducing permission checks from O(n) to O(1) per table/view, where n is the number of tables in the database. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
23715d6c00
commit
2620938661
2 changed files with 40 additions and 15 deletions
|
|
@ -48,6 +48,9 @@ class TableResource(Resource):
|
|||
return """
|
||||
SELECT database_name AS parent, table_name AS child
|
||||
FROM catalog_tables
|
||||
UNION ALL
|
||||
SELECT database_name AS parent, view_name AS child
|
||||
FROM catalog_views
|
||||
"""
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -71,17 +71,26 @@ class DatabaseView(View):
|
|||
|
||||
metadata = await datasette.get_database_metadata(database)
|
||||
|
||||
# Get all tables/views this actor can see in bulk
|
||||
from datasette.resources import TableResource
|
||||
|
||||
allowed_tables = await datasette.allowed_resources("view-table", request.actor)
|
||||
allowed_table_set = {
|
||||
(r.parent, r.child) for r in allowed_tables if r.parent == database
|
||||
}
|
||||
|
||||
sql_views = []
|
||||
for view_name in await db.view_names():
|
||||
view_visible, view_private = await datasette.check_visibility(
|
||||
request.actor,
|
||||
permissions=[
|
||||
("view-table", (database, view_name)),
|
||||
("view-database", database),
|
||||
"view-instance",
|
||||
],
|
||||
)
|
||||
if view_visible:
|
||||
if (database, view_name) in allowed_table_set:
|
||||
# Check if it's private (requires elevated permissions)
|
||||
_, view_private = await datasette.check_visibility(
|
||||
request.actor,
|
||||
permissions=[
|
||||
("view-table", (database, view_name)),
|
||||
("view-database", database),
|
||||
"view-instance",
|
||||
],
|
||||
)
|
||||
sql_views.append(
|
||||
{
|
||||
"name": view_name,
|
||||
|
|
@ -89,7 +98,7 @@ class DatabaseView(View):
|
|||
}
|
||||
)
|
||||
|
||||
tables = await get_tables(datasette, request, db)
|
||||
tables = await get_tables(datasette, request, db, allowed_table_set)
|
||||
canned_queries = []
|
||||
for query in (
|
||||
await datasette.get_canned_queries(database, request.actor)
|
||||
|
|
@ -332,7 +341,7 @@ class QueryContext(Context):
|
|||
)
|
||||
|
||||
|
||||
async def get_tables(datasette, request, db):
|
||||
async def get_tables(datasette, request, db, allowed_table_set):
|
||||
tables = []
|
||||
database = db.name
|
||||
table_counts = await db.table_counts(100)
|
||||
|
|
@ -340,7 +349,11 @@ async def get_tables(datasette, request, db):
|
|||
all_foreign_keys = await db.get_all_foreign_keys()
|
||||
|
||||
for table in table_counts:
|
||||
table_visible, table_private = await datasette.check_visibility(
|
||||
if (database, table) not in allowed_table_set:
|
||||
continue
|
||||
|
||||
# Check if it's private (requires elevated permissions)
|
||||
_, table_private = await datasette.check_visibility(
|
||||
request.actor,
|
||||
permissions=[
|
||||
("view-table", (database, table)),
|
||||
|
|
@ -348,8 +361,7 @@ async def get_tables(datasette, request, db):
|
|||
"view-instance",
|
||||
],
|
||||
)
|
||||
if not table_visible:
|
||||
continue
|
||||
|
||||
table_columns = await db.table_columns(table)
|
||||
tables.append(
|
||||
{
|
||||
|
|
@ -509,6 +521,14 @@ class QueryView(View):
|
|||
db = await datasette.resolve_database(request)
|
||||
database = db.name
|
||||
|
||||
# Get all tables/views this actor can see in bulk
|
||||
from datasette.resources import TableResource
|
||||
|
||||
allowed_tables = await datasette.allowed_resources("view-table", request.actor)
|
||||
allowed_table_set = {
|
||||
(r.parent, r.child) for r in allowed_tables if r.parent == database
|
||||
}
|
||||
|
||||
# Are we a canned query?
|
||||
canned_query = None
|
||||
canned_query_write = False
|
||||
|
|
@ -808,7 +828,9 @@ class QueryView(View):
|
|||
show_hide_text=show_hide_text,
|
||||
editable=not canned_query,
|
||||
allow_execute_sql=allow_execute_sql,
|
||||
tables=await get_tables(datasette, request, db),
|
||||
tables=await get_tables(
|
||||
datasette, request, db, allowed_table_set
|
||||
),
|
||||
named_parameter_values=named_parameter_values,
|
||||
edit_sql_url=edit_sql_url,
|
||||
display_rows=await display_rows(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue