Worktree pgdevkit testdb#1
Merged
Merged
Conversation
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015bpLodYTShC96vqY6gqsQy
Implements ProjectConfig dataclass and load_config() function for reading project configuration from pyproject.toml [tool.pgdevkit] section, with sensible defaults for name, database_dir, env_prefix, extensions, and root. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015bpLodYTShC96vqY6gqsQy
Implement query.execute() to run SQL statements against a PostgreSQL database via async connection, handling multiple statements and returning rows from the final statement if it produced any. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code
Ports the database-in-source-layout SQL walker and .test_data.json seeding from the postgres-test-setup skill's start_postgres.py, parameterized by database_dir instead of a module constant.
_iter_sql_files checked file.parent.parent.name == "tables" to detect
table files, but for the documented database/{schema}/tables/{name}.sql
layout the parent is "tables" and the grandparent is the schema name --
backwards. This meant the table-dependency-tracking branch never fired,
so delivered_tables/all_declared stayed empty and files were applied in
plain filename order instead of FK dependency order.
Fixing the parent/grandparent check alone exposed a second bug: sqlglot's
exp.Table walk in _get_sql_deps also matches a CREATE TABLE statement's
own target, so every table file's dependency set includes itself. Once
dependency tracking actually activates, that self-reference can never be
satisfied, deadlocking the delayed-resolution loop. Fixed by discarding
the file's own qualified name from its computed deps before checking.
Also extracted the schema-name leading-digit-prefix stripping (already
present, correctly, in the .test_data.json seeding path) into a shared
_strip_layer_prefix() helper used by both the table-dependency branch and
the seeding path.
Added a regression fixture (widget -> widget_part -> widget_part_detail,
a 3-table FK chain whose alphabetical filename order matches its real
dependency order) and confirmed empirically that this specific fixture
raises UndefinedTable pre-fix and applies cleanly post-fix. A simpler
2-table fixture (gadget referencing widget, sorting before it
alphabetically) was tried first per a reviewer's suggestion but was found
to pass even against the unfixed code, due to a coincidental interaction
between the always-empty all_declared set and the delayed-list's
reverse-iteration order -- it does not distinguish correct dependency
resolution from the bug for any chain length where alphabetical order is
simply the reverse of dependency order.
The all-databases prefix pattern used the project's slug directly in a SQL LIKE pattern without escaping "_", which LIKE treats as a single-character wildcard. This let clean_testdb(all=True) for a project like "app" also match and drop a differently-named project's databases (e.g. "apps"), violating the "never touch another project's databases" guarantee. Escape LIKE metacharacters in the prefix and add a regression test with slug-colliding project names.
Replace tests/conftest.py's ad hoc docker-package container/DB bootstrap with a call to pgdevkit.testdb.ensure_testdb(), so pgdevkit's own tests use the same shared Podman-backed container as consumers of the testdb CLI. Removes the now-unused docker dependency and static PGDB_TEST_POSTGRES_* pytest_env entries. Pin [tool.pgdevkit] name = "pgdevkit" explicitly so the env_prefix is deterministic regardless of the checkout directory name (worktrees are named differently from the main clone). Documents pgdb testdb usage in the README.
CREATE SCHEMA and CREATE FUNCTION parse to AST shapes under the pinned sqlglot==30.11.0 that the existing name-extraction in parser.py doesn't handle (Table.name resolves empty when the real name is in .db; UserDefinedFunction.name doesn't unwrap a nested Table), causing spurious "" schema and "public." function entries. Fix both by falling back to the db-arg/nested-Table extraction pattern already used elsewhere in the file. Also fix two more latent bugs of the same kind surfaced by the same test run: _parse_table_constraint referenced exp.UniqueKey/exp.Unique, which don't exist in this sqlglot version (real class is UniqueColumnConstraint), so any table with a FOREIGN KEY or UNIQUE constraint raised and was silently dropped entirely by the per-file exception handler; and _norm_sql didn't strip the trailing ";" that Postgres's pg_get_viewdef()/pg_get_indexdef() always add but sqlglot's .sql() rendering never does, so every structurally-identical view compared as a mismatch. Finally, simplify the active_users view fixture so it no longer selects users.email or filters on users.status -- Postgres refuses ALTER COLUMN TYPE on any column referenced by a view, which blocked two test scenarios. tests/test_compare.py goes from 5/9 failing to 9/9 passing; full suite (39 tests) passes with no regressions.
ty check pgdevkit now passes: - config.py: drop the dead tomli fallback (requires-python >= 3.14 guarantees tomllib, already flagged as dead code in review) - api.py: build CREATE/DROP DATABASE via psycopg.sql.SQL/Identifier instead of an f-string, matching psycopg's typed-query API - query.py: cast the caller-provided SQL text to LiteralString with an explanatory comment — this function's whole purpose is running arbitrary SQL, so it can never itself be a literal Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015bpLodYTShC96vqY6gqsQy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.