mirror of
https://github.com/simonw/sqlite-utils.git
synced 2026-09-29 05:14:28 +02:00
Fix transform() raising TransformError when renaming an indexed column
Renaming a column that has an index is valid — the index should be recreated using the new column name. Only dropping a column makes an index unrecoverable and warrants the error.
This commit is contained in:
parent
6a456830ca
commit
95826535c7
2 changed files with 33 additions and 11 deletions
|
|
@ -2851,13 +2851,17 @@ class Table(Queryable):
|
||||||
if keep_table:
|
if keep_table:
|
||||||
sqls.append(f"DROP INDEX IF EXISTS {quote_identifier(index.name)};")
|
sqls.append(f"DROP INDEX IF EXISTS {quote_identifier(index.name)};")
|
||||||
for col in index.columns:
|
for col in index.columns:
|
||||||
if col in rename or col in drop:
|
if col in drop:
|
||||||
raise TransformError(
|
raise TransformError(
|
||||||
f"Index '{index.name}' column '{col}' is not in updated table '{self.name}'. "
|
f"Index '{index.name}' column '{col}' is not in updated table '{self.name}'. "
|
||||||
f"You must manually drop this index prior to running this transformation "
|
f"You must manually drop this index prior to running this transformation "
|
||||||
f"and manually recreate the new index after running this transformation. "
|
f"and manually recreate the new index after running this transformation. "
|
||||||
f"The original index sql statement is: `{index_sql}`. No changes have been applied to this table."
|
f"The original index sql statement is: `{index_sql}`. No changes have been applied to this table."
|
||||||
)
|
)
|
||||||
|
elif col in rename:
|
||||||
|
index_sql = index_sql.replace(
|
||||||
|
quote_identifier(col), quote_identifier(rename[col])
|
||||||
|
)
|
||||||
sqls.append(index_sql)
|
sqls.append(index_sql)
|
||||||
return sqls
|
return sqls
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -827,6 +827,19 @@ def test_transform_indexes(fresh_db, indexes, transform_params):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_transform_rename_column_with_index(fresh_db):
|
||||||
|
# https://github.com/simonw/sqlite-utils/issues/822
|
||||||
|
table = fresh_db["t"]
|
||||||
|
table.insert({"id": 1, "name": "Alice"}, pk="id")
|
||||||
|
table.create_index(["name"])
|
||||||
|
# Renaming an indexed column should not raise TransformError
|
||||||
|
table.transform(rename={"name": "full_name"})
|
||||||
|
assert [col.name for col in table.columns] == ["id", "full_name"]
|
||||||
|
# The index should be recreated on the new column name
|
||||||
|
assert len(table.indexes) == 1
|
||||||
|
assert table.indexes[0].columns == ["full_name"]
|
||||||
|
|
||||||
|
|
||||||
def test_transform_retains_indexes_with_foreign_keys(fresh_db):
|
def test_transform_retains_indexes_with_foreign_keys(fresh_db):
|
||||||
dogs = fresh_db["dogs"]
|
dogs = fresh_db["dogs"]
|
||||||
owners = fresh_db["owners"]
|
owners = fresh_db["owners"]
|
||||||
|
|
@ -855,22 +868,15 @@ def test_transform_retains_indexes_with_foreign_keys(fresh_db):
|
||||||
), f"Indexes before transform: {indexes_before_transform}\nIndexes after transform: {dogs.indexes}"
|
), f"Indexes before transform: {indexes_before_transform}\nIndexes after transform: {dogs.indexes}"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
def test_transform_with_indexes_errors(fresh_db):
|
||||||
"transform_params",
|
# Should error with a compound (name, age) index if age is dropped
|
||||||
[
|
|
||||||
{"rename": {"age": "dog_age"}},
|
|
||||||
{"drop": ["age"]},
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_transform_with_indexes_errors(fresh_db, transform_params):
|
|
||||||
# Should error with a compound (name, age) index if age is renamed or dropped
|
|
||||||
dogs = fresh_db["dogs"]
|
dogs = fresh_db["dogs"]
|
||||||
dogs.insert({"id": 1, "name": "Cleo", "age": 5}, pk="id")
|
dogs.insert({"id": 1, "name": "Cleo", "age": 5}, pk="id")
|
||||||
|
|
||||||
dogs.create_index(["name", "age"])
|
dogs.create_index(["name", "age"])
|
||||||
|
|
||||||
with pytest.raises(TransformError) as excinfo:
|
with pytest.raises(TransformError) as excinfo:
|
||||||
dogs.transform(**transform_params)
|
dogs.transform(drop=["age"])
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
"Index 'idx_dogs_name_age' column 'age' is not in updated table 'dogs'. "
|
"Index 'idx_dogs_name_age' column 'age' is not in updated table 'dogs'. "
|
||||||
|
|
@ -879,6 +885,18 @@ def test_transform_with_indexes_errors(fresh_db, transform_params):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_transform_rename_column_in_compound_index(fresh_db):
|
||||||
|
# https://github.com/simonw/sqlite-utils/issues/822
|
||||||
|
# Renaming a column in a compound index should update the index, not error
|
||||||
|
dogs = fresh_db["dogs"]
|
||||||
|
dogs.insert({"id": 1, "name": "Cleo", "age": 5}, pk="id")
|
||||||
|
dogs.create_index(["name", "age"])
|
||||||
|
dogs.transform(rename={"age": "dog_age"})
|
||||||
|
assert [col.name for col in dogs.columns] == ["id", "name", "dog_age"]
|
||||||
|
assert len(dogs.indexes) == 1
|
||||||
|
assert dogs.indexes[0].columns == ["name", "dog_age"]
|
||||||
|
|
||||||
|
|
||||||
def test_transform_with_unique_constraint_implicit_index(fresh_db):
|
def test_transform_with_unique_constraint_implicit_index(fresh_db):
|
||||||
dogs = fresh_db["dogs"]
|
dogs = fresh_db["dogs"]
|
||||||
# Create a table with a UNIQUE constraint on 'name', which creates an implicit index
|
# Create a table with a UNIQUE constraint on 'name', which creates an implicit index
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue