Fix TypeError when sorting mixed compound/single foreign keys

sorted() on a foreign_keys list containing both compound (column=None)
and single-column ForeignKeys raised TypeError because dataclass
ordering compared None against str. column/other_column are now
excluded from comparison - ordering and equality use the always
populated columns/other_columns lists instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Simon Willison 2026-07-05 14:26:56 -07:00
commit d5bf51df35
2 changed files with 32 additions and 2 deletions

View file

@ -182,9 +182,11 @@ class ForeignKey:
"""
table: str
column: Optional[str]
# column/other_column are None for compound keys, which would break
# ordering against str values - comparison uses columns/other_columns
column: Optional[str] = field(compare=False)
other_table: str
other_column: Optional[str]
other_column: Optional[str] = field(compare=False)
columns: List[str] = field(default_factory=list)
other_columns: List[str] = field(default_factory=list)
is_compound: bool = False

View file

@ -80,3 +80,31 @@ def test_foreign_keys_are_sortable(fresh_db):
fks = sorted(fresh_db["books"].foreign_keys)
assert fks[0].column == "author_id"
assert fks[1].column == "category_id"
def test_mixed_compound_and_single_foreign_keys_are_sortable():
# compound FKs have column=None, which must not break sorting
# against single-column FKs (None < str raises TypeError)
db = Database(memory=True)
db.executescript("""
CREATE TABLE departments (
campus_name TEXT NOT NULL,
dept_code TEXT NOT NULL,
PRIMARY KEY (campus_name, dept_code)
);
CREATE TABLE accreditations (id INTEGER PRIMARY KEY);
CREATE TABLE courses (
course_code TEXT PRIMARY KEY,
campus_name TEXT NOT NULL,
dept_code TEXT NOT NULL,
accreditation_id INTEGER REFERENCES accreditations(id),
FOREIGN KEY (campus_name, dept_code)
REFERENCES departments(campus_name, dept_code)
);
""")
fks = db["courses"].foreign_keys
assert len(fks) == 2
assert {fk.is_compound for fk in fks} == {True, False}
fks_sorted = sorted(fks)
assert fks_sorted[0].other_table == "accreditations"
assert fks_sorted[1].other_table == "departments"