@astrale-os/sdk 0.6.0-beta.41 → 0.6.0-beta.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -2
- package/dist/application/action/context.d.ts +49 -18
- package/dist/application/action/index.d.ts +1 -1
- package/dist/application/error/error.d.ts +16 -1
- package/dist/application/error/error.js +39 -5
- package/dist/application/error/index.d.ts +1 -1
- package/dist/application/error/index.js +1 -1
- package/dist/application/mutation/authoring/builder.d.ts +81 -33
- package/dist/application/mutation/authoring/builder.js +100 -30
- package/dist/application/mutation/authoring/guard.d.ts +37 -0
- package/dist/application/mutation/authoring/guard.js +150 -0
- package/dist/application/mutation/authoring/index.d.ts +5 -2
- package/dist/application/mutation/authoring/index.js +2 -1
- package/dist/application/mutation/authoring/names.d.ts +19 -0
- package/dist/application/mutation/authoring/names.js +83 -0
- package/dist/application/mutation/authoring/transition.d.ts +3 -2
- package/dist/application/mutation/define.d.ts +24 -10
- package/dist/application/mutation/define.js +49 -53
- package/dist/application/mutation/execution/execute.d.ts +2 -2
- package/dist/application/mutation/execution/execute.js +78 -7
- package/dist/application/mutation/execution/executor.d.ts +4 -1
- package/dist/application/mutation/execution/executor.js +6 -1
- package/dist/application/mutation/failure.d.ts +11 -1
- package/dist/application/mutation/failure.js +18 -3
- package/dist/application/mutation/index.d.ts +8 -4
- package/dist/application/mutation/index.js +5 -2
- package/dist/application/mutation/legacy/v6/builder.d.ts +84 -0
- package/dist/application/mutation/legacy/v6/define.d.ts +18 -0
- package/dist/application/mutation/legacy/v6/define.js +56 -0
- package/dist/application/mutation/legacy/v6/mutation.d.ts +28 -0
- package/dist/application/mutation/legacy/v6/mutation.js +1 -0
- package/dist/application/mutation/{authoring → legacy/v6}/precondition.d.ts +4 -0
- package/dist/application/mutation/mutation.d.ts +30 -19
- package/dist/application/query/answer/answer.d.ts +117 -0
- package/dist/application/query/answer/answer.js +1 -0
- package/dist/application/query/answer/conformance.d.ts +4 -0
- package/dist/application/query/answer/conformance.js +27 -0
- package/dist/application/query/answer/facts.d.ts +17 -0
- package/dist/application/query/answer/facts.js +57 -0
- package/dist/application/query/composite/builder.d.ts +1 -1
- package/dist/application/query/composite/builder.js +1 -1
- package/dist/application/query/composite/plan.d.ts +1 -1
- package/dist/application/query/composite/plan.js +1 -1
- package/dist/application/query/composite/query.d.ts +1 -2
- package/dist/application/query/define.d.ts +2 -33
- package/dist/application/query/define.js +3 -130
- package/dist/application/query/definition.d.ts +12 -0
- package/dist/application/query/definition.js +47 -0
- package/dist/application/query/execution/bounds.d.ts +22 -0
- package/dist/application/query/execution/bounds.js +88 -0
- package/dist/application/query/execution/crossings.d.ts +25 -0
- package/dist/application/query/execution/crossings.js +192 -0
- package/dist/application/query/execution/error.d.ts +68 -0
- package/dist/application/query/execution/error.js +50 -0
- package/dist/application/query/execution/execute.d.ts +2 -7
- package/dist/application/query/execution/execute.js +3 -51
- package/dist/application/query/execution/recipe.d.ts +85 -0
- package/dist/application/query/execution/recipe.js +324 -0
- package/dist/application/query/execution/refusal.d.ts +37 -0
- package/dist/application/query/execution/refusal.js +80 -0
- package/dist/application/query/execution/rows.d.ts +42 -0
- package/dist/application/query/execution/rows.js +308 -0
- package/dist/application/query/execution/split.d.ts +24 -0
- package/dist/application/query/execution/split.js +190 -0
- package/dist/application/query/handles/build.d.ts +10 -0
- package/dist/application/query/handles/build.js +53 -0
- package/dist/application/query/handles/conditions.d.ts +94 -0
- package/dist/application/query/handles/conditions.js +1 -0
- package/dist/application/query/handles/domain.d.ts +157 -0
- package/dist/application/query/handles/domain.js +1 -0
- package/dist/application/query/handles/handles.d.ts +268 -0
- package/dist/application/query/handles/handles.js +1 -0
- package/dist/application/query/handles/model.d.ts +96 -0
- package/dist/application/query/handles/model.js +246 -0
- package/dist/application/query/handles/plan.d.ts +99 -0
- package/dist/application/query/handles/plan.js +37 -0
- package/dist/application/query/handles/reads.d.ts +106 -0
- package/dist/application/query/handles/reads.js +839 -0
- package/dist/application/query/handles/relations.d.ts +100 -0
- package/dist/application/query/handles/relations.js +1 -0
- package/dist/application/query/handles/rows.d.ts +94 -0
- package/dist/application/query/handles/rows.js +4 -0
- package/dist/application/query/handles/terms.d.ts +103 -0
- package/dist/application/query/handles/terms.js +282 -0
- package/dist/application/query/index.d.ts +10 -7
- package/dist/application/query/index.js +9 -4
- package/dist/application/query/language/index.d.ts +2 -0
- package/dist/application/query/language/index.js +2 -0
- package/dist/application/query/language/query.d.ts +323 -0
- package/dist/application/query/language/query.js +2 -0
- package/dist/application/query/{collection → legacy/v6/collection}/identity.d.ts +2 -2
- package/dist/application/query/{collection → legacy/v6/collection}/metadata.d.ts +1 -1
- package/dist/application/query/{collection → legacy/v6/collection}/union.d.ts +3 -3
- package/dist/application/query/{collection → legacy/v6/collection}/union.js +1 -1
- package/dist/application/query/{conformance.d.ts → legacy/v6/conformance.d.ts} +3 -3
- package/dist/application/query/{conformance.js → legacy/v6/conformance.js} +1 -1
- package/dist/application/query/legacy/v6/define.d.ts +37 -0
- package/dist/application/query/legacy/v6/define.js +90 -0
- package/dist/application/query/legacy/v6/execution/execute.d.ts +16 -0
- package/dist/application/query/legacy/v6/execution/execute.js +50 -0
- package/dist/application/query/legacy/v6/index.d.ts +6 -0
- package/dist/application/query/legacy/v6/index.js +3 -0
- package/dist/application/query/legacy/v6/kernel.d.ts +6 -0
- package/dist/application/query/legacy/v6/kernel.js +5 -0
- package/dist/application/query/{single → legacy/v6/single}/pagination.js +1 -1
- package/dist/application/query/{single → legacy/v6/single}/query.d.ts +2 -14
- package/dist/application/query/legacy/v6/single/query.js +1 -0
- package/dist/application/query/query.d.ts +16 -1
- package/dist/application/query/recipe/define.d.ts +44 -0
- package/dist/application/query/recipe/define.js +95 -0
- package/dist/application/query/recipe/recipe.d.ts +134 -0
- package/dist/application/query/recipe/recipe.js +1 -0
- package/dist/application/workflow/durable.d.ts +22 -8
- package/dist/deployment/build/build.d.ts +8 -1
- package/dist/deployment/build/material.js +3 -0
- package/dist/execution/invocation/capabilities/bind.d.ts +6 -4
- package/dist/execution/invocation/capabilities/bind.js +39 -3
- package/dist/execution/invocation/dispatch/action.js +4 -2
- package/dist/execution/invocation/dispatch/context.js +1 -1
- package/dist/execution/invocation/dispatch/workflow.js +4 -2
- package/dist/execution/invocation/result/index.d.ts +1 -0
- package/dist/execution/invocation/result/index.js +1 -0
- package/dist/execution/invocation/result/recipe.d.ts +6 -0
- package/dist/execution/invocation/result/recipe.js +17 -0
- package/dist/execution/service/create.js +1 -0
- package/dist/execution/workflows/failure.d.ts +23 -6
- package/dist/execution/workflows/failure.js +78 -18
- package/dist/execution/workflows/receiver.d.ts +3 -0
- package/dist/execution/workflows/receiver.js +1 -0
- package/dist/execution/workflows/run.js +13 -9
- package/dist/execution/workflows/steps.d.ts +3 -0
- package/dist/execution/workflows/steps.js +2 -2
- package/dist/platform/schema/kernel-compiled.d.ts +2 -0
- package/dist/platform/schema/kernel-compiled.js +2 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +1 -0
- package/dist/testing/recipe.d.ts +17 -0
- package/dist/testing/recipe.js +34 -0
- package/dist/tooling/cli/orchestrate.js +6 -2
- package/dist/tooling/linter/adapters/typescript/index.d.ts +2 -1
- package/dist/tooling/linter/adapters/typescript/index.js +2 -1
- package/dist/tooling/linter/adapters/typescript/query-observation.js +37 -12
- package/dist/tooling/linter/adapters/typescript/recipe-definitions.d.ts +34 -0
- package/dist/tooling/linter/adapters/typescript/recipe-definitions.js +88 -0
- package/dist/tooling/linter/adapters/typescript/type-analysis.d.ts +2 -0
- package/dist/tooling/linter/adapters/typescript/type-analysis.js +10 -0
- package/dist/tooling/linter/implementations/source/global.js +15 -9
- package/dist/tooling/linter/implementations/source/mutations.js +128 -19
- package/dist/tooling/linter/implementations/source/policy-edges.d.ts +2 -0
- package/dist/tooling/linter/implementations/source/policy-edges.js +113 -0
- package/dist/tooling/linter/implementations/source/recipes.d.ts +2 -0
- package/dist/tooling/linter/implementations/source/recipes.js +425 -0
- package/dist/tooling/linter/implementations/source/shared.d.ts +7 -1
- package/dist/tooling/linter/implementations/source/shared.js +31 -10
- package/dist/tooling/linter/implementations/source/verifiers.js +4 -0
- package/dist/tooling/linter/policy/generated.js +2 -2
- package/dist/tooling/linter/requirements/registry.js +4 -0
- package/docs/durable-workflows.md +48 -20
- package/docs/handler-dependencies.md +76 -4
- package/docs/legacy/query-v6.md +62 -0
- package/docs/queries.md +442 -0
- package/package.json +11 -8
- /package/dist/application/{query/single/query.js → mutation/legacy/v6/builder.js} +0 -0
- /package/dist/application/mutation/{authoring → legacy/v6}/precondition.js +0 -0
- /package/dist/application/query/{collection → legacy/v6/collection}/identity.js +0 -0
- /package/dist/application/query/{collection → legacy/v6/collection}/limits.d.ts +0 -0
- /package/dist/application/query/{collection → legacy/v6/collection}/limits.js +0 -0
- /package/dist/application/query/{collection → legacy/v6/collection}/metadata.js +0 -0
- /package/dist/application/query/{execution → legacy/v6/execution}/pages.d.ts +0 -0
- /package/dist/application/query/{execution → legacy/v6/execution}/pages.js +0 -0
- /package/dist/application/query/{single → legacy/v6/single}/index.d.ts +0 -0
- /package/dist/application/query/{single → legacy/v6/single}/index.js +0 -0
- /package/dist/application/query/{single → legacy/v6/single}/node.d.ts +0 -0
- /package/dist/application/query/{single → legacy/v6/single}/node.js +0 -0
- /package/dist/application/query/{single → legacy/v6/single}/pagination.d.ts +0 -0
- /package/dist/application/query/{single → legacy/v6/single}/selection.d.ts +0 -0
- /package/dist/application/query/{single → legacy/v6/single}/selection.js +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edge ends and the named to-one relations of a Class (S2), grouped once per Schema (D3).
|
|
3
|
+
*/
|
|
4
|
+
import type { HandleMembers } from './conditions.js';
|
|
5
|
+
import type { Cls, EdgesOf, Index, KeyOf, NodeRoot, OriginOf, PropNamesOf, Satisfies, Single } from './domain.js';
|
|
6
|
+
import type { RelSet } from './handles.js';
|
|
7
|
+
/** An Edge's two ends; an undirected Edge's are its two incident ends, in declared order. */
|
|
8
|
+
type EndsOf<E> = E extends {
|
|
9
|
+
readonly definition: {
|
|
10
|
+
readonly endpoints: infer P;
|
|
11
|
+
};
|
|
12
|
+
} ? P extends readonly [infer A, infer B] ? {
|
|
13
|
+
readonly source: A;
|
|
14
|
+
readonly target: B;
|
|
15
|
+
} : P : never;
|
|
16
|
+
type SourceOf<E> = EndsOf<E> extends {
|
|
17
|
+
readonly source: infer End;
|
|
18
|
+
} ? End : never;
|
|
19
|
+
type TargetOf<E> = EndsOf<E> extends {
|
|
20
|
+
readonly target: infer End;
|
|
21
|
+
} ? End : never;
|
|
22
|
+
export type RoleOf<End> = End extends {
|
|
23
|
+
readonly role: infer R extends string;
|
|
24
|
+
} ? R : never;
|
|
25
|
+
type RefKey<A> = A extends {
|
|
26
|
+
readonly origin: infer O extends string;
|
|
27
|
+
readonly name: infer N extends string;
|
|
28
|
+
} ? `${O}:class.${N}` : never;
|
|
29
|
+
type AcceptKeys<End> = End extends {
|
|
30
|
+
readonly accepts: readonly (infer A)[];
|
|
31
|
+
} ? RefKey<A> : never;
|
|
32
|
+
type CountOf<End> = End extends {
|
|
33
|
+
readonly outgoing: infer N;
|
|
34
|
+
} ? N : End extends {
|
|
35
|
+
readonly incoming: infer N;
|
|
36
|
+
} ? N : End extends {
|
|
37
|
+
readonly incident: infer N;
|
|
38
|
+
} ? N : never;
|
|
39
|
+
type Touches<Sat, End> = [Extract<Sat, AcceptKeys<End>>] extends [never] ? false : true;
|
|
40
|
+
/** An end names its relation only if it accepts specific Classes (S2). */
|
|
41
|
+
type Generic = NodeRoot | 'kernel.astrale.ai:class.Identity';
|
|
42
|
+
type Specific<End> = [Extract<AcceptKeys<End>, Generic>] extends [never] ? true : false;
|
|
43
|
+
/** The Class keys an Edge's source accepts, and its role. */
|
|
44
|
+
export type SourceKeys<S, E> = AcceptKeys<SourceOf<Cls<S, E>>> & keyof Index<S>;
|
|
45
|
+
export type TargetKeys<S, E> = AcceptKeys<TargetOf<Cls<S, E>>> & keyof Index<S>;
|
|
46
|
+
export type SourceRole<S, E> = RoleOf<SourceOf<Cls<S, E>>>;
|
|
47
|
+
export type TargetRole<S, E> = RoleOf<TargetOf<Cls<S, E>>>;
|
|
48
|
+
interface Candidate<N extends string, E extends string, Own extends boolean, Far extends string> {
|
|
49
|
+
readonly name: N;
|
|
50
|
+
readonly edge: E;
|
|
51
|
+
readonly own: Own;
|
|
52
|
+
readonly far: Far;
|
|
53
|
+
}
|
|
54
|
+
type IsOwn<S, E> = KeyOf<E> extends `${OriginOf<S>}:${string}` ? true : false;
|
|
55
|
+
type ToOne = '0..1' | '1';
|
|
56
|
+
/** One to-one end: the Class key it accepts, and the relation it names from there. */
|
|
57
|
+
interface EndEntry<At extends string, C> {
|
|
58
|
+
readonly at: At;
|
|
59
|
+
readonly candidate: C;
|
|
60
|
+
}
|
|
61
|
+
type EntriesAt<At, C> = At extends string ? EndEntry<At, C> : never;
|
|
62
|
+
type ToOneEnds<S> = EdgesOf<S> extends infer E ? E extends unknown ? (CountOf<SourceOf<E>> extends ToOne ? Specific<TargetOf<E>> extends true ? EntriesAt<AcceptKeys<SourceOf<E>>, Candidate<RoleOf<TargetOf<E>>, KeyOf<E>, IsOwn<S, E>, AcceptKeys<TargetOf<E>>>> : never : never) | (CountOf<TargetOf<E>> extends ToOne ? Specific<SourceOf<E>> extends true ? EntriesAt<AcceptKeys<TargetOf<E>>, Candidate<RoleOf<SourceOf<E>>, KeyOf<E>, IsOwn<S, E>, AcceptKeys<SourceOf<E>>>> : never : never) : never : never;
|
|
63
|
+
/** Every to-one end of the Domain, grouped by the Class key it accepts: computed once per Schema. */
|
|
64
|
+
type EndsByClass<S> = {
|
|
65
|
+
readonly [P in ToOneEnds<S> as P['at']]: P['candidate'];
|
|
66
|
+
};
|
|
67
|
+
/** The to-one relations a Class may name: one per end it reaches from a to-one end. */
|
|
68
|
+
type CandidatesOf<S, Sat> = EndsByClass<S>[Sat & keyof EndsByClass<S>];
|
|
69
|
+
type NameOf<C> = C extends {
|
|
70
|
+
readonly name: infer N extends string;
|
|
71
|
+
} ? N : never;
|
|
72
|
+
/** The Domain's own relations shadow its dependencies' (S2). */
|
|
73
|
+
type Shadowed<Cs> = Extract<Cs, {
|
|
74
|
+
readonly own: true;
|
|
75
|
+
}> | Exclude<Extract<Cs, {
|
|
76
|
+
readonly own: false;
|
|
77
|
+
}>, {
|
|
78
|
+
readonly name: NameOf<Extract<Cs, {
|
|
79
|
+
readonly own: true;
|
|
80
|
+
}>>;
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* The named to-one relations of one Class (S2), clashing with nothing on the Class. A name two
|
|
84
|
+
* ends claim names neither: its member is a message that says so.
|
|
85
|
+
*/
|
|
86
|
+
export type RelationsOf<S, K> = Shadowed<CandidatesOf<S, Satisfies<S, K>>> extends infer Cs ? {
|
|
87
|
+
readonly [C in Cs as Exclude<NameOf<C>, PropNamesOf<Cls<S, K>> | HandleMembers>]: Single<C> extends true ? C extends Candidate<string, infer E, boolean, infer Far> ? RelSet<S, Far & keyof Index<S>, E, {}, 'value', false> : never : `✗ "${NameOf<C>}" names several relations of this Class: use .via(d.<Edge>)`;
|
|
88
|
+
} : never;
|
|
89
|
+
export interface ViaOptions {
|
|
90
|
+
readonly direction?: 'outgoing' | 'incoming' | 'incident';
|
|
91
|
+
}
|
|
92
|
+
type DirectionOf<S, K, E, O> = O extends {
|
|
93
|
+
readonly direction: infer D;
|
|
94
|
+
} ? D extends 'outgoing' ? Touches<Satisfies<S, K>, SourceOf<Cls<S, E>>> extends true ? D : 'not the source' : D extends 'incoming' ? Touches<Satisfies<S, K>, TargetOf<Cls<S, E>>> extends true ? D : 'not the target' : D : Touches<Satisfies<S, K>, SourceOf<Cls<S, E>>> extends true ? Touches<Satisfies<S, K>, TargetOf<Cls<S, E>>> extends true ? 'ambiguous' : 'outgoing' : Touches<Satisfies<S, K>, TargetOf<Cls<S, E>>> extends true ? 'incoming' : 'none';
|
|
95
|
+
type FarKeys<S, E, Dir> = E extends unknown ? Dir extends 'outgoing' ? AcceptKeys<TargetOf<Cls<S, E>>> : Dir extends 'incoming' ? AcceptKeys<SourceOf<Cls<S, E>>> : AcceptKeys<TargetOf<Cls<S, E>>> | AcceptKeys<SourceOf<Cls<S, E>>> : never;
|
|
96
|
+
/** The Class keys a `.via` reaches. */
|
|
97
|
+
export type Far<S, K, E, O> = FarKeys<S, E, DirectionOf<S, K, E, O>> & keyof Index<S>;
|
|
98
|
+
/** A `.via` whose Edge has no end for this Class, or two, or reaches only foreign Classes. */
|
|
99
|
+
export type ViaCheck<S, K, E, O> = E extends unknown ? DirectionOf<S, K, E, O> extends 'none' ? `✗ ${E & string} has no end that accepts this Class: read it from a Class one of its ends accepts` : DirectionOf<S, K, E, O> extends `not the ${infer End}` ? `✗ this Class is not the ${End} of ${E & string}: check the direction` : DirectionOf<S, K, E, O> extends 'ambiguous' ? `✗ both ends of ${E & string} accept this Class: pass { direction }` : [Far<S, K, E, O>] extends [never] ? `✗ ${E & string} reaches only Classes this Domain does not declare or depend on: depend on the Domain that declares them` : unknown : never;
|
|
100
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a read answers: rows, pages and counts. Rows are portable JSON: `$class` is typed as the
|
|
3
|
+
* Class or any subclass the Domain can name (D6), and a Property whose name is taken goes under
|
|
4
|
+
* `$prop` (F6).
|
|
5
|
+
*/
|
|
6
|
+
import type { NodeId } from '../../../platform/graph/node/index.js';
|
|
7
|
+
import type { ClassOf, Cls, Layout, LayoutOf, PropNamesOf, RequiredEntry, SdkKeys, ValueOfEntry } from './domain.js';
|
|
8
|
+
import type { SourceKeys, SourceRole, TargetKeys, TargetRole } from './relations.js';
|
|
9
|
+
/**
|
|
10
|
+
* Names a row owns (`ROW_KEYS`): `id` and the SDK's keys. A Property named `id` goes under `$prop`
|
|
11
|
+
* (F6); no Property name starts with `$`. Frozen, as `ROW_KEYS` is.
|
|
12
|
+
*/
|
|
13
|
+
export type RowKeys = 'id' | SdkKeys;
|
|
14
|
+
/** An optional Property may be absent from a row (not delivered); `null` is a stored null. */
|
|
15
|
+
type Slot<P> = RequiredEntry<P> extends true ? ValueOfEntry<P> : ValueOfEntry<P> | undefined;
|
|
16
|
+
type ValuesOfLayout<L> = L extends Layout<infer Flat, infer Groups> ? {
|
|
17
|
+
readonly [N in keyof Flat]: Slot<Flat[N]>;
|
|
18
|
+
} & {
|
|
19
|
+
readonly [G in keyof Groups]: {
|
|
20
|
+
readonly [N in keyof Groups[G]]: Slot<Groups[G][N]>;
|
|
21
|
+
};
|
|
22
|
+
} : never;
|
|
23
|
+
type ValuesOf<S, K, Taken> = ValuesOfLayout<LayoutOf<Cls<S, K>, Taken>>;
|
|
24
|
+
/** A Node row: `id`, `$class` and every Property by name. One member per Class of a union. */
|
|
25
|
+
export type Row<S, K> = K extends unknown ? {
|
|
26
|
+
readonly id: NodeId;
|
|
27
|
+
readonly $class: ClassOf<S, K>;
|
|
28
|
+
} & ValuesOf<S, K, RowKeys> : never;
|
|
29
|
+
/** A reference row (`.pick()`): `id` and `$class`. */
|
|
30
|
+
export type Ref<S, K> = K extends unknown ? {
|
|
31
|
+
readonly id: NodeId;
|
|
32
|
+
readonly $class: ClassOf<S, K>;
|
|
33
|
+
} : never;
|
|
34
|
+
/** A row the reader may not read (`.includeWithheld()`): the names of the values withheld. */
|
|
35
|
+
export type WithheldRow<S, K> = K extends unknown ? {
|
|
36
|
+
readonly id: NodeId;
|
|
37
|
+
readonly $class: ClassOf<S, K>;
|
|
38
|
+
readonly $withheld: readonly PropNamesOf<Cls<S, K>>[];
|
|
39
|
+
} : never;
|
|
40
|
+
/**
|
|
41
|
+
* An Edge's identity: its Class and both ends. An object type, not an interface: a recipe's
|
|
42
|
+
* exported declaration then spells it out.
|
|
43
|
+
*/
|
|
44
|
+
type EdgeIdentity<E> = {
|
|
45
|
+
readonly $class: E;
|
|
46
|
+
readonly $source: NodeId;
|
|
47
|
+
readonly $target: NodeId;
|
|
48
|
+
};
|
|
49
|
+
/** An Edge row: its Class, both ends' ids and its Properties. */
|
|
50
|
+
export type EdgeRow<S, E> = E extends unknown ? EdgeIdentity<ClassOf<S, E>> & ValuesOf<S, E, never> : never;
|
|
51
|
+
/** What `.withEdge()` adds to a row under `$edge`: the Edge's Class and its Properties. */
|
|
52
|
+
export type EdgeValues<S, E> = E extends unknown ? {
|
|
53
|
+
readonly $class: ClassOf<S, E>;
|
|
54
|
+
} & ValuesOf<S, E, never> : never;
|
|
55
|
+
type Roles<S, E> = SourceRole<S, E> | TargetRole<S, E>;
|
|
56
|
+
/** An Edge row at the root: its values, and both ends' rows by role. */
|
|
57
|
+
export type EdgeRootRow<S, E> = E extends unknown ? EdgeIdentity<ClassOf<S, E>> & ValuesOf<S, E, Roles<S, E>> & {
|
|
58
|
+
readonly [R in SourceRole<S, E>]: Row<S, SourceKeys<S, E>>;
|
|
59
|
+
} & {
|
|
60
|
+
readonly [R in TargetRole<S, E>]: Row<S, TargetKeys<S, E>>;
|
|
61
|
+
} : never;
|
|
62
|
+
/** An Edge reference row at the root (`.pick()`): both ends as references. */
|
|
63
|
+
export type EdgeRootRef<S, E> = E extends unknown ? EdgeIdentity<ClassOf<S, E>> & {
|
|
64
|
+
readonly [R in SourceRole<S, E>]: Ref<S, SourceKeys<S, E>>;
|
|
65
|
+
} & {
|
|
66
|
+
readonly [R in TargetRole<S, E>]: Ref<S, TargetKeys<S, E>>;
|
|
67
|
+
} : never;
|
|
68
|
+
/** An Edge the reader may not read (`.includeWithheld()`). */
|
|
69
|
+
export type WithheldEdgeRow<S, E> = E extends unknown ? EdgeIdentity<ClassOf<S, E>> & {
|
|
70
|
+
readonly $withheld: readonly PropNamesOf<Cls<S, E>>[];
|
|
71
|
+
} : never;
|
|
72
|
+
/** An Edge's identity, as a Mutation or a guard names it. */
|
|
73
|
+
export interface EdgeKey<E extends string = string> {
|
|
74
|
+
readonly source: NodeId;
|
|
75
|
+
readonly target: NodeId;
|
|
76
|
+
readonly class: E;
|
|
77
|
+
}
|
|
78
|
+
/** The identity of an Edge row. */
|
|
79
|
+
export declare function edgeKey<E extends string>(row: {
|
|
80
|
+
readonly $class: E;
|
|
81
|
+
readonly $source: NodeId;
|
|
82
|
+
readonly $target: NodeId;
|
|
83
|
+
}): EdgeKey<E>;
|
|
84
|
+
/** One page of rows; `next` continues it. */
|
|
85
|
+
export interface Page<T> {
|
|
86
|
+
readonly rows: readonly T[];
|
|
87
|
+
readonly next?: string;
|
|
88
|
+
}
|
|
89
|
+
/** A bounded count: `more` says the count reached its bound. */
|
|
90
|
+
export interface Count {
|
|
91
|
+
readonly count: number;
|
|
92
|
+
readonly more: boolean;
|
|
93
|
+
}
|
|
94
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/** A condition of the canonical JSON, tagged by `op`. */
|
|
2
|
+
export type Where = {
|
|
3
|
+
readonly op: string;
|
|
4
|
+
} & {
|
|
5
|
+
readonly [field: string]: unknown;
|
|
6
|
+
};
|
|
7
|
+
/** What a condition or an order key is written on: one handle, by identity. */
|
|
8
|
+
export interface Scope {
|
|
9
|
+
readonly label: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function scope(label: string): Scope;
|
|
12
|
+
/** Where an order key reads: the item, a relation's Edge, or an Edge root's end. */
|
|
13
|
+
export type KeyTarget = 'item' | 'edge' | 'source' | 'target';
|
|
14
|
+
/** The context a handle writes in: its scope, how its conditions wrap, and its keys' target. */
|
|
15
|
+
export interface Context {
|
|
16
|
+
readonly scope: Scope;
|
|
17
|
+
readonly on: KeyTarget;
|
|
18
|
+
readonly wrap?: (where: Where) => Where;
|
|
19
|
+
}
|
|
20
|
+
/** One conjunct of a condition, on one scope. */
|
|
21
|
+
export interface Conjunct {
|
|
22
|
+
readonly scope: Scope;
|
|
23
|
+
readonly where: Where;
|
|
24
|
+
}
|
|
25
|
+
/** A condition: its conjuncts, or `null` for NEVER. No conjunct at all is ALWAYS. */
|
|
26
|
+
export declare class Condition {
|
|
27
|
+
readonly conjuncts: readonly Conjunct[] | null;
|
|
28
|
+
/** The Class keys a single-argument `is` or `isExactly` narrows to (S3). */
|
|
29
|
+
readonly narrows?: readonly string[] | undefined;
|
|
30
|
+
/** Its conjuncts as written: `conjuncts`, unless the input folds it. */
|
|
31
|
+
readonly written: readonly Conjunct[] | null;
|
|
32
|
+
readonly '~cond' = true;
|
|
33
|
+
constructor(conjuncts: readonly Conjunct[] | null,
|
|
34
|
+
/** The Class keys a single-argument `is` or `isExactly` narrows to (S3). */
|
|
35
|
+
narrows?: readonly string[] | undefined,
|
|
36
|
+
/** Its conjuncts as written: `conjuncts`, unless the input folds it. */
|
|
37
|
+
written?: readonly Conjunct[] | null);
|
|
38
|
+
static readonly ALWAYS: Condition;
|
|
39
|
+
static readonly NEVER: Condition;
|
|
40
|
+
get never(): boolean;
|
|
41
|
+
get always(): boolean;
|
|
42
|
+
/** The input folds it: as written, it is `asWritten`. */
|
|
43
|
+
get folded(): boolean;
|
|
44
|
+
get asWritten(): Condition;
|
|
45
|
+
and(...conditions: readonly unknown[]): Condition;
|
|
46
|
+
or(...conditions: readonly unknown[]): Condition;
|
|
47
|
+
not(): Condition;
|
|
48
|
+
}
|
|
49
|
+
/** A condition the input folds to `to`, which is `written` as written. */
|
|
50
|
+
export declare function foldedTo(to: Condition, written: Condition): Condition;
|
|
51
|
+
/** What `build` makes of some conditions, and as written, what it makes of them as written. */
|
|
52
|
+
export declare function folding(conditions: readonly Condition[], build: (conditions: readonly Condition[]) => Condition): Condition;
|
|
53
|
+
/** One condition from several conjuncts: NEVER if any is. */
|
|
54
|
+
export declare function and(conditions: readonly Condition[]): Condition;
|
|
55
|
+
/** The canonical condition of some conjuncts: one, or their `and`. */
|
|
56
|
+
export declare function whereOf(conjuncts: readonly Conjunct[]): Where;
|
|
57
|
+
/**
|
|
58
|
+
* The conditions a `where` callback returned: a condition, a falsy entry it skips (S6), or a list
|
|
59
|
+
* of those.
|
|
60
|
+
*/
|
|
61
|
+
export declare function kept(conditions: unknown, where?: string): Condition[];
|
|
62
|
+
/** Conditions on a scope: their conjuncts must be written on one of `scopes`. */
|
|
63
|
+
export declare function within(conditions: readonly Condition[], scopes: readonly Scope[]): void;
|
|
64
|
+
export declare function describe(value: unknown): string;
|
|
65
|
+
/** A condition on a handle's scope, wrapped as its context says. */
|
|
66
|
+
export declare function atom(context: Context, where: Where): Condition;
|
|
67
|
+
/** An order key; where it reads is written when its read is lowered. */
|
|
68
|
+
export declare class OrderKey {
|
|
69
|
+
readonly scope: Scope;
|
|
70
|
+
readonly property: string;
|
|
71
|
+
readonly direction: 'asc' | 'desc';
|
|
72
|
+
readonly missing: 'first' | 'last';
|
|
73
|
+
readonly target: KeyTarget;
|
|
74
|
+
readonly '~key' = true;
|
|
75
|
+
constructor(scope: Scope, property: string, direction: 'asc' | 'desc', missing: 'first' | 'last', target: KeyTarget);
|
|
76
|
+
}
|
|
77
|
+
/** The order keys an `orderBy` callback returned, each on one of `scopes`. */
|
|
78
|
+
export declare function orderKeys(ordering: unknown, scopes: readonly Scope[]): OrderKey[];
|
|
79
|
+
/** A value in its spelling: a scalar as itself, an object or an array as `{literal}` (R1). */
|
|
80
|
+
export declare function spell(value: unknown): unknown;
|
|
81
|
+
/**
|
|
82
|
+
* The handle of a Property: one key, or several on a union whose Classes each declare the name
|
|
83
|
+
* (a condition matches any of them; an order key needs one, F7).
|
|
84
|
+
*/
|
|
85
|
+
export declare function propertyHandle(keys: readonly string[], context: Context): object;
|
|
86
|
+
/** A Core node handle (`d.core.<node>`): its key, and the path it lowers to (F10). */
|
|
87
|
+
export declare class CoreNode {
|
|
88
|
+
readonly path: string;
|
|
89
|
+
readonly '~core': string;
|
|
90
|
+
constructor(key: string, path: string);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Whether text is written as a NodePath: it starts with `/` (a Domain anchor) or `@` (a Node's id
|
|
94
|
+
* as its anchor). A NodeId holds neither, so the two never meet.
|
|
95
|
+
*/
|
|
96
|
+
export declare function isPathText(value: unknown): value is string;
|
|
97
|
+
/**
|
|
98
|
+
* The condition a list of targets gives: ids by `id`, an `@<id>` path by its id, so a long list
|
|
99
|
+
* splits as ids do; any other path, and a Core node, by `path`.
|
|
100
|
+
*/
|
|
101
|
+
export declare function targetCondition(context: Context, targets: readonly unknown[]): Condition;
|
|
102
|
+
/** A target as an error names it: its id or its path. */
|
|
103
|
+
export declare function targetLabel(target: unknown): string;
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
export function scope(label) {
|
|
2
|
+
return Object.freeze({ label });
|
|
3
|
+
}
|
|
4
|
+
/** A condition: its conjuncts, or `null` for NEVER. No conjunct at all is ALWAYS. */
|
|
5
|
+
export class Condition {
|
|
6
|
+
conjuncts;
|
|
7
|
+
narrows;
|
|
8
|
+
written;
|
|
9
|
+
'~cond' = true;
|
|
10
|
+
constructor(conjuncts,
|
|
11
|
+
/** The Class keys a single-argument `is` or `isExactly` narrows to (S3). */
|
|
12
|
+
narrows,
|
|
13
|
+
/** Its conjuncts as written: `conjuncts`, unless the input folds it. */
|
|
14
|
+
written = conjuncts) {
|
|
15
|
+
this.conjuncts = conjuncts;
|
|
16
|
+
this.narrows = narrows;
|
|
17
|
+
this.written = written;
|
|
18
|
+
}
|
|
19
|
+
static ALWAYS = new Condition([]);
|
|
20
|
+
static NEVER = new Condition(null);
|
|
21
|
+
get never() {
|
|
22
|
+
return this.conjuncts === null;
|
|
23
|
+
}
|
|
24
|
+
get always() {
|
|
25
|
+
return this.conjuncts !== null && this.conjuncts.length === 0;
|
|
26
|
+
}
|
|
27
|
+
/** The input folds it: as written, it is `asWritten`. */
|
|
28
|
+
get folded() {
|
|
29
|
+
return this.written !== this.conjuncts;
|
|
30
|
+
}
|
|
31
|
+
get asWritten() {
|
|
32
|
+
return this.folded ? new Condition(this.written, this.narrows) : this;
|
|
33
|
+
}
|
|
34
|
+
and(...conditions) {
|
|
35
|
+
return and([this, ...kept(conditions, 'and')]);
|
|
36
|
+
}
|
|
37
|
+
or(...conditions) {
|
|
38
|
+
return or([this, ...kept(conditions, 'or')]);
|
|
39
|
+
}
|
|
40
|
+
not() {
|
|
41
|
+
return folding([this], ([c]) => {
|
|
42
|
+
if (c.conjuncts === null)
|
|
43
|
+
return Condition.ALWAYS;
|
|
44
|
+
if (c.conjuncts.length === 0)
|
|
45
|
+
return Condition.NEVER;
|
|
46
|
+
const scope = only(c, 'a `not`');
|
|
47
|
+
return new Condition([{ scope, where: negated(whereOf(c.conjuncts)) }]);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** A condition the input folds to `to`, which is `written` as written. */
|
|
52
|
+
export function foldedTo(to, written) {
|
|
53
|
+
return new Condition(to.conjuncts, written.narrows, written.written);
|
|
54
|
+
}
|
|
55
|
+
/** What `build` makes of some conditions, and as written, what it makes of them as written. */
|
|
56
|
+
export function folding(conditions, build) {
|
|
57
|
+
const made = build(conditions);
|
|
58
|
+
if (!conditions.some((c) => c.folded))
|
|
59
|
+
return made;
|
|
60
|
+
return foldedTo(made, build(conditions.map((c) => c.asWritten)));
|
|
61
|
+
}
|
|
62
|
+
/** One condition from several conjuncts: NEVER if any is. */
|
|
63
|
+
export function and(conditions) {
|
|
64
|
+
return folding(conditions, (operands) => {
|
|
65
|
+
const conjuncts = [];
|
|
66
|
+
for (const c of operands) {
|
|
67
|
+
if (c.conjuncts === null)
|
|
68
|
+
return Condition.NEVER;
|
|
69
|
+
conjuncts.push(...c.conjuncts);
|
|
70
|
+
}
|
|
71
|
+
return conjuncts.length === 0 ? Condition.ALWAYS : new Condition(conjuncts);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function or(conditions) {
|
|
75
|
+
return folding(conditions, (all) => {
|
|
76
|
+
const operands = all.filter((c) => !c.never);
|
|
77
|
+
if (operands.length === 0)
|
|
78
|
+
return Condition.NEVER;
|
|
79
|
+
if (operands.some((c) => c.always))
|
|
80
|
+
return Condition.ALWAYS;
|
|
81
|
+
if (operands.length === 1)
|
|
82
|
+
return operands[0];
|
|
83
|
+
const scopes = new Set(operands.map((c) => only(c, 'an `or`')));
|
|
84
|
+
if (scopes.size > 1)
|
|
85
|
+
throw new TypeError('An `or` across the node and its Edge is not in Query v7: write one `or` per side.');
|
|
86
|
+
const [scope] = scopes;
|
|
87
|
+
return new Condition([
|
|
88
|
+
{ scope: scope, where: { op: 'or', operands: operands.map((c) => whereOf(c.conjuncts)) } },
|
|
89
|
+
]);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/** The one scope of a condition that is neither NEVER nor ALWAYS. */
|
|
93
|
+
function only(c, what) {
|
|
94
|
+
const scopes = new Set(c.conjuncts.map((x) => x.scope));
|
|
95
|
+
if (scopes.size > 1)
|
|
96
|
+
throw new TypeError(`${what} across the node and its Edge is not in Query v7: write it per side.`);
|
|
97
|
+
return c.conjuncts[0].scope;
|
|
98
|
+
}
|
|
99
|
+
/** The canonical condition of some conjuncts: one, or their `and`. */
|
|
100
|
+
export function whereOf(conjuncts) {
|
|
101
|
+
return conjuncts.length === 1
|
|
102
|
+
? conjuncts[0].where
|
|
103
|
+
: { op: 'and', operands: conjuncts.map((c) => c.where) };
|
|
104
|
+
}
|
|
105
|
+
/** `not`, folding a double negation and a presence. */
|
|
106
|
+
function negated(where) {
|
|
107
|
+
if (where.op === 'not')
|
|
108
|
+
return where.operand;
|
|
109
|
+
if (where.op === 'present')
|
|
110
|
+
return { ...where, present: !where.present };
|
|
111
|
+
return { op: 'not', operand: where };
|
|
112
|
+
}
|
|
113
|
+
const isFalsy = (value) => !value;
|
|
114
|
+
/**
|
|
115
|
+
* The conditions a `where` callback returned: a condition, a falsy entry it skips (S6), or a list
|
|
116
|
+
* of those.
|
|
117
|
+
*/
|
|
118
|
+
export function kept(conditions, where = 'where') {
|
|
119
|
+
const list = Array.isArray(conditions) ? conditions.flat() : [conditions];
|
|
120
|
+
const out = [];
|
|
121
|
+
for (const entry of list) {
|
|
122
|
+
if (entry instanceof Condition)
|
|
123
|
+
out.push(entry);
|
|
124
|
+
else if (!isFalsy(entry))
|
|
125
|
+
throw new TypeError(`${where} takes conditions, falsy entries it skips, or a list of them; got ${describe(entry)}.`);
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
/** Conditions on a scope: their conjuncts must be written on one of `scopes`. */
|
|
130
|
+
export function within(conditions, scopes) {
|
|
131
|
+
for (const c of conditions)
|
|
132
|
+
for (const x of c.written ?? [])
|
|
133
|
+
if (!scopes.includes(x.scope))
|
|
134
|
+
throw new TypeError(`A condition on ${x.scope.label} is not in Query v7 here: a condition reads only the handles its callback receives.`);
|
|
135
|
+
}
|
|
136
|
+
export function describe(value) {
|
|
137
|
+
if (typeof value === 'string')
|
|
138
|
+
return JSON.stringify(value.length > 40 ? `${value.slice(0, 40)}…` : value);
|
|
139
|
+
if (typeof value === 'object' && value !== null)
|
|
140
|
+
return value.constructor?.name ?? 'an object';
|
|
141
|
+
return String(value);
|
|
142
|
+
}
|
|
143
|
+
/** A condition on a handle's scope, wrapped as its context says. */
|
|
144
|
+
export function atom(context, where) {
|
|
145
|
+
return new Condition([
|
|
146
|
+
{ scope: context.scope, where: context.wrap ? context.wrap(where) : where },
|
|
147
|
+
]);
|
|
148
|
+
}
|
|
149
|
+
// ─── Order keys ────────────────────────────────────────────────────────────────────────────────
|
|
150
|
+
/** An order key; where it reads is written when its read is lowered. */
|
|
151
|
+
export class OrderKey {
|
|
152
|
+
scope;
|
|
153
|
+
property;
|
|
154
|
+
direction;
|
|
155
|
+
missing;
|
|
156
|
+
target;
|
|
157
|
+
'~key' = true;
|
|
158
|
+
constructor(scope, property, direction, missing, target) {
|
|
159
|
+
this.scope = scope;
|
|
160
|
+
this.property = property;
|
|
161
|
+
this.direction = direction;
|
|
162
|
+
this.missing = missing;
|
|
163
|
+
this.target = target;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/** The order keys an `orderBy` callback returned, each on one of `scopes`. */
|
|
167
|
+
export function orderKeys(ordering, scopes) {
|
|
168
|
+
const list = Array.isArray(ordering) ? ordering : [ordering];
|
|
169
|
+
return list.map((key) => {
|
|
170
|
+
if (!(key instanceof OrderKey))
|
|
171
|
+
throw new TypeError(`orderBy takes order keys from asc() and desc(); got ${describe(key)}.`);
|
|
172
|
+
if (!scopes.includes(key.scope))
|
|
173
|
+
throw new TypeError(`An order key on ${key.scope.label} is not in Query v7 here: a read orders only by the handles its callback receives.`);
|
|
174
|
+
return key;
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// ─── Values and Properties ─────────────────────────────────────────────────────────────────────
|
|
178
|
+
/** A value in its spelling: a scalar as itself, an object or an array as `{literal}` (R1). */
|
|
179
|
+
export function spell(value) {
|
|
180
|
+
return value !== null && typeof value === 'object' ? { literal: value } : value;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* The handle of a Property: one key, or several on a union whose Classes each declare the name
|
|
184
|
+
* (a condition matches any of them; an order key needs one, F7).
|
|
185
|
+
*/
|
|
186
|
+
export function propertyHandle(keys, context) {
|
|
187
|
+
// A union's name matches if any of its keys does, and is missing only if every key is.
|
|
188
|
+
const condition = (build, op = 'or') => {
|
|
189
|
+
const atoms = keys.map(build);
|
|
190
|
+
return atom(context, atoms.length === 1 ? atoms[0] : { op, operands: atoms });
|
|
191
|
+
};
|
|
192
|
+
const range = (bounds) => {
|
|
193
|
+
for (const bound of Object.values(bounds))
|
|
194
|
+
if (typeof bound !== 'string' && typeof bound !== 'number')
|
|
195
|
+
throw new TypeError(`A range bound is text or a number; got ${describe(bound)}.`);
|
|
196
|
+
return condition((property) => ({ op: 'range', property, ...bounds }));
|
|
197
|
+
};
|
|
198
|
+
const key = (direction, options) => {
|
|
199
|
+
if (keys.length !== 1)
|
|
200
|
+
throw new TypeError('This name is a different Property on each Class of this union: order by a Property of one Class.');
|
|
201
|
+
return new OrderKey(context.scope, keys[0], direction, options?.missing ?? 'last', context.on);
|
|
202
|
+
};
|
|
203
|
+
return Object.freeze({
|
|
204
|
+
eq: (value) => condition((property) => ({ op: 'eq', property, value: spell(value) })),
|
|
205
|
+
in: (values) => {
|
|
206
|
+
if (!Array.isArray(values))
|
|
207
|
+
throw new TypeError(`in takes a list of values; got ${describe(values)}.`);
|
|
208
|
+
if (values.length === 0)
|
|
209
|
+
return foldedTo(Condition.NEVER, condition((property) => ({ op: 'in', property, values: [] })));
|
|
210
|
+
// The Kernel matches a Boolean by eq alone: `in` over booleans is one eq per value.
|
|
211
|
+
if (values.every((value) => typeof value === 'boolean' || value === null))
|
|
212
|
+
return or([...new Set(values)].map((value) => condition((property) => ({ op: 'eq', property, value }))));
|
|
213
|
+
return condition((property) => ({ op: 'in', property, values: values.map(spell) }));
|
|
214
|
+
},
|
|
215
|
+
gt: (value) => range({ gt: value }),
|
|
216
|
+
gte: (value) => range({ gte: value }),
|
|
217
|
+
lt: (value) => range({ lt: value }),
|
|
218
|
+
lte: (value) => range({ lte: value }),
|
|
219
|
+
between: (lower, upper) => range({ gte: lower, lt: upper }),
|
|
220
|
+
startsWith: (prefix) => {
|
|
221
|
+
if (typeof prefix !== 'string')
|
|
222
|
+
throw new TypeError(`startsWith takes text; got ${describe(prefix)}.`);
|
|
223
|
+
return condition((property) => ({ op: 'startsWith', property, prefix }));
|
|
224
|
+
},
|
|
225
|
+
isSet: () => condition((property) => ({ op: 'present', property, present: true })),
|
|
226
|
+
isMissing: () => condition((property) => ({ op: 'present', property, present: false }), 'and'),
|
|
227
|
+
asc: (options) => key('asc', options),
|
|
228
|
+
desc: (options) => key('desc', options),
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
// ─── Targets ───────────────────────────────────────────────────────────────────────────────────
|
|
232
|
+
/** A Core node handle (`d.core.<node>`): its key, and the path it lowers to (F10). */
|
|
233
|
+
export class CoreNode {
|
|
234
|
+
path;
|
|
235
|
+
'~core';
|
|
236
|
+
constructor(key, path) {
|
|
237
|
+
this.path = path;
|
|
238
|
+
this['~core'] = key;
|
|
239
|
+
Object.freeze(this);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Whether text is written as a NodePath: it starts with `/` (a Domain anchor) or `@` (a Node's id
|
|
244
|
+
* as its anchor). A NodeId holds neither, so the two never meet.
|
|
245
|
+
*/
|
|
246
|
+
export function isPathText(value) {
|
|
247
|
+
return typeof value === 'string' && (value.startsWith('/') || value.startsWith('@'));
|
|
248
|
+
}
|
|
249
|
+
/** A NodePath that is a Node's id and no step: `@<id>`, a NodeId being 1 to 255 of `A-Za-z0-9._-`. */
|
|
250
|
+
const ID_PATH = /^@([A-Za-z0-9._-]{1,255})$/;
|
|
251
|
+
/**
|
|
252
|
+
* The condition a list of targets gives: ids by `id`, an `@<id>` path by its id, so a long list
|
|
253
|
+
* splits as ids do; any other path, and a Core node, by `path`.
|
|
254
|
+
*/
|
|
255
|
+
export function targetCondition(context, targets) {
|
|
256
|
+
if (targets.length === 0)
|
|
257
|
+
return foldedTo(Condition.NEVER, atom(context, { op: 'id', ids: [] }));
|
|
258
|
+
const ids = [];
|
|
259
|
+
const paths = [];
|
|
260
|
+
for (const target of targets) {
|
|
261
|
+
if (target instanceof CoreNode)
|
|
262
|
+
paths.push(target.path);
|
|
263
|
+
else if (isPathText(target)) {
|
|
264
|
+
const id = ID_PATH.exec(target)?.[1];
|
|
265
|
+
if (id === undefined)
|
|
266
|
+
paths.push(target);
|
|
267
|
+
else
|
|
268
|
+
ids.push(id);
|
|
269
|
+
}
|
|
270
|
+
else if (typeof target === 'string' && target.length > 0)
|
|
271
|
+
ids.push(target);
|
|
272
|
+
else
|
|
273
|
+
throw new TypeError(`A target is a NodeId, a NodePath or a Core node; got ${describe(target)}.`);
|
|
274
|
+
}
|
|
275
|
+
const id = ids.length > 0 ? { op: 'id', ids } : undefined;
|
|
276
|
+
const path = paths.length > 0 ? { op: 'path', paths } : undefined;
|
|
277
|
+
return atom(context, id && path ? { op: 'or', operands: [id, path] } : (id ?? path));
|
|
278
|
+
}
|
|
279
|
+
/** A target as an error names it: its id or its path. */
|
|
280
|
+
export function targetLabel(target) {
|
|
281
|
+
return target instanceof CoreNode ? target.path : String(target);
|
|
282
|
+
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type { CollectionQuerySpec } from './collection/metadata.js';
|
|
1
|
+
export { defineCompositeQuery, realizeQuery } from './define.js';
|
|
3
2
|
export { executeQuery, type QueryClient, type QueryExecutor } from './execution/index.js';
|
|
4
3
|
export { QueryPaginationError, QueryValueMismatchError, type QueryFailure, type QueryPaginationErrorCode, } from './failure.js';
|
|
5
|
-
export type {
|
|
6
|
-
export { queryResult } from './single/index.js';
|
|
7
|
-
export type { CompleteQueryProjectionContext, PaginatedQuery, ProjectedQuery, QueryPages, QueryPagination, QueryProjectionContext, RawQuery, SingleQuery, } from './single/index.js';
|
|
4
|
+
export type { CompositeQueryDefinition, QueryDefinition, QueryInputOf, QueryOutputOf, QueryPagination, } from './query.js';
|
|
8
5
|
export type { CompositeQuery, ProjectedCompositeQuery, QueryComposition, QueryPlan, QueryPlanInput, QueryPlanOutput, QueryPlanValue, RawCompositeQuery, } from './composite/index.js';
|
|
9
|
-
|
|
10
|
-
export
|
|
6
|
+
export { defineQuery } from './recipe/define.js';
|
|
7
|
+
export { edgeKey, type Count, type EdgeKey, type EdgeRow, type Page, type Ref, type Row, } from './handles/rows.js';
|
|
8
|
+
export type { Handles } from './handles/handles.js';
|
|
9
|
+
export type { InputOf, OutputOf, Recipe } from './recipe/recipe.js';
|
|
10
|
+
export { isQueryError, QueryError, type QueryErrorCode, type QueryErrorDetails, } from './execution/error.js';
|
|
11
|
+
export { runQueryRecipe, type RecipeCallOptions, type RecipeClient, type RecipeOptions, type RecipeQueryOptions, } from './execution/recipe.js';
|
|
12
|
+
export { defineCollectionQuery, queryResult, type CollectionQueryDefinition, type CollectionQuerySpec, type CollectionValue, type CompleteQueryProjectionContext, type PaginatedQuery, type ProjectedQuery, type QueryAstOf, type QueryPages, type QueryProjectionContext, type RawQuery, type SingleQuery, type SingleQueryDefinition, } from './legacy/v6/index.js';
|
|
13
|
+
export * from './legacy/v6/kernel.js';
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { defineCompositeQuery, realizeQuery } from './define.js';
|
|
2
2
|
export { executeQuery } from './execution/index.js';
|
|
3
3
|
export { QueryPaginationError, QueryValueMismatchError, } from './failure.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export
|
|
4
|
+
// Query v7: recipes. `defineQuery` defines a recipe from a string id, and a V6 Query from a function.
|
|
5
|
+
export { defineQuery } from './recipe/define.js';
|
|
6
|
+
export { edgeKey, } from './handles/rows.js';
|
|
7
|
+
export { isQueryError, QueryError, } from './execution/error.js';
|
|
8
|
+
export { runQueryRecipe, } from './execution/recipe.js';
|
|
9
|
+
// Query V6.
|
|
10
|
+
export { defineCollectionQuery, queryResult, } from './legacy/v6/index.js';
|
|
11
|
+
export * from './legacy/v6/kernel.js';
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** The Query v7 language: the static type of a Query's canonical JSON, over one Domain. */
|
|
2
|
+
export { QUERY, type AnyQuery, type Query, type QueryBounds, type QueryBranch, type QueryClassKey, type QueryCondition, type QueryDomainOf, type QueryEdgeClassKey, type QueryNodeClassKey, type QueryOperatorOf, type QueryOrderKey, type QueryPropertyKey, type QueryPropertyValue, type QueryPropertyValues, type QueryRange, type QueryRendering, type QueryRoot, type QueryTraversal, type Refused, type SizedList, type SizedQuery, type TraversalDirection, type UnsizedList, } from './query.js';
|