Database schema lists each column's foreign key

Without them a model guessed joins: it joined video.channel_id to collection.id
(it is channel.id), and the query silently returned the wrong channel names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Roland 2026-10-11 19:00:04 -06:00
parent 61e58fac17
commit 99cb3395ca
No known key found for this signature in database
GPG key ID: 1BA620CE6C9A4680
2 changed files with 15 additions and 2 deletions

View file

@ -157,7 +157,8 @@ def _is_fts_shadow_table(name: str, virtual_tables: List[str]) -> bool:
def get_schema() -> List[dict]:
"""Describe every table and view (but not SQLite internals or FTS5's shadow tables)."""
"""Describe every table and view (but not SQLite internals or FTS5's shadow tables), with the foreign key each
column references."""
with read_only_connection() as conn:
objects = conn.execute(
"SELECT name, type, sql FROM sqlite_master"
@ -169,8 +170,14 @@ def get_schema() -> List[dict]:
if _is_fts_shadow_table(name, virtual_tables):
continue
is_virtual = name in virtual_tables
# How this table joins to others, e.g. {'channel_id': 'channel.id'}.
references = {
from_: f'{table}.{to}' for _, _, table, from_, to, *_ in conn.execute(
'SELECT * FROM pragma_foreign_key_list(?)', (name,)).fetchall()
}
columns = [
dict(name=col_name, type=col_type, not_null=bool(not_null), primary_key=bool(pk))
dict(name=col_name, type=col_type, not_null=bool(not_null), primary_key=bool(pk),
references=references.get(col_name))
for _, col_name, col_type, not_null, _, pk in conn.execute(
'SELECT * FROM pragma_table_info(?)', (name,)).fetchall()
]

View file

@ -186,6 +186,12 @@ async def test_database_schema(test_session, async_client, allow_database_query)
assert 'name' in columns
assert any(i['columns'] == ['name'] for i in tag['indexes'])
# Foreign keys say how tables join; `video.channel_id` is a channel, not a collection.
video_columns = {i['name']: i for i in tables['video']['columns']}
assert video_columns['channel_id']['references'] == 'channel.id'
assert video_columns['file_group_id']['references'] == 'file_group.id'
assert columns['name']['references'] is None
# FTS5 tables are described (with their definition), but their shadow tables are not.
virtual = [i for i in tables.values() if i['type'] == 'virtual']
assert virtual and all('fts5' in i['sql'].lower() for i in virtual)