Skip to content

Commit ee14f1c

Browse files
committed
refactor(executor): reduce statements in migrate method
1 parent 9f42589 commit ee14f1c

1 file changed

Lines changed: 117 additions & 66 deletions

File tree

tortoise/migrations/executor.py

Lines changed: 117 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -53,72 +53,17 @@ async def migrate(
5353
direction: str = "both",
5454
progress: Callable[[str, str, str], object] | None = None,
5555
) -> None:
56-
self._logger.debug("Building migration graph")
57-
await self.loader.build_graph()
58-
59-
# Create a non-atomic schema editor for recorder operations only
60-
recorder_schema_editor = self._schema_editor(atomic=False)
61-
self._logger.debug("Ensuring migration schema")
62-
await self.recorder.ensure_schema(recorder_schema_editor)
63-
64-
self._logger.debug("Loading applied migrations")
65-
applied = set(await self.recorder.applied_migrations())
66-
67-
self._logger.debug("Building migration plan")
68-
plan = self._migration_plan(targets, applied, self.loader.graph)
69-
self._validate_plan_direction(plan, direction)
70-
71-
state_cache_by_key: dict[MigrationKey, State] | None = None
72-
if any(step.backward for step in plan):
73-
self._logger.debug("Building rollback state cache")
74-
state_cache_by_key = await self._project_state_cache(applied)
75-
76-
state_cache: State | None = None
77-
for step in plan:
78-
key = MigrationKey(app_label=step.migration.app_label, name=step.migration.name)
79-
if step.backward:
80-
if state_cache_by_key is not None:
81-
state_before = state_cache_by_key[key]
82-
else:
83-
state_before = await self._project_state(applied, upto=key)
84-
if not fake:
85-
self._emit(progress, "rollback_start", key)
86-
schema_editor = self._schema_editor(atomic=step.migration.atomic)
87-
if schema_editor.atomic_migration:
88-
async with in_transaction(self.connection.connection_name) as txn_client:
89-
schema_editor.client = txn_client
90-
await step.migration.unapply(
91-
state_before, dry_run=dry_run, schema_editor=schema_editor
92-
)
93-
else:
94-
await step.migration.unapply(
95-
state_before, dry_run=dry_run, schema_editor=schema_editor
96-
)
97-
self._emit(progress, "rollback_done", key)
98-
if not dry_run:
99-
await self.recorder.record_unapplied(key.app_label, key.name)
100-
applied.discard(key)
101-
state_cache = None
102-
else:
103-
if state_cache is None:
104-
state_cache = await self._project_state(applied)
105-
if not fake:
106-
self._emit(progress, "apply_start", key)
107-
schema_editor = self._schema_editor(atomic=step.migration.atomic)
108-
if schema_editor.atomic_migration:
109-
async with in_transaction(self.connection.connection_name) as txn_client:
110-
schema_editor.client = txn_client
111-
await step.migration.apply(
112-
state_cache, dry_run=dry_run, schema_editor=schema_editor
113-
)
114-
else:
115-
await step.migration.apply(
116-
state_cache, dry_run=dry_run, schema_editor=schema_editor
117-
)
118-
self._emit(progress, "apply_done", key)
119-
if not dry_run:
120-
await self.recorder.record_applied(key.app_label, key.name)
121-
applied.add(key)
56+
plan, applied, state_cache_by_key = await self._prepare_migration_run(
57+
targets, direction
58+
)
59+
await self._run_plan(
60+
plan,
61+
applied=applied,
62+
state_cache_by_key=state_cache_by_key,
63+
fake=fake,
64+
dry_run=dry_run,
65+
progress=progress,
66+
)
12267

