Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions packages/objectql/src/engine-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
* with its body. The state stays on `ObjectQL`.
*
* The bodies reach the class through {@link ActionsHost}: exactly the
* `ObjectQL` members they read, private ones included. Each stub hands its
* body one literal of the members that body reads, plus a `.call`: methods go
* as closures that call them on the engine at call time, so a subclass
* override or an instance spy is still the one reached; fields and accessors
* go as GETTERS, read when the body reads them, as they were on the class,
* and a field a body assigns goes with a SETTER that assigns it on the engine.
* `ObjectQL` members they read, private ones included. Every stub hands its
* body, by a `.call`, the same host: `actionsHost` in `engine-facet-hosts.ts`,
* built once per engine by the class's static block. Methods go as closures
* that call them on the engine at call time, so a subclass override or an
* instance spy is still the one reached; fields and accessors go as GETTERS,
* read when the body reads them, as they were on the class, and a field a body
* assigns goes with a SETTER that assigns it on the engine.
*
* The module imports `engine.ts` for types only, so the two modules form no
* evaluation cycle. `index.ts` re-exports nothing from this module.
Expand Down
14 changes: 8 additions & 6 deletions packages/objectql/src/engine-cascade-planning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
* with its body. The state stays on `ObjectQL`.
*
* The bodies reach the class through {@link CascadePlanningHost}: exactly the
* `ObjectQL` members they read, private ones included. Each stub hands its
* body one literal of the members that body reads, plus a `.call`: methods go
* as closures that call them on the engine at call time, so a subclass
* override or an instance spy is still the one reached; fields and accessors
* go as GETTERS, read when the body reads them, as they were on the class,
* and a field a body assigns goes with a SETTER that assigns it on the engine.
* `ObjectQL` members they read, private ones included. Every stub hands its
* body, by a `.call`, the same host: `cascadePlanningHost` in
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
* Methods go as closures that call them on the engine at call time, so a
* subclass override or an instance spy is still the one reached; fields and
* accessors go as GETTERS, read when the body reads them, as they were on the
* class, and a field a body assigns goes with a SETTER that assigns it on the
* engine.
*
* `ObjectQL` here is `ObjectQLStatics` (imported AS `ObjectQL`): forwarders to the
* statics the bodies read, private ones included, which the class fills in a
Expand Down
16 changes: 9 additions & 7 deletions packages/objectql/src/engine-compatibility-section.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
* docblock on the class, the contract; a private method's docblock moved here
* with its body. The state stays on `ObjectQL`.
*
* The bodies reach the class through {@link CompatibilitySectionHost}: exactly the
* `ObjectQL` members they read, private ones included. Each stub hands its
* body one literal of the members that body reads, plus a `.call`: methods go
* as closures that call them on the engine at call time, so a subclass
* override or an instance spy is still the one reached; fields and accessors
* go as GETTERS, read when the body reads them, as they were on the class,
* and a field a body assigns goes with a SETTER that assigns it on the engine.
* The bodies reach the class through {@link CompatibilitySectionHost}: exactly
* the `ObjectQL` members they read, private ones included. Every stub hands its
* body, by a `.call`, the same host: `compatibilitySectionHost` in
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
* Methods go as closures that call them on the engine at call time, so a
* subclass override or an instance spy is still the one reached; fields and
* accessors go as GETTERS, read when the body reads them, as they were on the
* class, and a field a body assigns goes with a SETTER that assigns it on the
* engine.
*
* Values that stayed in `engine.ts` are imported from it (lever (a) of
* ruling 6591753301); every use is inside a function body, so the import
Expand Down
16 changes: 9 additions & 7 deletions packages/objectql/src/engine-defaults-and-autonumbers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
* docblock on the class, the contract; a private method's docblock moved here
* with its body. The state stays on `ObjectQL`.
*
* The bodies reach the class through {@link DefaultsAndAutonumbersHost}: exactly the
* `ObjectQL` members they read, private ones included. Each stub hands its
* body one literal of the members that body reads, plus a `.call`: methods go
* as closures that call them on the engine at call time, so a subclass
* override or an instance spy is still the one reached; fields and accessors
* go as GETTERS, read when the body reads them, as they were on the class,
* and a field a body assigns goes with a SETTER that assigns it on the engine.
* The bodies reach the class through {@link DefaultsAndAutonumbersHost}:
* exactly the `ObjectQL` members they read, private ones included. Every stub
* hands its body, by a `.call`, the same host: `defaultsAndAutonumbersHost` in
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
* Methods go as closures that call them on the engine at call time, so a
* subclass override or an instance spy is still the one reached; fields and
* accessors go as GETTERS, read when the body reads them, as they were on the
* class, and a field a body assigns goes with a SETTER that assigns it on the
* engine.
*
* The module imports `engine.ts` for types only, so the two modules form no
* evaluation cycle. `index.ts` re-exports nothing from this module.
Expand Down
16 changes: 9 additions & 7 deletions packages/objectql/src/engine-delete-and-aggregate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
* docblock on the class, the contract; a private method's docblock moved here
* with its body. The state stays on `ObjectQL`.
*
* The bodies reach the class through {@link DeleteAndAggregateHost}: exactly the
* `ObjectQL` members they read, private ones included. Each stub hands its
* body one literal of the members that body reads, plus a `.call`: methods go
* as closures that call them on the engine at call time, so a subclass
* override or an instance spy is still the one reached; fields and accessors
* go as GETTERS, read when the body reads them, as they were on the class,
* and a field a body assigns goes with a SETTER that assigns it on the engine.
* The bodies reach the class through {@link DeleteAndAggregateHost}: exactly
* the `ObjectQL` members they read, private ones included. Every stub hands its
* body, by a `.call`, the same host: `deleteAndAggregateHost` in
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
* Methods go as closures that call them on the engine at call time, so a
* subclass override or an instance spy is still the one reached; fields and
* accessors go as GETTERS, read when the body reads them, as they were on the
* class, and a field a body assigns goes with a SETTER that assigns it on the
* engine.
*
* The module imports `engine.ts` for types only, so the two modules form no
* evaluation cycle. `index.ts` re-exports nothing from this module.
Expand Down
78 changes: 78 additions & 0 deletions packages/objectql/src/engine-facet-hosts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

