Skip to content

Commit 4bc7aa5

Browse files
committed
can now reverse deleting tables and columns
1 parent 0db7993 commit 4bc7aa5

File tree

5 files changed

+64
-7
lines changed

5 files changed

+64
-7
lines changed

piccolo/apps/migrations/auto/migration_manager.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class MigrationManager:
123123
"""
124124

125125
migration_id: str = ""
126+
app_name: str = ""
126127
add_tables: t.List[DiffableTable] = field(default_factory=list)
127128
drop_tables: t.List[DiffableTable] = field(default_factory=list)
128129
rename_tables: t.List[RenameTable] = field(default_factory=list)
@@ -324,8 +325,8 @@ def deserialise_params(
324325

325326
def get_table_from_snaphot(
326327
self,
327-
app_name: str,
328328
table_class_name: str,
329+
app_name: t.Optional[str],
329330
offset: int = 0,
330331
migration_id: t.Optional[str] = None,
331332
) -> t.Type[Table]:
@@ -343,6 +344,9 @@ def get_table_from_snaphot(
343344
if migration_id is None:
344345
migration_id = self.migration_id
345346

347+
if app_name is None:
348+
app_name = self.app_name
349+
346350
return (
347351
BaseMigrationManager()
348352
.get_table_from_snaphot(
@@ -397,14 +401,31 @@ async def _run_alter_columns(self, backwards=False):
397401

398402
async def _run_drop_tables(self, backwards=False):
399403
if backwards:
400-
print("Dropped tables can't currently be reversed.")
404+
for diffable_table in self.drop_tables:
405+
_Table = self.get_table_from_snaphot(
406+
table_class_name=diffable_table.class_name,
407+
app_name=self.app_name,
408+
offset=-1,
409+
)
410+
await _Table.create_table().run()
401411
else:
402-
for table in self.drop_tables:
403-
await table.to_table_class().alter().drop_table().run()
412+
for diffable_table in self.drop_tables:
413+
await diffable_table.to_table_class().alter().drop_table().run()
404414

405415
async def _run_drop_columns(self, backwards=False):
406416
if backwards:
407-
print("Dropped columns can't currently be reversed.")
417+
for drop_column in self.drop_columns.drop_columns:
418+
_Table = self.get_table_from_snaphot(
419+
table_class_name=drop_column.table_class_name,
420+
app_name=self.app_name,
421+
offset=-1,
422+
)
423+
column_to_restore = _Table._meta.get_column_by_name(
424+
drop_column.column_name
425+
)
426+
await _Table.alter().add_column(
427+
name=drop_column.column_name, column=column_to_restore
428+
).run()
408429
else:
409430
for table_class_name in self.drop_columns.table_class_names:
410431
columns = self.drop_columns.for_table_class_name(

piccolo/apps/migrations/commands/new.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ def _create_new_migration(app_config: AppConfig, auto=False) -> None:
6666
sys.exit(1)
6767

6868
file_contents = render_template(
69-
migration_id=_id, auto=True, alter_statements=alter_statements,
69+
migration_id=_id,
70+
auto=True,
71+
alter_statements=alter_statements,
72+
app_name=app_config.app_name,
7073
)
7174
else:
7275
file_contents = render_template(migration_id=_id, auto=False)

piccolo/apps/migrations/commands/templates/migration.py.jinja

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ ID = '{{ migration_id }}'
55

66

77
async def forwards():
8-
manager = MigrationManager(migration_id=ID)
8+
manager = MigrationManager(migration_id=ID, app_name="{{ app_name }}")
99
{% if auto %}
1010
{% for alter_statement in alter_statements %}
1111
{{ alter_statement }}

tests/apps/migrations/auto/test_migration_manager.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import asyncio
2+
from unittest.mock import patch, MagicMock
23

34
from asyncpg.exceptions import UniqueViolationError
45
from piccolo.apps.migrations.auto import MigrationManager
6+
from piccolo.apps.migrations.commands.base import BaseMigrationManager
57
from piccolo.columns import Varchar
68

79
from tests.base import DBTestCase
@@ -193,3 +195,33 @@ def test_alter_column(self):
193195
)
194196
response = self.run_sync("SELECT name FROM manager;")
195197
self.assertEqual(response, [{"name": "Dave"}, {"name": "Dave"}])
198+
199+
@patch.object(BaseMigrationManager, "get_migration_managers")
200+
def test_drop_table(self, get_migration_managers: MagicMock):
201+
self.run_sync("DROP TABLE IF EXISTS musician;")
202+
203+
name_column = Varchar()
204+
name_column._meta.name = "name"
205+
206+
manager_1 = MigrationManager(migration_id="1", app_name="music")
207+
manager_1.add_table(
208+
class_name="Musician", tablename="musician", columns=[name_column]
209+
)
210+
asyncio.run(manager_1.run())
211+
212+
manager_2 = MigrationManager(migration_id="2", app_name="music")
213+
manager_2.drop_table(class_name="Musician", tablename="musician")
214+
asyncio.run(manager_2.run())
215+
216+
get_migration_managers.return_value = [manager_1]
217+
218+
self.assertTrue(not self.table_exists("musician"))
219+
220+
asyncio.run(manager_2.run_backwards())
221+
222+
get_migration_managers.assert_called_with(
223+
app_name="music", max_migration_id="2", offset=-1
224+
)
225+
self.assertTrue(self.table_exists("musician"))
226+
227+
self.run_sync("DROP TABLE IF EXISTS musician;")

tests/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def run_sync(self, query):
3333

3434
def table_exists(self, tablename: str):
3535
_Table: t.Type[Table] = type(tablename.upper(), (Table,), {})
36+
_Table._meta.tablename = tablename
3637
return _Table.table_exists().run_sync()
3738

3839
def create_table(self):

0 commit comments

Comments
 (0)