Skip to content

[MAINTENANCE] Consult the backend declaration when constructing harness tables - #12028

Draft
joshua-stauffer wants to merge 1 commit into
f/sql-harness/generic-sql-escape-hatchfrom
f/sql-harness/table-schema-item-hook
Draft

[MAINTENANCE] Consult the backend declaration when constructing harness tables#12028
joshua-stauffer wants to merge 1 commit into
f/sql-harness/generic-sql-escape-hatchfrom
f/sql-harness/table-schema-item-hook

Conversation

@joshua-stauffer

Copy link
Copy Markdown
Collaborator

Stacked on #12023 — review #12021, #12022 and #12023 first. This PR shows only its own commit;
GitHub retargets it as its parents merge.

First change in this series that touches the shared SQL setup rather than adding inert
declarations, so the existing backend suites become the real oracle from here.

Two bindings and one hook:

  • SQLBatchTestSetup's generic parameter moves from _ConfigT to the SQL config base, so every
    concrete setup is statically tied to a config that carries a declared SqlBackendSpec and can
    read it off self.config without a cast. A backend_spec property exposes it.
  • At the single table-construction site, a declared zero-argument factory is called and its items
    passed positionally after the generated columns. Nothing is contributed when no factory is
    declared, so behavior is unchanged for all nine existing configs.

Why a factory rather than a stored value

Two independent reasons, and the tests pin both. A dialect storage-engine construct is not
accepted as a Table keyword argument, so it must arrive positionally. And it binds to the first
table it is attached to, so reusing one instance across tables corrupts every table after the
first — each table needs its own.

That second property is what the call-count test exists for. A design that built the items once
and reused them would still put an item on both tables and pass a "does the item appear" check;
it fails here, because the factory must be invoked once per created table and the items reachable
from two tables must not be the same object.

_create_table was confirmed to still be the only Table(...) construction in the module and
_create_table_data its sole caller — invoked once for the primary table and once per extra
table — so one edit covers both. No subclass overrides it.

Session-cache regression coverage

Equivalent batch setups are meant to be created and torn down once per session, not once per
test. A regression there costs session time rather than turning a test red, so it needs a
counting oracle rather than "the fixtures were not edited".

Two tests over the same declaration and the same data must share one setup. The second asserts it
sees the very object the first recorded — not merely that the setup count is still one, which
would hold either way if the test ran alone. Run in isolation it now fails outright, which is the
evidence the assertion binds.

Verification

SQLite 544 passed (539 before, +5 exactly the new tests); PostgreSQL 472 and MySQL 160 both
unchanged; collection 3332 → 3337. Registry suite unaffected at 39.

Every new assertion was mutation-tested rather than accepted on inspection. Removing the hook
turns both table-item tests red; memoizing the factory result leaves the first passing and fails
only the call-count and identity checks; forcing a cache miss fails the cache test; recording a
decoy object fails the identity assert on its own. All mutations reverted.

ruff clean. mypy adds no diagnostics over an untouched-file baseline, and a probe confirmed
the new generic bound is enforced: subscripting SQLBatchTestSetup with a config outside the
bound is a hard type-var error.

Binds SQLBatchTestSetup's generic parameter to the SQL config base, so every
concrete setup is statically tied to a config carrying a declared
SqlBackendSpec and can read it off self.config without a cast. Exposes that
declaration through a backend_spec property.

Adds the dialect table-schema-item hook at the single table-construction site.
A backend that needs dialect-required schema items declares a zero-argument
factory; the harness calls it once per table and passes the returned items
positionally after the generated columns, contributing nothing when no factory
is declared.

The factory shape is load-bearing rather than incidental. Such constructs are
not accepted as Table keyword arguments, so they must arrive positionally; and
they bind to the first table they are attached to, so reusing one instance
across tables corrupts every table after the first. Calling a factory once per
table is what makes each table's items its own. A test pins exactly that: a
counting factory must be invoked once per created table and the items reachable
from two tables must not be the same object - a design storing one instance
would still put an item on both tables and pass a weaker check.

Also pins the session-scoped batch-setup cache with a counting oracle. Two
tests over the same declaration and data must share one setup; a regression
there costs session time rather than turning a test red, so only a counter
catches it. The second test asserts it sees the very object the first recorded,
which is what stops it passing vacuously when run alone.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant