Skip to content

Commit 77d2419

Browse files
simonwclaude
andcommitted
Match column names case-insensitively, closes #760
Column names passed to Python API methods are now resolved against the table schema case-insensitively, mirroring how SQLite itself compares identifiers (ASCII-only case folding). Fixes KeyError populating last_pk from insert()/upsert(), silently ignored transform() rename/drop/types options, duplicate column errors from create_table(transform=True), redundant lookup() indexes, and case-sensitive foreign key validation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 50938ee commit 77d2419

3 files changed

Lines changed: 442 additions & 42 deletions

File tree

docs/changelog.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ Other foreign key improvements:
2929
- Foreign keys declared as ``REFERENCES other_table`` with no explicit column are now resolved to the other table's primary key by ``table.foreign_keys``, instead of reporting ``other_column=None``.
3030
- Fixed a ``TypeError`` when sorting ``ForeignKey`` objects where some were compound.
3131

32+
Case-insensitive column matching:
33+
34+
Column names passed to Python API methods are now matched against the table schema case-insensitively, mirroring how SQLite itself treats identifiers. Previously many methods accepted mixed-case identifiers in the SQL they generated but then failed - or silently did nothing - when performing Python-side comparisons against the schema. (:issue:`760`) Fixes include:
35+
36+
- ``table.insert()`` and ``table.upsert()`` now populate ``table.last_pk`` correctly when the ``pk=`` argument uses different casing to the table schema or the record keys - previously this raised a ``KeyError`` after the row had already been written.
37+
- Upserts no longer raise or misbehave when the casing of ``pk=`` differs from the casing of the record keys. The primary key columns are correctly excluded from the generated ``DO UPDATE SET`` clause.
38+
- ``table.transform()`` arguments ``types=``, ``rename=``, ``drop=``, ``pk=``, ``not_null=``, ``defaults=``, ``column_order=`` and ``drop_foreign_keys=`` all resolve column names case-insensitively. Previously options like ``rename={"name": "title"}`` against a column called ``Name`` were silently ignored.
39+
- ``db.create_table(..., transform=True)`` now recognizes existing columns that differ only by case, instead of attempting to add them again and failing with ``duplicate column name``. The casing used in the existing schema is preserved.
40+
- ``table.lookup()`` returns the primary key value even if ``pk=`` casing differs from the schema, and recognizes existing unique indexes case-insensitively instead of creating redundant ones.
41+
- ``table.extract()`` and ``table.convert()`` - including ``multi=True`` and ``output=`` - accept column names in any casing.
42+
- Foreign key columns are validated and recorded using the casing of the actual schema columns, in ``foreign_keys=`` when creating tables, ``db.add_foreign_keys()``, ``table.add_foreign_key()`` and ``table.add_column(fk_col=...)``. Duplicate foreign key detection is also case-insensitive.
43+
- ``table.create()`` with ``pk=``, ``not_null=``, ``defaults=`` or ``column_order=`` referencing columns using different casing no longer creates an unwanted extra primary key column or raises a ``ValueError``.
44+
3245
.. _v4_0rc2:
3346

3447
4.0rc2 (2026-07-04)

0 commit comments

Comments
 (0)