Spaces:
Running
Running
File size: 2,490 Bytes
aa89cb5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | import type { EntitySchema } from '../sql/core';
import type { EntityChecker } from './checker';
import type { UserContext } from './context';
export type BootstrapEntity = Readonly<{
entity: string;
id: string;
values?: Readonly<Record<string, unknown>>;
}>;
export type RuntimeBootstrap = Readonly<{
defaultDomainRoot?: BootstrapEntity;
constants?: readonly BootstrapEntity[];
/** Generated typed Mutation program. Application workspaces cannot replace it. */
ensure?: (context: UserContext) => Promise<void>;
}>;
export function mergeRuntimeBootstrap(
left: RuntimeBootstrap,
right: RuntimeBootstrap,
): RuntimeBootstrap {
const leftRoot = left.defaultDomainRoot;
const rightRoot = right.defaultDomainRoot;
if (leftRoot && rightRoot &&
(leftRoot.entity !== rightRoot.entity || leftRoot.id !== rightRoot.id)) {
throw new Error('Cannot compose Runtime Modules with different Default Domain Roots');
}
const constants = new Map<string, BootstrapEntity>();
for (const value of [...(left.constants ?? []), ...(right.constants ?? [])]) {
constants.set(`${value.entity}:${value.id}`, value);
}
return {
defaultDomainRoot: rightRoot ?? leftRoot,
constants: [...constants.values()],
ensure: left.ensure && right.ensure
? async context => { await left.ensure!(context); await right.ensure!(context); }
: right.ensure ?? left.ensure,
};
}
export interface RuntimeModuleTarget {
install(module: RuntimeModule): RuntimeModuleTarget;
}
/** Passive, immutable metadata manifest. It never creates or alters database tables. */
export class RuntimeModule {
readonly schemas: Readonly<Record<string, EntitySchema>>;
readonly checkers: Readonly<Record<string, EntityChecker>>;
readonly bootstrap: RuntimeBootstrap;
constructor(
schemas: Record<string, EntitySchema> = {},
checkers: Record<string, EntityChecker> = {},
bootstrap: RuntimeBootstrap = {},
) {
this.schemas = Object.freeze({ ...schemas });
this.checkers = Object.freeze({ ...checkers });
this.bootstrap = Object.freeze({
defaultDomainRoot: bootstrap.defaultDomainRoot,
constants: Object.freeze([...(bootstrap.constants ?? [])]),
ensure: bootstrap.ensure,
});
}
and(other: RuntimeModule): RuntimeModule {
return new RuntimeModule(
{ ...this.schemas, ...other.schemas },
{ ...this.checkers, ...other.checkers },
mergeRuntimeBootstrap(this.bootstrap, other.bootstrap),
);
}
}
|