Files
quixos-protocol/src/execution-world/queries.ts
T

134 lines
5.1 KiB
TypeScript
Raw Normal View History

import { compileKernelProgram } from "./kernel.js";
import { compileInspectionTemplates } from "./inspection.js";
import { portableValueSchema } from "../bindings/portable.js";
import { ExecutionPlanError, hexDigest, type ExecutionPlan } from "./plan.js";
import type { ValueType } from "../capability-model/types.js";
import { compileQueryComposition } from "../query/composition.js";
import { queryTreeBlueprint } from "./query-trees.js";
const lowerTypes = (value: unknown): unknown =>
JSON.parse(
JSON.stringify(value, (key, value: unknown) => {
if (
key === "type" &&
value &&
typeof value === "object" &&
"kind" in value &&
["scalar", "builtin", "optional", "list", "record", "object-ref"].includes(String(value.kind))
)
return portableValueSchema(value as ValueType);
return value;
}),
);
/** Checked query IR and installed getter identities, without GraphQL schemas/parsers or SQL adapters.
* Keep authored selection names only for output paths; field access uses resolved interface/member IDs. */
export function compileQueryProgram(plan: ExecutionPlan): unknown {
if (hexDigest(plan.definition) !== plan.digest)
throw new ExecutionPlanError("INVALID_PLAN", "queries", "Plan digest mismatch");
const allQueries = new Map(plan.definition.queries.map(({ id, query }) => [id, query.checked]));
const compositions = plan.definition.workspace.packageImports.flatMap((pkg) =>
(pkg.queryCompositions ?? []).map((composition) => {
const scoped = new Map(allQueries);
for (const query of pkg.checkedQueries ?? []) scoped.set(query.declaration.id, query);
const checked = compileQueryComposition(
{
id: composition.id,
input: composition.input,
steps: composition.steps,
maxQueries: composition.maxQueries,
},
scoped,
);
if (checked.definitionDigest !== composition.definitionDigest)
throw new ExecutionPlanError("INVALID_QUERY_COMPOSITION", composition.id, "Checked dependencies changed");
return {
id: JSON.stringify([pkg.revisionId, composition.id]),
input: portableValueSchema(checked.input),
output: portableValueSchema(checked.output),
maxQueries: checked.maxQueries,
steps: checked.steps.map((step) => ({
...step,
query: (pkg.checkedQueries ?? []).some((query) => query.declaration.id === step.query)
? JSON.stringify([pkg.revisionId, step.query])
: step.query,
})),
};
}),
);
return {
codec: "camino-query-program-v1",
plan: (compileKernelProgram(plan) as { plan: string }).plan,
...(compositions.length ? { compositions } : {}),
trees: plan.definition.queries
.filter((entry) => entry.query.checked.tree)
.map((entry) => ({
id: entry.id,
...queryTreeBlueprint(entry.query.packageRevisionId, entry.query.checked),
})),
queries: [
...compileInspectionTemplates(plan).queries,
...plan.definition.queries.map((entry) => queryProgramEntry(plan, entry)),
],
};
}
export function queryProgramEntry(plan: ExecutionPlan, entry: import("./plan.js").PlannedQuery) {
const { id, query, admittedOperations } = entry;
const interfaces = plan.definition.workspace.interfaceImports;
const checked = query.checked;
return {
id,
...(checked.declaration.fragment && !checked.declaration.fragment.admission
? {
fragment: {
package: query.packageRevisionId,
id: checked.declaration.id,
digest: checked.definitionDigest,
},
}
: {}),
placement: checked.declaration.placement?.kind ?? "remote",
source:
checked.declaration.placement?.kind === "local"
? JSON.stringify([
query.packageRevisionId,
checked.treeProjection?.tree ?? checked.declaration.placement.sourceQueryId,
])
: null,
root: checked.declaration.root,
atoms: query.rootAtoms,
variables: portableValueSchema(checked.variables),
defaults: checked.variableDefaults,
selection: lowerTypes(checked.selection),
budgets: checked.declaration.budgets,
fields: query.fields.map((field) => {
const member = interfaces
.find((i) => i.revisionId === field.interfaceRevisionId)!
.members.find((m) => m.id === field.memberId)!;
return {
atom: field.atomId,
interface: field.interfaceRevisionId,
member: field.memberId,
name: member.displayName,
operation: JSON.stringify([field.atomId, field.interfaceRevisionId, field.getter]),
};
}),
admittedOperations: checked.tree
? [
...new Set([
...admittedOperations,
...plan.definition.queries
.filter(
(entry) =>
entry.query.packageRevisionId === query.packageRevisionId &&
entry.query.checked.treeProjection?.tree === checked.declaration.id,
)
.flatMap((entry) => entry.operations),
]),
].sort()
: admittedOperations,
};
}