Add explicit CRDT edit contracts and structured query values
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { compileCapabilityResourceSource } from "../src/capability-language/index.js";
|
||||
import { compileQuery } from "../src/query/compile.js";
|
||||
import { querySelectionToWire } from "../src/query/proto.js";
|
||||
import { defaultQueryBudgets, type QueryDeclaration } from "../src/query/types.js";
|
||||
const source = { repository: "https://example.test/structured.git", commit: "a".repeat(40) };
|
||||
const result = compileCapabilityResourceSource(
|
||||
`interface Highlight id "highlight" revision "highlight@1" {
|
||||
queryable value range id "range" : record { sourceRevision:string; start:int32; end:int32; } { get id "range:get" execution snapshot targets [browser, server]; }
|
||||
queryable value content id "content" : record { text:string; tags:list<string>; metadata:optional<record { score:int32; }>; } { get id "content:get" execution snapshot targets [browser, server]; }
|
||||
}`,
|
||||
{ source },
|
||||
);
|
||||
assert.ok(result.ok && result.resource.kind === "interface", JSON.stringify(result.diagnostics));
|
||||
const iface = result.resource.revision;
|
||||
const declaration: QueryDeclaration = {
|
||||
id: "rows",
|
||||
displayName: "Rows",
|
||||
root: { kind: "workspace-interface", interface: iface.revisionId },
|
||||
document: "rows.graphql",
|
||||
operation: "Rows",
|
||||
fragments: [],
|
||||
views: [],
|
||||
allowances: [],
|
||||
budgets: { ...defaultQueryBudgets },
|
||||
watch: false,
|
||||
};
|
||||
const compile = (selection: string) =>
|
||||
compileQuery(
|
||||
declaration,
|
||||
[iface],
|
||||
async () =>
|
||||
`query Rows {root {objects(first:10, ${selection}) {entries {node {position:range {begin:start end} content {text tags metadata {score}}}}}}}`,
|
||||
);
|
||||
test("record/list query values preserve nested projections and leaf predicates", async () => {
|
||||
const checked = await compile(
|
||||
"where:{range:{start:{gte:4}},content:{metadata:{score:{gt:2}}}}, orderBy:{range:{start:ASC}}",
|
||||
);
|
||||
const extent = checked.selection[0]!.selection[0]!;
|
||||
assert.equal(extent.predicate?.kind, "and");
|
||||
if (extent.predicate?.kind !== "and") return;
|
||||
const expressions = extent.predicate.children.map((p) => (p.kind === "compare" ? p.expression : undefined));
|
||||
assert.deepEqual(
|
||||
expressions.map((e) => e?.leaf),
|
||||
[
|
||||
{ kind: "field", interfaceRevisionId: "highlight@1", memberId: "range", valuePath: ["start"] },
|
||||
{ kind: "field", interfaceRevisionId: "highlight@1", memberId: "content", valuePath: ["metadata", "score"] },
|
||||
],
|
||||
);
|
||||
assert.deepEqual(expressions[1]?.type, { kind: "optional", value: { kind: "scalar", name: "int32" } });
|
||||
const wire = querySelectionToWire(extent);
|
||||
assert.equal(wire.predicate?.predicate.case, "and");
|
||||
if (wire.predicate?.predicate.case === "and") {
|
||||
const child = wire.predicate.predicate.value.children[0]!;
|
||||
assert.equal(child.predicate.case, "compare");
|
||||
if (child.predicate.case === "compare") {
|
||||
const operand = child.predicate.value.operand?.operand;
|
||||
assert.ok(operand?.case === "expression" && operand.value.leaf.case === "field");
|
||||
assert.deepEqual(operand.value.leaf.value.valuePath, ["start"]);
|
||||
}
|
||||
}
|
||||
const raw = JSON.stringify(checked.output);
|
||||
assert.match(raw, /"begin"/);
|
||||
assert.match(raw, /"tags":\{"kind":"list"/);
|
||||
assert.equal(checked.effects.filter((e) => e.memberId === "range").length, 1);
|
||||
});
|
||||
test("structured predicates reject whole-record scalar comparisons and implicit list expansion", async () => {
|
||||
await assert.rejects(compile("where:{range:{eq:4}}"), /not defined/);
|
||||
await assert.rejects(compile('where:{content:{tags:{eq:"x"}}}'), /not defined/);
|
||||
});
|
||||
|
||||
test("explicit budgets can exceed defaults without exceeding wire bounds", () => {
|
||||
const compile = (rows: string) =>
|
||||
compileCapabilityResourceSource(
|
||||
`import interface Highlight;
|
||||
package P id "p" revision "p@1" {
|
||||
query Rows id "rows" root Highlight document "rows.graphql" operation "Rows" { replica; max rows ${rows}; max result-bytes 8388608; }
|
||||
}`,
|
||||
{ source, environment: { interfaces: new Map([["Highlight", iface]]), interfaceClosure: [iface] } },
|
||||
);
|
||||
const result = compile("5000");
|
||||
assert.ok(result.ok && result.resource.kind === "package", JSON.stringify(result.diagnostics));
|
||||
assert.equal(result.resource.revision.queries![0]!.budgets.rows, 5000);
|
||||
assert.equal(compile("4294967296").ok, false);
|
||||
});
|
||||
Reference in New Issue
Block a user