From 0b01e18ba4f1b79917d38b54be9b30b85316f7e8 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 26 Oct 2026 11:40:33 +0000 Subject: [PATCH] refactor(driver-sql): move resolveHashShadowKeys' body out of sql-driver.ts into sql-driver-introspection.ts (#25521 cut 7) The MySQL hash-shadow enrichment moves unedited beside its only caller, introspectIndexes, and reaches the class through the existing IntrospectionHost (knex only). The class method keeps its name, docblock and signature (less async) and hands the body its host. sql-driver.ts 21,398 -> 21,380 lines; isHashShadowCarrier leaves its import. Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01AuyWbsvLe5peToiMx3LiTd --- .../src/sql-driver-introspection.ts | 50 ++++++++++++++++++- packages/drivers/driver-sql/src/sql-driver.ts | 40 ++++----------- 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/packages/drivers/driver-sql/src/sql-driver-introspection.ts b/packages/drivers/driver-sql/src/sql-driver-introspection.ts index b0a23bbdccd..966f40caf77 100644 --- a/packages/drivers/driver-sql/src/sql-driver-introspection.ts +++ b/packages/drivers/driver-sql/src/sql-driver-introspection.ts @@ -28,6 +28,15 @@ * `schema-drift.ts`, where they live; `sql-driver.ts` no longer reads the two * functions and dropped them from its import. * + * [#25521 cut 7] `resolveHashShadowKeys` moved here too, beside its only + * caller. `introspectIndexes`' body still reaches it through the host + * closure above, which calls the class method on the driver, which hands this + * body its host; so a subclass override or a test spy on the instance is + * still the one reached. It reads only `knex`. `isHashShadowCarrier` and + * `parseHashShadowKeyParts` are imported from `schema-drift.ts`, where they + * live; `sql-driver.ts` still reads `parseHashShadowKeyParts` and dropped + * `isHashShadowCarrier` from its import. + * * A MOVE, not a redesign. Each function below is the body of the `SqlDriver` * method of the same name as it stood, re-indented one level and otherwise * unedited: the same catalog statements, the same dialect arms, the same @@ -81,7 +90,13 @@ import type { UniqueConstraintMember, } from './sql-driver.js'; import { postgresTableNameCollisionError, singleColumnUniqueColumns } from './sql-driver.js'; -import { applyIndexKeyParts, parseIndexDdl, type PhysicalIndex } from './schema-drift.js'; +import { + applyIndexKeyParts, + isHashShadowCarrier, + parseHashShadowKeyParts, + parseIndexDdl, + type PhysicalIndex, +} from './schema-drift.js'; /** * The `SqlDriver` members the functions below read — every one of them, and @@ -925,3 +940,36 @@ export async function introspectIndexes( } return [...byName.values()]; } + +/** The body of `SqlDriver#resolveHashShadowKeys`; the method's docblock there is its contract. */ +export async function resolveHashShadowKeys( + this: Pick, + tableName: string, + indexes: PhysicalIndex[], +): Promise { + const carriers = indexes.filter((i) => isHashShadowCarrier(i)); + if (carriers.length === 0) return; + try { + const rows: Array> = await this.knex + .select('COLUMN_NAME', 'GENERATION_EXPRESSION') + .from('information_schema.COLUMNS') + .where({ TABLE_SCHEMA: this.knex.client.database(), TABLE_NAME: tableName }) + .whereIn( + 'COLUMN_NAME', + carriers.map((i) => i.columns[0]!), + ); + const exprByColumn = new Map(); + for (const r of rows) { + const column = String(r.COLUMN_NAME ?? r.column_name ?? ''); + if (column) { + exprByColumn.set(column, String(r.GENERATION_EXPRESSION ?? r.generation_expression ?? '')); + } + } + for (const i of carriers) { + const parts = parseHashShadowKeyParts(exprByColumn.get(i.columns[0]!) ?? ''); + if (parts.length > 0) i.shadowKey = parts; + } + } catch { + /* see the head note: an unresolved carrier degrades to "no finding". */ + } +} diff --git a/packages/drivers/driver-sql/src/sql-driver.ts b/packages/drivers/driver-sql/src/sql-driver.ts index 1087ddb01ee..8ab06f234ab 100644 --- a/packages/drivers/driver-sql/src/sql-driver.ts +++ b/packages/drivers/driver-sql/src/sql-driver.ts @@ -123,7 +123,6 @@ import { ceremonyOwnedDropFinding, isCeremonyOwnedColumnDrop, hashShadowColumnFor, - isHashShadowCarrier, parseHashShadowKeyParts, indexedKeyColumns, isIndexDriftOp, @@ -160,8 +159,9 @@ import { recoverUnencodedJsonText } from './unencoded-json-text.js'; // [#25521 cut 1] The catalog-introspection helpers (`introspectColumnOrder`, // `introspectColumns` and the foreign-key, primary-key and unique-constraint reads), // [cut 4] `introspectSchema`, the whole-schema read built on them, and [cut 5] -// `introspectIndexes`, the per-table index read schema sync is built on; the methods -// of the same names below hand each body the members it reads (`IntrospectionHost`). +// `introspectIndexes`, the per-table index read schema sync is built on, and [cut 7] +// `resolveHashShadowKeys`, its MySQL hash-shadow enrichment; the methods of the +// same names below hand each body the members it reads (`IntrospectionHost`). import { introspectColumnOrder, introspectColumns, @@ -170,6 +170,7 @@ import { introspectPrimaryKeys, introspectSchema, introspectUniqueConstraints, + resolveHashShadowKeys, } from './sql-driver-introspection.js'; // [#25521 cut 2] The raw-execution path (`execute`, its refusal terminal // `rawStatementFault`, and `noteRuntimeIndexDdl`, which keeps the ledger of the @@ -15080,35 +15081,16 @@ export class SqlDriver implements IDataDriver { * rather than proposing a rebuild it cannot reason about. The degraded * outcome is a missing finding, never a dropped constraint. */ - protected async resolveHashShadowKeys( + protected resolveHashShadowKeys( tableName: string, indexes: PhysicalIndex[], ): Promise { - const carriers = indexes.filter((i) => isHashShadowCarrier(i)); - if (carriers.length === 0) return; - try { - const rows: Array> = await this.knex - .select('COLUMN_NAME', 'GENERATION_EXPRESSION') - .from('information_schema.COLUMNS') - .where({ TABLE_SCHEMA: this.knex.client.database(), TABLE_NAME: tableName }) - .whereIn( - 'COLUMN_NAME', - carriers.map((i) => i.columns[0]!), - ); - const exprByColumn = new Map(); - for (const r of rows) { - const column = String(r.COLUMN_NAME ?? r.column_name ?? ''); - if (column) { - exprByColumn.set(column, String(r.GENERATION_EXPRESSION ?? r.generation_expression ?? '')); - } - } - for (const i of carriers) { - const parts = parseHashShadowKeyParts(exprByColumn.get(i.columns[0]!) ?? ''); - if (parts.length > 0) i.shadowKey = parts; - } - } catch { - /* see the head note: an unresolved carrier degrades to "no finding". */ - } + // [#25521 cut 7] The body moved to `sql-driver-introspection.ts` (see `IntrospectionHost`). + const readKnex = () => this.knex; + const host: ThisParameterType = { + get knex() { return readKnex(); }, + }; + return resolveHashShadowKeys.call(host, tableName, indexes); } /**