12368
async def plan(self, targets: Iterable[MigrationTarget] | None = None) -> list[PlanStep]:
12469
await self.loader.build_graph()
@@ -193,6 +138,112 @@ async def collect_sql(
193138

194139
return editor.collected_sql
195140

141+
async def _execute_plan_step(
142+
self,
143+
step: PlanStep,
144+
*,
145+
applied: set[MigrationKey],
146+
state_cache: State | None,
147+
state_cache_by_key: dict[MigrationKey, State] | None,
148+
fake: bool,
149+
dry_run: bool,
150+
progress: Callable[[str, str, str], object] | None,
151+
) -> State | None:
152+
key = MigrationKey(app_label=step.migration.app_label, name=step.migration.name)
153+
if step.backward:
154+
if state_cache_by_key is not None:
155+
state_before = state_cache_by_key[key]
156+
else:
157+
state_before = await self._project_state(applied, upto=key)
158+
if not fake:
159+
self._emit(progress, "rollback_start", key)
160+
schema_editor = self._schema_editor(atomic=step.migration.atomic)
161+
if schema_editor.atomic_migration:
162+
async with in_transaction(self.connection.connection_name) as txn_client:
163+
schema_editor.client = txn_client
164+
await step.migration.unapply(
165+
state_before, dry_run=dry_run, schema_editor=schema_editor
166+
)
167+
else:
168+
await step.migration.unapply(
169+
state_before, dry_run=dry_run, schema_editor=schema_editor
170+
)
171+
self._emit(progress, "rollback_done", key)
172+
if not dry_run:
173+
await self.recorder.record_unapplied(key.app_label, key.name)
174+
applied.discard(key)
175+
return None
176+
177+
if state_cache is None:
178+
state_cache = await self._project_state(applied)
179+
if not fake:
180+
self._emit(progress, "apply_start", key)
181+
schema_editor = self._schema_editor(atomic=step.migration.atomic)
182+
if schema_editor.atomic_migration:
183+
async with in_transaction(self.connection.connection_name) as txn_client:
184+
schema_editor.client = txn_client
185+
await step.migration.apply(
186+
state_cache, dry_run=dry_run, schema_editor=schema_editor
187+
)
188+
else:
189+
await step.migration.apply(
190+
state_cache, dry_run=dry_run, schema_editor=schema_editor
191+
)
192+
self._emit(progress, "apply_done", key)
193+
if not dry_run:
194+
await self.recorder.record_applied(key.app_label, key.name)
195+
applied.add(key)
196+
return state_cache
197+
198+
async def _prepare_migration_run(
199+
self,
200+
targets: Iterable[MigrationTarget] | None,
201+
direction: str,
202+
) -> tuple[list[PlanStep], set[MigrationKey], dict[MigrationKey, State] | None]:
203+
self._logger.debug("Building migration graph")
204+
await self.loader.build_graph()
205+
206+
# Create a non-atomic schema editor for recorder operations only
207+
recorder_schema_editor = self._schema_editor(atomic=False)
208+
self._logger.debug("Ensuring migration schema")
209+
await self.recorder.ensure_schema(recorder_schema_editor)
210+
211+
self._logger.debug("Loading applied migrations")
212+
applied = set(await self.recorder.applied_migrations())
213+
214+
self._logger.debug("Building migration plan")
215+
plan = self._migration_plan(targets, applied, self.loader.graph)
216+
self._validate_plan_direction(plan, direction)
217+
218+
state_cache_by_key: dict[MigrationKey, State] | None = None
219+
if any(step.backward for step in plan):
220+
self._logger.debug("Building rollback state cache")
221+
state_cache_by_key = await self._project_state_cache(applied)
222+
223+
return plan, applied, state_cache_by_key
224+
225+
async def _run_plan(
226+
self,
227+
plan: list[PlanStep],
228+
*,
229+
applied: set[MigrationKey],
230+
state_cache_by_key: dict[MigrationKey, State] | None,
231+
fake: bool,
232+
dry_run: bool,
233+
progress: Callable[[str, str, str], object] | None,
234+
) -> None:
235+
state_cache: State | None = None
236+
for step in plan:
237+
state_cache = await self._execute_plan_step(
238+
step,
239+
applied=applied,
240+
state_cache=state_cache,
241+
state_cache_by_key=state_cache_by_key,
242+
fake=fake,
243+
dry_run=dry_run,
244+
progress=progress,
245+
)
246+
196247
def _resolve_migration_key(self, app_label: str, migration_name: str) -> MigrationKey:
197248
"""Resolve a migration name to a MigrationKey, supporting prefix matching."""
198249
exact_key = MigrationKey(app_label=app_label, name=migration_name)

0 commit comments

Comments
 (0)