pgbelt 0.8.0__py3-none-any.whl → 0.8.2__py3-none-any.whl

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.
pgbelt/cmd/schema.py CHANGED
@@ -6,9 +6,7 @@ from pgbelt.config.models import DbupgradeConfig
6
6
  from pgbelt.util.dump import apply_target_constraints
7
7
  from pgbelt.util.dump import apply_target_schema
8
8
  from pgbelt.util.dump import create_target_indexes
9
- from pgbelt.util.dump import dump_dst_not_valid_constraints
10
9
  from pgbelt.util.dump import dump_source_schema
11
- from pgbelt.util.dump import dump_dst_create_index
12
10
  from pgbelt.util.dump import remove_dst_not_valid_constraints
13
11
  from pgbelt.util.dump import remove_dst_indexes
14
12
  from pgbelt.util.logs import get_logger
@@ -58,17 +56,6 @@ async def load_constraints(config_future: Awaitable[DbupgradeConfig]) -> None:
58
56
  await apply_target_constraints(conf, logger)
59
57
 
60
58
 
61
- @run_with_configs(skip_src=True)
62
- async def dump_constraints(config_future: Awaitable[DbupgradeConfig]) -> None:
63
- """
64
- Dumps the NOT VALID constraints from the target database onto disk, in
65
- the schemas directory.
66
- """
67
- conf = await config_future
68
- logger = get_logger(conf.db, conf.dc, "schema.dst")
69
- await dump_dst_not_valid_constraints(conf, logger)
70
-
71
-
72
59
  @run_with_configs(skip_src=True)
73
60
  async def remove_constraints(config_future: Awaitable[DbupgradeConfig]) -> None:
74
61
  """
@@ -81,17 +68,6 @@ async def remove_constraints(config_future: Awaitable[DbupgradeConfig]) -> None:
81
68
  await remove_dst_not_valid_constraints(conf, logger)
82
69
 
83
70
 
84
- @run_with_configs(skip_src=True)
85
- async def dump_indexes(config_future: Awaitable[DbupgradeConfig]) -> None:
86
- """
87
- Dumps the CREATE INDEX statements from the target database onto disk, in
88
- the schemas directory.
89
- """
90
- conf = await config_future
91
- logger = get_logger(conf.db, conf.dc, "schema.dst")
92
- await dump_dst_create_index(conf, logger)
93
-
94
-
95
71
  @run_with_configs(skip_src=True)
96
72
  async def remove_indexes(config_future: Awaitable[DbupgradeConfig]) -> None:
97
73
  """
@@ -134,9 +110,7 @@ COMMANDS = [
134
110
  dump_schema,
135
111
  load_schema,
136
112
  load_constraints,
137
- dump_constraints,
138
113
  remove_constraints,
139
- dump_indexes,
140
114
  remove_indexes,
141
115
  create_indexes,
142
116
  ]
