catalog_views table, closes #2495

Refs https://github.com/datasette/datasette-queries/issues/1#issuecomment-3074491003
This commit is contained in:
Simon Willison 2025-07-15 10:22:56 -07:00
commit 7a602140df
3 changed files with 46 additions and 1 deletions

View file

@ -19,6 +19,14 @@ async def init_internal_db(db):
PRIMARY KEY (database_name, table_name),
FOREIGN KEY (database_name) REFERENCES catalog_databases(database_name)
);
CREATE TABLE IF NOT EXISTS catalog_views (
database_name TEXT,
view_name TEXT,
rootpage INTEGER,
sql TEXT,
PRIMARY KEY (database_name, view_name),
FOREIGN KEY (database_name) REFERENCES catalog_databases(database_name)
);
CREATE TABLE IF NOT EXISTS catalog_columns (
database_name TEXT,
table_name TEXT,
@ -111,6 +119,9 @@ async def populate_schema_tables(internal_db, db):
conn.execute(
"DELETE FROM catalog_tables WHERE database_name = ?", [database_name]
)
conn.execute(
"DELETE FROM catalog_views WHERE database_name = ?", [database_name]
)
conn.execute(
"DELETE FROM catalog_columns WHERE database_name = ?", [database_name]
)
@ -125,13 +136,21 @@ async def populate_schema_tables(internal_db, db):
await internal_db.execute_write_fn(delete_everything)
tables = (await db.execute("select * from sqlite_master WHERE type = 'table'")).rows
views = (await db.execute("select * from sqlite_master WHERE type = 'view'")).rows
def collect_info(conn):
tables_to_insert = []
views_to_insert = []
columns_to_insert = []
foreign_keys_to_insert = []
indexes_to_insert = []
for view in views:
view_name = view["name"]
views_to_insert.append(
(database_name, view_name, view["rootpage"], view["sql"])
)
for table in tables:
table_name = table["name"]
tables_to_insert.append(
@ -165,6 +184,7 @@ async def populate_schema_tables(internal_db, db):
)
return (
tables_to_insert,
views_to_insert,
columns_to_insert,
foreign_keys_to_insert,
indexes_to_insert,
@ -172,6 +192,7 @@ async def populate_schema_tables(internal_db, db):
(
tables_to_insert,
views_to_insert,
columns_to_insert,
foreign_keys_to_insert,
indexes_to_insert,
@ -184,6 +205,13 @@ async def populate_schema_tables(internal_db, db):
""",
tables_to_insert,
)
await internal_db.execute_write_many(
"""
INSERT INTO catalog_views (database_name, view_name, rootpage, sql)
values (?, ?, ?, ?)
""",
views_to_insert,
)
await internal_db.execute_write_many(
"""
INSERT INTO catalog_columns (

View file

@ -1378,7 +1378,7 @@ Datasette's internal database
Datasette maintains an "internal" SQLite database used for configuration, caching, and storage. Plugins can store configuration, settings, and other data inside this database. By default, Datasette will use a temporary in-memory SQLite database as the internal database, which is created at startup and destroyed at shutdown. Users of Datasette can optionally pass in a ``--internal`` flag to specify the path to a SQLite database to use as the internal database, which will persist internal data across Datasette instances.
Datasette maintains tables called ``catalog_databases``, ``catalog_tables``, ``catalog_columns``, ``catalog_indexes``, ``catalog_foreign_keys`` with details of the attached databases and their schemas. These tables should not be considered a stable API - they may change between Datasette releases.
Datasette maintains tables called ``catalog_databases``, ``catalog_tables``, ``catalog_views``, ``catalog_columns``, ``catalog_indexes``, ``catalog_foreign_keys`` with details of the attached databases and their schemas. These tables should not be considered a stable API - they may change between Datasette releases.
Metadata is stored in tables ``metadata_instance``, ``metadata_databases``, ``metadata_resources`` and ``metadata_columns``. Plugins can interact with these tables via the :ref:`get_*_metadata() and set_*_metadata() methods <datasette_get_set_metadata>`.
@ -1421,6 +1421,14 @@ The internal database schema is as follows:
PRIMARY KEY (database_name, table_name),
FOREIGN KEY (database_name) REFERENCES catalog_databases(database_name)
);
CREATE TABLE catalog_views (
database_name TEXT,
view_name TEXT,
rootpage INTEGER,
sql TEXT,
PRIMARY KEY (database_name, view_name),
FOREIGN KEY (database_name) REFERENCES catalog_databases(database_name)
);
CREATE TABLE catalog_columns (
database_name TEXT,
table_name TEXT,

View file

@ -25,6 +25,15 @@ async def test_internal_tables(ds_client):
assert set(table.keys()) == {"rootpage", "table_name", "database_name", "sql"}
@pytest.mark.asyncio
async def test_internal_views(ds_client):
internal_db = await ensure_internal(ds_client)
views = await internal_db.execute("select * from catalog_views")
assert len(views) >= 4
view = views.rows[0]
assert set(view.keys()) == {"rootpage", "view_name", "database_name", "sql"}
@pytest.mark.asyncio
async def test_internal_indexes(ds_client):
internal_db = await ensure_internal(ds_client)