Skip to content

Strip the remaining nominal members from the published declarations - #6204

Closed
candrewlee14 wants to merge 6 commits into
drizzle-team:rc5from
candrewlee14:strip-db-chain-internals
Closed

Strip the remaining nominal members from the published declarations#6204
candrewlee14 wants to merge 6 commits into
drizzle-team:rc5from
candrewlee14:strip-db-chain-internals

Conversation

@candrewlee14

@candrewlee14 candrewlee14 commented Aug 29, 2026

Copy link
Copy Markdown

Stacked on #6200, #6201, #6202, #6203 and #6206. Review only the last commit.

What

Sweeps the private/protected members that still reached the emitted .d.ts on the dialect, session, transaction, prepared-query and relational-query-builder classes.

Done with an AST codemod rather than by hand, since it spans ~20 files. Constructor parameter properties are desugared into declared fields: on a parameter the @internal marker strips the member but survives into the emitted constructor signature as a stray comment.

This PR flips no row on its own

That is expected, and worth being upfront about. With these members gone the dialects come to rest on EmptyFilter's unique symbol, which is an API decision handled separately in #6205. This change is the prerequisite: #6205 flips the three dialect rows only on top of it.

If #6205 is not wanted, this PR is largely inert and can be dropped too — the rows it would enable are the same three.

And it re-records the database object

NodePgDatabase outlasts every marker. Its blocker is re-recorded in the matrix: BuildQueryResult<..., TConfig, ...> is a mapped type deferred on an unresolved type parameter from findMany<TConfig>, and the compiler cannot relate keyof X from one declaration site to keyof X from the other while X stays deferred — it widens to string | number | symbol and fails. That is a TypeScript comparison limit, not something drizzle emits, and no marker or contained type change reaches it.

Verification

Full drizzle-orm suite green (27 files, 1344 tests); test:types clean. drizzle-kit and drizzle-seed — the in-repo consumers — also typecheck clean against the modified ORM.

cursoragent and others added 4 commits August 29, 2026 11:44
Strip implementation-only query-builder details from published declarations, infer decoder results structurally, and compile two physical package copies to prevent regressions.
The single SQL assignment only guarded one type. Replace it with a table of
public types probed in one tsc program, asserting both directions: a portable
type regressing fails, and a known leak becoming portable fails too, prompting
the flag to be flipped.

Records the measured state of the surface, annotating each known leak with the
private/protected member responsible.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qd99Mmmi1fZkKQiV3u1jXy
Name#brand, Param#brand and CodecsCollection#resolveTypes are implementation
details that reached the emitted .d.ts as protected members, making all three
types nominal and so non-portable between two installs of the package.

resolveTypes is declared as a field rather than left as a constructor parameter
property: on a parameter the @internal marker survives into the emitted
constructor signature as a stray comment.

Flips Param, Name and CodecsCollection to portable in the matrix. The three
dialects do not follow -- with the nominal blocker gone they fail structurally
instead, on the anonymous recursive BuildRelationalQueryResult['selection'],
which is recorded as their blocker.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qd99Mmmi1fZkKQiV3u1jXy
PgColumn#toBuilder returns a PgColumnBuilder, so the builder's private and
protected members are part of PgColumn's published shape, and PgTable's
_.columns index signature carries them up to the table. One private field was
therefore enough to make every pg table and column type non-portable between
two installs.

config follows its base: ColumnBuilder#config is already @internal and the pg
override had not inherited the marker.

The other dialects declare the same foreignKeyConfigs field but are unaffected,
since only pg-core exposes toBuilder() in a public return type.

Flips PgTable and PgColumn to portable. NodePgDatabase stays recorded as a known
leak: its chain runs through the session, transaction and relational query
builder classes and does not converge to a contained change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qd99Mmmi1fZkKQiV3u1jXy
candrewlee14 and others added 2 commits August 29, 2026 12:45
The view classes leaked two kinds of nominal member into the emitted .d.ts:

Symbol.for-keyed config properties ([PgViewConfig], [MySqlViewConfig] and the
materialized/dialect equivalents). A Symbol.for key is a distinct computed key
per declaration site, so copy A's PgView carries a property copy B's does not,
even though Symbol.for guarantees the runtime symbol is shared. Table already
marks every Symbol.for key it declares @internal, which is why the table and
column types were portable while the views were not; this applies the same
treatment.

Protected brand members ($MySqlViewBrand and friends), which exist only to keep
the view classes distinct at type level.

Flips PgView, MySqlView and SQLiteView to portable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qd99Mmmi1fZkKQiV3u1jXy
Sweeps the private/protected members that still reached the emitted .d.ts on the
dialect, session, transaction, prepared-query, relational-query-builder and view
classes, and the Symbol.for-keyed view config properties.

The symbol-keyed properties follow Table's precedent: every Symbol.for key it
declares is already @internal, which is exactly why Table and the column types
were portable while the views were not. A Symbol.for key is a distinct computed
key per declaration site, so an unstripped one makes its class non-portable even
though the runtime symbol is shared.

Constructor parameter properties are desugared into declared fields; on a
parameter the marker survives into the emitted constructor signature as a stray
comment.

Flips PgView, MySqlView and SQLiteView to portable. The dialects do not follow:
with their nominal members gone they come to rest on EmptyFilter's unique symbol,
which is an API decision and is left to its own change. NodePgDatabase outlasts
every marker and its blocker is re-recorded accordingly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qd99Mmmi1fZkKQiV3u1jXy
@candrewlee14
candrewlee14 force-pushed the strip-db-chain-internals branch from fe6112b to fbe8cde Compare August 29, 2026 18:46
@candrewlee14

Copy link
Copy Markdown
Author

Superseded. The dialect half of this sweep is what actually mattered and is now 41 lines of @internal markers in #6205; the remaining ~590 lines were chasing NodePgDatabase, which turns out to be blocked by a TypeScript comparison limit that no marker reaches (recorded on its matrix row in #6205). Not worth carrying.

@candrewlee14
candrewlee14 deleted the strip-db-chain-internals branch August 29, 2026 19:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants