| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -23,6 +23,7 @@ | |||
| 23 | 23 | from spanner_orm import model | |
| 24 | 24 | from spanner_orm import relationship | |
| 25 | 25 | from spanner_orm.admin import api as admin_api | |
| 26 | + from spanner_orm.admin import update | ||
| 26 | 27 | ||
| 27 | 28 | # add NullHandler to root-module logger so that individual modules | |
| 28 | 29 | # won't have to. | |
@@ -62,3 +63,13 @@ | |||
| 62 | 63 | ||
| 63 | 64 | transactional_read = decorator.transactional_read | |
| 64 | 65 | transactional_write = decorator.transactional_write | |
| 66 | + | ||
| 67 | + CreateTable = update.CreateTable | ||
| 68 | + DropTable = update.DropTable | ||
| 69 | + AddColumn = update.AddColumn | ||
| 70 | + DropColumn = update.DropColumn | ||
| 71 | + AlterColumn = update.AlterColumn | ||
| 72 | + CreateIndex = update.CreateIndex | ||
| 73 | + DropIndex = update.DropIndex | ||
| 74 | + NoUpdate = update.NoUpdate | ||
| 75 | + model_creation_ddl = update.model_creation_ddl | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,55 @@ | |||
| 1 | + # python3 | ||
| 2 | + # Copyright 2019 Google LLC | ||
| 3 | + # | ||
| 4 | + # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + # you may not use this file except in compliance with the License. | ||
| 6 | + # You may obtain a copy of the License at | ||
| 7 | + # | ||
| 8 | + # https://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + # | ||
| 10 | + # Unless required by applicable law or agreed to in writing, software | ||
| 11 | + # distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + # See the License for the specific language governing permissions and | ||
| 14 | + # limitations under the License. | ||
| 15 | + """Holds information about a specific migration.""" | ||
| 16 | + | ||
| 17 | + from __future__ import annotations | ||
| 18 | + | ||
| 19 | + from typing import Callable, Optional | ||
| 20 | + | ||
| 21 | + from spanner_orm.admin import update | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + def no_update_callable() -> update.SchemaUpdate: | ||
| 25 | + return update.NoUpdate() | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + class Migration: | ||
| 29 | + """Holds information about a specific migration.""" | ||
| 30 | + | ||
| 31 | + def __init__(self, | ||
| 32 | + migration_id: str, | ||
| 33 | + prev_migration_id: Optional[str], | ||
| 34 | + upgrade: Optional[Callable[[], update.SchemaUpdate]] = None, | ||
| 35 | + downgrade: Optional[Callable[[], update.SchemaUpdate]] = None): | ||
| 36 | + self._id = migration_id | ||
| 37 | + self._prev = prev_migration_id | ||
| 38 | + self._upgrade = upgrade or no_update_callable | ||
| 39 | + self._downgrade = downgrade or no_update_callable | ||
| 40 | + | ||
| 41 | + @property | ||
| 42 | + def migration_id(self) -> str: | ||
| 43 | + return self._id | ||
| 44 | + | ||
| 45 | + @property | ||
| 46 | + def prev_migration_id(self) -> Optional[str]: | ||
| 47 | + return self._prev | ||
| 48 | + | ||
| 49 | + @property | ||
| 50 | + def upgrade(self) -> Optional[Callable[[], update.SchemaUpdate]]: | ||
| 51 | + return self._upgrade | ||
| 52 | + | ||
| 53 | + @property | ||
| 54 | + def downgrade(self) -> Optional[Callable[[], update.SchemaUpdate]]: | ||
| 55 | + return self._downgrade | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,15 +4,15 @@ Migration ID: $migration_id | |||
| 4 | 4 | Created: $current_date | |
| 5 | 5 | """ | |
| 6 | 6 | ||
| 7 | + import spanner_orm | ||
| 8 | + | ||
| 7 | 9 | migration_id = $migration_id | |
| 8 | 10 | prev_migration_id = $prev_migration_id | |
| 9 | 11 | ||
| 10 | - from spanner_orm.admin import update | ||
| 11 | - | ||
| 12 | 12 | # Returns a SchemaUpdate object that tells what should be changed | |
| 13 | - def upgrade(): | ||
| 14 | - pass | ||
| 13 | + def upgrade() -> spanner_orm.NoUpdate: | ||
| 14 | + return spanner_orm.NoUpdate() | ||
| 15 | 15 | ||
| 16 | 16 | # Returns a SchemaUpdate object that tells how to roll back the changes | |
| 17 | - def downgrade(): | ||
| 18 | - pass | ||
| 17 | + def downgrade() -> spanner_orm.NoUpdate: | ||
| 18 | + return spanner_orm.NoUpdate() | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,12 +18,13 @@ | |||
| 18 | 18 | ||
| 19 | 19 | import datetime | |
| 20 | 20 | import logging | |
| 21 | - from typing import Any, Dict, Optional | ||
| 21 | + from typing import Iterable, List, Dict, Optional | ||
| 22 | 22 | ||
| 23 | 23 | from spanner_orm import api | |
| 24 | 24 | from spanner_orm import error | |
| 25 | 25 | from spanner_orm.admin import api as admin_api | |
| 26 | 26 | from spanner_orm.admin import metadata | |
| 27 | + from spanner_orm.admin import migration | ||
| 27 | 28 | from spanner_orm.admin import migration_manager | |
| 28 | 29 | from spanner_orm.admin import migration_status | |
| 29 | 30 | from spanner_orm.admin import update | |
@@ -54,8 +55,7 @@ def migrated(self, migration_id: str) -> bool: | |||
| 54 | 55 | return True | |
| 55 | 56 | return self._migration_status().get(migration_id, False) | |
| 56 | 57 | ||
| 57 | - # TODO(dbrandao): make a Migration object so this is no longer Any | ||
| 58 | - def migrations(self) -> Any: | ||
| 58 | + def migrations(self) -> List[migration.Migration]: | ||
| 59 | 59 | return self._manager.migrations | |
| 60 | 60 | ||
| 61 | 61 | def migrate(self, target_migration: Optional[str] = None) -> None: | |
@@ -74,16 +74,16 @@ def migrate(self, target_migration: Optional[str] = None) -> None: | |||
| 74 | 74 | # Filter to unmigrated migrations | |
| 75 | 75 | migrations = self._filter_migrations(self.migrations(), False, | |
| 76 | 76 | target_migration) | |
| 77 | - for migration in migrations: | ||
| 78 | - _logger.info('Processing migration %s', migration.migration_id) | ||
| 79 | - schema_update = migration.upgrade() | ||
| 77 | + for migration_ in migrations: | ||
| 78 | + _logger.info('Processing migration %s', migration_.migration_id) | ||
| 79 | + schema_update = migration_.upgrade() | ||
| 80 | 80 | if not isinstance(schema_update, update.SchemaUpdate): | |
| 81 | 81 | raise error.SpannerError( | |
| 82 | 82 | 'Migration {} did not return a SchemaUpdate'.format( | |
| 83 | - migration.migration_id)) | ||
| 83 | + migration_.migration_id)) | ||
| 84 | 84 | schema_update.execute() | |
| 85 | 85 | ||
| 86 | - self._update_status(migration.migration_id, True) | ||
| 86 | + self._update_status(migration_.migration_id, True) | ||
| 87 | 87 | self._hangup() | |
| 88 | 88 | ||
| 89 | 89 | def rollback(self, target_migration: str) -> None: | |
@@ -105,16 +105,16 @@ def rollback(self, target_migration: str) -> None: | |||
| 105 | 105 | # Filter to migrated migrations from most recently applied | |
| 106 | 106 | migrations = self._filter_migrations( | |
| 107 | 107 | reversed(self.migrations()), True, target_migration) | |
| 108 | - for migration in migrations: | ||
| 109 | - _logger.info('Processing migration %s', migration.migration_id) | ||
| 110 | - schema_update = migration.downgrade() | ||
| 108 | + for migration_ in migrations: | ||
| 109 | + _logger.info('Processing migration %s', migration_.migration_id) | ||
| 110 | + schema_update = migration_.downgrade() | ||
| 111 | 111 | if not isinstance(schema_update, update.SchemaUpdate): | |
| 112 | 112 | raise error.SpannerError( | |
| 113 | 113 | 'Migration {} did not return a SchemaUpdate'.format( | |
| 114 | - migration.migration_id)) | ||
| 114 | + migration_.migration_id)) | ||
| 115 | 115 | schema_update.execute() | |
| 116 | 116 | ||
| 117 | - self._update_status(migration.migration_id, False) | ||
| 117 | + self._update_status(migration_.migration_id, False) | ||
| 118 | 118 | self._hangup() | |
| 119 | 119 | ||
| 120 | 120 | def _connect(self) -> None: | |
@@ -133,8 +133,9 @@ def _hangup(self) -> None: | |||
| 133 | 133 | admin_api.SpannerAdminApi.hangup() | |
| 134 | 134 | api.SpannerApi.hangup() | |
| 135 | 135 | ||
| 136 | - def _filter_migrations(self, migrations: Any, migrated: bool, | ||
| 137 | - last_migration: Optional[str]) -> Any: | ||
| 136 | + def _filter_migrations( | ||
| 137 | + self, migrations: Iterable[migration.Migration], migrated: bool, | ||
| 138 | + last_migration: Optional[str]) -> List[migration.Migration]: | ||
| 138 | 139 | """Filters the list of migrations according to the desired conditions. | |
| 139 | 140 | ||
| 140 | 141 | Args: | |
@@ -147,11 +148,11 @@ def _filter_migrations(self, migrations: Any, migrated: bool, | |||
| 147 | 148 | """ | |
| 148 | 149 | filtered = [] | |
| 149 | 150 | last_migration_found = False | |
| 150 | - for migration in migrations: | ||
| 151 | - if self.migrated(migration.migration_id) == migrated: | ||
| 152 | - filtered.append(migration) | ||
| 151 | + for migration_ in migrations: | ||
| 152 | + if self.migrated(migration_.migration_id) == migrated: | ||
| 153 | + filtered.append(migration_) | ||
| 153 | 154 | ||
| 154 | - if last_migration and migration.migration_id == last_migration: | ||
| 155 | + if last_migration and migration_.migration_id == last_migration: | ||
| 155 | 156 | last_migration_found = True | |
| 156 | 157 | break | |
| 157 | 158 | ||
@@ -169,8 +170,8 @@ def _migration_status(self) -> Dict[str, bool]: | |||
| 169 | 170 | if not model_from_db: | |
| 170 | 171 | update.CreateTable(migration_status.MigrationStatus).execute() | |
| 171 | 172 | self._migration_status_map = { | |
| 172 | - migration.id: migration.migrated | ||
| 173 | - for migration in migration_status.MigrationStatus.all() | ||
| 173 | + migration_.id: migration_.migrated | ||
| 174 | + for migration_ in migration_status.MigrationStatus.all() | ||
| 174 | 175 | } | |
| 175 | 176 | ||
| 176 | 177 | return self._migration_status_map | |
@@ -198,9 +199,9 @@ def _validate_migrations(self) -> None: | |||
| 198 | 199 | 'First migration {} depends on unmigrated migration {}'.format( | |
| 199 | 200 | first.migration_id, first.prev_migration_id)) | |
| 200 | 201 | ||
| 201 | - for migration in migrations: | ||
| 202 | - if (self.migrated(migration.migration_id) and | ||
| 203 | - not self.migrated(migration.prev_migration_id)): | ||
| 202 | + for migration_ in migrations: | ||
| 203 | + if (self.migrated(migration_.migration_id) and | ||
| 204 | + not self.migrated(migration_.prev_migration_id)): | ||
| 204 | 205 | raise error.SpannerError( | |
| 205 | 206 | 'Migrated migration {} depends on an unmigrated migration'.format( | |
| 206 | - migration.migration_id)) | ||
| 207 | + migration_.migration_id)) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,16 +16,16 @@ | |||
| 16 | 16 | ||
| 17 | 17 | from __future__ import annotations | |
| 18 | 18 | ||
| 19 | - | ||
| 20 | 19 | import datetime | |
| 21 | 20 | import importlib | |
| 22 | 21 | import os | |
| 23 | 22 | import re | |
| 24 | 23 | import string | |
| 25 | - from typing import Any, Iterable, List, Optional | ||
| 24 | + from typing import Iterable, List, Optional | ||
| 26 | 25 | import uuid | |
| 27 | 26 | ||
| 28 | 27 | from spanner_orm import error | |
| 28 | + from spanner_orm.admin import migration | ||
| 29 | 29 | ||
| 30 | 30 | ||
| 31 | 31 | class MigrationManager: | |
@@ -63,25 +63,30 @@ def generate(self, migration_name: str) -> str: | |||
| 63 | 63 | return filepath | |
| 64 | 64 | ||
| 65 | 65 | @property | |
| 66 | - def migrations(self) -> Any: | ||
| 66 | + def migrations(self) -> List[migration.Migration]: | ||
| 67 | 67 | """Loads and orders all migrations in the base dir.""" | |
| 68 | 68 | if self._migrations is None: | |
| 69 | 69 | unordered_migrations = self._all_migrations() | |
| 70 | 70 | self._migrations = self._order_migrations(unordered_migrations) | |
| 71 | 71 | return self._migrations | |
| 72 | 72 | ||
| 73 | - def _migration_from_file(self, filename: str) -> Any: | ||
| 73 | + def _migration_from_file(self, filename: str) -> migration.Migration: | ||
| 74 | 74 | """Loads a single migration from the given filename in the base dir.""" | |
| 75 | 75 | module_name = re.sub(r'\W', '_', filename) | |
| 76 | 76 | path = os.path.join(self.basedir, filename) | |
| 77 | 77 | spec = importlib.util.spec_from_file_location(module_name, path) | |
| 78 | 78 | module = importlib.util.module_from_spec(spec) | |
| 79 | 79 | spec.loader.exec_module(module) | |
| 80 | - if not hasattr(module, 'migration_id'): | ||
| 80 | + try: | ||
| 81 | + result = migration.Migration(module.migration_id, | ||
| 82 | + module.prev_migration_id, | ||
| 83 | + getattr(module, 'upgrade', None), | ||
| 84 | + getattr(module, 'downgrade', None)) | ||
| 85 | + except AttributeError: | ||
| 81 | 86 | raise error.SpannerError('{} has no migration id'.format(path)) | |
| 82 | - return module | ||
| 87 | + return result | ||
| 83 | 88 | ||
| 84 | - def _all_migrations(self) -> List[Any]: | ||
| 89 | + def _all_migrations(self) -> List[migration.Migration]: | ||
| 85 | 90 | """Loads all migrations from the base dir.""" | |
| 86 | 91 | migrations = [] | |
| 87 | 92 | for filename in os.listdir(self.basedir): | |
@@ -90,16 +95,17 @@ def _all_migrations(self) -> List[Any]: | |||
| 90 | 95 | migrations.append(self._migration_from_file(filename)) | |
| 91 | 96 | return migrations | |
| 92 | 97 | ||
| 93 | - def _order_migrations(self, migrations: Iterable[Any]) -> List[Any]: | ||
| 98 | + def _order_migrations(self, migrations: Iterable[migration.Migration] | ||
| 99 | + ) -> List[migration.Migration]: | ||
| 94 | 100 | """Returns list of migrations in the order they have to be applied.""" | |
| 95 | 101 | if not migrations: | |
| 96 | 102 | return [] | |
| 97 | 103 | ||
| 98 | - id_map = {migration.migration_id: migration for migration in migrations} | ||
| 104 | + id_map = {migration_.migration_id: migration_ for migration_ in migrations} | ||
| 99 | 105 | start_migration = None | |
| 100 | - for migration_id, migration in id_map.items(): | ||
| 101 | - if migration.prev_migration_id and migration.prev_migration_id in id_map: | ||
| 102 | - current = id_map[migration.prev_migration_id] | ||
| 106 | + for migration_id, migration_ in id_map.items(): | ||
| 107 | + if migration_.prev_migration_id and migration_.prev_migration_id in id_map: | ||
| 108 | + current = id_map[migration_.prev_migration_id] | ||
| 103 | 109 | if hasattr(current, 'next'): | |
| 104 | 110 | raise error.SpannerError( | |
| 105 | 111 | '{name} has unclear successor migration'.format( | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,15 +18,17 @@ | |||
| 18 | 18 | Created: 2019-02-27 18:52 | |
| 19 | 19 | """ | |
| 20 | 20 | ||
| 21 | + import spanner_orm | ||
| 22 | + | ||
| 21 | 23 | migration_id = '4a7a7dee0718' | |
| 22 | 24 | prev_migration_id = None | |
| 23 | 25 | ||
| 24 | 26 | ||
| 25 | 27 | # Returns a SchemaUpdate object that tells what should be changed | |
| 26 | - def upgrade(): | ||
| 27 | - pass | ||
| 28 | + def upgrade() -> spanner_orm.NoUpdate: | ||
| 29 | + return spanner_orm.NoUpdate() | ||
| 28 | 30 | ||
| 29 | 31 | ||
| 30 | 32 | # Returns a SchemaUpdate object that tells how to roll back the changes | |
| 31 | - def downgrade(): | ||
| 32 | - pass | ||
| 33 | + def downgrade() -> spanner_orm.NoUpdate: | ||
| 34 | + return spanner_orm.NoUpdate() | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,15 +18,17 @@ | |||
| 18 | 18 | Created: 2019-02-27 18:52 | |
| 19 | 19 | """ | |
| 20 | 20 | ||
| 21 | + import spanner_orm | ||
| 22 | + | ||
| 21 | 23 | migration_id = '5c078bbb4d43' | |
| 22 | 24 | prev_migration_id = '4a7a7dee0718' | |
| 23 | 25 | ||
| 24 | 26 | ||
| 25 | 27 | # Returns a SchemaUpdate object that tells what should be changed | |
| 26 | - def upgrade(): | ||
| 27 | - pass | ||
| 28 | + def upgrade() -> spanner_orm.NoUpdate: | ||
| 29 | + return spanner_orm.NoUpdate() | ||
| 28 | 30 | ||
| 29 | 31 | ||
| 30 | 32 | # Returns a SchemaUpdate object that tells how to roll back the changes | |
| 31 | - def downgrade(): | ||
| 32 | - pass | ||
| 33 | + def downgrade() -> spanner_orm.NoUpdate: | ||
| 34 | + return spanner_orm.NoUpdate() | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,15 +18,17 @@ | |||
| 18 | 18 | Created: 2019-02-27 18:52 | |
| 19 | 19 | """ | |
| 20 | 20 | ||
| 21 | + import spanner_orm | ||
| 22 | + | ||
| 21 | 23 | migration_id = 'eceb25f170dd' | |
| 22 | 24 | prev_migration_id = '5c078bbb4d43' | |
| 23 | 25 | ||
| 24 | 26 | ||
| 25 | 27 | # Returns a SchemaUpdate object that tells what should be changed | |
| 26 | - def upgrade(): | ||
| 27 | - pass | ||
| 28 | + def upgrade() -> spanner_orm.NoUpdate: | ||
| 29 | + return spanner_orm.NoUpdate() | ||
| 28 | 30 | ||
| 29 | 31 | ||
| 30 | 32 | # Returns a SchemaUpdate object that tells how to roll back the changes | |
| 31 | - def downgrade(): | ||
| 32 | - pass | ||
| 33 | + def downgrade() -> spanner_orm.NoUpdate: | ||
| 34 | + return spanner_orm.NoUpdate() | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments