spark-sql-migrations 0.0.3__tar.gz → 0.0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/PKG-INFO +6 -4
  2. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/setup.py +6 -4
  3. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations/spark_sql/spark_sql.py +28 -14
  4. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations.egg-info/PKG-INFO +6 -4
  5. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/LICENSE +0 -0
  6. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/MANIFEST.in +0 -0
  7. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/backend_shim.py +0 -0
  8. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/setup.cfg +0 -0
  9. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations/__init__.py +0 -0
  10. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations/migration_templates/default_migration_template.sql +0 -0
  11. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations/migrations_initial/first_01_intial_create_cat_dbr_only.sql +0 -0
  12. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations/migrations_initial/first_02_intial_create_schema_all.sql +0 -0
  13. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations/migrations_initial/first_03_intial_create_state_table_all.sql +0 -0
  14. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations/py.typed +0 -0
  15. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations/spark_sql/__init__.py +0 -0
  16. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations/spark_utils.py +0 -0
  17. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations.egg-info/SOURCES.txt +0 -0
  18. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations.egg-info/dependency_links.txt +0 -0
  19. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations.egg-info/entry_points.txt +0 -0
  20. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations.egg-info/namespace_packages.txt +0 -0
  21. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations.egg-info/requires.txt +0 -0
  22. {spark_sql_migrations-0.0.3 → spark_sql_migrations-0.0.5}/spark_sql_migrations.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spark_sql_migrations
3
- Version: 0.0.3
3
+ Version: 0.0.5
4
4
  Summary: Chained, idempotent SQL migrations for Spark and Databricks.
5
5
  Home-page: https://github.com/mcjug2015/spark_sql_migrations
6
6
  Author: Victor Semenov
@@ -81,10 +81,12 @@ Migrations come from two different owners, and they behave differently:
81
81
  | **what** | catalog, schema, `_spark_migrations_version` table | your tables and columns |
82
82
  | **where** | `spark_sql_migrations/migrations_initial/` | `all_spark_migrations/`, `dbr_only_migrations/` |
83
83
  | **selected by** | filename suffix — `_all.sql` everywhere, `_dbr_only.sql` on Databricks | the `prev_revision_id` chain |
84
- | **when applied** | every run | once, then recorded |
84
+ | **when applied** | until the version table exists | once, then recorded |
85
85
 
86
- The bootstrap chain is re-applied on **every** run, so it must be idempotent. Your own
87
- chains are applied once each and their head revision is written to the version table.
86
+ The bootstrap chain is applied on every run until `_spark_migrations_version` exists, and
87
+ skipped from then on. A run that fails partway through bootstrapping replays it, so it must
88
+ still be idempotent. Your own chains are applied once each and their head revision is
89
+ written to the version table.
88
90
 
89
91
  ## Laying out your chains
90
92
 
@@ -82,10 +82,12 @@ Migrations come from two different owners, and they behave differently:
82
82
  | **what** | catalog, schema, `_spark_migrations_version` table | your tables and columns |
83
83
  | **where** | `spark_sql_migrations/migrations_initial/` | `all_spark_migrations/`, `dbr_only_migrations/` |
84
84
  | **selected by** | filename suffix — `_all.sql` everywhere, `_dbr_only.sql` on Databricks | the `prev_revision_id` chain |
85
- | **when applied** | every run | once, then recorded |
85
+ | **when applied** | until the version table exists | once, then recorded |
86
86
 
87
- The bootstrap chain is re-applied on **every** run, so it must be idempotent. Your own
88
- chains are applied once each and their head revision is written to the version table.
87
+ The bootstrap chain is applied on every run until `_spark_migrations_version` exists, and
88
+ skipped from then on. A run that fails partway through bootstrapping replays it, so it must
89
+ still be idempotent. Your own chains are applied once each and their head revision is
90
+ written to the version table.
89
91
 
90
92
  ## Laying out your chains
91
93
 
@@ -252,5 +254,5 @@ Apache License 2.0 — see [LICENSE](LICENSE).
252
254
  },
253
255
  'python_requires': '>=3.10',
254
256
  'url': 'https://github.com/mcjug2015/spark_sql_migrations',
255
- 'version': '0.0.3',
257
+ 'version': '0.0.5',
256
258
  })
@@ -5,7 +5,8 @@ Two kinds of migration exist, and they are owned by different parties:
5
5
  * the *initial* chain and the new-migration template ship inside this package.
6
6
  They bootstrap the catalog, the schema and the version table, are selected by
7
7
  filename suffix (``_all.sql`` / ``_dbr_only.sql``) rather than by revision,
8
- and are re-applied on every run -- so they must be idempotent.
8
+ and are applied on every run until the version table exists -- so a run that
9
+ failed partway through replays them, and they must be idempotent.
9
10
  * the ``all_spark_migrations/`` and ``dbr_only_migrations/`` chains belong to
10
11
  the consuming project. The caller passes their parent directory as
11
12
  ``migrations_root``; each chain is walked from its root via
@@ -149,20 +150,20 @@ def get_migrations_list(migrations_dir):
149
150
  return get_ordered_migration_objs(migrations)
150
151
 
151
152
 
153
+ def get_table_version(spark, migration_type, cat: str, schema: str):
154
+ version_table = f"{cat}.{schema}.{VERSION_TABLE}"
155
+ if not spark.catalog.tableExists(version_table):
156
+ return None
157
+ return spark.read.table(version_table).where(col("migration_type") == migration_type).select("version_num").head()
158
+
159
+
152
160
  def get_unapplied_migrations_list(spark, migrations_dir, migration_type, cat: str, schema: str):
