Skip to content

Commit 61aaa69

Browse files
committed
.transform(..., keep_table=name) parameter, closes #571
Also type hints for the transform_sql() method
1 parent 2c12c01 commit 61aaa69

3 files changed

Lines changed: 42 additions & 13 deletions

File tree

docs/python-api.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,12 @@ The ``.transform()`` method takes a number of parameters, all of which are optio
13761376

13771377
As a bonus, calling ``.transform()`` will reformat the schema for the table that is stored in SQLite to make it more readable. This works even if you call it without any arguments.
13781378

1379+
To keep the original table around instead of dropping it, pass the ``keep_table=`` option and specify the name of the table you would like it to be renamed to:
1380+
1381+
.. code-block:: python
1382+
1383+
table.transform(types={"age": int}, keep_table="original_table")
1384+
13791385
Altering column types
13801386
---------------------
13811387

sqlite_utils/db.py

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,6 +1702,7 @@ def transform(
17021702
defaults: Optional[Dict[str, Any]] = None,
17031703
drop_foreign_keys: Optional[Iterable] = None,
17041704
column_order: Optional[List[str]] = None,
1705+
keep_table: Optional[str] = None,
17051706
) -> "Table":
17061707
"""
17071708
Apply an advanced alter table, including operations that are not supported by
@@ -1717,7 +1718,9 @@ def transform(
17171718
:param defaults: Default values for columns
17181719
:param drop_foreign_keys: Names of columns that should have their foreign key constraints removed
17191720
:param column_order: List of strings specifying a full or partial column order
1720-
to use when creating the table.
1721+
to use when creating the table
1722+
:param keep_table: If specified, the existing table will be renamed to this and will not be
1723+
dropped
17211724
"""
17221725
assert self.exists(), "Cannot transform a table that doesn't exist yet"
17231726
sqls = self.transform_sql(
@@ -1729,6 +1732,7 @@ def transform(
17291732
defaults=defaults,
17301733
drop_foreign_keys=drop_foreign_keys,
17311734
column_order=column_order,
1735+
keep_table=keep_table,
17321736
)
17331737
pragma_foreign_keys_was_on = self.db.execute("PRAGMA foreign_keys").fetchone()[
17341738
0
@@ -1750,15 +1754,16 @@ def transform(
17501754
def transform_sql(
17511755
self,
17521756
*,
1753-
types=None,
1754-
rename=None,
1755-
drop=None,
1756-
pk=DEFAULT,
1757-
not_null=None,
1758-
defaults=None,
1759-
drop_foreign_keys=None,
1760-
column_order=None,
1761-
tmp_suffix=None,
1757+
types: Optional[dict] = None,
1758+
rename: Optional[dict] = None,
1759+
drop: Optional[Iterable] = None,
1760+
pk: Optional[Any] = DEFAULT,
1761+
not_null: Optional[Iterable[str]] = None,
1762+
defaults: Optional[Dict[str, Any]] = None,
1763+
drop_foreign_keys: Optional[Iterable] = None,
1764+
column_order: Optional[List[str]] = None,
1765+
tmp_suffix: Optional[str] = None,
1766+
keep_table: Optional[str] = None,
17621767
) -> List[str]:
17631768
"""
17641769
Return a list of SQL statements that should be executed in order to apply this transformation.
@@ -1771,7 +1776,10 @@ def transform_sql(
17711776
:param defaults: Default values for columns
17721777
:param drop_foreign_keys: Names of columns that should have their foreign key constraints removed
17731778
:param column_order: List of strings specifying a full or partial column order
1774-
to use when creating the table.
1779+
to use when creating the table
1780+
:param tmp_suffix: Suffix to use for the temporary table name
1781+
:param keep_table: If specified, the existing table will be renamed to this and will not be
1782+
dropped
17751783
"""
17761784
types = types or {}
17771785
rename = rename or {}
@@ -1872,8 +1880,13 @@ def transform_sql(
18721880
new_cols=", ".join("[{}]".format(col) for col in new_cols),
18731881
)
18741882
sqls.append(copy_sql)
1875-
# Drop the old table
1876-
sqls.append("DROP TABLE [{}];".format(self.name))
1883+
# Drop (or keep) the old table
1884+
if keep_table:
1885+
sqls.append(
1886+
"ALTER TABLE [{}] RENAME TO [{}];".format(self.name, keep_table)
1887+
)
1888+
else:
1889+
sqls.append("DROP TABLE [{}];".format(self.name))
18771890
# Rename the new one
18781891
sqls.append(
18791892
"ALTER TABLE [{}] RENAME TO [{}];".format(new_table_name, self.name)

tests/test_transform.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,16 @@
8686
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
8787
],
8888
),
89+
# Keeping the table
90+
(
91+
{"drop": ["age"], "keep_table": "kept_table"},
92+
[
93+
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER PRIMARY KEY,\n [name] TEXT\n);",
94+
"INSERT INTO [dogs_new_suffix] ([id], [name])\n SELECT [id], [name] FROM [dogs];",
95+
"ALTER TABLE [dogs] RENAME TO [kept_table];",
96+
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
97+
],
98+
),
8999
],
90100
)
91101
@pytest.mark.parametrize("use_pragma_foreign_keys", [False, True])

0 commit comments

Comments
 (0)