/**
* [#29986 codemod] The host of each facet of `ObjectQL`, built ONCE per engine (#30051):
* what every stub of a facet hands that facet's bodies as `this`, in place of
* a host literal built on every call. Each `FacetHost` below is filled by the
* factory `ObjectQL`'s static block installs, the one place that can read
* the class's private members; the host is built on the first call that needs
* it and kept for the engine's life. A method goes as a closure that calls it
* on the engine at call time, a field or accessor as a getter (and a setter
* when a body assigns it), so a body reads and writes the engine exactly as
* the per-call literal let it.
*
* Written by `scripts/codemod-split-engine.mjs`; it imports types only, so it forms no
* evaluation cycle and is evaluated before the class whichever module loads
* first. `index.ts` re-exports nothing from this module.
*/

import type { ObjectQL } from './engine.js';
import type { ActionsHost } from './engine-actions.js';
import type { CascadePlanningHost } from './engine-cascade-planning.js';
import type { CompatibilitySectionHost } from './engine-compatibility-section.js';
import type { DefaultsAndAutonumbersHost } from './engine-defaults-and-autonumbers.js';
import type { DeleteAndAggregateHost } from './engine-delete-and-aggregate.js';
import type { FindHost } from './engine-find.js';
import type { HooksAndFunctionsHost } from './engine-hooks-and-functions.js';
import type { InsertHost } from './engine-insert.js';
import type { MiddlewareAndContextHost } from './engine-middleware-and-context.js';
import type { MigrationStateHost } from './engine-migration-state.js';
import type { ReferencesAndMasterDetailHost } from './engine-references-and-master-detail.js';
import type { RegistrationHost } from './engine-registration.js';
import type { SecretsAndRoutingHost } from './engine-secrets-and-routing.js';
import type { SecurityResolversHost } from './engine-security-resolvers.js';
import type { SummariesAndExpansionHost } from './engine-summaries-and-expansion.js';
import type { TransactionsSectionHost } from './engine-transactions-section.js';

/** One facet's host for each engine: built on first use, kept for the engine's life. */
export class FacetHost<H> {
private readonly hosts = new WeakMap<ObjectQL, H>();
private build: ((engine: ObjectQL) => H) | undefined;

constructor(private readonly facet: string) {}

/** Called once, from `ObjectQL`'s static block. */
install(build: (engine: ObjectQL) => H): void {
this.build = build;
}

/** The host of `engine`, built on first use. */
of(engine: ObjectQL): H {
let host = this.hosts.get(engine);
if (host === undefined) {
if (this.build === undefined) {
throw new Error(`${this.facet}: ObjectQL has not installed its host factory`);
}
host = this.build(engine);
this.hosts.set(engine, host);
}
return host;
}
}

