| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 16c1978 commit 04f7138
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -50,18 +50,21 @@ class TestModel(spanner_orm.Model): | |||
| 50 | 50 | ``` | |
| 51 | 51 | ||
| 52 | 52 | If the model does not refer to an existing table on Spanner, we can create | |
| 53 | - the corresponding table on the database through the ORM in one of two ways: | ||
| 53 | + the corresponding table on the database through the ORM in one of two ways. If | ||
| 54 | + the database has not yet been created, we can create it and the table at the | ||
| 55 | + same time by: | ||
| 54 | 56 | ||
| 55 | 57 | ``` python | |
| 56 | - spanner_orm.connect_admin( | ||
| 58 | + admin_api = spanner_orm.connect_admin( | ||
| 57 | 59 | 'instance_name', | |
| 58 | 60 | 'database_name', | |
| 59 | 61 | create_ddl=spanner_orm.model_creation_ddl(TestModel)) | |
| 60 | - spanner_orm.spanner_admin_api().create() | ||
| 62 | + admin_api.create() | ||
| 61 | 63 | ``` | |
| 62 | 64 | ||
| 63 | - or by executing a Migration where the upgrade method returns a CreateTable for | ||
| 64 | - the model you have just defined (see section on migrations) | ||
| 65 | + If the database already exists, we can execute a Migration where the upgrade | ||
| 66 | + method returns a CreateTable for the model you have just defined (see section | ||
| 67 | + on migrations) | ||
| 65 | 68 | ||
| 66 | 69 | ||
| 67 | 70 | ### Retrieve data from Spanner | |
@@ -137,4 +140,32 @@ complex use cases, but you will have to do more work in order to use those | |||
| 137 | 140 | correctly. See the documentation on those methods for more information. | |
| 138 | 141 | ||
| 139 | 142 | ## Migrations | |
| 140 | - TODO(dbrandao): work in progress | ||
| 143 | + ### Creating migrations | ||
| 144 | + Running ```spanner-orm generate <migration name>``` will generate a new | ||
| 145 | + migration file to be filled out in the directory specified (or 'migrations' by | ||
| 146 | + default). The ```upgrade``` function is executed when migrating, and the | ||
| 147 | + ```downgrade``` function is executed when rolling back the migration. Each of | ||
| 148 | + these should return a single SchemaUpdate object (e.g., CreateTable, AddColumn, | ||
| 149 | + etc.), as Spanner cannot execute multiple schema updates atomically. | ||
| 150 | + | ||
| 151 | + ### Executing migrations | ||
| 152 | + Running ```spanner-orm migrate <Spanner instance> <Spanner database>``` will | ||
| 153 | + execute all the unmigrated migrations for that database in the correct order, | ||
| 154 | + using the application default credentials. If that won't work for your use case, | ||
| 155 | + ```MigrationExecutor``` can be used instead: | ||
| 156 | + | ||
| 157 | + ``` python | ||
| 158 | + connection = spanner_orm.SpannerConnection( | ||
| 159 | + instance_name, | ||
| 160 | + database_name, | ||
| 161 | + credentials) | ||
| 162 | + executor = spanner_orm.MigrationExecutor(connection) | ||
| 163 | + executor.migrate() | ||
| 164 | + ``` | ||
| 165 | + | ||
| 166 | + Note that there is no protection against trying execute migrations concurrently | ||
| 167 | + multiple times, so try not to do that. | ||
| 168 | + | ||
| 169 | + If a migration needs to be rolled back, | ||
| 170 | + ```spanner_orm rollback <migration_name> <Spanner instance> <Spanner database>``` | ||
| 171 | + or the corresponding ```MigrationExecutor``` method should be used. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,7 +16,7 @@ | |||
| 16 | 16 | from setuptools import setup | |
| 17 | 17 | setup( | |
| 18 | 18 | name='spanner-orm', | |
| 19 | - version='0.1.8', | ||
| 19 | + version='0.1.9', | ||
| 20 | 20 | description='Basic ORM for Spanner', | |
| 21 | 21 | maintainer='Derek Brandao', | |
| 22 | 22 | maintainer_email='dbrandao@google.com', | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -20,9 +20,11 @@ | |||
| 20 | 20 | from spanner_orm import decorator | |
| 21 | 21 | from spanner_orm import error | |
| 22 | 22 | from spanner_orm import field | |
| 23 | + from spanner_orm import index | ||
| 23 | 24 | from spanner_orm import model | |
| 24 | 25 | from spanner_orm import relationship | |
| 25 | 26 | from spanner_orm.admin import api as admin_api | |
| 27 | + from spanner_orm.admin import migration_executor | ||
| 26 | 28 | from spanner_orm.admin import update | |
| 27 | 29 | ||
| 28 | 30 | # add NullHandler to root-module logger so that individual modules | |
@@ -50,6 +52,7 @@ | |||
| 50 | 52 | Boolean = field.Boolean | |
| 51 | 53 | Field = field.Field | |
| 52 | 54 | Integer = field.Integer | |
| 55 | + Index = index.Index | ||
| 53 | 56 | Relationship = relationship.Relationship | |
| 54 | 57 | String = field.String | |
| 55 | 58 | StringArray = field.StringArray | |
@@ -84,3 +87,5 @@ | |||
| 84 | 87 | DropIndex = update.DropIndex | |
| 85 | 88 | NoUpdate = update.NoUpdate | |
| 86 | 89 | model_creation_ddl = update.model_creation_ddl | |
| 90 | + | ||
| 91 | + MigrationExecutor = migration_executor.MigrationExecutor | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -34,8 +34,10 @@ class SpannerMetadata(object): | |||
| 34 | 34 | """Gathers information about a table from Spanner.""" | |
| 35 | 35 | ||
| 36 | 36 | @classmethod | |
| 37 | - def _class_name_from_table(cls, table_name: str) -> str: | ||
| 38 | - return 'table_{}_model'.format(table_name) | ||
| 37 | + def _class_name_from_table(cls, table_name: Optional[str]) -> Optional[str]: | ||
| 38 | + if table_name: | ||
| 39 | + return 'table_{}_model'.format(table_name) | ||
| 40 | + return None | ||
| 39 | 41 | ||
| 40 | 42 | @classmethod | |
| 41 | 43 | def models(cls) -> Dict[str, Type[model.Model]]: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -110,7 +110,9 @@ def rollback(self, target_migration: str) -> None: | |||
| 110 | 110 | self._hangup() | |
| 111 | 111 | ||
| 112 | 112 | def _connect(self) -> None: | |
| 113 | - admin_api.from_connection(self._connection) | ||
| 113 | + api_connection = admin_api.from_connection(self._connection) | ||
| 114 | + if not self._connection.database.exists(): | ||
| 115 | + api_connection.create_database() | ||
| 114 | 116 | ||
| 115 | 117 | def _hangup(self) -> None: | |
| 116 | 118 | admin_api.hangup() | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,6 +19,8 @@ | |||
| 19 | 19 | import argparse | |
| 20 | 20 | from typing import Any | |
| 21 | 21 | ||
| 22 | + from spanner_orm import api | ||
| 23 | + from spanner_orm.admin import migration_executor | ||
| 22 | 24 | from spanner_orm.admin import migration_manager | |
| 23 | 25 | ||
| 24 | 26 | ||
@@ -27,23 +29,53 @@ def generate(args: Any) -> None: | |||
| 27 | 29 | manager.generate(args.name) | |
| 28 | 30 | ||
| 29 | 31 | ||
| 32 | + def migrate(args: Any) -> None: | ||
| 33 | + connection = api.SpannerConnection(args.instance, args.database) | ||
| 34 | + executor = migration_executor.MigrationExecutor(connection, args.directory) | ||
| 35 | + executor.migrate(args.name) | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + def rollback(args: Any) -> None: | ||
| 39 | + connection = api.SpannerConnection(args.instance, args.database) | ||
| 40 | + executor = migration_executor.MigrationExecutor(connection, args.directory) | ||
| 41 | + executor.rollback(args.name) | ||
| 42 | + | ||
| 43 | + | ||
| 30 | 44 | def main(as_module: bool = False) -> None: | |
| 31 | 45 | prog = 'spanner-orm' if as_module else None | |
| 32 | 46 | parser = argparse.ArgumentParser(prog=prog) | |
| 33 | 47 | subparsers = parser.add_subparsers( | |
| 34 | - title='subcommands', description='valid subcommands') | ||
| 48 | + dest='subcommand', | ||
| 49 | + title='subcommands', | ||
| 50 | + description='valid subcommands', | ||
| 51 | + required=True) | ||
| 35 | 52 | ||
| 36 | 53 | generate_parser = subparsers.add_parser( | |
| 37 | 54 | 'generate', help='Generate a new migration') | |
| 38 | 55 | generate_parser.add_argument('name', help='Short name of the migration') | |
| 39 | 56 | generate_parser.add_argument('--directory') | |
| 40 | 57 | generate_parser.set_defaults(execute=generate) | |
| 41 | 58 | ||
| 59 | + migrate_parser = subparsers.add_parser( | ||
| 60 | + 'migrate', help='Execute unmigrated migrations') | ||
| 61 | + migrate_parser.add_argument( | ||
| 62 | + '--name', help='Stop migrating after this migration') | ||
| 63 | + migrate_parser.add_argument('--directory') | ||
| 64 | + migrate_parser.add_argument('instance', help='Name of Spanner instance') | ||
| 65 | + migrate_parser.add_argument('database', help='Name of Spanner database') | ||
| 66 | + migrate_parser.set_defaults(execute=migrate) | ||
| 67 | + | ||
| 68 | + rollback_parser = subparsers.add_parser( | ||
| 69 | + 'rollback', help='Roll back migrated migrations') | ||
| 70 | + rollback_parser.add_argument( | ||
| 71 | + 'name', help='Keep rolling back past this migration') | ||
| 72 | + rollback_parser.add_argument('--directory') | ||
| 73 | + rollback_parser.add_argument('instance', help='Name of Spanner instance') | ||
| 74 | + rollback_parser.add_argument('database', help='Name of Spanner database') | ||
| 75 | + rollback_parser.set_defaults(execute=rollback) | ||
| 76 | + | ||
| 42 | 77 | args = parser.parse_args() | |
| 43 | - if hasattr(args, 'execute'): | ||
| 44 | - args.execute(args) | ||
| 45 | - else: | ||
| 46 | - parser.print_help() | ||
| 78 | + args.execute(args) | ||
| 47 | 79 | ||
| 48 | 80 | ||
| 49 | 81 | if __name__ == '__main__': | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -126,7 +126,7 @@ def __init__(self, | |||
| 126 | 126 | client = spanner.Client(project=project, credentials=credentials) | |
| 127 | 127 | instance = client.instance(instance) | |
| 128 | 128 | self.database = instance.database( | |
| 129 | - database, pool=pool, ddl_statements=create_ddl) | ||
| 129 | + database, pool=pool, ddl_statements=create_ddl or ()) | ||
| 130 | 130 | ||
| 131 | 131 | ||
| 132 | 132 | class SpannerApi(SpannerReadApi, SpannerWriteApi): | |
| Back | FazBrowse Home | New Git URL |
0 commit comments