Skip to content

Commit 1c6ea54

Browse files
authored
.transform() now preserves rowid values
* .transform() now preserves rowid values, refs #592 * Test transform rowids against different table types, closes #592
1 parent 5d123f0 commit 1c6ea54

File tree

2 files changed

+49
-13
lines changed

2 files changed

+49
-13
lines changed

sqlite_utils/db.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,6 +1917,10 @@ def transform_sql(
19171917
for from_, to_ in copy_from_to.items():
19181918
old_cols.append(from_)
19191919
new_cols.append(to_)
1920+
# Ensure rowid is copied too
1921+
if "rowid" not in new_cols:
1922+
new_cols.insert(0, "rowid")
1923+
old_cols.insert(0, "rowid")
19201924
copy_sql = "INSERT INTO [{new_table}] ({new_cols})\n SELECT {old_cols} FROM [{old_table}];".format(
19211925
new_table=new_table_name,
19221926
old_table=self.name,

tests/test_transform.py

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
{},
1212
[
1313
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER PRIMARY KEY,\n [name] TEXT,\n [age] TEXT\n);",
14-
"INSERT INTO [dogs_new_suffix] ([id], [name], [age])\n SELECT [id], [name], [age] FROM [dogs];",
14+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name], [age])\n SELECT [rowid], [id], [name], [age] FROM [dogs];",
1515
"DROP TABLE [dogs];",
1616
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
1717
],
@@ -21,7 +21,7 @@
2121
{"types": {"age": int}},
2222
[
2323
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER PRIMARY KEY,\n [name] TEXT,\n [age] INTEGER\n);",
24-
"INSERT INTO [dogs_new_suffix] ([id], [name], [age])\n SELECT [id], [name], [age] FROM [dogs];",
24+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name], [age])\n SELECT [rowid], [id], [name], [age] FROM [dogs];",
2525
"DROP TABLE [dogs];",
2626
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
2727
],
@@ -31,7 +31,7 @@
3131
{"rename": {"age": "dog_age"}},
3232
[
3333
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER PRIMARY KEY,\n [name] TEXT,\n [dog_age] TEXT\n);",
34-
"INSERT INTO [dogs_new_suffix] ([id], [name], [dog_age])\n SELECT [id], [name], [age] FROM [dogs];",
34+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name], [dog_age])\n SELECT [rowid], [id], [name], [age] FROM [dogs];",
3535
"DROP TABLE [dogs];",
3636
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
3737
],
@@ -41,7 +41,7 @@
4141
{"drop": ["age"]},
4242
[
4343
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER PRIMARY KEY,\n [name] TEXT\n);",
44-
"INSERT INTO [dogs_new_suffix] ([id], [name])\n SELECT [id], [name] FROM [dogs];",
44+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name])\n SELECT [rowid], [id], [name] FROM [dogs];",
4545
"DROP TABLE [dogs];",
4646
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
4747
],
@@ -51,7 +51,7 @@
5151
{"types": {"age": int}, "rename": {"age": "dog_age"}},
5252
[
5353
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER PRIMARY KEY,\n [name] TEXT,\n [dog_age] INTEGER\n);",
54-
"INSERT INTO [dogs_new_suffix] ([id], [name], [dog_age])\n SELECT [id], [name], [age] FROM [dogs];",
54+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name], [dog_age])\n SELECT [rowid], [id], [name], [age] FROM [dogs];",
5555
"DROP TABLE [dogs];",
5656
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
5757
],
@@ -61,7 +61,7 @@
6161
{"pk": "age"},
6262
[
6363
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER,\n [name] TEXT,\n [age] TEXT PRIMARY KEY\n);",
64-
"INSERT INTO [dogs_new_suffix] ([id], [name], [age])\n SELECT [id], [name], [age] FROM [dogs];",
64+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name], [age])\n SELECT [rowid], [id], [name], [age] FROM [dogs];",
6565
"DROP TABLE [dogs];",
6666
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
6767
],
@@ -71,7 +71,7 @@
7171
{"pk": ("age", "name")},
7272
[
7373
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER,\n [name] TEXT,\n [age] TEXT,\n PRIMARY KEY ([age], [name])\n);",
74-
"INSERT INTO [dogs_new_suffix] ([id], [name], [age])\n SELECT [id], [name], [age] FROM [dogs];",
74+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name], [age])\n SELECT [rowid], [id], [name], [age] FROM [dogs];",
7575
"DROP TABLE [dogs];",
7676
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
7777
],
@@ -81,7 +81,7 @@
8181
{"pk": None},
8282
[
8383
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER,\n [name] TEXT,\n [age] TEXT\n);",
84-
"INSERT INTO [dogs_new_suffix] ([id], [name], [age])\n SELECT [id], [name], [age] FROM [dogs];",
84+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name], [age])\n SELECT [rowid], [id], [name], [age] FROM [dogs];",
8585
"DROP TABLE [dogs];",
8686
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
8787
],
@@ -91,7 +91,7 @@
9191
{"drop": ["age"], "keep_table": "kept_table"},
9292
[
9393
"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];",
94+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name])\n SELECT [rowid], [id], [name] FROM [dogs];",
9595
"ALTER TABLE [dogs] RENAME TO [kept_table];",
9696
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
9797
],
@@ -134,7 +134,7 @@ def tracer(sql, params):
134134
{},
135135
[
136136
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER,\n [name] TEXT,\n [age] TEXT\n);",
137-
"INSERT INTO [dogs_new_suffix] ([id], [name], [age])\n SELECT [id], [name], [age] FROM [dogs];",
137+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name], [age])\n SELECT [rowid], [id], [name], [age] FROM [dogs];",
138138
"DROP TABLE [dogs];",
139139
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
140140
],
@@ -144,7 +144,7 @@ def tracer(sql, params):
144144
{"types": {"age": int}},
145145
[
146146
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER,\n [name] TEXT,\n [age] INTEGER\n);",
147-
"INSERT INTO [dogs_new_suffix] ([id], [name], [age])\n SELECT [id], [name], [age] FROM [dogs];",
147+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name], [age])\n SELECT [rowid], [id], [name], [age] FROM [dogs];",
148148
"DROP TABLE [dogs];",
149149
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
150150
],
@@ -154,7 +154,7 @@ def tracer(sql, params):
154154
{"rename": {"age": "dog_age"}},
155155
[
156156
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER,\n [name] TEXT,\n [dog_age] TEXT\n);",
157-
"INSERT INTO [dogs_new_suffix] ([id], [name], [dog_age])\n SELECT [id], [name], [age] FROM [dogs];",
157+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name], [dog_age])\n SELECT [rowid], [id], [name], [age] FROM [dogs];",
158158
"DROP TABLE [dogs];",
159159
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
160160
],
@@ -164,7 +164,7 @@ def tracer(sql, params):
164164
{"pk": "id"},
165165
[
166166
"CREATE TABLE [dogs_new_suffix] (\n [id] INTEGER PRIMARY KEY,\n [name] TEXT,\n [age] TEXT\n);",
167-
"INSERT INTO [dogs_new_suffix] ([id], [name], [age])\n SELECT [id], [name], [age] FROM [dogs];",
167+
"INSERT INTO [dogs_new_suffix] ([rowid], [id], [name], [age])\n SELECT [rowid], [id], [name], [age] FROM [dogs];",
168168
"DROP TABLE [dogs];",
169169
"ALTER TABLE [dogs_new_suffix] RENAME TO [dogs];",
170170
],
@@ -498,3 +498,35 @@ def test_transform_replace_foreign_keys(fresh_db, foreign_keys):
498498
" [city] INTEGER\n"
499499
")"
500500
)
501+
502+
503+
@pytest.mark.parametrize("table_type", ("id_pk", "rowid", "compound_pk"))
504+
def test_transform_preserves_rowids(fresh_db, table_type):
505+
pk = None
506+
if table_type == "id_pk":
507+
pk = "id"
508+
elif table_type == "compound_pk":
509+
pk = ("id", "name")
510+
elif table_type == "rowid":
511+
pk = None
512+
fresh_db["places"].insert_all(
513+
[
514+
{"id": "1", "name": "Paris", "country": "France"},
515+
{"id": "2", "name": "London", "country": "UK"},
516+
{"id": "3", "name": "New York", "country": "USA"},
517+
],
518+
pk=pk,
519+
)
520+
# Now delete and insert a row to mix up the `rowid` sequence
521+
fresh_db["places"].delete_where("id = ?", ["2"])
522+
fresh_db["places"].insert({"id": "4", "name": "London", "country": "UK"})
523+
previous_rows = list(
524+
tuple(row) for row in fresh_db.execute("select rowid, id, name from places")
525+
)
526+
# Transform it
527+
fresh_db["places"].transform(column_order=("country", "name"))
528+
# Should be the same
529+
next_rows = list(
530+
tuple(row) for row in fresh_db.execute("select rowid, id, name from places")
531+
)
532+
assert previous_rows == next_rows

0 commit comments

Comments
 (0)