import assert from "node:assert/strict"; import { compileCapabilityResourceSource, compileCapabilitySource } from "../../src/capability-language/index.js"; import { compileQuery } from "../../src/query/compile.js"; import { linkQueries } from "../../src/query/link.js"; import type { InterfaceRevision, PackageRevision } from "../../src/capability-model/types.js"; export const queryFixtureSource = { repository: "https://query-fixture.example.test/source.git", commit: "1".repeat(40), }; export async function queryWorkspaceFixture() { const interfaces = new Map(); const sources: Record = {}; function iface(name: string, members: string, parameters = "") { const text = `${[...interfaces.keys()].map((name) => `import interface ${name};`).join("\n")} interface ${name}${parameters} id "${name}" revision "${name}@1" {${members}}`; sources[name] = text; const result = compileCapabilityResourceSource(text, { source: queryFixtureSource, environment: { interfaces, interfaceClosure: [...interfaces.values()] }, }); assert.ok(result.ok, JSON.stringify(result.diagnostics)); if (result.resource.kind !== "interface") throw new Error("interface expected"); interfaces.set(name, result.resource.revision); } iface("PersonFacts", `queryable value name id "name" : string {get id "name:get";}`); iface( "TaskFacts", ` queryable value title id "title" : string {get id "title:get"; set id "title:set";} queryable value done id "done" : bool {get id "done:get";} queryable value rank id "rank" : int64 {get id "rank:get";} queryable relation assignee id "assignee" : optional-one interface PersonFacts {resolve id "assignee:resolve";} queryable rpc value score id "score" : int32 {get id "score:get";} `, ); iface( "Collection", `queryable relation items id "items" : many object Item ordered {resolve id "items:resolve";}`, "", ); const packageSource = `${[...interfaces.keys()].map((name) => `import interface ${name};`).join("\n")} package Queries id "queries" revision "queries@1" { operation titleSet id "title-set" : string -> unit mode call receiver any requires {state title id "title-port" : string [write];}; operation score id "score" : unit -> int32 mode call receiver any; query Upcoming id "upcoming" root Collection document "upcoming.graphql" operation "Upcoming" { fragments "row.graphql"; max rows 30; watch; } query Enriched id "enriched" root Collection document "enriched.graphql" operation "Enriched" { max rows 30; allow TaskFacts.score select "Small visible page only"; } query Ranked id "ranked" root Collection document "ranked.graphql" operation "Ranked" { max rows 30; max candidates 60; allow TaskFacts.score predicate "Bounded local collection"; allow TaskFacts.score order "Bounded local collection"; } query Totals id "totals" root Collection document "totals.graphql" operation "Totals" { max rows 30; watch; } query ScoreTotals id "score-totals" root Collection document "score-totals.graphql" operation "ScoreTotals" { max rows 30; max candidates 60; allow TaskFacts.score aggregate "Complete bounded collection report"; } }`; sources.Queries = packageSource; const pkgResult = compileCapabilityResourceSource(packageSource, { source: queryFixtureSource, environment: { interfaces, interfaceClosure: [...interfaces.values()] }, }); assert.ok(pkgResult.ok, JSON.stringify(pkgResult.diagnostics)); if (pkgResult.resource.kind !== "package") throw new Error("package expected"); const pkg: PackageRevision = pkgResult.resource.revision; const allInterfaces = [...interfaces.values(), ...(pkgResult.resource.specializations ?? [])]; const documents: Record = { "upcoming.graphql": `query Upcoming($first: Int!, $after: Cursor) {root {items(first: $first, after: $after, where: {done: {eq: false}}, orderBy: [{rank: ASC}]) {entries {key cursor node {_qx {ref} ...TaskRow}} pageInfo {hasNextPage endCursor}}}}`, "row.graphql": `fragment TaskRow on TaskFacts {title rank done assignee {name}}`, "enriched.graphql": `query Enriched {root {items(first: 3) {entries {key node {_qx {ref} title score}}}}}`, "ranked.graphql": `query Ranked {root {items(first: 3, where: {score: {gt: 0}}, orderBy: [{score: DESC}]) {entries {key node {_qx {ref} title}}}}}`, "totals.graphql": `query Totals {root {_qx {relations {items {aggregate {count sum {rank}} groups(by: {done: true}, first: 10) {entries {group {done} aggregate {count sum {rank}}}}}}}}}`, "score-totals.graphql": `query ScoreTotals {root {_qx {relations {items {aggregate {count sum {score}}}}}}}`, }; pkg.checkedQueries = await Promise.all( pkg.queries!.map((query) => compileQuery(query, allInterfaces, async (name) => documents[name]!)), ); const implementation = (atom: string) => `conform ${atom} as TaskFacts id "${atom}-facts" { private state Title${atom} id "${atom}:title" on ${atom} : string policy crdt(string) default "Untitled"; private state Done${atom} id "${atom}:done" on ${atom} : bool policy optimistic-register default false; private state Rank${atom} id "${atom}:rank" on ${atom} : int64 policy optimistic-register default 0; private edge Assignee${atom} id "${atom}:assignee" { atom ${atom} projection assignee id "${atom}:assignee:forward" optional-one; interface PersonFacts projection tasks id "${atom}:assignee:inverse" many; } bind title.get to state Title${atom}.read; bind title.set to package Queries.titleSet with {title to state Title${atom};}; bind done to state Done${atom}; bind rank to state Rank${atom}; bind assignee.resolve to edge Assignee${atom}.assignee.resolve; bind score.get to package Queries.score query-reason "Explicit bounded score computation"; }`; const workspaceSource = `workspace QueryFixture id "query-fixture" revision "query-fixture@1" commit "${queryFixtureSource.commit}" { import interface PersonFacts; import interface TaskFacts; import interface Collection; import package Queries; atom Task id "Task"; atom Reminder id "Reminder"; atom Person id "Person"; atom Tasks id "Tasks"; conform Person as PersonFacts id "person-facts" { private state Name id "person:name" on Person : string policy optimistic-register default "Nobody"; bind name to state Name; } ${implementation("Task")} ${implementation("Reminder")} conform Tasks as Collection id "tasks-collection" { private edge Items id "items" { atom Tasks projection items id "items:forward" many ordered; interface TaskFacts projection collections id "items:inverse" many; } bind items.resolve to edge Items.items.resolve; } }`; sources.workspace = workspaceSource; const result = compileCapabilitySource(workspaceSource, "workspace.qx", { interfaces, interfaceClosure: allInterfaces, packages: new Map([["Queries", pkg]]), packageClosure: [pkg], }); assert.ok(result.ok, JSON.stringify(result.diagnostics)); const workspace = { ...result.workspace, linkedQueries: linkQueries(result.workspace) }; return { workspace, pkg, interfaces: allInterfaces, sources, documents }; }