Detect single unique text column in label_column_for_table, closes #2458

Also added new tests for label_column_for_table()
main
Simon Willison 2025-02-01 17:02:49 -08:00
rodzic d9a450b197
commit b190b87ec6
2 zmienionych plików z 126 dodań i 1 usunięć

Wyświetl plik

@ -3,6 +3,7 @@ from collections import namedtuple
from pathlib import Path
import janus
import queue
import sqlite_utils
import sys
import threading
import uuid
@ -442,7 +443,33 @@ class Database:
)
if explicit_label_column:
return explicit_label_column
column_names = await self.execute_fn(lambda conn: table_columns(conn, table))
def column_details(conn):
# Returns {column_name: (type, is_unique)}
db = sqlite_utils.Database(conn)
columns = db[table].columns_dict
indexes = db[table].indexes
details = {}
for name in columns:
is_unique = any(
index
for index in indexes
if index.columns == [name] and index.unique
)
details[name] = (columns[name], is_unique)
return details
column_details = await self.execute_fn(column_details)
# Is there just one unique column that's text?
unique_text_columns = [
name
for name, (type_, is_unique) in column_details.items()
if is_unique and type_ is str
]
if len(unique_text_columns) == 1:
return unique_text_columns[0]
column_names = list(column_details.keys())
# Is there a name or title column?
name_or_title = [c for c in column_names if c.lower() in ("name", "title")]
if name_or_title:
@ -452,6 +479,7 @@ class Database:
column_names
and len(column_names) == 2
and ("id" in column_names or "pk" in column_names)
and not set(column_names) == {"id", "pk"}
):
return [c for c in column_names if c not in ("id", "pk")][0]
# Couldn't find a label:

Wyświetl plik

@ -0,0 +1,97 @@
import pytest
from datasette.database import Database
from datasette.app import Datasette
@pytest.mark.asyncio
@pytest.mark.parametrize(
"create_sql,table_name,config,expected_label_column",
[
# Explicit label_column
(
"create table t1 (id integer primary key, name text, title text);",
"t1",
{"t1": {"label_column": "title"}},
"title",
),
# Single unique text column
(
"create table t2 (id integer primary key, name2 text unique, title text);",
"t2",
{},
"name2",
),
(
"create table t3 (id integer primary key, title2 text unique, name text);",
"t3",
{},
"title2",
),
# Two unique text columns means it cannot decide on one
(
"create table t3x (id integer primary key, name2 text unique, title2 text unique);",
"t3x",
{},
None,
),
# Name or title column
(
"create table t4 (id integer primary key, name text);",
"t4",
{},
"name",
),
(
"create table t5 (id integer primary key, title text);",
"t5",
{},
"title",
),
# But not if there are multiple non-unique text that are not called title
(
"create table t5x (id integer primary key, other1 text, other2 text);",
"t5x",
{},
None,
),
(
"create table t6 (id integer primary key, Name text);",
"t6",
{},
"Name",
),
(
"create table t7 (id integer primary key, Title text);",
"t7",
{},
"Title",
),
# Two columns, one of which is id
(
"create table t8 (id integer primary key, content text);",
"t8",
{},
"content",
),
(
"create table t9 (pk integer primary key, content text);",
"t9",
{},
"content",
),
],
)
async def test_label_column_for_table(
create_sql, table_name, config, expected_label_column
):
"""Test cases for label_column_for_table method"""
ds = Datasette()
db = ds.add_database(Database(ds, memory_name="test_label_column_for_table"))
await db.execute_write_script(create_sql)
if config:
ds.config = {"databases": {"test_label_column_for_table": {"tables": config}}}
actual_label_column = await db.label_column_for_table(table_name)
if expected_label_column is None:
assert actual_label_column is None
else:
assert actual_label_column == expected_label_column