Implement query execution, scoped RPC enrichment, live collections, and scaffold integration

This commit is contained in:
Timothy J. Aveni
2026-09-17 14:34:16 -07:00
parent 7e69e675ba
commit c1330ae8e3
29 changed files with 2217 additions and 77 deletions
+82
View File
@@ -0,0 +1,82 @@
import { decodeQxValue, type QxValueType } from "./bindings.js";
import type { QueryResponse } from "./camino/api_pb.js";
import type { QxObjectRef } from "./references.js";
export type QxQueryPartial<T> = T extends QxObjectRef
? T
: T extends readonly (infer Item)[]
? QxQueryPartial<Item>[]
: T extends object
? { [Key in keyof T]?: QxQueryPartial<T[Key]> }
: T;
export type QxQuerySnapshot<T> = {
runId: string;
sequence: bigint;
dataVersion: string;
bindingDigest: string;
consistency: string;
fields: { path: readonly (string | number)[]; status: "pending" | "error"; error?: string }[];
} & ({ status: "ready"; data: T } | { status: "partial"; data: QxQueryPartial<T> });
declare const queryTypes: unique symbol;
/** Generated shape evidence, not permission to run a query. */
export interface QxQueryDescriptor<Variables, Result, Root extends string = string> {
readonly id: string;
readonly definitionDigest: string;
readonly rootInterfaceRevisionId: Root;
readonly variables: QxValueType;
readonly output: QxValueType;
readonly watch: boolean;
readonly [queryTypes]?: (variables: Variables, result: Result) => [Variables, Result];
}
export function decodeQuerySnapshot<T>(
response: QueryResponse,
output: QxValueType,
runId: string,
sequence: bigint,
): QxQuerySnapshot<T> {
if (response.preparationToken || response.residualWindows.length)
throw new Error("QUERY_RESULT_UNFINISHED: private preparation is not a query result");
const fields = [
...response.pending.map((field) => ({ path: field.path, status: "pending" as const })),
...response.errors.map((field) => ({ path: field.path, status: "error" as const, error: field.error })),
].map((field) => ({
...field,
path: field.path.map((part) => {
if (part.part.case !== "field" && part.part.case !== "index") throw new Error("QUERY_PATCH_INVALID");
return part.part.value;
}),
}));
// Pending/error values are absent, not successful nulls of a scalar type.
const shape = structuredClone(output);
for (const field of fields) {
let cursor = shape;
for (const [index, part] of field.path.entries()) {
while (cursor.kind === "optional") cursor = cursor.value;
const last = index === field.path.length - 1;
if (typeof part === "string" && cursor.kind === "record" && cursor.fields[part]) {
if (last) cursor.fields[part] = { kind: "optional", value: cursor.fields[part]! };
else cursor = cursor.fields[part]!;
} else if (typeof part === "number" && cursor.kind === "list") cursor = cursor.value;
else throw new Error("QUERY_PATCH_INVALID");
}
}
const data = decodeQxValue(shape, response.value, {}) as Record<string, unknown>;
for (const field of fields) {
let cursor: unknown = data;
for (const [index, part] of field.path.entries()) {
if (!cursor || typeof cursor !== "object") throw new Error("QUERY_PATCH_INVALID");
if (index === field.path.length - 1) delete (cursor as Record<string | number, unknown>)[part];
else cursor = (cursor as Record<string | number, unknown>)[part];
}
}
return {
runId,
sequence,
dataVersion: response.dataVersion,
bindingDigest: response.bindingDigest,
consistency: response.consistency,
fields,
...(fields.length ? { status: "partial", data } : { status: "ready", data }),
} as QxQuerySnapshot<T>;
}