spark-sql-migrations 0.0.7__tar.gz → 0.0.8__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.
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/PKG-INFO +1 -1
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/setup.py +1 -1
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations/spark_sql/spark_sql.py +72 -20
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations.egg-info/PKG-INFO +1 -1
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/LICENSE +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/MANIFEST.in +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/backend_shim.py +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/setup.cfg +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations/__init__.py +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations/migration_templates/default_migration_template.sql +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations/migrations_initial/first_01_intial_create_cat.sql +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations/migrations_initial/first_02_intial_create_schema.sql +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations/migrations_initial/first_03_intial_create_state_table.sql +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations/py.typed +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations/spark_sql/__init__.py +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations/spark_utils.py +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations.egg-info/SOURCES.txt +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations.egg-info/dependency_links.txt +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations.egg-info/entry_points.txt +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations.egg-info/namespace_packages.txt +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations.egg-info/requires.txt +0 -0
- {spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations.egg-info/top_level.txt +0 -0
|
@@ -54,7 +54,7 @@ _COMMENT_OR_BLANK_RE = re.compile(r"^\s*(--.*)?$")
|
|
|
54
54
|
@dataclass(frozen=True)
|
|
55
55
|
class Migration:
|
|
56
56
|
revision_id: str
|
|
57
|
-
prev_revision_id: str
|
|
57
|
+
prev_revision_id: Optional[str]
|
|
58
58
|
template_name: str
|
|
59
59
|
|
|
60
60
|
|
|
@@ -122,7 +122,7 @@ def get_ordered_migration_objs(migration_objs: List[Migration]) -> List[Migratio
|
|
|
122
122
|
next_by_revision[migration.prev_revision_id] = migration
|
|
123
123
|
|
|
124
124
|
ordered = []
|
|
125
|
-
current: Migration
|
|
125
|
+
current: Optional[Migration] = roots[0]
|
|
126
126
|
while current:
|
|
127
127
|
ordered.append(current)
|
|
128
128
|
current = next_by_revision.get(current.revision_id)
|
|
@@ -137,8 +137,14 @@ def get_ordered_migration_objs(migration_objs: List[Migration]) -> List[Migratio
|
|
|
137
137
|
return ordered
|
|
138
138
|
|
|
139
139
|
|
|
140
|
-
def get_migrations_list(migrations_dir: str) -> List[Migration]:
|
|
141
|
-
"""every migration in one directory, walked from its root to its head.
|
|
140
|
+
def get_migrations_list(migrations_dir: str, max_revision_id: Optional[str] = None) -> List[Migration]:
|
|
141
|
+
"""every migration in one directory, walked from its root to its head.
|
|
142
|
+
|
|
143
|
+
``revision_id`` cuts the walk short: the chain is returned up to and including
|
|
144
|
+
the migration carrying that revision. A revision no migration in the directory
|
|
145
|
+
carries is not an error -- the whole chain comes back, same as for no revision
|
|
146
|
+
at all.
|
|
147
|
+
"""
|
|
142
148
|
if not os.path.isdir(migrations_dir):
|
|
143
149
|
raise ValueError(f"no migrations dir at {migrations_dir};")
|
|
144
150
|
|
|
@@ -150,7 +156,15 @@ def get_migrations_list(migrations_dir: str) -> List[Migration]:
|
|
|
150
156
|
if not migrations:
|
|
151
157
|
return []
|
|
152
158
|
|
|
153
|
-
|
|
159
|
+
ordered = get_ordered_migration_objs(migrations)
|
|
160
|
+
if max_revision_id is None:
|
|
161
|
+
return ordered
|
|
162
|
+
|
|
163
|
+
for index, migration in enumerate(ordered):
|
|
164
|
+
if migration.revision_id == max_revision_id:
|
|
165
|
+
return ordered[: index + 1]
|
|
166
|
+
|
|
167
|
+
return ordered
|
|
154
168
|
|
|
155
169
|
|
|
156
170
|
def get_table_version(spark: SparkSession, cat: str, schema: str) -> Optional[Row]:
|
|
@@ -161,8 +175,10 @@ def get_table_version(spark: SparkSession, cat: str, schema: str) -> Optional[Ro
|
|
|
161
175
|
return spark.read.table(version_table).select("version_num").head()
|
|
162
176
|
|
|
163
177
|
|
|
164
|
-
def get_unapplied_migrations_list(
|
|
165
|
-
|
|
178
|
+
def get_unapplied_migrations_list(
|
|
179
|
+
spark: SparkSession, migrations_dir: str, cat: str, schema: str, max_revision_id: Optional[str] = None
|
|
180
|
+
) -> List[Migration]:
|
|
181
|
+
ordered = get_migrations_list(migrations_dir, max_revision_id)
|
|
166
182
|
current = get_table_version(spark, cat, schema)
|
|
167
183
|
if not current:
|
|
168
184
|
return ordered
|
|
@@ -239,9 +255,15 @@ def apply_template(output_dir: str, template, cat: str, schema: str) -> str:
|
|
|
239
255
|
|
|
240
256
|
|
|
241
257
|
def get_ascending_letters_within_minute() -> str:
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
258
|
+
"""a letter stamp that sorts in the order it was taken, within one minute.
|
|
259
|
+
|
|
260
|
+
the full microseconds since the minute began, not timedelta.microseconds -- that
|
|
261
|
+
holds only the sub-second part and so starts over every second. zero-padded to a
|
|
262
|
+
fixed width, because these are compared as text once they are folder names.
|
|
263
|
+
"""
|
|
264
|
+
now = datetime.datetime.now()
|
|
265
|
+
micros_since_minute = (now - now.replace(second=0, microsecond=0)) // datetime.timedelta(microseconds=1)
|
|
266
|
+
return f"{micros_since_minute:08d}".translate(str.maketrans("0123456789", "ABCDEFGHIJ"))
|
|
245
267
|
|
|
246
268
|
|
|
247
269
|
def get_output_folder(output_parent_path: str) -> str:
|
|
@@ -286,7 +308,14 @@ def record_revision(spark: SparkSession, cat: str, schema: str, revision_id: str
|
|
|
286
308
|
spark.sql(f"insert into {version_table} (version_num) values ('{revision_literal}')")
|
|
287
309
|
|
|
288
310
|
|
|
289
|
-
def
|
|
311
|
+
def upgrade(
|
|
312
|
+
spark: SparkSession,
|
|
313
|
+
output_folder: str,
|
|
314
|
+
migrations_dir: str,
|
|
315
|
+
cat: str,
|
|
316
|
+
schema: str,
|
|
317
|
+
max_revision_id: Optional[str] = None,
|
|
318
|
+
) -> None:
|
|
290
319
|
"""
|
|
291
320
|
TODO XXX permit applying up to a revision below the head revision
|
|
292
321
|
TODO XXX add backwards migrations, permit migrating backwards
|
|
@@ -294,7 +323,9 @@ def migrate_w_rev(spark: SparkSession, output_folder: str, migrations_dir: str,
|
|
|
294
323
|
if not os.path.isdir(migrations_dir):
|
|
295
324
|
logger.info(f"no chain at {migrations_dir}; skipping it;")
|
|
296
325
|
return
|
|
297
|
-
unapplied = get_unapplied_migrations_list(
|
|
326
|
+
unapplied = get_unapplied_migrations_list(
|
|
327
|
+
spark, migrations_dir, cat=cat, schema=schema, max_revision_id=max_revision_id
|
|
328
|
+
)
|
|
298
329
|
|
|
299
330
|
logger.info(
|
|
300
331
|
f"{len(unapplied)} unapplied migrations; "
|
|
@@ -308,7 +339,14 @@ def migrate_w_rev(spark: SparkSession, output_folder: str, migrations_dir: str,
|
|
|
308
339
|
logger.info(f"{migration.template_name} done; now at {migration.revision_id};")
|
|
309
340
|
|
|
310
341
|
|
|
311
|
-
def
|
|
342
|
+
def run_upgrade(
|
|
343
|
+
spark: SparkSession,
|
|
344
|
+
cat: str,
|
|
345
|
+
schema: str,
|
|
346
|
+
output_folder: str,
|
|
347
|
+
migrations_dir: str,
|
|
348
|
+
max_revision_id: Optional[str] = None,
|
|
349
|
+
) -> None:
|
|
312
350
|
initial_output_folder = os.path.join(output_folder, INITIAL_MIGRATIONS_PACKAGE_PATH)
|
|
313
351
|
client_output_folder = os.path.join(output_folder, CLIENT_OUTPUT_DIRNAME)
|
|
314
352
|
os.makedirs(initial_output_folder, exist_ok=True)
|
|
@@ -318,17 +356,25 @@ def run_migrations(spark: SparkSession, cat: str, schema: str, output_folder: st
|
|
|
318
356
|
logger.info(f"{version_table} already exists; skipping the initial migrations;")
|
|
319
357
|
else:
|
|
320
358
|
migrate_initial(spark, initial_output_folder, cat, schema)
|
|
321
|
-
|
|
359
|
+
upgrade(spark, client_output_folder, migrations_dir, cat, schema, max_revision_id)
|
|
322
360
|
|
|
323
361
|
|
|
324
|
-
def main(
|
|
362
|
+
def main(
|
|
363
|
+
cat: str,
|
|
364
|
+
schema: str,
|
|
365
|
+
migrations_dir: str,
|
|
366
|
+
output_parent_path: Optional[str] = None,
|
|
367
|
+
max_revision_id: Optional[str] = None,
|
|
368
|
+
) -> None:
|
|
325
369
|
output_folder = get_output_folder(output_parent_path or os.path.join(os.getcwd(), "migrations_out"))
|
|
326
370
|
os.makedirs(output_folder)
|
|
327
|
-
|
|
371
|
+
run_upgrade(get_spark(), cat, schema, output_folder, migrations_dir, max_revision_id)
|
|
328
372
|
|
|
329
373
|
|
|
330
|
-
def _cli_main(
|
|
331
|
-
|
|
374
|
+
def _cli_main(
|
|
375
|
+
cat: str, schema: str, migrations_dir: str, max_revision_id: Optional[str] = None
|
|
376
|
+
) -> None: # pragma: no cover
|
|
377
|
+
main(cat, schema, migrations_dir, max_revision_id=max_revision_id)
|
|
332
378
|
|
|
333
379
|
|
|
334
380
|
def _cli_create_new_migration(
|
|
@@ -341,10 +387,16 @@ def build_parser() -> argparse.ArgumentParser: # pragma: no cover
|
|
|
341
387
|
parser = argparse.ArgumentParser(description="spark_sql_migrations migration utilities")
|
|
342
388
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
343
389
|
|
|
344
|
-
p_run = subparsers.add_parser("run", help="apply
|
|
390
|
+
p_run = subparsers.add_parser("run", help="upgrade to head/apply pending migrations")
|
|
345
391
|
p_run.add_argument("--cat", type=str, default="spark_catalog")
|
|
346
392
|
p_run.add_argument("--schema", type=str, default="default")
|
|
347
393
|
p_run.add_argument("--migrations-dir", type=str, required=True, help="the directory holding the migration chain")
|
|
394
|
+
p_run.add_argument(
|
|
395
|
+
"--max-revision-id",
|
|
396
|
+
type=str,
|
|
397
|
+
default=None,
|
|
398
|
+
help="apply the migration carrying this revision_id and stop; defaults to applying the chain to its head",
|
|
399
|
+
)
|
|
348
400
|
p_run.set_defaults(func=_cli_main)
|
|
349
401
|
|
|
350
402
|
p_create = subparsers.add_parser("create_new_migration", help="create a new migration from the template")
|
|
@@ -370,7 +422,7 @@ def build_parser() -> argparse.ArgumentParser: # pragma: no cover
|
|
|
370
422
|
return parser
|
|
371
423
|
|
|
372
424
|
|
|
373
|
-
def cli(argv: list[str]
|
|
425
|
+
def cli(argv: Optional[list[str]] = None) -> None: # pragma: no cover
|
|
374
426
|
"""the `spark-sql-migrations` console command.
|
|
375
427
|
|
|
376
428
|
an application entry point, so unlike the rest of this package it configures
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations/spark_sql/__init__.py
RENAMED
|
File without changes
|
{spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations/spark_utils.py
RENAMED
|
File without changes
|
{spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spark_sql_migrations-0.0.7 → spark_sql_migrations-0.0.8}/spark_sql_migrations.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|