2026-09-17 14:34:16 -07:00
|
|
|
import assert from "node:assert/strict";
|
|
|
|
|
import test from "node:test";
|
|
|
|
|
import { queryWorkspaceFixture } from "./fixtures/query-workspace.js";
|
|
|
|
|
import { linkQueries } from "../src/query/link.js";
|
2026-09-18 14:55:12 -07:00
|
|
|
import { compileQuery } from "../src/query/compile.js";
|
2026-09-17 14:34:16 -07:00
|
|
|
|
|
|
|
|
test("query fixture links generic collections, both implementations, and native getter/RPC setter", async () => {
|
|
|
|
|
const { workspace } = await queryWorkspaceFixture();
|
|
|
|
|
const query = workspace.linkedQueries.find((query) => query.id.endsWith(":upcoming"))!;
|
|
|
|
|
assert.ok(query);
|
|
|
|
|
assert.equal(query.fields.filter((field) => field.memberId === "title").length, 2);
|
|
|
|
|
assert.ok(
|
|
|
|
|
query.fields.filter((field) => field.memberId === "title").every((field) => field.binding.kind === "state"),
|
|
|
|
|
);
|
|
|
|
|
const broken = structuredClone(workspace);
|
|
|
|
|
const facts = broken.interfaceImports.find((iface) => iface.displayName === "TaskFacts")!;
|
|
|
|
|
const title = facts.members.find((member) => member.id === "title")!;
|
|
|
|
|
assert.equal(title.kind, "value");
|
|
|
|
|
delete title.queryRead;
|
|
|
|
|
assert.throws(() => linkQueries(broken), /changed/);
|
2026-09-17 18:23:16 -07:00
|
|
|
const aggregateBroken = structuredClone(workspace);
|
|
|
|
|
const rank = aggregateBroken.interfaceImports
|
|
|
|
|
.find((i) => i.displayName === "TaskFacts")!
|
|
|
|
|
.members.find((m) => m.id === "rank")!;
|
|
|
|
|
assert.equal(rank.kind, "value");
|
|
|
|
|
delete rank.queryRead;
|
|
|
|
|
assert.throws(() => linkQueries(aggregateBroken), /changed/);
|
|
|
|
|
const totals = workspace.linkedQueries.find((q) => q.id.endsWith(":totals"))!;
|
|
|
|
|
assert.equal(totals.fields.filter((f) => f.memberId === "rank").length, 2);
|
2026-09-17 14:34:16 -07:00
|
|
|
});
|
2026-09-18 14:55:12 -07:00
|
|
|
|
|
|
|
|
test("reference-only workspace queries hash every eligible conformance, including empty atoms", async () => {
|
|
|
|
|
const { workspace } = await queryWorkspaceFixture();
|
|
|
|
|
const pkg = workspace.packageImports.find((pkg) => pkg.queries?.some((q) => q.id === "upcoming"))!;
|
|
|
|
|
const query = pkg.queries!.find((q) => q.id === "upcoming")!;
|
|
|
|
|
const contract = workspace.interfaceImports.find((iface) => iface.displayName === "TaskFacts")!;
|
|
|
|
|
query.root = { kind: "workspace-interface", interface: contract.revisionId };
|
|
|
|
|
query.fragments = [];
|
|
|
|
|
const checked = await compileQuery(
|
|
|
|
|
query,
|
|
|
|
|
workspace.interfaceImports,
|
2026-09-22 15:31:42 -07:00
|
|
|
async () => `query ${query.operation} {root {objects(first: 10) {entries {node {_camino {ref}}}}}}`,
|
2026-09-18 14:55:12 -07:00
|
|
|
);
|
|
|
|
|
pkg.checkedQueries = pkg.checkedQueries!.map((q) => (q.declaration.id === query.id ? checked : q));
|
|
|
|
|
const linked = linkQueries(workspace).find((q) => q.id.endsWith(":upcoming"))!;
|
|
|
|
|
assert.equal(linked.fields.length, 0);
|
|
|
|
|
assert.equal(linked.rootAtoms.length, 2);
|
|
|
|
|
workspace.conformances = workspace.conformances.filter(
|
|
|
|
|
(c) => !(c.atomId === linked.rootAtoms[0] && c.interfaceRevisionId === contract.revisionId),
|
|
|
|
|
);
|
|
|
|
|
const changed = linkQueries(workspace).find((q) => q.id === linked.id)!;
|
|
|
|
|
assert.equal(changed.rootAtoms.length, 1);
|
|
|
|
|
assert.notEqual(linked.bindingDigest, changed.bindingDigest);
|
|
|
|
|
});
|