import { executionPlanDigest, ExecutionPlanError, type ExecutionPlan } from "./plan.js"; import { compileKernelProgram } from "./kernel.js"; import { compileInspectionTemplates } from "./inspection.js"; import { portableValueSchema } from "../bindings/portable.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 (executionPlanDigest(plan) !== 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, }; }