pgdevkit 0.8.0__py3-none-any.whl → 0.9.0__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.
- pgdevkit/migrate.py +42 -5
- {pgdevkit-0.8.0.dist-info → pgdevkit-0.9.0.dist-info}/METADATA +1 -1
- {pgdevkit-0.8.0.dist-info → pgdevkit-0.9.0.dist-info}/RECORD +5 -5
- {pgdevkit-0.8.0.dist-info → pgdevkit-0.9.0.dist-info}/WHEEL +0 -0
- {pgdevkit-0.8.0.dist-info → pgdevkit-0.9.0.dist-info}/entry_points.txt +0 -0
pgdevkit/migrate.py
CHANGED
|
@@ -303,6 +303,14 @@ def record_applied(conninfo: str, tracking_table: str, filename: str) -> bool:
|
|
|
303
303
|
return False
|
|
304
304
|
|
|
305
305
|
|
|
306
|
+
def created_table_names(sql: str) -> list[str]:
|
|
307
|
+
"""Table names any CREATE TABLE statement in this raw SQL script targets. Public
|
|
308
|
+
wrapper around the same detection `apply_migration` uses internally, for callers that
|
|
309
|
+
run a script directly (e.g. via `execute_sql_script`) instead of through a tracked
|
|
310
|
+
migration file, and still want to know what tables -- if any -- it created."""
|
|
311
|
+
return _created_table_names(_split_sql(sql))
|
|
312
|
+
|
|
313
|
+
|
|
306
314
|
def verify_created_tables(conninfo: str, stmts: list[str]) -> list[str]:
|
|
307
315
|
"""Table names from this migration's CREATE TABLE statements that do NOT exist in the
|
|
308
316
|
database. Empty means everything landed."""
|
|
@@ -318,6 +326,39 @@ def verify_created_tables(conninfo: str, stmts: list[str]) -> list[str]:
|
|
|
318
326
|
return missing
|
|
319
327
|
|
|
320
328
|
|
|
329
|
+
def missing_privileges(conninfo: str, role: str, tables: list[str], privilege: str = "select") -> list[str]:
|
|
330
|
+
"""Table names from `tables` that `role` cannot currently exercise `privilege` on
|
|
331
|
+
(checked via Postgres's own `has_table_privilege`). Empty means the role can access
|
|
332
|
+
all of them. For guarding against the classic "migration creates a table, nobody
|
|
333
|
+
grants it to the app's runtime role" gap: check the tables a migration just created
|
|
334
|
+
against the role that will actually query them at runtime."""
|
|
335
|
+
if not tables:
|
|
336
|
+
return []
|
|
337
|
+
missing = []
|
|
338
|
+
with psycopg.connect(conninfo) as con:
|
|
339
|
+
for tbl in tables:
|
|
340
|
+
row = con.execute("select has_table_privilege(%s, %s, %s)", (role, tbl, privilege)).fetchone()
|
|
341
|
+
if not (row and row[0]):
|
|
342
|
+
missing.append(tbl)
|
|
343
|
+
return missing
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _execute_stmts(conninfo: str, stmts: list[str]) -> None:
|
|
347
|
+
with psycopg.connect(conninfo) as con:
|
|
348
|
+
for stmt in stmts:
|
|
349
|
+
con.execute(cast(LiteralString, stmt))
|
|
350
|
+
con.commit()
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def execute_sql_script(conninfo: str, sql: str) -> None:
|
|
354
|
+
"""Run a raw SQL script as one committed transaction, split into statements the same
|
|
355
|
+
statement-boundary-safe way apply_migration is (dollar-quoted blocks, string literals,
|
|
356
|
+
and line comments never get split mid-statement). Unlike apply_migration, this does
|
|
357
|
+
no tracking-table bookkeeping and isn't forward-only -- for scripts meant to re-run
|
|
358
|
+
every time, like an idempotent `GRANT ... ON ALL TABLES IN SCHEMA` privilege sync."""
|
|
359
|
+
_execute_stmts(conninfo, _split_sql(sql))
|
|
360
|
+
|
|
361
|
+
|
|
321
362
|
@dataclass
|
|
322
363
|
class ApplyResult:
|
|
323
364
|
filename: str
|
|
@@ -337,11 +378,7 @@ def apply_migration(
|
|
|
337
378
|
stmts = _split_sql(sql)
|
|
338
379
|
|
|
339
380
|
if not already_done:
|
|
340
|
-
|
|
341
|
-
with psycopg.connect(conninfo) as con:
|
|
342
|
-
for stmt in stmts:
|
|
343
|
-
con.execute(cast(LiteralString, stmt))
|
|
344
|
-
con.commit()
|
|
381
|
+
_execute_stmts(conninfo, stmts)
|
|
345
382
|
|
|
346
383
|
# Tracking insert is a separate connection/transaction so a missing tracking table
|
|
347
384
|
# never rolls back the DDL that was just applied.
|
|
@@ -8,7 +8,7 @@ pgdevkit/envtag.py,sha256=FdRqjLRdS9O9LSvoEzrRsFNeqiyZTLLzFgEkIirJyZI,2006
|
|
|
8
8
|
pgdevkit/fetch_missing.py,sha256=vb8hXWBKMWgqkxHso5SuhX9l6rxNXfaybAEsajPLYow,8495
|
|
9
9
|
pgdevkit/introspect.py,sha256=QYIlRuZk4lBHGxaW7zb_kFRIuNfi3AxH0Q2F_GKzlVI,7870
|
|
10
10
|
pgdevkit/lakebase.py,sha256=0PABOk4p-2klLTY8QAUibQf9QeyNHKywUWEWGdkUY8k,3165
|
|
11
|
-
pgdevkit/migrate.py,sha256=
|
|
11
|
+
pgdevkit/migrate.py,sha256=gyZLsioM-Kr8Qped2dqJykNUB3iGHp943vNN6tFZdeo,15380
|
|
12
12
|
pgdevkit/models.py,sha256=dAZ8f7pgDsxoLVrDWsM4h0qwJ0pOzXDdWMGsnjrW80E,2103
|
|
13
13
|
pgdevkit/mssql_introspect.py,sha256=Fhv1N4zHYEDZ0PEy0OIpawUmoIFeoi-Lm97pmEyDmYY,12031
|
|
14
14
|
pgdevkit/parser.py,sha256=FmXL6-eCFzP_0FNyTrg4wF3aPzPeq7re2i0xvrSJIcs,16885
|
|
@@ -43,7 +43,7 @@ pgdevkit/docs/database-layout.md,sha256=j9N8GuT63D2oVf9rIOEv8GTWs4yTtjZTGH-zM5Wr
|
|
|
43
43
|
pgdevkit/skills/pgdevkit/SKILL.md,sha256=ADqEaQtMJPUUAiieqokzUUmIf27bWWJNB1ZvsfgiKAE,12205
|
|
44
44
|
pgdevkit/skills/pgdevkit/references/dynamic-sql.md,sha256=aTR1sx81moiTwaMaiOecaqk-9rT8y5Zxz7W1BoC3vK0,2774
|
|
45
45
|
pgdevkit/skills/pgdevkit/references/temporal-tables.md,sha256=LwZnItvQWI7bB0oRHxIfUc0ynnq7N0V5Mnv-QHvFN3Q,1364
|
|
46
|
-
pgdevkit-0.
|
|
47
|
-
pgdevkit-0.
|
|
48
|
-
pgdevkit-0.
|
|
49
|
-
pgdevkit-0.
|
|
46
|
+
pgdevkit-0.9.0.dist-info/METADATA,sha256=wmx2V7kjwyFEgTNZZhngSM8JnigCShnKc65XQIdhaa0,21824
|
|
47
|
+
pgdevkit-0.9.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
48
|
+
pgdevkit-0.9.0.dist-info/entry_points.txt,sha256=FK2P55lf0WaGlOZJIINOGgCt8WB7ep0OnPsgnrp80bg,42
|
|
49
|
+
pgdevkit-0.9.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|