export const actionsHost = new FacetHost<ActionsHost>('ActionsFacet');
export const cascadePlanningHost = new FacetHost<CascadePlanningHost>('CascadePlanningFacet');
export const compatibilitySectionHost = new FacetHost<CompatibilitySectionHost>('CompatibilitySectionFacet');
export const defaultsAndAutonumbersHost = new FacetHost<DefaultsAndAutonumbersHost>('DefaultsAndAutonumbersFacet');
export const deleteAndAggregateHost = new FacetHost<DeleteAndAggregateHost>('DeleteAndAggregateFacet');
export const findHost = new FacetHost<FindHost>('FindFacet');
export const hooksAndFunctionsHost = new FacetHost<HooksAndFunctionsHost>('HooksAndFunctionsFacet');
export const insertHost = new FacetHost<InsertHost>('InsertFacet');
export const middlewareAndContextHost = new FacetHost<MiddlewareAndContextHost>('MiddlewareAndContextFacet');
export const migrationStateHost = new FacetHost<MigrationStateHost>('MigrationStateFacet');
export const referencesAndMasterDetailHost = new FacetHost<ReferencesAndMasterDetailHost>('ReferencesAndMasterDetailFacet');
export const registrationHost = new FacetHost<RegistrationHost>('RegistrationFacet');
export const secretsAndRoutingHost = new FacetHost<SecretsAndRoutingHost>('SecretsAndRoutingFacet');
export const securityResolversHost = new FacetHost<SecurityResolversHost>('SecurityResolversFacet');
export const summariesAndExpansionHost = new FacetHost<SummariesAndExpansionHost>('SummariesAndExpansionFacet');
export const transactionsSectionHost = new FacetHost<TransactionsSectionHost>('TransactionsSectionFacet');
15 changes: 8 additions & 7 deletions packages/objectql/src/engine-find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
* docblock on the class, the contract; a private method's docblock moved here
* with its body. The state stays on `ObjectQL`.
*
* The bodies reach the class through {@link FindHost}: exactly the
* `ObjectQL` members they read, private ones included. Each stub hands its
* body one literal of the members that body reads, plus a `.call`: methods go
* as closures that call them on the engine at call time, so a subclass
* override or an instance spy is still the one reached; fields and accessors
* go as GETTERS, read when the body reads them, as they were on the class,
* and a field a body assigns goes with a SETTER that assigns it on the engine.
* The bodies reach the class through {@link FindHost}: exactly the `ObjectQL`
* members they read, private ones included. Every stub hands its body, by a
* `.call`, the same host: `findHost` in `engine-facet-hosts.ts`, built once per
* engine by the class's static block. Methods go as closures that call them on
* the engine at call time, so a subclass override or an instance spy is still
* the one reached; fields and accessors go as GETTERS, read when the body reads
* them, as they were on the class, and a field a body assigns goes with a
* SETTER that assigns it on the engine.
*
* The module imports `engine.ts` for types only, so the two modules form no
* evaluation cycle. `index.ts` re-exports nothing from this module.
Expand Down
14 changes: 8 additions & 6 deletions packages/objectql/src/engine-hooks-and-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@
* with its body. The state stays on `ObjectQL`.
*
* The bodies reach the class through {@link HooksAndFunctionsHost}: exactly the
* `ObjectQL` members they read, private ones included. Each stub hands its
* body one literal of the members that body reads, plus a `.call`: methods go
* as closures that call them on the engine at call time, so a subclass
* override or an instance spy is still the one reached; fields and accessors
* go as GETTERS, read when the body reads them, as they were on the class,
* and a field a body assigns goes with a SETTER that assigns it on the engine.
* `ObjectQL` members they read, private ones included. Every stub hands its
* body, by a `.call`, the same host: `hooksAndFunctionsHost` in
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
* Methods go as closures that call them on the engine at call time, so a
* subclass override or an instance spy is still the one reached; fields and
* accessors go as GETTERS, read when the body reads them, as they were on the
* class, and a field a body assigns goes with a SETTER that assigns it on the
* engine.
*
* The module imports `engine.ts` for types only, so the two modules form no
* evaluation cycle. `index.ts` re-exports nothing from this module.
Expand Down
15 changes: 8 additions & 7 deletions packages/objectql/src/engine-insert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
* docblock on the class, the contract; a private method's docblock moved here
* with its body. The state stays on `ObjectQL`.
*
* The bodies reach the class through {@link InsertHost}: exactly the
* `ObjectQL` members they read, private ones included. Each stub hands its
* body one literal of the members that body reads, plus a `.call`: methods go
* as closures that call them on the engine at call time, so a subclass
* override or an instance spy is still the one reached; fields and accessors
* go as GETTERS, read when the body reads them, as they were on the class,
* and a field a body assigns goes with a SETTER that assigns it on the engine.
* The bodies reach the class through {@link InsertHost}: exactly the `ObjectQL`
* members they read, private ones included. Every stub hands its body, by a
* `.call`, the same host: `insertHost` in `engine-facet-hosts.ts`, built once
* per engine by the class's static block. Methods go as closures that call them
* on the engine at call time, so a subclass override or an instance spy is
* still the one reached; fields and accessors go as GETTERS, read when the body
* reads them, as they were on the class, and a field a body assigns goes with a
* SETTER that assigns it on the engine.
*
* The module imports `engine.ts` for types only, so the two modules form no
* evaluation cycle. `index.ts` re-exports nothing from this module.
Expand Down
16 changes: 9 additions & 7 deletions packages/objectql/src/engine-middleware-and-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
* docblock on the class, the contract; a private method's docblock moved here
* with its body. The state stays on `ObjectQL`.
*
* The bodies reach the class through {@link MiddlewareAndContextHost}: exactly the
* `ObjectQL` members they read, private ones included. Each stub hands its
* body one literal of the members that body reads, plus a `.call`: methods go
* as closures that call them on the engine at call time, so a subclass
* override or an instance spy is still the one reached; fields and accessors
* go as GETTERS, read when the body reads them, as they were on the class,
* and a field a body assigns goes with a SETTER that assigns it on the engine.
* The bodies reach the class through {@link MiddlewareAndContextHost}: exactly
* the `ObjectQL` members they read, private ones included. Every stub hands its
* body, by a `.call`, the same host: `middlewareAndContextHost` in
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
* Methods go as closures that call them on the engine at call time, so a
* subclass override or an instance spy is still the one reached; fields and
* accessors go as GETTERS, read when the body reads them, as they were on the
* class, and a field a body assigns goes with a SETTER that assigns it on the
* engine.
*
* The module imports `engine.ts` for types only, so the two modules form no
* evaluation cycle. `index.ts` re-exports nothing from this module.
Expand Down
14 changes: 8 additions & 6 deletions packages/objectql/src/engine-migration-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
* with its body. The state stays on `ObjectQL`.
*
* The bodies reach the class through {@link MigrationStateHost}: exactly the
* `ObjectQL` members they read, private ones included. Each stub hands its
* body one literal of the members that body reads, plus a `.call`: methods go
* as closures that call them on the engine at call time, so a subclass
* override or an instance spy is still the one reached; fields and accessors
* go as GETTERS, read when the body reads them, as they were on the class,
* and a field a body assigns goes with a SETTER that assigns it on the engine.
* `ObjectQL` members they read, private ones included. Every stub hands its
* body, by a `.call`, the same host: `migrationStateHost` in
* `engine-facet-hosts.ts`, built once per engine by the class's static block.
* Methods go as closures that call them on the engine at call time, so a
* subclass override or an instance spy is still the one reached; fields and
* accessors go as GETTERS, read when the body reads them, as they were on the
* class, and a field a body assigns goes with a SETTER that assigns it on the
* engine.
*
* `ObjectQL` here is `ObjectQLStatics` (imported AS `ObjectQL`): forwarders to the
* statics the bodies read, private ones included, which the class fills in a
Expand Down
16 changes: 9 additions & 7 deletions packages/objectql/src/engine-references-and-master-detail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
* docblock on the class, the contract; a private method's docblock moved here
* with its body. The state stays on `ObjectQL`.
*
* The bodies reach the class through {@link ReferencesAndMasterDetailHost}: exactly the
* `ObjectQL` members they read, private ones included. Each stub hands its
* body one literal of the members that body reads, plus a `.call`: methods go
* as closures that call them on the engine at call time, so a subclass
* override or an instance spy is still the one reached; fields and accessors
* go as GETTERS, read when the body reads them, as they were on the class,
* and a field a body assigns goes with a SETTER that assigns it on the engine.
* The bodies reach the class through {@link ReferencesAndMasterDetailHost}:
* exactly the `ObjectQL` members they read, private ones included. Every stub
* hands its body, by a `.call`, the same host: `referencesAndMasterDetailHost`
* in `engine-facet-hosts.ts`, built once per engine by the class's static
* block. Methods go as closures that call them on the engine at call time, so a
* subclass override or an instance spy is still the one reached; fields and
* accessors go as GETTERS, read when the body reads them, as they were on the
* class, and a field a body assigns goes with a SETTER that assigns it on the
* engine.
*
* `ObjectQL` here is `ObjectQLStatics` (imported AS `ObjectQL`): forwarders to the
* statics the bodies read, private ones included, which the class fills in a
Expand Down
Loading
Loading