From 0522e4d4eac550e86d0f9f61915e4107696b7b91 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Oct 2026 01:05:46 +0000 Subject: [PATCH] refactor(metadata-protocol): move the legacy-organization row filters out of protocol.ts into protocol-legacy-organization-rows.ts (#25467 cut 29) Move-only, shape B. withoutLegacyOrganizationRows and legacyOrganizationRowsOf move, unedited, into one module. The engine field is handed over as a getter; withoutLegacyOrganizationRows's call to legacyOrganizationRowsOf is handed over as a closure, so it still reaches the class method. Claude-Session: https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6 Co-authored-by: Claude --- .../src/protocol-legacy-organization-rows.ts | 74 +++++++++++++++++++ packages/metadata-protocol/src/protocol.ts | 22 +++--- 2 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 packages/metadata-protocol/src/protocol-legacy-organization-rows.ts diff --git a/packages/metadata-protocol/src/protocol-legacy-organization-rows.ts b/packages/metadata-protocol/src/protocol-legacy-organization-rows.ts new file mode 100644 index 00000000000..aba54e58163 --- /dev/null +++ b/packages/metadata-protocol/src/protocol-legacy-organization-rows.ts @@ -0,0 +1,74 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * [#25467 cut 29] The legacy-organization row filters, from + * `ObjectStackProtocolImplementation`, moved out of `protocol.ts` whole: on a + * database the ADR-0131 ceremony has not migrated, the rows that still belong + * to one organization rather than to the environment. + * + * - `legacyOrganizationRowsOf` — those rows of one table, read off the + * physical column through the table's driver (a read inside a transaction + * joins it). + * - `withoutLegacyOrganizationRows` — a row list with those rows left out. + * + * A MOVE, not a redesign. Each function below is the body of the + * `ObjectStackProtocolImplementation` method of the same name as it stood, + * re-indented one level and otherwise unedited. + * + * ## How the moved bodies reach the class + * + * The shape #23050 set for `rest-server.ts` (its `data-action-routes.ts` + * header carries the full reasoning), as `protocol-batch-data.ts` applies it. + * The class keeps each method — the published `dist/*.d.ts` lists its name, + * docblock and declared signature — and its body is one literal of exactly + * the {@link LegacyOrganizationRowsHost} members it reads, plus a `.call`. + * The `engine` field is handed over as a getter, so each read finds it as it + * stands at call time; `withoutLegacyOrganizationRows`'s call to + * `legacyOrganizationRowsOf` is handed over as a closure, so it still reaches + * the class method. Every caller keeps calling the class methods. + * + * What the bodies read from elsewhere, they import from where `protocol.ts` + * imports it. Nothing re-exports this module, so the published surface does + * not move. + */ + +import { readLegacyOrganizationRows } from '@objectstack/metadata-core'; +import type { ObjectStackProtocolImplementation } from './protocol.js'; + +/** + * The `ObjectStackProtocolImplementation` members the functions below read — + * every one of them, and no other; each function's `this` is the `Pick` of + * the members it reads. Each is typed AS the class member (an indexed access + * on the class), so a change to a member's signature on the class is a change + * here too, and naming a member the class does not have is a compile error. + */ +export interface LegacyOrganizationRowsHost { + readonly engine: ObjectStackProtocolImplementation['engine']; + readonly legacyOrganizationRowsOf: ObjectStackProtocolImplementation['legacyOrganizationRowsOf']; +} + +/** The body of `ObjectStackProtocolImplementation#withoutLegacyOrganizationRows`; the method's docblock there is its contract. */ +export async function withoutLegacyOrganizationRows( + this: Pick, + table: string, + rows: R[] | null | undefined, + context?: unknown, +): Promise { + if (!rows || rows.length === 0) return rows ?? []; + const legacy = await this.legacyOrganizationRowsOf(table, context); + return legacy.size === 0 ? rows : rows.filter((row) => !legacy.has(String((row as { id?: unknown }).id))); +} + +/** The body of `ObjectStackProtocolImplementation#legacyOrganizationRowsOf`; the method's docblock there is its contract. */ +export function legacyOrganizationRowsOf( + this: Pick, + table: string, + context?: unknown, +): Promise> { + const transaction = (context as { transaction?: unknown } | undefined)?.transaction; + return readLegacyOrganizationRows( + (this.engine as { getDriverForObject?: (objectName: string) => unknown }).getDriverForObject?.(table), + table, + transaction !== undefined ? { transaction } : {}, + ); +} diff --git a/packages/metadata-protocol/src/protocol.ts b/packages/metadata-protocol/src/protocol.ts index 0a03fbea679..ef3428eda4f 100644 --- a/packages/metadata-protocol/src/protocol.ts +++ b/packages/metadata-protocol/src/protocol.ts @@ -421,6 +421,8 @@ import { hierarchyResolverMounted, orgWallEnforced, rlsMembershipResolverKeys, t import { flowRegistrationsOf, resolveFlowCanonicalizer, resolveFlowRegistrationReader } from './protocol-automation-flow-reads.js'; // [#25467 cut 28] The code-datasource predicates: declared by an installed package, or registered by the host. import { isDeclaredCodeDatasource, isHostCodeDatasource } from './protocol-code-datasource-predicates.js'; +// [#25467 cut 29] The legacy-organization row filters: which rows a not-yet-migrated database still holds. +import { legacyOrganizationRowsOf, withoutLegacyOrganizationRows } from './protocol-legacy-organization-rows.js'; /** * Canonical Zod schema per metadata type lives in @@ -10210,18 +10212,20 @@ export class ObjectStackProtocolImplementation implements } private async withoutLegacyOrganizationRows(table: string, rows: R[] | null | undefined, context?: unknown): Promise { - if (!rows || rows.length === 0) return rows ?? []; - const legacy = await this.legacyOrganizationRowsOf(table, context); - return legacy.size === 0 ? rows : rows.filter((row) => !legacy.has(String((row as { id?: unknown }).id))); + // [#25467 cut 29] The body moved to `protocol-legacy-organization-rows.ts` (see `LegacyOrganizationRowsHost`). + const host: ThisParameterType = { + legacyOrganizationRowsOf: (...a) => this.legacyOrganizationRowsOf(...a), + }; + return (withoutLegacyOrganizationRows).call(host, table, rows, context); } private legacyOrganizationRowsOf(table: string, context?: unknown): Promise> { - const transaction = (context as { transaction?: unknown } | undefined)?.transaction; - return readLegacyOrganizationRows( - (this.engine as { getDriverForObject?: (objectName: string) => unknown }).getDriverForObject?.(table), - table, - transaction !== undefined ? { transaction } : {}, - ); + // [#25467 cut 29] The body moved to `protocol-legacy-organization-rows.ts` (see `LegacyOrganizationRowsHost`). + const readEngine = () => this.engine; + const host: ThisParameterType = { + get engine() { return readEngine(); }, + }; + return legacyOrganizationRowsOf.call(host, table, context); } /**