Compare commits
6 Commits
aadc35581d
...
exported
| Author | SHA1 | Date | |
|---|---|---|---|
| b0d31ba51c | |||
| 2dffdbcd9f | |||
| c9265e7903 | |||
| a05f58f7fe | |||
| 93c8cae1e6 | |||
| 5a611bbc9b |
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"sourceRepo": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos",
|
"sourceRepo": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos",
|
||||||
"sourceCommit": "1c2dbc6ca2c3917292f158cbbaef531836eaacca",
|
"sourceCommit": "c87835bff85794bc232dbaaddc1eb3b593c2aab8",
|
||||||
"sourcePath": "quixos-protocol",
|
"sourcePath": "quixos-protocol",
|
||||||
"exportName": "quixos-protocol",
|
"exportName": "quixos-protocol",
|
||||||
"mirrorRemote": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos-protocol.git"
|
"mirrorRemote": "https://gitea-external.egads.tutti.syntaxblitz.net/quixos/quixos-protocol.git"
|
||||||
|
|||||||
@@ -408,6 +408,9 @@ identifier
|
|||||||
| POLL
|
| POLL
|
||||||
| RPC
|
| RPC
|
||||||
| QUERYABLE
|
| QUERYABLE
|
||||||
|
| RESULT_BYTES
|
||||||
|
| RPC_CALLS
|
||||||
|
| DEADLINE_MS
|
||||||
;
|
;
|
||||||
|
|
||||||
stringLiteral
|
stringLiteral
|
||||||
@@ -415,6 +418,9 @@ stringLiteral
|
|||||||
;
|
;
|
||||||
|
|
||||||
WORKSPACE: 'workspace';
|
WORKSPACE: 'workspace';
|
||||||
|
RESULT_BYTES: 'result-bytes';
|
||||||
|
RPC_CALLS: 'rpc-calls';
|
||||||
|
DEADLINE_MS: 'deadline-ms';
|
||||||
QUERY: 'query';
|
QUERY: 'query';
|
||||||
SPECIALIZE: 'specialize';
|
SPECIALIZE: 'specialize';
|
||||||
ROOT: 'root';
|
ROOT: 'root';
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ syntax = "proto3";
|
|||||||
package camino;
|
package camino;
|
||||||
|
|
||||||
import "camino/schema.proto";
|
import "camino/schema.proto";
|
||||||
|
import "quixos/refs.proto";
|
||||||
|
|
||||||
service CaminoService {
|
service CaminoService {
|
||||||
rpc ExecuteQuery(QueryRequest) returns (QueryResponse);
|
rpc ExecuteQuery(QueryRequest) returns (QueryResponse);
|
||||||
@@ -69,6 +70,27 @@ message Value {
|
|||||||
CrdtValue crdt_value = 10;
|
CrdtValue crdt_value = 10;
|
||||||
}
|
}
|
||||||
ValueSource source = 11;
|
ValueSource source = 11;
|
||||||
|
// Trusted query coordinator annotation. Travels with values through residual
|
||||||
|
// row selection, then is removed in favor of final-path hydration metadata.
|
||||||
|
QueryFieldOrigin query_origin = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
message QueryFieldOrigin {
|
||||||
|
string selection_id = 1;
|
||||||
|
string atom_id = 2;
|
||||||
|
string interface_revision_id = 3;
|
||||||
|
string member_id = 4;
|
||||||
|
StateValueSource source = 5;
|
||||||
|
}
|
||||||
|
message QueryLiveField {
|
||||||
|
repeated QueryPathPart path = 1;
|
||||||
|
string selection_id = 2;
|
||||||
|
string object_id = 3;
|
||||||
|
quixos.CapabilityRef capability = 4;
|
||||||
|
string watch_operation_id = 5;
|
||||||
|
string setter_operation_id = 6;
|
||||||
|
quixos.FieldEditing editing = 7;
|
||||||
|
StateValueSource source = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message InstallPersistencePlanRequest {
|
message InstallPersistencePlanRequest {
|
||||||
@@ -256,6 +278,7 @@ message QueryStats {
|
|||||||
uint32 relational_stages = 8;
|
uint32 relational_stages = 8;
|
||||||
uint32 captured_candidates = 9;
|
uint32 captured_candidates = 9;
|
||||||
double relational_ms = 10;
|
double relational_ms = 10;
|
||||||
|
double residual_ms = 11;
|
||||||
}
|
}
|
||||||
message QueryResponse {
|
message QueryResponse {
|
||||||
Value value = 1;
|
Value value = 1;
|
||||||
@@ -270,6 +293,7 @@ message QueryResponse {
|
|||||||
// Native reads share one database snapshot; package enrichment does not.
|
// Native reads share one database snapshot; package enrichment does not.
|
||||||
string consistency = 9; // native-snapshot | mixed
|
string consistency = 9; // native-snapshot | mixed
|
||||||
repeated QueryRelationalCapture relational_captures = 10;
|
repeated QueryRelationalCapture relational_captures = 10;
|
||||||
|
repeated QueryLiveField live_fields = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private coordinator input, removed before publishing a result. Memberships
|
// Private coordinator input, removed before publishing a result. Memberships
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ message QuerySelection {
|
|||||||
repeated QuerySelection selection = 8;
|
repeated QuerySelection selection = 8;
|
||||||
QueryRelationalPlan relational = 9;
|
QueryRelationalPlan relational = 9;
|
||||||
QueryPredicate predicate = 10;
|
QueryPredicate predicate = 10;
|
||||||
|
// Stable checked selection identity; empty for ordinary value projections.
|
||||||
|
string live_selection_id = 11;
|
||||||
}
|
}
|
||||||
// Resolved IDs, not GraphQL names, determine execution. Response selections
|
// Resolved IDs, not GraphQL names, determine execution. Response selections
|
||||||
// remain separate so aliases and fragments cannot change relational semantics.
|
// remain separate so aliases and fragments cannot change relational semantics.
|
||||||
|
|||||||
@@ -87,20 +87,16 @@ message InvokeCapabilityResponse {
|
|||||||
FieldEditing field_editing = 7;
|
FieldEditing field_editing = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolved from the checked native getter/setter binding, not Value.source.
|
|
||||||
message FieldEditing {
|
|
||||||
string getter_operation_id = 1;
|
|
||||||
string setter_operation_id = 2;
|
|
||||||
string document_type = 3;
|
|
||||||
string binding_digest = 4;
|
|
||||||
}
|
|
||||||
message EditCapabilityFieldRequest {
|
message EditCapabilityFieldRequest {
|
||||||
// The public getter; setter must belong to the same value member.
|
// The public getter; setter must belong to the same value member.
|
||||||
quixos.CapabilityRef capability = 1;
|
quixos.CapabilityRef capability = 1;
|
||||||
string object_id = 2;
|
string object_id = 2;
|
||||||
string setter_operation_id = 3;
|
string setter_operation_id = 3;
|
||||||
string binding_digest = 4;
|
string binding_digest = 4;
|
||||||
|
oneof edit {
|
||||||
camino.CrdtValue update = 5;
|
camino.CrdtValue update = 5;
|
||||||
|
camino.Value replacement = 7;
|
||||||
|
}
|
||||||
string client_mutation_id = 6;
|
string client_mutation_id = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,20 @@ message CapabilityRef {
|
|||||||
ConformanceWitness conformance = 3;
|
ConformanceWitness conformance = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolved native editing semantics. A source snapshot alone grants no writer.
|
||||||
|
message FieldEditing {
|
||||||
|
string getter_operation_id = 1;
|
||||||
|
string setter_operation_id = 2;
|
||||||
|
string document_type = 3;
|
||||||
|
string binding_digest = 4;
|
||||||
|
enum Mode {
|
||||||
|
UNSPECIFIED = 0;
|
||||||
|
REGISTER = 1;
|
||||||
|
CRDT = 2;
|
||||||
|
}
|
||||||
|
Mode mode = 5;
|
||||||
|
}
|
||||||
|
|
||||||
message ConformanceWitness {
|
message ConformanceWitness {
|
||||||
string object_id = 1;
|
string object_id = 1;
|
||||||
string interface_revision_id = 2;
|
string interface_revision_id = 2;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ declare module "@quixos/web-studio-react-runtime" {
|
|||||||
import type * as React from "react";
|
import type * as React from "react";
|
||||||
export function useComponentOverlayContainer(): HTMLElement;
|
export function useComponentOverlayContainer(): HTMLElement;
|
||||||
export function useComponentStyleRoot(): ShadowRoot;
|
export function useComponentStyleRoot(): ShadowRoot;
|
||||||
|
/** Aggregate transport counters only; contains no object identities or values. */
|
||||||
|
export function getFieldTransportMetrics(): Partial<Record<"get" | "watch" | "register" | "crdt" | "setter", Readonly<{started: number; active: number; completed: number; failed: number; totalMs: number}>>>;
|
||||||
export type ObjectRef<AtomId extends string> = string & {
|
export type ObjectRef<AtomId extends string> = string & {
|
||||||
readonly $quixosAtom: AtomId;
|
readonly $quixosAtom: AtomId;
|
||||||
};
|
};
|
||||||
@@ -22,8 +24,9 @@ declare module "@quixos/web-studio-react-runtime" {
|
|||||||
export function useTryConform<View>(object: string | {readonly $quixosRef: string}, contract: ReactInterfaceContract<View>): ConformanceResult<View>;
|
export function useTryConform<View>(object: string | {readonly $quixosRef: string}, contract: ReactInterfaceContract<View>): ConformanceResult<View>;
|
||||||
export type QueryValueType = {kind: "builtin" | "scalar"; name: string} | {kind: "record"; fields: Record<string, QueryValueType>} | {kind: "optional" | "list"; value: QueryValueType} | {kind: "object-ref"; expectation: {kind: "atom"; atomId: string} | {kind: "interface"; interfaceRevisionId: string}};
|
export type QueryValueType = {kind: "builtin" | "scalar"; name: string} | {kind: "record"; fields: Record<string, QueryValueType>} | {kind: "optional" | "list"; value: QueryValueType} | {kind: "object-ref"; expectation: {kind: "atom"; atomId: string} | {kind: "interface"; interfaceRevisionId: string}};
|
||||||
export type QueryReference<Contract extends string = string> = {readonly $quixosRef: string; readonly queryContract: Contract};
|
export type QueryReference<Contract extends string = string> = {readonly $quixosRef: string; readonly queryContract: Contract};
|
||||||
export interface QueryDescriptor<Variables, Result> {readonly id: string; readonly definitionDigest: string; readonly rootInterfaceRevisionId: string; readonly variables: QueryValueType; readonly output: QueryValueType; readonly watch: boolean; readonly $types?: (variables: Variables, result: Result) => [Variables, Result]}
|
export type QueryLiveProjection = {path: readonly string[]; selectionId: string; interfaceRevisionId: string; getOperationId: string; setOperationId?: string; watchOperationId?: string; inputKind: "fields" | "value"; valueType: QueryValueType; conditions: {include: boolean; defaultValue?: boolean; value: {kind: "variable"; name: string} | {kind: "literal"; value: unknown}}[]};
|
||||||
export type QueryPartial<T> = T extends QueryReference ? T : T extends readonly (infer Item)[] ? QueryPartial<Item>[] : T extends object ? {[Key in keyof T]?: QueryPartial<T[Key]>} : T;
|
export interface QueryDescriptor<Variables, Result> {readonly id: string; readonly definitionDigest: string; readonly rootInterfaceRevisionId: string; readonly variables: QueryValueType; readonly output: QueryValueType; readonly watch: boolean; readonly liveFields?: readonly QueryLiveProjection[]; readonly $types?: (variables: Variables, result: Result) => [Variables, Result]}
|
||||||
|
export type QueryPartial<T> = T extends {readonly $quixosRef: string} | {readonly capability: {readonly getOperationId: string}} ? T : T extends readonly (infer Item)[] ? QueryPartial<Item>[] : T extends object ? {[Key in keyof T]?: QueryPartial<T[Key]>} : T;
|
||||||
export type QueryFieldState = {path: readonly (string | number)[]; status: "pending" | "error"; error?: string};
|
export type QueryFieldState = {path: readonly (string | number)[]; status: "pending" | "error"; error?: string};
|
||||||
export type QueryState<T> = {refreshing: boolean; fields: QueryFieldState[]; runId?: string; sequence?: bigint; consistency?: string} & ({status: "loading"; data?: undefined; error?: undefined} | {status: "ready"; data: T; error?: undefined} | {status: "partial"; data: QueryPartial<T>; error?: undefined} | {status: "error"; data?: T | QueryPartial<T>; error: Error});
|
export type QueryState<T> = {refreshing: boolean; fields: QueryFieldState[]; runId?: string; sequence?: bigint; consistency?: string} & ({status: "loading"; data?: undefined; error?: undefined} | {status: "ready"; data: T; error?: undefined} | {status: "partial"; data: QueryPartial<T>; error?: undefined} | {status: "error"; data?: T | QueryPartial<T>; error: Error});
|
||||||
export function useQuery<Variables, Result>(descriptor: QueryDescriptor<Variables, Result>, options: {root: string | {readonly $quixosRef: string}; variables: Variables}): QueryState<Result> & {refresh(): void};
|
export function useQuery<Variables, Result>(descriptor: QueryDescriptor<Variables, Result>, options: {root: string | {readonly $quixosRef: string}; variables: Variables}): QueryState<Result> & {refresh(): void};
|
||||||
@@ -55,8 +58,12 @@ declare module "@quixos/web-studio-react-runtime" {
|
|||||||
options?: {clientMutationId?: string; signal?: AbortSignal},
|
options?: {clientMutationId?: string; signal?: AbortSignal},
|
||||||
) => Promise<Result>;
|
) => Promise<Result>;
|
||||||
export const h: typeof React.createElement;
|
export const h: typeof React.createElement;
|
||||||
export function useLiveField<T>(field: ReadableField<T>, options: {write: (value: T) => Promise<void>}): readonly [T, (value: T) => Promise<void>];
|
export type LiveFieldState<T> = {refreshing: boolean; stale: boolean; pendingWrites: number; writeError?: Error; refresh(): Promise<void>; discard(): void} & ({status: "loading"; value?: undefined; error?: undefined} | {status: "ready"; value: T; error?: Error} | {status: "error"; value?: undefined; error: Error});
|
||||||
export function useLiveField<T>(field: WritableField<T>): readonly [T, (value: T) => Promise<void>];
|
export type WritableLiveFieldState<T> = LiveFieldState<T> & {set(value: T): Promise<void>; retry(): Promise<void>};
|
||||||
export function useLiveField<T>(field: ReadableField<T>): readonly [T];
|
export function useLiveField<T>(field: ReadableField<T>, options: {id: string; write: (value: T) => Promise<void>}): WritableLiveFieldState<T>;
|
||||||
|
export function useLiveField<T>(field: WritableField<T>): WritableLiveFieldState<T>;
|
||||||
|
export function useLiveField<T>(field: ReadableField<T>): LiveFieldState<T>;
|
||||||
|
export function useSuspenseLiveField<T>(field: WritableField<T>): WritableLiveFieldState<T> & {status: "ready"; value: T};
|
||||||
|
export function useSuspenseLiveField<T>(field: ReadableField<T>): LiveFieldState<T> & {status: "ready"; value: T};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
+19
-1
@@ -1,5 +1,6 @@
|
|||||||
import type { BindingSchema } from "./index.js";
|
import type { BindingSchema } from "./index.js";
|
||||||
import type { ValueType } from "../capability-model/types.js";
|
import type { ValueType } from "../capability-model/types.js";
|
||||||
|
import { queryPresentation } from "../query/presentation.js";
|
||||||
|
|
||||||
/** Browser projection of the SAME checked RPC types, not a second props schema. */
|
/** Browser projection of the SAME checked RPC types, not a second props schema. */
|
||||||
export function generateReactBindings(
|
export function generateReactBindings(
|
||||||
@@ -128,9 +129,25 @@ export function generateReactBindings(
|
|||||||
return type(value);
|
return type(value);
|
||||||
};
|
};
|
||||||
const queries = pkg.checkedQueries ?? [];
|
const queries = pkg.checkedQueries ?? [];
|
||||||
|
const presentedType = (
|
||||||
|
value: ValueType,
|
||||||
|
fields: ReturnType<typeof queryPresentation>,
|
||||||
|
path: string[] = [],
|
||||||
|
): string => {
|
||||||
|
const field = fields.find((field) => JSON.stringify(field.path) === JSON.stringify(path));
|
||||||
|
if (field)
|
||||||
|
return `${field.conditions.length ? "(" : ""}${field.setOperationId ? "WritableField" : "ReadableField"}<${type(field.valueType)}>${field.conditions.length ? " | null)" : ""}`;
|
||||||
|
if (value.kind === "optional") return `(${presentedType(value.value, fields, path)} | null)`;
|
||||||
|
if (value.kind === "list") return `Array<${presentedType(value.value, fields, [...path, "*"])}>`;
|
||||||
|
if (value.kind === "record")
|
||||||
|
return `{${Object.entries(value.fields)
|
||||||
|
.map(([key, child]) => `${q(key)}: ${presentedType(child, fields, [...path, key])}`)
|
||||||
|
.join(";")}}`;
|
||||||
|
return queryType(value);
|
||||||
|
};
|
||||||
const queryCode =
|
const queryCode =
|
||||||
`export type QueryVariables = {${queries.map((query) => `${q(query.declaration.displayName)}: ${queryType(query.variables)}`).join(";")}};\n` +
|
`export type QueryVariables = {${queries.map((query) => `${q(query.declaration.displayName)}: ${queryType(query.variables)}`).join(";")}};\n` +
|
||||||
`export type QueryResults = {${queries.map((query) => `${q(query.declaration.displayName)}: ${queryType(query.output)}`).join(";")}};\n` +
|
`export type QueryResults = {${queries.map((query) => `${q(query.declaration.displayName)}: ${presentedType(query.output, queryPresentation(query, schema.interfaces))}`).join(";")}};\n` +
|
||||||
`export const queries: {${queries.map((query) => `${q(query.declaration.displayName)}: QueryDescriptor<QueryVariables[${q(query.declaration.displayName)}], QueryResults[${q(query.declaration.displayName)}]>`).join(";")}} = ${JSON.stringify(
|
`export const queries: {${queries.map((query) => `${q(query.declaration.displayName)}: QueryDescriptor<QueryVariables[${q(query.declaration.displayName)}], QueryResults[${q(query.declaration.displayName)}]>`).join(";")}} = ${JSON.stringify(
|
||||||
Object.fromEntries(
|
Object.fromEntries(
|
||||||
queries.map((query) => [
|
queries.map((query) => [
|
||||||
@@ -141,6 +158,7 @@ export function generateReactBindings(
|
|||||||
rootInterfaceRevisionId: query.declaration.root,
|
rootInterfaceRevisionId: query.declaration.root,
|
||||||
variables: query.variables,
|
variables: query.variables,
|
||||||
output: query.output,
|
output: query.output,
|
||||||
|
liveFields: queryPresentation(query, schema.interfaces),
|
||||||
watch: query.declaration.watch,
|
watch: query.declaration.watch,
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,253 +1,259 @@
|
|||||||
WORKSPACE=1
|
WORKSPACE=1
|
||||||
QUERY=2
|
RESULT_BYTES=2
|
||||||
SPECIALIZE=3
|
RPC_CALLS=3
|
||||||
ROOT=4
|
DEADLINE_MS=4
|
||||||
DOCUMENT=5
|
QUERY=5
|
||||||
FRAGMENTS=6
|
SPECIALIZE=6
|
||||||
VIEW=7
|
ROOT=7
|
||||||
MAX=8
|
DOCUMENT=8
|
||||||
ALLOW=9
|
FRAGMENTS=9
|
||||||
POLL=10
|
VIEW=10
|
||||||
QUERYABLE=11
|
MAX=11
|
||||||
RPC=12
|
ALLOW=12
|
||||||
QUERY_REASON=13
|
POLL=13
|
||||||
TYPE=14
|
QUERYABLE=14
|
||||||
OBJECT=15
|
RPC=15
|
||||||
STORABLE=16
|
QUERY_REASON=16
|
||||||
IMPLEMENTS=17
|
TYPE=17
|
||||||
REF=18
|
OBJECT=18
|
||||||
FRAGMENT=19
|
STORABLE=19
|
||||||
IMPORT=20
|
IMPLEMENTS=20
|
||||||
EXTERNAL=21
|
REF=21
|
||||||
ATOM=22
|
FRAGMENT=22
|
||||||
INTERFACE=23
|
IMPORT=23
|
||||||
INTERFACES=24
|
EXTERNAL=24
|
||||||
PACKAGE=25
|
ATOM=25
|
||||||
VALUE=26
|
INTERFACE=26
|
||||||
RELATION=27
|
INTERFACES=27
|
||||||
OPERATION=28
|
PACKAGE=28
|
||||||
FUNCTION=29
|
VALUE=29
|
||||||
CONSTRUCTOR=30
|
RELATION=30
|
||||||
CONSTRUCTS=31
|
OPERATION=31
|
||||||
INPUT=32
|
FUNCTION=32
|
||||||
CONFORM=33
|
CONSTRUCTOR=33
|
||||||
AS=34
|
CONSTRUCTS=34
|
||||||
BIND=35
|
INPUT=35
|
||||||
STATIC=36
|
CONFORM=36
|
||||||
TO=37
|
AS=37
|
||||||
PRIVATE=38
|
BIND=38
|
||||||
SHARED=39
|
STATIC=39
|
||||||
STATE=40
|
TO=40
|
||||||
EDGE=41
|
PRIVATE=41
|
||||||
PROJECTION=42
|
SHARED=42
|
||||||
WITH=43
|
STATE=43
|
||||||
USING=44
|
EDGE=44
|
||||||
VIA=45
|
PROJECTION=45
|
||||||
MATERIALIZE=46
|
WITH=46
|
||||||
IF=47
|
USING=47
|
||||||
ABSENT=48
|
VIA=48
|
||||||
ON=49
|
MATERIALIZE=49
|
||||||
POLICY=50
|
IF=50
|
||||||
DEFAULT=51
|
ABSENT=51
|
||||||
SOURCE=52
|
ON=52
|
||||||
REPOSITORY=53
|
POLICY=53
|
||||||
COMMIT=54
|
DEFAULT=54
|
||||||
REVISION=55
|
SOURCE=55
|
||||||
SEMANTIC_MAJOR=56
|
REPOSITORY=56
|
||||||
ON_DELETE=57
|
COMMIT=57
|
||||||
RETAIN_OTHER=58
|
REVISION=58
|
||||||
KEYED=59
|
SEMANTIC_MAJOR=59
|
||||||
PUBLIC_TRAVERSAL=60
|
ON_DELETE=60
|
||||||
ID=61
|
RETAIN_OTHER=61
|
||||||
DOC=62
|
KEYED=62
|
||||||
MODE=63
|
PUBLIC_TRAVERSAL=63
|
||||||
EMITS=64
|
ID=64
|
||||||
RECEIVER=65
|
DOC=65
|
||||||
REQUIRES=66
|
MODE=66
|
||||||
ANY=67
|
EMITS=67
|
||||||
GET=68
|
RECEIVER=68
|
||||||
SET=69
|
REQUIRES=69
|
||||||
WATCH=70
|
ANY=70
|
||||||
START=71
|
GET=71
|
||||||
STOP=72
|
SET=72
|
||||||
READ=73
|
WATCH=73
|
||||||
WRITE=74
|
START=74
|
||||||
RESOLVE=75
|
STOP=75
|
||||||
CONNECT=76
|
READ=76
|
||||||
DISCONNECT=77
|
WRITE=77
|
||||||
CALL=78
|
RESOLVE=78
|
||||||
WATCH_START=79
|
CONNECT=79
|
||||||
WATCH_STOP=80
|
DISCONNECT=80
|
||||||
SUBSCRIBE=81
|
CALL=81
|
||||||
UNSUBSCRIBE=82
|
WATCH_START=82
|
||||||
OPTIMISTIC_REGISTER=83
|
WATCH_STOP=83
|
||||||
CRDT=84
|
SUBSCRIBE=84
|
||||||
OPTIONAL_ONE=85
|
UNSUBSCRIBE=85
|
||||||
EXACTLY_ONE=86
|
OPTIMISTIC_REGISTER=86
|
||||||
MANY_UNIQUE=87
|
CRDT=87
|
||||||
MANY=88
|
OPTIONAL_ONE=88
|
||||||
ORDERED=89
|
EXACTLY_ONE=89
|
||||||
UNIT=90
|
MANY_UNIQUE=90
|
||||||
WATCH_HANDLE=91
|
MANY=91
|
||||||
MESSAGE=92
|
ORDERED=92
|
||||||
ATOM_REF=93
|
UNIT=93
|
||||||
INTERFACE_REF=94
|
WATCH_HANDLE=94
|
||||||
OPTIONAL=95
|
MESSAGE=95
|
||||||
LIST=96
|
ATOM_REF=96
|
||||||
RECORD=97
|
INTERFACE_REF=97
|
||||||
BOOL=98
|
OPTIONAL=98
|
||||||
BYTES=99
|
LIST=99
|
||||||
DOUBLE=100
|
RECORD=100
|
||||||
INT32=101
|
BOOL=101
|
||||||
INT64=102
|
BYTES=102
|
||||||
STRING=103
|
DOUBLE=103
|
||||||
UINT32=104
|
INT32=104
|
||||||
UINT64=105
|
INT64=105
|
||||||
TRUE=106
|
STRING=106
|
||||||
FALSE=107
|
UINT32=107
|
||||||
NULL=108
|
UINT64=108
|
||||||
ARROW=109
|
TRUE=109
|
||||||
COLON=110
|
FALSE=110
|
||||||
SEMI=111
|
NULL=111
|
||||||
COMMA=112
|
ARROW=112
|
||||||
DOT=113
|
COLON=113
|
||||||
LBRACE=114
|
SEMI=114
|
||||||
RBRACE=115
|
COMMA=115
|
||||||
LBRACK=116
|
DOT=116
|
||||||
RBRACK=117
|
LBRACE=117
|
||||||
LPAREN=118
|
RBRACE=118
|
||||||
RPAREN=119
|
LBRACK=119
|
||||||
LT=120
|
RBRACK=120
|
||||||
GT=121
|
LPAREN=121
|
||||||
AMP=122
|
RPAREN=122
|
||||||
EQUAL=123
|
LT=123
|
||||||
INTEGER=124
|
GT=124
|
||||||
JSON_NUMBER=125
|
AMP=125
|
||||||
IDENTIFIER=126
|
EQUAL=126
|
||||||
STRING_LITERAL=127
|
INTEGER=127
|
||||||
LINE_COMMENT=128
|
JSON_NUMBER=128
|
||||||
BLOCK_COMMENT=129
|
IDENTIFIER=129
|
||||||
WS=130
|
STRING_LITERAL=130
|
||||||
|
LINE_COMMENT=131
|
||||||
|
BLOCK_COMMENT=132
|
||||||
|
WS=133
|
||||||
'workspace'=1
|
'workspace'=1
|
||||||
'query'=2
|
'result-bytes'=2
|
||||||
'specialize'=3
|
'rpc-calls'=3
|
||||||
'root'=4
|
'deadline-ms'=4
|
||||||
'document'=5
|
'query'=5
|
||||||
'fragments'=6
|
'specialize'=6
|
||||||
'view'=7
|
'root'=7
|
||||||
'max'=8
|
'document'=8
|
||||||
'allow'=9
|
'fragments'=9
|
||||||
'poll'=10
|
'view'=10
|
||||||
'queryable'=11
|
'max'=11
|
||||||
'rpc'=12
|
'allow'=12
|
||||||
'query-reason'=13
|
'poll'=13
|
||||||
'type'=14
|
'queryable'=14
|
||||||
'object'=15
|
'rpc'=15
|
||||||
'storable'=16
|
'query-reason'=16
|
||||||
'implements'=17
|
'type'=17
|
||||||
'ref'=18
|
'object'=18
|
||||||
'fragment'=19
|
'storable'=19
|
||||||
'import'=20
|
'implements'=20
|
||||||
'external'=21
|
'ref'=21
|
||||||
'atom'=22
|
'fragment'=22
|
||||||
'interface'=23
|
'import'=23
|
||||||
'interfaces'=24
|
'external'=24
|
||||||
'package'=25
|
'atom'=25
|
||||||
'value'=26
|
'interface'=26
|
||||||
'relation'=27
|
'interfaces'=27
|
||||||
'operation'=28
|
'package'=28
|
||||||
'function'=29
|
'value'=29
|
||||||
'constructor'=30
|
'relation'=30
|
||||||
'constructs'=31
|
'operation'=31
|
||||||
'input'=32
|
'function'=32
|
||||||
'conform'=33
|
'constructor'=33
|
||||||
'as'=34
|
'constructs'=34
|
||||||
'bind'=35
|
'input'=35
|
||||||
'static'=36
|
'conform'=36
|
||||||
'to'=37
|
'as'=37
|
||||||
'private'=38
|
'bind'=38
|
||||||
'shared'=39
|
'static'=39
|
||||||
'state'=40
|
'to'=40
|
||||||
'edge'=41
|
'private'=41
|
||||||
'projection'=42
|
'shared'=42
|
||||||
'with'=43
|
'state'=43
|
||||||
'using'=44
|
'edge'=44
|
||||||
'via'=45
|
'projection'=45
|
||||||
'materialize'=46
|
'with'=46
|
||||||
'if'=47
|
'using'=47
|
||||||
'absent'=48
|
'via'=48
|
||||||
'on'=49
|
'materialize'=49
|
||||||
'policy'=50
|
'if'=50
|
||||||
'default'=51
|
'absent'=51
|
||||||
'source'=52
|
'on'=52
|
||||||
'repository'=53
|
'policy'=53
|
||||||
'commit'=54
|
'default'=54
|
||||||
'revision'=55
|
'source'=55
|
||||||
'semantic-major'=56
|
'repository'=56
|
||||||
'on-delete'=57
|
'commit'=57
|
||||||
'retain-other'=58
|
'revision'=58
|
||||||
'keyed'=59
|
'semantic-major'=59
|
||||||
'public-traversal'=60
|
'on-delete'=60
|
||||||
'id'=61
|
'retain-other'=61
|
||||||
'doc'=62
|
'keyed'=62
|
||||||
'mode'=63
|
'public-traversal'=63
|
||||||
'emits'=64
|
'id'=64
|
||||||
'receiver'=65
|
'doc'=65
|
||||||
'requires'=66
|
'mode'=66
|
||||||
'any'=67
|
'emits'=67
|
||||||
'get'=68
|
'receiver'=68
|
||||||
'set'=69
|
'requires'=69
|
||||||
'watch'=70
|
'any'=70
|
||||||
'start'=71
|
'get'=71
|
||||||
'stop'=72
|
'set'=72
|
||||||
'read'=73
|
'watch'=73
|
||||||
'write'=74
|
'start'=74
|
||||||
'resolve'=75
|
'stop'=75
|
||||||
'connect'=76
|
'read'=76
|
||||||
'disconnect'=77
|
'write'=77
|
||||||
'call'=78
|
'resolve'=78
|
||||||
'watch-start'=79
|
'connect'=79
|
||||||
'watch-stop'=80
|
'disconnect'=80
|
||||||
'subscribe'=81
|
'call'=81
|
||||||
'unsubscribe'=82
|
'watch-start'=82
|
||||||
'optimistic-register'=83
|
'watch-stop'=83
|
||||||
'crdt'=84
|
'subscribe'=84
|
||||||
'optional-one'=85
|
'unsubscribe'=85
|
||||||
'exactly-one'=86
|
'optimistic-register'=86
|
||||||
'many-unique'=87
|
'crdt'=87
|
||||||
'many'=88
|
'optional-one'=88
|
||||||
'ordered'=89
|
'exactly-one'=89
|
||||||
'unit'=90
|
'many-unique'=90
|
||||||
'watch-handle'=91
|
'many'=91
|
||||||
'message'=92
|
'ordered'=92
|
||||||
'atom-ref'=93
|
'unit'=93
|
||||||
'interface-ref'=94
|
'watch-handle'=94
|
||||||
'optional'=95
|
'message'=95
|
||||||
'list'=96
|
'atom-ref'=96
|
||||||
'record'=97
|
'interface-ref'=97
|
||||||
'bool'=98
|
'optional'=98
|
||||||
'bytes'=99
|
'list'=99
|
||||||
'double'=100
|
'record'=100
|
||||||
'int32'=101
|
'bool'=101
|
||||||
'int64'=102
|
'bytes'=102
|
||||||
'string'=103
|
'double'=103
|
||||||
'uint32'=104
|
'int32'=104
|
||||||
'uint64'=105
|
'int64'=105
|
||||||
'true'=106
|
'string'=106
|
||||||
'false'=107
|
'uint32'=107
|
||||||
'null'=108
|
'uint64'=108
|
||||||
'->'=109
|
'true'=109
|
||||||
':'=110
|
'false'=110
|
||||||
';'=111
|
'null'=111
|
||||||
','=112
|
'->'=112
|
||||||
'.'=113
|
':'=113
|
||||||
'{'=114
|
';'=114
|
||||||
'}'=115
|
','=115
|
||||||
'['=116
|
'.'=116
|
||||||
']'=117
|
'{'=117
|
||||||
'('=118
|
'}'=118
|
||||||
')'=119
|
'['=119
|
||||||
'<'=120
|
']'=120
|
||||||
'>'=121
|
'('=121
|
||||||
'&'=122
|
')'=122
|
||||||
'='=123
|
'<'=123
|
||||||
|
'>'=124
|
||||||
|
'&'=125
|
||||||
|
'='=126
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,253 +1,259 @@
|
|||||||
WORKSPACE=1
|
WORKSPACE=1
|
||||||
QUERY=2
|
RESULT_BYTES=2
|
||||||
SPECIALIZE=3
|
RPC_CALLS=3
|
||||||
ROOT=4
|
DEADLINE_MS=4
|
||||||
DOCUMENT=5
|
QUERY=5
|
||||||
FRAGMENTS=6
|
SPECIALIZE=6
|
||||||
VIEW=7
|
ROOT=7
|
||||||
MAX=8
|
DOCUMENT=8
|
||||||
ALLOW=9
|
FRAGMENTS=9
|
||||||
POLL=10
|
VIEW=10
|
||||||
QUERYABLE=11
|
MAX=11
|
||||||
RPC=12
|
ALLOW=12
|
||||||
QUERY_REASON=13
|
POLL=13
|
||||||
TYPE=14
|
QUERYABLE=14
|
||||||
OBJECT=15
|
RPC=15
|
||||||
STORABLE=16
|
QUERY_REASON=16
|
||||||
IMPLEMENTS=17
|
TYPE=17
|
||||||
REF=18
|
OBJECT=18
|
||||||
FRAGMENT=19
|
STORABLE=19
|
||||||
IMPORT=20
|
IMPLEMENTS=20
|
||||||
EXTERNAL=21
|
REF=21
|
||||||
ATOM=22
|
FRAGMENT=22
|
||||||
INTERFACE=23
|
IMPORT=23
|
||||||
INTERFACES=24
|
EXTERNAL=24
|
||||||
PACKAGE=25
|
ATOM=25
|
||||||
VALUE=26
|
INTERFACE=26
|
||||||
RELATION=27
|
INTERFACES=27
|
||||||
OPERATION=28
|
PACKAGE=28
|
||||||
FUNCTION=29
|
VALUE=29
|
||||||
CONSTRUCTOR=30
|
RELATION=30
|
||||||
CONSTRUCTS=31
|
OPERATION=31
|
||||||
INPUT=32
|
FUNCTION=32
|
||||||
CONFORM=33
|
CONSTRUCTOR=33
|
||||||
AS=34
|
CONSTRUCTS=34
|
||||||
BIND=35
|
INPUT=35
|
||||||
STATIC=36
|
CONFORM=36
|
||||||
TO=37
|
AS=37
|
||||||
PRIVATE=38
|
BIND=38
|
||||||
SHARED=39
|
STATIC=39
|
||||||
STATE=40
|
TO=40
|
||||||
EDGE=41
|
PRIVATE=41
|
||||||
PROJECTION=42
|
SHARED=42
|
||||||
WITH=43
|
STATE=43
|
||||||
USING=44
|
EDGE=44
|
||||||
VIA=45
|
PROJECTION=45
|
||||||
MATERIALIZE=46
|
WITH=46
|
||||||
IF=47
|
USING=47
|
||||||
ABSENT=48
|
VIA=48
|
||||||
ON=49
|
MATERIALIZE=49
|
||||||
POLICY=50
|
IF=50
|
||||||
DEFAULT=51
|
ABSENT=51
|
||||||
SOURCE=52
|
ON=52
|
||||||
REPOSITORY=53
|
POLICY=53
|
||||||
COMMIT=54
|
DEFAULT=54
|
||||||
REVISION=55
|
SOURCE=55
|
||||||
SEMANTIC_MAJOR=56
|
REPOSITORY=56
|
||||||
ON_DELETE=57
|
COMMIT=57
|
||||||
RETAIN_OTHER=58
|
REVISION=58
|
||||||
KEYED=59
|
SEMANTIC_MAJOR=59
|
||||||
PUBLIC_TRAVERSAL=60
|
ON_DELETE=60
|
||||||
ID=61
|
RETAIN_OTHER=61
|
||||||
DOC=62
|
KEYED=62
|
||||||
MODE=63
|
PUBLIC_TRAVERSAL=63
|
||||||
EMITS=64
|
ID=64
|
||||||
RECEIVER=65
|
DOC=65
|
||||||
REQUIRES=66
|
MODE=66
|
||||||
ANY=67
|
EMITS=67
|
||||||
GET=68
|
RECEIVER=68
|
||||||
SET=69
|
REQUIRES=69
|
||||||
WATCH=70
|
ANY=70
|
||||||
START=71
|
GET=71
|
||||||
STOP=72
|
SET=72
|
||||||
READ=73
|
WATCH=73
|
||||||
WRITE=74
|
START=74
|
||||||
RESOLVE=75
|
STOP=75
|
||||||
CONNECT=76
|
READ=76
|
||||||
DISCONNECT=77
|
WRITE=77
|
||||||
CALL=78
|
RESOLVE=78
|
||||||
WATCH_START=79
|
CONNECT=79
|
||||||
WATCH_STOP=80
|
DISCONNECT=80
|
||||||
SUBSCRIBE=81
|
CALL=81
|
||||||
UNSUBSCRIBE=82
|
WATCH_START=82
|
||||||
OPTIMISTIC_REGISTER=83
|
WATCH_STOP=83
|
||||||
CRDT=84
|
SUBSCRIBE=84
|
||||||
OPTIONAL_ONE=85
|
UNSUBSCRIBE=85
|
||||||
EXACTLY_ONE=86
|
OPTIMISTIC_REGISTER=86
|
||||||
MANY_UNIQUE=87
|
CRDT=87
|
||||||
MANY=88
|
OPTIONAL_ONE=88
|
||||||
ORDERED=89
|
EXACTLY_ONE=89
|
||||||
UNIT=90
|
MANY_UNIQUE=90
|
||||||
WATCH_HANDLE=91
|
MANY=91
|
||||||
MESSAGE=92
|
ORDERED=92
|
||||||
ATOM_REF=93
|
UNIT=93
|
||||||
INTERFACE_REF=94
|
WATCH_HANDLE=94
|
||||||
OPTIONAL=95
|
MESSAGE=95
|
||||||
LIST=96
|
ATOM_REF=96
|
||||||
RECORD=97
|
INTERFACE_REF=97
|
||||||
BOOL=98
|
OPTIONAL=98
|
||||||
BYTES=99
|
LIST=99
|
||||||
DOUBLE=100
|
RECORD=100
|
||||||
INT32=101
|
BOOL=101
|
||||||
INT64=102
|
BYTES=102
|
||||||
STRING=103
|
DOUBLE=103
|
||||||
UINT32=104
|
INT32=104
|
||||||
UINT64=105
|
INT64=105
|
||||||
TRUE=106
|
STRING=106
|
||||||
FALSE=107
|
UINT32=107
|
||||||
NULL=108
|
UINT64=108
|
||||||
ARROW=109
|
TRUE=109
|
||||||
COLON=110
|
FALSE=110
|
||||||
SEMI=111
|
NULL=111
|
||||||
COMMA=112
|
ARROW=112
|
||||||
DOT=113
|
COLON=113
|
||||||
LBRACE=114
|
SEMI=114
|
||||||
RBRACE=115
|
COMMA=115
|
||||||
LBRACK=116
|
DOT=116
|
||||||
RBRACK=117
|
LBRACE=117
|
||||||
LPAREN=118
|
RBRACE=118
|
||||||
RPAREN=119
|
LBRACK=119
|
||||||
LT=120
|
RBRACK=120
|
||||||
GT=121
|
LPAREN=121
|
||||||
AMP=122
|
RPAREN=122
|
||||||
EQUAL=123
|
LT=123
|
||||||
INTEGER=124
|
GT=124
|
||||||
JSON_NUMBER=125
|
AMP=125
|
||||||
IDENTIFIER=126
|
EQUAL=126
|
||||||
STRING_LITERAL=127
|
INTEGER=127
|
||||||
LINE_COMMENT=128
|
JSON_NUMBER=128
|
||||||
BLOCK_COMMENT=129
|
IDENTIFIER=129
|
||||||
WS=130
|
STRING_LITERAL=130
|
||||||
|
LINE_COMMENT=131
|
||||||
|
BLOCK_COMMENT=132
|
||||||
|
WS=133
|
||||||
'workspace'=1
|
'workspace'=1
|
||||||
'query'=2
|
'result-bytes'=2
|
||||||
'specialize'=3
|
'rpc-calls'=3
|
||||||
'root'=4
|
'deadline-ms'=4
|
||||||
'document'=5
|
'query'=5
|
||||||
'fragments'=6
|
'specialize'=6
|
||||||
'view'=7
|
'root'=7
|
||||||
'max'=8
|
'document'=8
|
||||||
'allow'=9
|
'fragments'=9
|
||||||
'poll'=10
|
'view'=10
|
||||||
'queryable'=11
|
'max'=11
|
||||||
'rpc'=12
|
'allow'=12
|
||||||
'query-reason'=13
|
'poll'=13
|
||||||
'type'=14
|
'queryable'=14
|
||||||
'object'=15
|
'rpc'=15
|
||||||
'storable'=16
|
'query-reason'=16
|
||||||
'implements'=17
|
'type'=17
|
||||||
'ref'=18
|
'object'=18
|
||||||
'fragment'=19
|
'storable'=19
|
||||||
'import'=20
|
'implements'=20
|
||||||
'external'=21
|
'ref'=21
|
||||||
'atom'=22
|
'fragment'=22
|
||||||
'interface'=23
|
'import'=23
|
||||||
'interfaces'=24
|
'external'=24
|
||||||
'package'=25
|
'atom'=25
|
||||||
'value'=26
|
'interface'=26
|
||||||
'relation'=27
|
'interfaces'=27
|
||||||
'operation'=28
|
'package'=28
|
||||||
'function'=29
|
'value'=29
|
||||||
'constructor'=30
|
'relation'=30
|
||||||
'constructs'=31
|
'operation'=31
|
||||||
'input'=32
|
'function'=32
|
||||||
'conform'=33
|
'constructor'=33
|
||||||
'as'=34
|
'constructs'=34
|
||||||
'bind'=35
|
'input'=35
|
||||||
'static'=36
|
'conform'=36
|
||||||
'to'=37
|
'as'=37
|
||||||
'private'=38
|
'bind'=38
|
||||||
'shared'=39
|
'static'=39
|
||||||
'state'=40
|
'to'=40
|
||||||
'edge'=41
|
'private'=41
|
||||||
'projection'=42
|
'shared'=42
|
||||||
'with'=43
|
'state'=43
|
||||||
'using'=44
|
'edge'=44
|
||||||
'via'=45
|
'projection'=45
|
||||||
'materialize'=46
|
'with'=46
|
||||||
'if'=47
|
'using'=47
|
||||||
'absent'=48
|
'via'=48
|
||||||
'on'=49
|
'materialize'=49
|
||||||
'policy'=50
|
'if'=50
|
||||||
'default'=51
|
'absent'=51
|
||||||
'source'=52
|
'on'=52
|
||||||
'repository'=53
|
'policy'=53
|
||||||
'commit'=54
|
'default'=54
|
||||||
'revision'=55
|
'source'=55
|
||||||
'semantic-major'=56
|
'repository'=56
|
||||||
'on-delete'=57
|
'commit'=57
|
||||||
'retain-other'=58
|
'revision'=58
|
||||||
'keyed'=59
|
'semantic-major'=59
|
||||||
'public-traversal'=60
|
'on-delete'=60
|
||||||
'id'=61
|
'retain-other'=61
|
||||||
'doc'=62
|
'keyed'=62
|
||||||
'mode'=63
|
'public-traversal'=63
|
||||||
'emits'=64
|
'id'=64
|
||||||
'receiver'=65
|
'doc'=65
|
||||||
'requires'=66
|
'mode'=66
|
||||||
'any'=67
|
'emits'=67
|
||||||
'get'=68
|
'receiver'=68
|
||||||
'set'=69
|
'requires'=69
|
||||||
'watch'=70
|
'any'=70
|
||||||
'start'=71
|
'get'=71
|
||||||
'stop'=72
|
'set'=72
|
||||||
'read'=73
|
'watch'=73
|
||||||
'write'=74
|
'start'=74
|
||||||
'resolve'=75
|
'stop'=75
|
||||||
'connect'=76
|
'read'=76
|
||||||
'disconnect'=77
|
'write'=77
|
||||||
'call'=78
|
'resolve'=78
|
||||||
'watch-start'=79
|
'connect'=79
|
||||||
'watch-stop'=80
|
'disconnect'=80
|
||||||
'subscribe'=81
|
'call'=81
|
||||||
'unsubscribe'=82
|
'watch-start'=82
|
||||||
'optimistic-register'=83
|
'watch-stop'=83
|
||||||
'crdt'=84
|
'subscribe'=84
|
||||||
'optional-one'=85
|
'unsubscribe'=85
|
||||||
'exactly-one'=86
|
'optimistic-register'=86
|
||||||
'many-unique'=87
|
'crdt'=87
|
||||||
'many'=88
|
'optional-one'=88
|
||||||
'ordered'=89
|
'exactly-one'=89
|
||||||
'unit'=90
|
'many-unique'=90
|
||||||
'watch-handle'=91
|
'many'=91
|
||||||
'message'=92
|
'ordered'=92
|
||||||
'atom-ref'=93
|
'unit'=93
|
||||||
'interface-ref'=94
|
'watch-handle'=94
|
||||||
'optional'=95
|
'message'=95
|
||||||
'list'=96
|
'atom-ref'=96
|
||||||
'record'=97
|
'interface-ref'=97
|
||||||
'bool'=98
|
'optional'=98
|
||||||
'bytes'=99
|
'list'=99
|
||||||
'double'=100
|
'record'=100
|
||||||
'int32'=101
|
'bool'=101
|
||||||
'int64'=102
|
'bytes'=102
|
||||||
'string'=103
|
'double'=103
|
||||||
'uint32'=104
|
'int32'=104
|
||||||
'uint64'=105
|
'int64'=105
|
||||||
'true'=106
|
'string'=106
|
||||||
'false'=107
|
'uint32'=107
|
||||||
'null'=108
|
'uint64'=108
|
||||||
'->'=109
|
'true'=109
|
||||||
':'=110
|
'false'=110
|
||||||
';'=111
|
'null'=111
|
||||||
','=112
|
'->'=112
|
||||||
'.'=113
|
':'=113
|
||||||
'{'=114
|
';'=114
|
||||||
'}'=115
|
','=115
|
||||||
'['=116
|
'.'=116
|
||||||
']'=117
|
'{'=117
|
||||||
'('=118
|
'}'=118
|
||||||
')'=119
|
'['=119
|
||||||
'<'=120
|
']'=120
|
||||||
'>'=121
|
'('=121
|
||||||
'&'=122
|
')'=122
|
||||||
'='=123
|
'<'=123
|
||||||
|
'>'=124
|
||||||
|
'&'=125
|
||||||
|
'='=126
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+155
-46
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+36
-58
File diff suppressed because one or more lines are too long
@@ -2,15 +2,15 @@
|
|||||||
// @generated from file quixos/refs.proto (package quixos, syntax proto3)
|
// @generated from file quixos/refs.proto (package quixos, syntax proto3)
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2";
|
import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2";
|
||||||
import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2";
|
import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2";
|
||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes the file quixos/refs.proto.
|
* Describes the file quixos/refs.proto.
|
||||||
*/
|
*/
|
||||||
export const file_quixos_refs: GenFile = /*@__PURE__*/
|
export const file_quixos_refs: GenFile = /*@__PURE__*/
|
||||||
fileDesc("ChFxdWl4b3MvcmVmcy5wcm90bxIGcXVpeG9zInUKDUNhcGFiaWxpdHlSZWYSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhQKDG9wZXJhdGlvbl9pZBgCIAEoCRIvCgtjb25mb3JtYW5jZRgDIAEoCzIaLnF1aXhvcy5Db25mb3JtYW5jZVdpdG5lc3MilgEKEkNvbmZvcm1hbmNlV2l0bmVzcxIRCglvYmplY3RfaWQYASABKAkSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAIgASgJEhYKDmNvbmZvcm1hbmNlX2lkGAMgASgJEh0KFXdvcmtzcGFjZV9yZXZpc2lvbl9pZBgEIAEoCRIXCg93b3Jrc3BhY2VfZXBvY2gYBSABKAkiQgoQUGFja2FnZUV4cG9ydFJlZhIbChNwYWNrYWdlX3JldmlzaW9uX2lkGAEgASgJEhEKCWV4cG9ydF9pZBgCIAEoCSLYAQoSSW5qZWN0ZWREZXBlbmRlbmN5Eg8KB3BvcnRfaWQYASABKAkSFwoNc3RhdGVfc2xvdF9pZBgCIAEoCUgAEiYKBGVkZ2UYAyABKAsyFi5xdWl4b3MuRWRnZURlcGVuZGVuY3lIABIfChVpbnRlcmZhY2VfcmV2aXNpb25faWQYBCABKAlIABIdChNjb25zdHJ1Y3Rvcl9hdG9tX2lkGAUgASgJSAASEgoIcXVlcnlfaWQYByABKAlIABIRCglvYmplY3RfaWQYBiABKAlCCQoHYmluZGluZyI9Cg5FZGdlRGVwZW5kZW5jeRIUCgxlZGdlX3R5cGVfaWQYASABKAkSFQoNcHJvamVjdGlvbl9pZBgCIAEoCWIGcHJvdG8z");
|
fileDesc("ChFxdWl4b3MvcmVmcy5wcm90bxIGcXVpeG9zInUKDUNhcGFiaWxpdHlSZWYSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhQKDG9wZXJhdGlvbl9pZBgCIAEoCRIvCgtjb25mb3JtYW5jZRgDIAEoCzIaLnF1aXhvcy5Db25mb3JtYW5jZVdpdG5lc3Mi0QEKDEZpZWxkRWRpdGluZxIbChNnZXR0ZXJfb3BlcmF0aW9uX2lkGAEgASgJEhsKE3NldHRlcl9vcGVyYXRpb25faWQYAiABKAkSFQoNZG9jdW1lbnRfdHlwZRgDIAEoCRIWCg5iaW5kaW5nX2RpZ2VzdBgEIAEoCRInCgRtb2RlGAUgASgOMhkucXVpeG9zLkZpZWxkRWRpdGluZy5Nb2RlIi8KBE1vZGUSDwoLVU5TUEVDSUZJRUQQABIMCghSRUdJU1RFUhABEggKBENSRFQQAiKWAQoSQ29uZm9ybWFuY2VXaXRuZXNzEhEKCW9iamVjdF9pZBgBIAEoCRIdChVpbnRlcmZhY2VfcmV2aXNpb25faWQYAiABKAkSFgoOY29uZm9ybWFuY2VfaWQYAyABKAkSHQoVd29ya3NwYWNlX3JldmlzaW9uX2lkGAQgASgJEhcKD3dvcmtzcGFjZV9lcG9jaBgFIAEoCSJCChBQYWNrYWdlRXhwb3J0UmVmEhsKE3BhY2thZ2VfcmV2aXNpb25faWQYASABKAkSEQoJZXhwb3J0X2lkGAIgASgJItgBChJJbmplY3RlZERlcGVuZGVuY3kSDwoHcG9ydF9pZBgBIAEoCRIXCg1zdGF0ZV9zbG90X2lkGAIgASgJSAASJgoEZWRnZRgDIAEoCzIWLnF1aXhvcy5FZGdlRGVwZW5kZW5jeUgAEh8KFWludGVyZmFjZV9yZXZpc2lvbl9pZBgEIAEoCUgAEh0KE2NvbnN0cnVjdG9yX2F0b21faWQYBSABKAlIABISCghxdWVyeV9pZBgHIAEoCUgAEhEKCW9iamVjdF9pZBgGIAEoCUIJCgdiaW5kaW5nIj0KDkVkZ2VEZXBlbmRlbmN5EhQKDGVkZ2VfdHlwZV9pZBgBIAEoCRIVCg1wcm9qZWN0aW9uX2lkGAIgASgJYgZwcm90bzM");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message quixos.CapabilityRef
|
* @generated from message quixos.CapabilityRef
|
||||||
@@ -41,6 +41,71 @@ export type CapabilityRef = Message<"quixos.CapabilityRef"> & {
|
|||||||
export const CapabilityRefSchema: GenMessage<CapabilityRef> = /*@__PURE__*/
|
export const CapabilityRefSchema: GenMessage<CapabilityRef> = /*@__PURE__*/
|
||||||
messageDesc(file_quixos_refs, 0);
|
messageDesc(file_quixos_refs, 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolved native editing semantics. A source snapshot alone grants no writer.
|
||||||
|
*
|
||||||
|
* @generated from message quixos.FieldEditing
|
||||||
|
*/
|
||||||
|
export type FieldEditing = Message<"quixos.FieldEditing"> & {
|
||||||
|
/**
|
||||||
|
* @generated from field: string getter_operation_id = 1;
|
||||||
|
*/
|
||||||
|
getterOperationId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: string setter_operation_id = 2;
|
||||||
|
*/
|
||||||
|
setterOperationId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: string document_type = 3;
|
||||||
|
*/
|
||||||
|
documentType: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: string binding_digest = 4;
|
||||||
|
*/
|
||||||
|
bindingDigest: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: quixos.FieldEditing.Mode mode = 5;
|
||||||
|
*/
|
||||||
|
mode: FieldEditing_Mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message quixos.FieldEditing.
|
||||||
|
* Use `create(FieldEditingSchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const FieldEditingSchema: GenMessage<FieldEditing> = /*@__PURE__*/
|
||||||
|
messageDesc(file_quixos_refs, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from enum quixos.FieldEditing.Mode
|
||||||
|
*/
|
||||||
|
export enum FieldEditing_Mode {
|
||||||
|
/**
|
||||||
|
* @generated from enum value: UNSPECIFIED = 0;
|
||||||
|
*/
|
||||||
|
UNSPECIFIED = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from enum value: REGISTER = 1;
|
||||||
|
*/
|
||||||
|
REGISTER = 1,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from enum value: CRDT = 2;
|
||||||
|
*/
|
||||||
|
CRDT = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the enum quixos.FieldEditing.Mode.
|
||||||
|
*/
|
||||||
|
export const FieldEditing_ModeSchema: GenEnum<FieldEditing_Mode> = /*@__PURE__*/
|
||||||
|
enumDesc(file_quixos_refs, 1, 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message quixos.ConformanceWitness
|
* @generated from message quixos.ConformanceWitness
|
||||||
*/
|
*/
|
||||||
@@ -76,7 +141,7 @@ export type ConformanceWitness = Message<"quixos.ConformanceWitness"> & {
|
|||||||
* Use `create(ConformanceWitnessSchema)` to create a new message.
|
* Use `create(ConformanceWitnessSchema)` to create a new message.
|
||||||
*/
|
*/
|
||||||
export const ConformanceWitnessSchema: GenMessage<ConformanceWitness> = /*@__PURE__*/
|
export const ConformanceWitnessSchema: GenMessage<ConformanceWitness> = /*@__PURE__*/
|
||||||
messageDesc(file_quixos_refs, 1);
|
messageDesc(file_quixos_refs, 2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message quixos.PackageExportRef
|
* @generated from message quixos.PackageExportRef
|
||||||
@@ -98,7 +163,7 @@ export type PackageExportRef = Message<"quixos.PackageExportRef"> & {
|
|||||||
* Use `create(PackageExportRefSchema)` to create a new message.
|
* Use `create(PackageExportRefSchema)` to create a new message.
|
||||||
*/
|
*/
|
||||||
export const PackageExportRefSchema: GenMessage<PackageExportRef> = /*@__PURE__*/
|
export const PackageExportRefSchema: GenMessage<PackageExportRef> = /*@__PURE__*/
|
||||||
messageDesc(file_quixos_refs, 2);
|
messageDesc(file_quixos_refs, 3);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message quixos.InjectedDependency
|
* @generated from message quixos.InjectedDependency
|
||||||
@@ -158,7 +223,7 @@ export type InjectedDependency = Message<"quixos.InjectedDependency"> & {
|
|||||||
* Use `create(InjectedDependencySchema)` to create a new message.
|
* Use `create(InjectedDependencySchema)` to create a new message.
|
||||||
*/
|
*/
|
||||||
export const InjectedDependencySchema: GenMessage<InjectedDependency> = /*@__PURE__*/
|
export const InjectedDependencySchema: GenMessage<InjectedDependency> = /*@__PURE__*/
|
||||||
messageDesc(file_quixos_refs, 3);
|
messageDesc(file_quixos_refs, 4);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message quixos.EdgeDependency
|
* @generated from message quixos.EdgeDependency
|
||||||
@@ -180,5 +245,5 @@ export type EdgeDependency = Message<"quixos.EdgeDependency"> & {
|
|||||||
* Use `create(EdgeDependencySchema)` to create a new message.
|
* Use `create(EdgeDependencySchema)` to create a new message.
|
||||||
*/
|
*/
|
||||||
export const EdgeDependencySchema: GenMessage<EdgeDependency> = /*@__PURE__*/
|
export const EdgeDependencySchema: GenMessage<EdgeDependency> = /*@__PURE__*/
|
||||||
messageDesc(file_quixos_refs, 4);
|
messageDesc(file_quixos_refs, 5);
|
||||||
|
|
||||||
|
|||||||
+37
-4
@@ -101,7 +101,7 @@ export async function compileQuery(
|
|||||||
if (node.name.value.startsWith("__")) fail("QUERY_UNSUPPORTED_FEATURE", "Introspection is not supported", node);
|
if (node.name.value.startsWith("__")) fail("QUERY_UNSUPPORTED_FEATURE", "Introspection is not supported", node);
|
||||||
},
|
},
|
||||||
Directive(node) {
|
Directive(node) {
|
||||||
if (!["include", "skip"].includes(node.name.value))
|
if (!["include", "skip", "live"].includes(node.name.value))
|
||||||
fail("QUERY_UNSUPPORTED_FEATURE", `Unsupported directive ${node.name.value}`, node);
|
fail("QUERY_UNSUPPORTED_FEATURE", `Unsupported directive ${node.name.value}`, node);
|
||||||
},
|
},
|
||||||
InlineFragment(node) {
|
InlineFragment(node) {
|
||||||
@@ -180,6 +180,15 @@ export async function compileQuery(
|
|||||||
Field(node) {
|
Field(node) {
|
||||||
const parent = info.getParentType();
|
const parent = info.getParentType();
|
||||||
const contract = parent && generated.byName.get(parent.name);
|
const contract = parent && generated.byName.get(parent.name);
|
||||||
|
if (node.directives?.some((directive) => directive.name.value === "live")) {
|
||||||
|
const member = contract?.members.find((entry) => entry.displayName === node.name.value);
|
||||||
|
if (!member || member.kind !== "value" || member.queryRead?.execution !== "native")
|
||||||
|
fail(
|
||||||
|
"QUERY_LIVE_UNSUPPORTED",
|
||||||
|
"@live requires a direct native-queryable value field, not RPC enrichment or a synthetic result",
|
||||||
|
node,
|
||||||
|
);
|
||||||
|
}
|
||||||
if (!contract || node.name.value === "_qx") return;
|
if (!contract || node.name.value === "_qx") return;
|
||||||
mark(contract.revisionId, node.name.value, "select", node);
|
mark(contract.revisionId, node.name.value, "select", node);
|
||||||
const member = contract.members.find((entry) => entry.displayName === node.name.value)!;
|
const member = contract.members.find((entry) => entry.displayName === node.name.value)!;
|
||||||
@@ -286,9 +295,12 @@ export async function compileQuery(
|
|||||||
field.type,
|
field.type,
|
||||||
selection.selectionSet,
|
selection.selectionSet,
|
||||||
depth + 1,
|
depth + 1,
|
||||||
conditional || !!selection.directives?.length,
|
conditional || !!selection.directives?.some((entry) => entry.name.value !== "live"),
|
||||||
);
|
);
|
||||||
if ((conditional || selection.directives?.length) && fields[key]!.kind !== "optional")
|
if (
|
||||||
|
(conditional || selection.directives?.some((entry) => entry.name.value !== "live")) &&
|
||||||
|
fields[key]!.kind !== "optional"
|
||||||
|
)
|
||||||
fields[key] = valueType.optional(fields[key]!);
|
fields[key] = valueType.optional(fields[key]!);
|
||||||
if (previous) fields[key] = mergeOutput(previous, fields[key]!);
|
if (previous) fields[key] = mergeOutput(previous, fields[key]!);
|
||||||
}
|
}
|
||||||
@@ -354,7 +366,9 @@ export async function compileQuery(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const conditions = (directives: readonly DirectiveNode[] = []) =>
|
const conditions = (directives: readonly DirectiveNode[] = []) =>
|
||||||
directives.map((directive) => ({
|
directives
|
||||||
|
.filter((directive) => directive.name.value !== "live")
|
||||||
|
.map((directive) => ({
|
||||||
include: directive.name.value === "include",
|
include: directive.name.value === "include",
|
||||||
value: argument(directive.arguments!.find((entry) => entry.name.value === "if")!.value),
|
value: argument(directive.arguments!.find((entry) => entry.name.value === "if")!.value),
|
||||||
}));
|
}));
|
||||||
@@ -390,6 +404,13 @@ export async function compileQuery(
|
|||||||
{
|
{
|
||||||
name: node.name.value,
|
name: node.name.value,
|
||||||
key: node.alias?.value ?? node.name.value,
|
key: node.alias?.value ?? node.name.value,
|
||||||
|
...(node.directives?.some((directive) => directive.name.value === "live")
|
||||||
|
? {
|
||||||
|
liveSelectionId: createHash("sha256")
|
||||||
|
.update(JSON.stringify([node.loc?.source.name, node.loc?.start, contract?.revisionId, member?.id]))
|
||||||
|
.digest("hex"),
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
...(member && contract ? { interfaceRevisionId: contract.revisionId, memberId: member.id } : {}),
|
...(member && contract ? { interfaceRevisionId: contract.revisionId, memberId: member.id } : {}),
|
||||||
...(member?.kind === "relationship" ? { targetInterfaceRevisionId: generated.target(member) } : {}),
|
...(member?.kind === "relationship" ? { targetInterfaceRevisionId: generated.target(member) } : {}),
|
||||||
conditions: [...inherited, ...conditions(node.directives)],
|
conditions: [...inherited, ...conditions(node.directives)],
|
||||||
@@ -405,6 +426,18 @@ export async function compileQuery(
|
|||||||
const normalized = print(document),
|
const normalized = print(document),
|
||||||
schema = printSchema(generated.schema);
|
schema = printSchema(generated.schema);
|
||||||
const selections = selection(operations[0]!.selectionSet, generated.schema.getQueryType()!);
|
const selections = selection(operations[0]!.selectionSet, generated.schema.getQueryType()!);
|
||||||
|
const checkPresentation = (entries: QuerySelection[]) => {
|
||||||
|
for (const key of new Set(entries.map((entry) => entry.key))) {
|
||||||
|
const siblings = entries.filter((entry) => entry.key === key);
|
||||||
|
if (siblings.some((entry) => entry.liveSelectionId) && siblings.some((entry) => !entry.liveSelectionId))
|
||||||
|
throw new QueryCompileError(
|
||||||
|
"QUERY_LIVE_CONFLICT",
|
||||||
|
`${key} mixes live and plain selections; use separate aliases`,
|
||||||
|
);
|
||||||
|
checkPresentation(siblings.flatMap((entry) => entry.selection));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkPresentation(selections);
|
||||||
const definitionDigest = createHash("sha256")
|
const definitionDigest = createHash("sha256")
|
||||||
.update(
|
.update(
|
||||||
canonicalJson({
|
canonicalJson({
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import type { InterfaceRevision, ValueType } from "../capability-model/types.js";
|
||||||
|
import type { CheckedQuery, QuerySelection } from "./types.js";
|
||||||
|
|
||||||
|
/** Browser presentation is separate from the portable query value contract. */
|
||||||
|
export function queryPresentation(query: CheckedQuery, interfaces: readonly InterfaceRevision[]) {
|
||||||
|
const result: {
|
||||||
|
path: string[];
|
||||||
|
selectionId: string;
|
||||||
|
interfaceRevisionId: string;
|
||||||
|
getOperationId: string;
|
||||||
|
setOperationId?: string;
|
||||||
|
watchOperationId?: string;
|
||||||
|
inputKind: "value" | "fields";
|
||||||
|
valueType: ValueType;
|
||||||
|
conditions: (QuerySelection["conditions"][number] & { defaultValue?: boolean })[];
|
||||||
|
}[] = [];
|
||||||
|
const visit = (type: ValueType, selections: QuerySelection[], path: string[]) => {
|
||||||
|
if (type.kind === "optional") return visit(type.value, selections, path);
|
||||||
|
if (type.kind === "list") return visit(type.value, selections, [...path, "*"]);
|
||||||
|
if (type.kind !== "record") return;
|
||||||
|
for (const [name, field] of Object.entries(type.fields)) {
|
||||||
|
const matches = selections.filter((entry) => entry.key === name);
|
||||||
|
if (matches.some((entry) => entry.liveSelectionId) && matches.some((entry) => !entry.liveSelectionId))
|
||||||
|
throw new Error(`QUERY_LIVE_CONFLICT: ${[...path, name].join(".")} mixes live and plain selections`);
|
||||||
|
for (const entry of matches) {
|
||||||
|
if (entry.liveSelectionId) {
|
||||||
|
const iface = interfaces.find((iface) => iface.revisionId === entry.interfaceRevisionId)!;
|
||||||
|
const member = iface.members.find((member) => member.id === entry.memberId)!;
|
||||||
|
if (member.kind !== "value") throw new Error("QUERY_LIVE_UNSUPPORTED");
|
||||||
|
const get = member.operations.find((op) => op.displayName === "get")!;
|
||||||
|
const set = member.operations.find((op) => op.displayName === "set");
|
||||||
|
result.push({
|
||||||
|
path: [...path, name],
|
||||||
|
selectionId: entry.liveSelectionId,
|
||||||
|
interfaceRevisionId: iface.revisionId,
|
||||||
|
getOperationId: get.id,
|
||||||
|
setOperationId: set?.id,
|
||||||
|
watchOperationId: member.operations.find((op) => op.displayName === "watch-start")?.id,
|
||||||
|
inputKind: set?.inputType.kind === "record" ? "fields" : "value",
|
||||||
|
valueType: get.outputType,
|
||||||
|
conditions: entry.conditions.map((condition) => {
|
||||||
|
const fallback =
|
||||||
|
condition.value.kind === "variable" ? query.variableDefaults[condition.value.name] : undefined;
|
||||||
|
return {
|
||||||
|
...condition,
|
||||||
|
...(fallback?.kind === "literal" && typeof fallback.value === "boolean"
|
||||||
|
? { defaultValue: fallback.value }
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
} else visit(field, entry.selection, [...path, name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
visit(query.output, query.selection, []);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -10,6 +10,9 @@ import {
|
|||||||
GraphQLList,
|
GraphQLList,
|
||||||
GraphQLNonNull,
|
GraphQLNonNull,
|
||||||
GraphQLSchema,
|
GraphQLSchema,
|
||||||
|
GraphQLDirective,
|
||||||
|
DirectiveLocation,
|
||||||
|
specifiedDirectives,
|
||||||
type GraphQLOutputType,
|
type GraphQLOutputType,
|
||||||
type GraphQLInputType,
|
type GraphQLInputType,
|
||||||
type GraphQLFieldConfigMap,
|
type GraphQLFieldConfigMap,
|
||||||
@@ -241,6 +244,7 @@ export function querySchema(
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
const schema = new GraphQLSchema({
|
const schema = new GraphQLSchema({
|
||||||
|
directives: [...specifiedDirectives, new GraphQLDirective({ name: "live", locations: [DirectiveLocation.FIELD] })],
|
||||||
query: new GraphQLObjectType({
|
query: new GraphQLObjectType({
|
||||||
name: "QxQuery",
|
name: "QxQuery",
|
||||||
fields: { root: { type: new GraphQLNonNull(object(declaration.root)) } },
|
fields: { root: { type: new GraphQLNonNull(object(declaration.root)) } },
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ export type QueryArgument =
|
|||||||
| { kind: "list"; values: QueryArgument[] }
|
| { kind: "list"; values: QueryArgument[] }
|
||||||
| { kind: "object"; fields: Record<string, QueryArgument> };
|
| { kind: "object"; fields: Record<string, QueryArgument> };
|
||||||
export interface QuerySelection {
|
export interface QuerySelection {
|
||||||
|
liveSelectionId?: string;
|
||||||
name: string;
|
name: string;
|
||||||
key: string;
|
key: string;
|
||||||
interfaceRevisionId?: InterfaceRevisionId;
|
interfaceRevisionId?: InterfaceRevisionId;
|
||||||
|
|||||||
Vendored
+3
@@ -42,6 +42,9 @@ const pkg = resource(`import interface Tasks; import interface Task;
|
|||||||
package Reports id "reports" revision "reports@1" {
|
package Reports id "reports" revision "reports@1" {
|
||||||
query Report id "report" root Tasks document "report.graphql" operation "Report" {
|
query Report id "report" root Tasks document "report.graphql" operation "Report" {
|
||||||
max rows 50;
|
max rows 50;
|
||||||
|
max result-bytes 1048576;
|
||||||
|
max rpc-calls 100;
|
||||||
|
max deadline-ms 10000;
|
||||||
view TaskObject as Task;
|
view TaskObject as Task;
|
||||||
allow Task.score aggregate "Bounded aggregation fixture";
|
allow Task.score aggregate "Bounded aggregation fixture";
|
||||||
allow Task.score predicate "Bounded aggregation fixture";
|
allow Task.score predicate "Bounded aggregation fixture";
|
||||||
|
|||||||
Vendored
+13
-4
@@ -8,7 +8,7 @@ export const queryFixtureSource = {
|
|||||||
repository: "https://query-fixture.example.test/source.git",
|
repository: "https://query-fixture.example.test/source.git",
|
||||||
commit: "1".repeat(40),
|
commit: "1".repeat(40),
|
||||||
};
|
};
|
||||||
export async function queryWorkspaceFixture() {
|
export async function queryWorkspaceFixture(options: { live?: boolean } = {}) {
|
||||||
const interfaces = new Map<string, InterfaceRevision>();
|
const interfaces = new Map<string, InterfaceRevision>();
|
||||||
const sources: Record<string, string> = {};
|
const sources: Record<string, string> = {};
|
||||||
function iface(name: string, members: string, parameters = "") {
|
function iface(name: string, members: string, parameters = "") {
|
||||||
@@ -29,7 +29,7 @@ export async function queryWorkspaceFixture() {
|
|||||||
`
|
`
|
||||||
queryable value title id "title" : string {get id "title:get"; set id "title:set";}
|
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 done id "done" : bool {get id "done:get";}
|
||||||
queryable value rank id "rank" : int64 {get id "rank:get";}
|
queryable value rank id "rank" : int64 {get id "rank:get"; set id "rank:set";}
|
||||||
queryable relation assignee id "assignee" : optional-one interface PersonFacts {resolve id "assignee:resolve";}
|
queryable relation assignee id "assignee" : optional-one interface PersonFacts {resolve id "assignee:resolve";}
|
||||||
queryable rpc value score id "score" : int32 {get id "score:get";}
|
queryable rpc value score id "score" : int32 {get id "score:get";}
|
||||||
`,
|
`,
|
||||||
@@ -81,7 +81,16 @@ export async function queryWorkspaceFixture() {
|
|||||||
"score-totals.graphql": `query ScoreTotals {root {_qx {relations {items {aggregate {count sum {score}}}}}}}`,
|
"score-totals.graphql": `query ScoreTotals {root {_qx {relations {items {aggregate {count sum {score}}}}}}}`,
|
||||||
};
|
};
|
||||||
pkg.checkedQueries = await Promise.all(
|
pkg.checkedQueries = await Promise.all(
|
||||||
pkg.queries!.map((query) => compileQuery(query, allInterfaces, async (name) => documents[name]!)),
|
pkg.queries!.map((query) =>
|
||||||
|
compileQuery(query, allInterfaces, async (name) =>
|
||||||
|
options.live
|
||||||
|
? documents[name]!.replace(/\btitle\b/g, "title @live").replace(
|
||||||
|
"title @live rank done",
|
||||||
|
"title @live rank @live done @live",
|
||||||
|
)
|
||||||
|
: documents[name]!,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
const implementation = (atom: string) => `conform ${atom} as TaskFacts id "${atom}-facts" {
|
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 Title${atom} id "${atom}:title" on ${atom} : string policy crdt(string) default "Untitled";
|
||||||
@@ -92,7 +101,7 @@ export async function queryWorkspaceFixture() {
|
|||||||
interface PersonFacts projection tasks id "${atom}:assignee:inverse" many;
|
interface PersonFacts projection tasks id "${atom}:assignee:inverse" many;
|
||||||
}
|
}
|
||||||
bind title.get to state Title${atom}.read;
|
bind title.get to state Title${atom}.read;
|
||||||
bind title.set to package Queries.titleSet with {title to state Title${atom};};
|
${options.live ? `bind title.set to state Title${atom}.write;` : `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 done to state Done${atom}; bind rank to state Rank${atom};
|
||||||
bind assignee.resolve to edge Assignee${atom}.assignee.resolve;
|
bind assignee.resolve to edge Assignee${atom}.assignee.resolve;
|
||||||
bind score.get to package Queries.score query-reason "Explicit bounded score computation";
|
bind score.get to package Queries.score query-reason "Explicit bounded score computation";
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { compileCapabilityResourceSource } from "../src/capability-language/inde
|
|||||||
import { compileQuery } from "../src/query/compile.js";
|
import { compileQuery } from "../src/query/compile.js";
|
||||||
import { QueryCompileError } from "../src/query/types.js";
|
import { QueryCompileError } from "../src/query/types.js";
|
||||||
import { checkQueryTemplate } from "../src/query/templates.js";
|
import { checkQueryTemplate } from "../src/query/templates.js";
|
||||||
|
import { queryPresentation } from "../src/query/presentation.js";
|
||||||
|
import { querySelectionToWire } from "../src/query/proto.js";
|
||||||
import type { InterfaceRevision } from "../src/capability-model/types.js";
|
import type { InterfaceRevision } from "../src/capability-model/types.js";
|
||||||
|
|
||||||
const source = { repository: "https://example.test/queries.git", commit: "a".repeat(40) };
|
const source = { repository: "https://example.test/queries.git", commit: "a".repeat(40) };
|
||||||
@@ -125,6 +127,48 @@ const document = `query Upcoming($first: Int!, $before: Int64!) {
|
|||||||
const compile = (query = document, row = "fragment Row on TaskFacts { title due }", clauses = "") =>
|
const compile = (query = document, row = "fragment Row on TaskFacts { title due }", clauses = "") =>
|
||||||
compileQuery(fixture(clauses), [collection, facts], async (name) => (name.endsWith("row.graphql") ? row : query));
|
compileQuery(fixture(clauses), [collection, facts], async (name) => (name.endsWith("row.graphql") ? row : query));
|
||||||
|
|
||||||
|
test("live selections preserve aliases, nullable values, fragment conditions and wire identity", async () => {
|
||||||
|
const checked = await compile(
|
||||||
|
`query Upcoming($show: Boolean!) {root {items(first: 3) {entries {node {plain: title ...Row @include(if: $show)}}}}}`,
|
||||||
|
`fragment Row on TaskFacts {label: title @live due @live}`,
|
||||||
|
);
|
||||||
|
const fields = queryPresentation(checked, [collection, facts]);
|
||||||
|
assert.deepEqual(
|
||||||
|
fields.map((f) => f.path),
|
||||||
|
[
|
||||||
|
["root", "items", "entries", "*", "node", "label"],
|
||||||
|
["root", "items", "entries", "*", "node", "due"],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert.equal(fields[0]!.getOperationId, "title:get");
|
||||||
|
assert.equal(fields[0]!.setOperationId, undefined);
|
||||||
|
assert.equal(fields[1]!.valueType.kind, "optional");
|
||||||
|
assert.equal(fields[0]!.conditions.length, 1);
|
||||||
|
assert.ok(JSON.stringify(checked.selection.map(querySelectionToWire)).includes(fields[0]!.selectionId));
|
||||||
|
const defaults = await compile(
|
||||||
|
`query Upcoming($show: Boolean! = true) {root {items(first: 3) {entries {node {...Row @include(if: $show)}}}}}`,
|
||||||
|
"fragment Row on TaskFacts {title @live}",
|
||||||
|
);
|
||||||
|
assert.equal(queryPresentation(defaults, [collection, facts])[0]!.conditions[0]!.defaultValue, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("live selections reject RPC getters, synthetic selections and conflicting presentations", async () => {
|
||||||
|
for (const [selected, code] of [
|
||||||
|
["score @live", "QUERY_LIVE_UNSUPPORTED"],
|
||||||
|
["_qx @live {ref}", "QUERY_LIVE_UNSUPPORTED"],
|
||||||
|
["title @live title", "QUERY_LIVE_CONFLICT"],
|
||||||
|
["title @live(unchecked: true)", "QUERY_VALIDATION"],
|
||||||
|
])
|
||||||
|
await assert.rejects(
|
||||||
|
compile(
|
||||||
|
`query Upcoming {root {items(first: 3) {entries {node {...Row}}}}}`,
|
||||||
|
`fragment Row on TaskFacts {${selected}}`,
|
||||||
|
'allow TaskFacts.score select "bounded";',
|
||||||
|
),
|
||||||
|
(error: unknown) => error instanceof QueryCompileError && error.code === code,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test("query dependency ports resolve exact exports without declaration ordering constraints", () => {
|
test("query dependency ports resolve exact exports without declaration ordering constraints", () => {
|
||||||
const result = compileCapabilityResourceSource(
|
const result = compileCapabilityResourceSource(
|
||||||
`import interface Tasks;
|
`import interface Tasks;
|
||||||
|
|||||||
+26
-10
@@ -7,13 +7,14 @@ import { spawnSync } from "node:child_process";
|
|||||||
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/parser.js";
|
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/parser.js";
|
||||||
import { generateReactBindings } from "../src/bindings/react.js";
|
import { generateReactBindings } from "../src/bindings/react.js";
|
||||||
import { reactPlatformTypes } from "../src/bindings/react-platform.js";
|
import { reactPlatformTypes } from "../src/bindings/react-platform.js";
|
||||||
|
import { compileQuery } from "../src/query/compile.js";
|
||||||
|
|
||||||
const source = { repository: "https://example.test/fields.git", commit: "a".repeat(40) };
|
const source = { repository: "https://example.test/fields.git", commit: "a".repeat(40) };
|
||||||
test("React bindings preserve read-only, writable and nested reference contracts", async (t) => {
|
test("React bindings preserve read-only, writable and nested reference contracts", async (t) => {
|
||||||
const iface = compileCapabilityResourceSource(
|
const iface = compileCapabilityResourceSource(
|
||||||
`interface Fields id "fields" revision "fields@1" {
|
`interface Fields id "fields" revision "fields@1" {
|
||||||
value title id "title" : string { get id "title:get"; set id "title:set"; watch start id "watch" stop id "stop"; }
|
queryable value title id "title" : string { get id "title:get"; set id "title:set"; watch start id "watch" stop id "stop"; }
|
||||||
value summary id "summary" : string { get id "summary:get"; }
|
queryable value summary id "summary" : string { get id "summary:get"; }
|
||||||
}`,
|
}`,
|
||||||
{ source },
|
{ source },
|
||||||
);
|
);
|
||||||
@@ -22,11 +23,19 @@ test("React bindings preserve read-only, writable and nested reference contracts
|
|||||||
const pkg = compileCapabilityResourceSource(
|
const pkg = compileCapabilityResourceSource(
|
||||||
`import interface Fields; package P id "p" revision "p@1" {
|
`import interface Fields; package P id "p" revision "p@1" {
|
||||||
function props id "props" : unit -> record {fields: interface-ref<Fields>; caption: string;};
|
function props id "props" : unit -> record {fields: interface-ref<Fields>; caption: string;};
|
||||||
|
query Editor id "editor" root Fields document "editor.graphql" operation "Editor" {max rows 1; watch;}
|
||||||
}`,
|
}`,
|
||||||
{ source, environment: { interfaces: new Map([["Fields", iface.resource.revision]]) } },
|
{ source, environment: { interfaces: new Map([["Fields", iface.resource.revision]]) } },
|
||||||
);
|
);
|
||||||
assert.ok(pkg.ok && pkg.resource.kind === "package");
|
assert.ok(pkg.ok && pkg.resource.kind === "package");
|
||||||
if (!pkg.ok || pkg.resource.kind !== "package") throw new Error("package failed");
|
if (!pkg.ok || pkg.resource.kind !== "package") throw new Error("package failed");
|
||||||
|
pkg.resource.revision.checkedQueries = [
|
||||||
|
await compileQuery(
|
||||||
|
pkg.resource.revision.queries![0]!,
|
||||||
|
[iface.resource.revision],
|
||||||
|
async () => "query Editor {root {title @live summary @live plain: title}}",
|
||||||
|
),
|
||||||
|
];
|
||||||
const schema = {
|
const schema = {
|
||||||
format: "quixos-bindings",
|
format: "quixos-bindings",
|
||||||
version: 1,
|
version: 1,
|
||||||
@@ -68,7 +77,14 @@ test("React bindings preserve read-only, writable and nested reference contracts
|
|||||||
path.join(root, "consumer.ts"),
|
path.join(root, "consumer.ts"),
|
||||||
`import {useLiveField, tryConform, type ReadableField, type WritableField} from "@quixos/web-studio-react-runtime";
|
`import {useLiveField, tryConform, type ReadableField, type WritableField} from "@quixos/web-studio-react-runtime";
|
||||||
import {reactInterfaces} from "./react-props.gen.js";
|
import {reactInterfaces} from "./react-props.gen.js";
|
||||||
import type {ReactResults} from "./react-props.gen.js";
|
import type {ReactResults, QueryResults} from "./react-props.gen.js";
|
||||||
|
declare const query: QueryResults["Editor"];
|
||||||
|
useLiveField(query.root.title).set("new");
|
||||||
|
// @ts-expect-error live query fields retain exact setter types
|
||||||
|
useLiveField(query.root.title).set(123);
|
||||||
|
// @ts-expect-error readonly query fields do not acquire a setter
|
||||||
|
useLiveField(query.root.summary).set("no");
|
||||||
|
const plain: string = query.root.plain;
|
||||||
async function lookup() {
|
async function lookup() {
|
||||||
const view = await tryConform("object", reactInterfaces.Fields);
|
const view = await tryConform("object", reactInterfaces.Fields);
|
||||||
if (!view) return;
|
if (!view) return;
|
||||||
@@ -79,14 +95,14 @@ async function lookup() {
|
|||||||
await view.call["summary.set"]("no setter");
|
await view.call["summary.set"]("no setter");
|
||||||
}
|
}
|
||||||
declare const props: ReactResults["props"];
|
declare const props: ReactResults["props"];
|
||||||
const [title, setTitle] = useLiveField(props.fields.fields.title);
|
const title = useLiveField(props.fields.fields.title);
|
||||||
setTitle("new");
|
title.set("new");
|
||||||
// @ts-expect-error wrong setter value
|
// @ts-expect-error wrong setter value
|
||||||
setTitle(123);
|
title.set(123);
|
||||||
// @ts-expect-error read-only hook has no setter
|
// @ts-expect-error read-only hook has no setter
|
||||||
const [summary, setSummary] = useLiveField(props.fields.fields.summary);
|
useLiveField(props.fields.fields.summary).set("no");
|
||||||
const [manual, write] = useLiveField(props.fields.fields.summary, {write: async (value: string) => {}});
|
const manual = useLiveField(props.fields.fields.summary, {id: "manual", write: async (value: string) => {}});
|
||||||
write("new");
|
manual.set("new");
|
||||||
const readonly: ReadableField<string> = props.fields.fields.title;
|
const readonly: ReadableField<string> = props.fields.fields.title;
|
||||||
// @ts-expect-error read-only does not satisfy writable
|
// @ts-expect-error read-only does not satisfy writable
|
||||||
const writable: WritableField<string> = props.fields.fields.summary;
|
const writable: WritableField<string> = props.fields.fields.summary;
|
||||||
@@ -94,7 +110,7 @@ declare const narrow: WritableField<"only">;
|
|||||||
// @ts-expect-error writable references are invariant
|
// @ts-expect-error writable references are invariant
|
||||||
const widened: WritableField<string> = narrow;
|
const widened: WritableField<string> = narrow;
|
||||||
// @ts-expect-error callbacks must accept the field's type
|
// @ts-expect-error callbacks must accept the field's type
|
||||||
useLiveField(props.fields.fields.summary, {write: async (value: number) => {}});
|
useLiveField(props.fields.fields.summary, {id: "manual", write: async (value: number) => {}});
|
||||||
`,
|
`,
|
||||||
);
|
);
|
||||||
const result = spawnSync(
|
const result = spawnSync(
|
||||||
|
|||||||
Reference in New Issue
Block a user