From 371bdbed285157bb0c25c28d8d11ced8a804301f Mon Sep 17 00:00:00 2001 From: Adrian Ehrsam Date: Fri, 17 Jul 2026 15:07:37 +0200 Subject: [PATCH] Fix dependency-name computation in schema-apply ordering Two real bugs in how _iter_sql_files/_get_sql_deps compute the name a file is tracked under, both silently degrading dependency ordering to "untracked -> assumed already satisfied" instead of an actual wait: - _get_sql_deps used str(t) on a matched Table node, which includes the alias for an aliased reference (e.g. "FROM app.visit v" -> "app.visit AS v"). That never matches the plain name a dependency's own CREATE target is recorded under. Use exp.table_name(t) instead. - _iter_sql_files derived a file's own declared name from the raw file stem, so a numeric ordering prefix (e.g. "0_visit_unified.sql") landed in all_declared as "schema.0_visit_unified" instead of "schema.visit_unified" -- never matching what any dependent file's SQL actually references. Strip it the same way the schema-directory name already is. apply_schema()'s retry-until-no-progress loop (this version) still converges even with these bugs present, since it retries raw SQL execution directly rather than relying on this bookkeeping - but the computed ordering itself was wrong, causing avoidable extra retry passes. --- pgdevkit/testdb/schema.py | 11 ++++++++--- pyproject.toml | 2 +- uv.lock | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pgdevkit/testdb/schema.py b/pgdevkit/testdb/schema.py index a0bf797..3afe255 100644 --- a/pgdevkit/testdb/schema.py +++ b/pgdevkit/testdb/schema.py @@ -94,7 +94,11 @@ def _get_sql_deps(sql: str) -> set[str]: continue for t in e.find_all(exp.Table): if t.args.get("this") is not None and t.args.get("db") is not None: - deps.add(str(t)) + # exp.table_name(), not str(t): str() includes " AS alias" for + # an aliased reference (e.g. "FROM editing.visit v"), which + # would never match the plain declared name any dependent + # file's own CREATE target is recorded under. + deps.add(exp.table_name(t)) return deps @@ -119,7 +123,7 @@ def _iter_sql_files(database_dir: Path): deps = _get_sql_deps(content) if file.parent.name in _SCHEMA_QUALIFIED_TYPES: schema = _strip_layer_prefix(file.parent.parent.name) - full_name = f"{schema}.{file.stem}" + full_name = f"{schema}.{_strip_layer_prefix(file.stem)}" deps.discard(full_name) # the file's own CREATE target is not a real dependency all_declared.add(full_name) if not deps or all(d in delivered for d in deps): @@ -219,7 +223,8 @@ async def _apply(file: Path, sql: str) -> None: json_file = file.with_suffix(".test_data.json") if json_file.exists(): schema_name = _strip_layer_prefix(file.parent.parent.name) - await _insert_test_data(json_file, f"{schema_name}.{file.stem}", force_reset, con, complex_helper) + table_stem = _strip_layer_prefix(file.stem) + await _insert_test_data(json_file, f"{schema_name}.{table_stem}", force_reset, con, complex_helper) failures: list[tuple[Path, str]] = [] for file, sql in _iter_sql_files(database_dir): diff --git a/pyproject.toml b/pyproject.toml index 8e8d334..1e7df01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ packages = ["pgdevkit"] [project] name = "pgdevkit" -version = "0.2.2" +version = "0.2.3" description = "A helper for developing with Postgres" readme = "README.md" requires-python = ">=3.14" diff --git a/uv.lock b/uv.lock index 108689d..b85ca82 100644 --- a/uv.lock +++ b/uv.lock @@ -281,7 +281,7 @@ wheels = [ [[package]] name = "pgdevkit" -version = "0.2.2" +version = "0.2.3" source = { editable = "." } dependencies = [ { name = "docker" },