Implement progressive query admission, session boundaries and event-driven Studio observations
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import type { CheckedQuery, QueryTreeNode } from "../query/types.js";
|
||||
import type { ValueType } from "../capability-model/types.js";
|
||||
import { treeProjectionQuery } from "../query/tree.js";
|
||||
import { tsType } from "../bindings/portable.js";
|
||||
|
||||
export function queryTreeBlueprint(packageId: string, query: CheckedQuery) {
|
||||
const tree = query.tree!;
|
||||
const projection = (id: string) =>
|
||||
JSON.stringify([packageId, treeProjectionQuery(query.declaration.id, id, "local")]);
|
||||
const admission = (id: string) =>
|
||||
JSON.stringify([packageId, treeProjectionQuery(query.declaration.id, id, "replica")]);
|
||||
return {
|
||||
root: tree.root,
|
||||
maxOccurrences: tree.maxOccurrences,
|
||||
nodes: tree.nodes.map((node) => ({
|
||||
...node,
|
||||
projection: projection(node.projection),
|
||||
admission: admission(node.projection),
|
||||
bindings: node.bindings.map((binding) => ({
|
||||
...binding,
|
||||
projection: projection(binding.projection),
|
||||
admission: admission(binding.projection),
|
||||
})),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
/** Emit the shape of owned handles separately from graph result codecs. */
|
||||
export function queryTreeType(query: CheckedQuery): string {
|
||||
const tree = query.tree!;
|
||||
const nodes = new Map(tree.nodes.map((node) => [node.id, node]));
|
||||
const projections = new Map(tree.projections.map((projection) => [projection.id, projection]));
|
||||
const rootOutput = (id: string) => {
|
||||
const shape = projections.get(id)!.output;
|
||||
if (shape.kind !== "record" || !shape.fields.root) throw Error("Unchecked Query Tree projection");
|
||||
return shape.fields.root;
|
||||
};
|
||||
const shape = (id: string): string => {
|
||||
const node = nodes.get(id)!;
|
||||
return `QueryTreeShape<${tsType(rootOutput(node.projection))}, {${node.boundaries
|
||||
.map(
|
||||
(boundary) =>
|
||||
`readonly ${JSON.stringify(boundary.name)}${boundary.conditions.length ? "?" : ""}: ${shape(boundary.node)}`,
|
||||
)
|
||||
.join(";")}}, {readonly root: {${node.bindings
|
||||
.map(
|
||||
(binding) =>
|
||||
`readonly ${JSON.stringify(binding.name)}: ${bindingType(rootOutput(binding.projection), binding.targets, [binding.name])}`,
|
||||
)
|
||||
.join(";")}}}>`;
|
||||
};
|
||||
const bindingType = (
|
||||
type: ValueType,
|
||||
targets: QueryTreeNode["bindings"][number]["targets"],
|
||||
prefix: string[],
|
||||
): string => {
|
||||
const at = (type: ValueType, targets: QueryTreeNode["bindings"][number]["targets"]): string => {
|
||||
if (type.kind === "optional") return `(${at(type.value, targets)} | null)`;
|
||||
if (type.kind === "list")
|
||||
return `ReadonlyArray<${at(
|
||||
type.value,
|
||||
targets.map((target) => ({ ...target, path: target.path.slice(1) })),
|
||||
)}>`;
|
||||
const target = targets.find((target) => !target.path.length);
|
||||
if (target) {
|
||||
if (type.kind !== "record" || type.fields._camino?.kind !== "record" || !type.fields._camino.fields.ref)
|
||||
throw Error("Unchecked binding identity");
|
||||
return `QueryTreeOccurrence<${tsType(type.fields._camino.fields.ref)}, ${shape(target.node)}>`;
|
||||
}
|
||||
if (type.kind !== "record") return tsType(type);
|
||||
return `{${Object.entries(type.fields)
|
||||
.map(
|
||||
([key, value]) =>
|
||||
`readonly ${JSON.stringify(key)}: ${at(
|
||||
value,
|
||||
targets
|
||||
.filter((target) => target.path[0] === key)
|
||||
.map((target) => ({ ...target, path: target.path.slice(1) })),
|
||||
)}`,
|
||||
)
|
||||
.join(";")}}`;
|
||||
};
|
||||
let selected = type;
|
||||
for (const key of prefix) {
|
||||
if (selected.kind !== "record" || !selected.fields[key]) throw Error("Unchecked binding field");
|
||||
selected = selected.fields[key];
|
||||
}
|
||||
return at(
|
||||
selected,
|
||||
targets.map((target) => ({ ...target, path: target.path.slice(prefix.length) })),
|
||||
);
|
||||
};
|
||||
return shape(tree.root);
|
||||
}
|
||||
Reference in New Issue
Block a user