pgbelt/util/dump.py CHANGED
@@ -93,7 +93,7 @@ async def dump_source_tables(
93
93
  [
94
94
  "pg_dump",
95
95
  "--data-only",
96
- f"--table={config.schema_name}.{table}",
96
+ f'--table={config.schema_name}."{table}"',
97
97
  "-Fc",
98
98
  "-f",
99
99
  table_file(config.db, config.dc, table),
@@ -310,11 +310,14 @@ async def remove_dst_not_valid_constraints(
310
310
  if (config.tables and table in config.tables) or not config.tables:
311
311
  queries = queries + f"ALTER TABLE {table} DROP CONSTRAINT {constraint};"
312
312
 
313
- command = ["psql", config.dst.owner_dsn, "-c", f"'{queries}'"]
313
+ if queries != "":
314
+ command = ["psql", config.dst.owner_dsn, "-c", f"'{queries}'"]
314
315
 
315
- await _execute_subprocess(
316
- command, "Finished removing NOT VALID constraints from the target.", logger
317
- )
316
+ await _execute_subprocess(
317
+ command, "Finished removing NOT VALID constraints from the target.", logger
318
+ )
319
+ else:
320
+ logger.info("No NOT VALID detected for removal.")
318
321
 
319
322
 
320
323
  async def apply_target_constraints(config: DbupgradeConfig, logger: Logger) -> None:
@@ -336,53 +339,6 @@ async def apply_target_constraints(config: DbupgradeConfig, logger: Logger) -> N
336
339
  )
337
340
 
338
341
 
339
- async def dump_dst_create_index(config: DbupgradeConfig, logger: Logger) -> None:
340
- """
341
- Dump CREATE INDEX statements from the target database.
342
- Used when schema is loaded in outside of pgbelt.
343
- """
344
-
345
- logger.info("Dumping target CREATE INDEX statements...")
346
-
347
- command = [
348
- "pg_dump",
349
- "--schema-only",
350
- "--no-owner",
351
- "-n",
352
- config.schema_name,
353
- config.dst.pglogical_dsn,
354
- ]
355
-
356
- out = await _execute_subprocess(command, "Retrieved target schema", logger)
357
-
358
- # No username replacement needs to be done, so replace dst user with the same.
359
- commands_raw = _parse_dump_commands(
360
- out.decode("utf-8"), config.dst.owner_user.name, config.dst.owner_user.name
361
- )
362
-
363
- commands = []
364
- for c in commands_raw:
365
- if "CREATE" in command and "INDEX" in command:
366
- regex_matches = search(
367
- r"CREATE [UNIQUE ]*INDEX (?P<index>[a-zA-Z0-9._]+)+.*",
368
- c,
369
- )
370
- if not regex_matches:
371
- continue
372
- commands.append(c)
373
-
374
- try:
375
- await makedirs(schema_dir(config.db, config.dc))
376
- except FileExistsError:
377
- pass
378
-
379
- async with aopen(schema_file(config.db, config.dc, ONLY_INDEXES), "w") as out:
380
- for command in commands:
381
- await out.write(command)
382
-
383
- logger.debug("Finished dumping CREATE INDEX statements from the target.")
384
-
385
-
386
342
  async def remove_dst_indexes(config: DbupgradeConfig, logger: Logger) -> None:
387
343
  """
388
344
  Remove the INDEXes from the schema of the target database.
@@ -395,7 +351,6 @@ async def remove_dst_indexes(config: DbupgradeConfig, logger: Logger) -> None:
395
351
 
396
352
  logger.info("Removing Indexes from the target...")
397
353
 
398
- queries = ""
399
354
  for c in create_index_statements.split(";"):
400
355
  regex_matches = search(
401
356
  r"CREATE [UNIQUE ]*INDEX (?P<index>[a-zA-Z0-9._]+)+.*",
@@ -404,14 +359,20 @@ async def remove_dst_indexes(config: DbupgradeConfig, logger: Logger) -> None:
404
359
  if not regex_matches:
405
360
  continue
406
361
  index = regex_matches.groupdict()["index"]
407
-
408
- queries = queries + f"DROP INDEX {index};"
409
-
410
- command = ["psql", config.dst.owner_dsn, "-c", f"'{queries}'"]
411
-
412
- await _execute_subprocess(
413
- command, "Finished removing indexes from the target.", logger
414
- )
362
+ if config.schema_name:
363
+ index = f"{config.schema_name}.{index}"
364
+
365
+ # DROP the index
366
+ # Note that the host DSN must have a statement timeout of 0.
367
+ # Example DSN: `host=server-hostname user=user dbname=db_name options='-c statement_timeout=3600000'`
368
+ host_dsn = config.dst.owner_dsn + " options='-c statement_timeout=0'"
369
+
370
+ # DROP INDEX IF EXISTS so no need to catch exceptions
371
+ command = ["psql", host_dsn, "-c", f"DROP INDEX IF EXISTS {index};"]
372
+ logger.info(f"Dropping index {index} on the target...")
373
+ await _execute_subprocess(
374
+ command, f"Finished dropping index {index} on the target.", logger
375
+ )
415
376
 
416
377
 
417
378
  async def create_target_indexes(
@@ -440,15 +401,21 @@ async def create_target_indexes(
440
401
  for c in create_index_statements.split(";"):
441
402
  # Get the Index Name
442
403
  regex_matches = search(
443
- r"CREATE [UNIQUE ]*INDEX (?P<index>[a-zA-Z0-9._]+)+.*",
404
+ r"CREATE [UNIQUE ]*INDEX (?P<index>[a-zA-Z0-9._\"]+)+.*",
444
405
  c,
445
406
  )
446
407
  if not regex_matches:
447
408
  continue
448
409
  index = regex_matches.groupdict()["index"]
449
410
 
411
+ # Sometimes the index name is quoted, so remove the quotes
412
+ index = index.replace('"', "")
413
+
450
414
  # Create the index
451
- command = ["psql", config.dst.owner_dsn, "-c", f"{c};"]
415
+ # Note that the host DSN must have a statement timeout of 0.
416
+ # Example DSN: `host=server-hostname user=user dbname=db_name options='-c statement_timeout=3600000'`
417
+ host_dsn = config.dst.owner_dsn + " options='-c statement_timeout=0'"
418
+ command = ["psql", host_dsn, "-c", f"{c};"]
452
419
  logger.info(f"Creating index {index} on the target...")
453
420
  try:
454
421
  await _execute_subprocess(
pgbelt/util/postgres.py CHANGED
@@ -264,7 +264,7 @@ async def table_empty(pool: Pool, table: str, schema: str, logger: Logger) -> bo
264
264
  return true if the table is empty
265
265
  """
266
266
  logger.info(f"Checking if table {table} is empty...")
267
- result = await pool.fetch(f"SELECT * FROM {schema}.{table} LIMIT 1;")
267
+ result = await pool.fetch(f'SELECT * FROM {schema}."{table}" LIMIT 1;')
268
268
  return len(result) == 0
269
269
 
270
270
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pgbelt
3
- Version: 0.8.0
3
+ Version: 0.8.2
4
4
  Summary: A CLI tool used to manage Postgres data migrations from beginning to end, for a single database or a fleet, leveraging pglogical replication.
5
5
  Author: Varjitt Jeeva
6
6
  Author-email: varjitt.jeeva@autodesk.com
@@ -15,7 +15,7 @@ Requires-Dist: aiofiles (>=0.8,<24.2)
15
15
  Requires-Dist: asyncpg (>=0.27,<0.31)
16
16
  Requires-Dist: pydantic (>=2.0,<3.0)
17
17
  Requires-Dist: tabulate (>=0.9.0,<0.10.0)
18
- Requires-Dist: typer (>=0.9,<0.14)
18
+ Requires-Dist: typer (>=0.9,<0.16)
19
19
  Description-Content-Type: text/markdown
20
20
 
21
21
  # Pgbelt
@@ -4,7 +4,7 @@ pgbelt/cmd/convenience.py,sha256=RY762BYoyOccmhHqSOaHWIPVBzY4kU0qZautTprGps0,585
4
4
  pgbelt/cmd/helpers.py,sha256=anMAkZjJRy7n0EwewyMNJGJ4Jx9keSNZdzWqi3ICNgI,5292
5
5
  pgbelt/cmd/login.py,sha256=FNg7shEIC2iwiDjOMza2ZvBv_33U1GMKRh51vsGMTb8,3351
6
6
  pgbelt/cmd/preflight.py,sha256=-78Puqqf1rCxNQEyn4bQIAORez_tsy6zJAbSuO_de9s,20676
7
- pgbelt/cmd/schema.py,sha256=NT0ccfzykEezxGcUDDgbAN_jBXovGSWWac5VOvb9TGs,5277
7
+ pgbelt/cmd/schema.py,sha256=OuxJdUILxlNCvaBV71Si8035pX3LVwHm5Urt0vftO8E,4389
8
8
  pgbelt/cmd/setup.py,sha256=Jp5sqT9_whoVBiOzAlOzX1ubtXQADYBkBrJldch_fKk,6627
9
9
  pgbelt/cmd/status.py,sha256=8K1c2OMZ3uHNmEh-5a2a0fhTDmCU0RohzgjjVfXoKGo,5385
10
10
  pgbelt/cmd/sync.py,sha256=MrrBqCtsBqhL4nyzp78gKYp90xXxlzuHcqWQ5Nt6_hs,8156
@@ -16,12 +16,12 @@ pgbelt/config/remote.py,sha256=D9bOekVfMU1xX2Wy0OiJwSXetxJUdt9Tn5Fukwn9rnE,5307
16
16
  pgbelt/main.py,sha256=YiagBiGt8pbNlukkRxROXnQX1Tx6ax7c6riuHRCrPYU,186
17
17
  pgbelt/util/__init__.py,sha256=-6KkvVMz-yGNQfeoo4CZZrgWKXYmFd4CMyoiao8OnFE,40
18
18
  pgbelt/util/asyncfuncs.py,sha256=7i_GpBmUNNZ8RUGvU-q5nclsoaCm6Lx8jLP8usYvmZc,583
19
- pgbelt/util/dump.py,sha256=AwyOAd9CP014gvsl-qlo1lbnXZfxoeN4ujZWUIq7KM8,14715
19
+ pgbelt/util/dump.py,sha256=R5eI1MFwbv5M6ICnkmjhugj3ZhpWu5sjT20ixEXNfC4,14218
20
20
  pgbelt/util/logs.py,sha256=E6doEhi8vrusmYUTZRdjKHP-h2dDiExCjgEtMl7epPw,1793
21
21
  pgbelt/util/pglogical.py,sha256=Y6KZBeiH85zhNSvhATqh0xozhfUMyQnPWN1HwRosZFo,13613
22
- pgbelt/util/postgres.py,sha256=pDl5CTlLUeuWdQgC_wHbO9Ywd69hHYNaasstog0uzvw,20074
23
- pgbelt-0.8.0.dist-info/LICENSE,sha256=FQ5cFkW02dKK3LmKH8z-rwn93tWSCh7lsxfNUiWcFsg,10758
24
- pgbelt-0.8.0.dist-info/METADATA,sha256=SzxroPhFZmph0yzRtV2FqEPqU30NCIfaNsk18R2LTIE,3011
25
- pgbelt-0.8.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
26
- pgbelt-0.8.0.dist-info/entry_points.txt,sha256=SCz_poPjkaVnWpJ-CeytAnDzbVc6l0WalOwitIqW_3g,40
27
- pgbelt-0.8.0.dist-info/RECORD,,
22
+ pgbelt/util/postgres.py,sha256=0Jx0auJZsSigDX57M1J9ntN1booL1AUxPc8oBYzsbUE,20076
23
+ pgbelt-0.8.2.dist-info/LICENSE,sha256=FQ5cFkW02dKK3LmKH8z-rwn93tWSCh7lsxfNUiWcFsg,10758
24
+ pgbelt-0.8.2.dist-info/METADATA,sha256=dhrSqkEUjn642o_hu0sZn8zUhCQLAMDZmUZSqrBmY4s,3011
25
+ pgbelt-0.8.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
26
+ pgbelt-0.8.2.dist-info/entry_points.txt,sha256=SCz_poPjkaVnWpJ-CeytAnDzbVc6l0WalOwitIqW_3g,40
27
+ pgbelt-0.8.2.dist-info/RECORD,,
File without changes