153
161
  """the tail of one chain after the revision VERSION_TABLE records for it.
154
162
 
155
163
  the whole chain when the table is missing or holds no row for this type.
156
164
  """
157
165
  ordered = get_migrations_list(migrations_dir)
158
-
159
- version_table = f"{cat}.{schema}.{VERSION_TABLE}"
160
- if not spark.catalog.tableExists(version_table):
161
- return ordered
162
-
163
- current = (
164
- spark.read.table(version_table).where(col("migration_type") == migration_type).select("version_num").head()
165
- )
166
+ current = get_table_version(spark, migration_type, cat, schema)
166
167
  if not current:
167
168
  return ordered
168
169
 
@@ -179,9 +180,6 @@ def get_unapplied_migrations_list(spark, migrations_dir, migration_type, cat: st
179
180
 
180
181
 
181
182
  def create_new_migration(message: str, template_path: str, output_path: str, truncate_slug_length: int = 40):
182
- """
183
- TODO XXX start looking up prev revision id from db or files and including it
184
- """
185
183
  rev_id = uuid.uuid4().hex[-12:]
186
184
 
187
185
  date_prefix = datetime.datetime.today().strftime("%y%m%d")
@@ -194,8 +192,15 @@ def create_new_migration(message: str, template_path: str, output_path: str, tru
194
192
 
195
193
  migration_path = os.path.join(output_path, migration_filename)
196
194
 
195
+ try:
196
+ ordered_migrations = get_migrations_list(output_path)
197
+ last_migration_rev_id = ordered_migrations[-1].revision_id if len(ordered_migrations) > 0 else ""
198
+ except ValueError:
199
+ last_migration_rev_id = ""
200
+
197
201
  default_migration_content = open(template_path).read()
198
202
  default_migration_content = default_migration_content.replace("{{revision_id}}", rev_id)
203
+ default_migration_content = default_migration_content.replace("{{prev_revision_id}}", last_migration_rev_id)
199
204
 
200
205
  with open(migration_path, "w") as migration_file:
201
206
  migration_file.write(default_migration_content)
@@ -288,7 +293,11 @@ def run_migrations(spark, cat, schema, output_folder, migrations_root):
288
293
  os.makedirs(initial_output_folder, exist_ok=True)
289
294
  os.makedirs(dbr_ouput_folder, exist_ok=True)
290
295
  os.makedirs(all_spark_ouput_folder, exist_ok=True)
291
- migrate_initial(spark, initial_output_folder, cat, schema)
296
+ version_table = f"{cat}.{schema}.{VERSION_TABLE}"
297
+ if spark.catalog.tableExists(version_table):
298
+ logger.info(f"{version_table} already exists; skipping the initial migrations;")
299
+ else:
300
+ migrate_initial(spark, initial_output_folder, cat, schema)
292
301
  if is_dbr():
293
302
  migrate_w_rev(spark, dbr_ouput_folder, migrations_root, cat, schema, DBR_ONLY)
294
303
  migrate_w_rev(spark, all_spark_ouput_folder, migrations_root, cat, schema, ALL_SPARK)
@@ -322,7 +331,12 @@ def build_parser(): # pragma: no cover
322
331
 
323
332
  p_create = subparsers.add_parser("create_new_migration", help="create a new migration from the template")
324
333
  p_create.add_argument("--message", required=True)
325
- p_create.add_argument("--output-path", required=True, help="the chain directory to write the new migration into")
334
+ p_create.add_argument(
335
+ "--output-path",
336
+ required=True,
337
+ help="the chain directory to write the new migration into. if sql files are in there, the last sql's rev_id"
338
+ "will be set as the new migrations prev_rev_id.",
339
+ )
326
340
  p_create.add_argument("--template-path", default=None, help="defaults to the template shipped in this package")
327
341
  p_create.set_defaults(func=_cli_create_new_migration)
328
342
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spark_sql_migrations
3
- Version: 0.0.3
3
+ Version: 0.0.5
4
4
  Summary: Chained, idempotent SQL migrations for Spark and Databricks.
5
5
  Home-page: https://github.com/mcjug2015/spark_sql_migrations
6
6
  Author: Victor Semenov
@@ -81,10 +81,12 @@ Migrations come from two different owners, and they behave differently:
81
81
  | **what** | catalog, schema, `_spark_migrations_version` table | your tables and columns |
82
82
  | **where** | `spark_sql_migrations/migrations_initial/` | `all_spark_migrations/`, `dbr_only_migrations/` |
83
83
  | **selected by** | filename suffix — `_all.sql` everywhere, `_dbr_only.sql` on Databricks | the `prev_revision_id` chain |
84
- | **when applied** | every run | once, then recorded |
84
+ | **when applied** | until the version table exists | once, then recorded |
85
85
 
86
- The bootstrap chain is re-applied on **every** run, so it must be idempotent. Your own
87
- chains are applied once each and their head revision is written to the version table.
86
+ The bootstrap chain is applied on every run until `_spark_migrations_version` exists, and
87
+ skipped from then on. A run that fails partway through bootstrapping replays it, so it must
88
+ still be idempotent. Your own chains are applied once each and their head revision is
89
+ written to the version table.
88
90
 
89
91
  ## Laying out your chains
90
92