@jarenjs/linq 0.49.2 → 0.56.0
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/ARCHITECTURE.md +217 -0
- package/README.md +559 -17
- package/docs/APP-PEN.md +1143 -0
- package/docs/CONTRACT-PEN.md +1217 -0
- package/docs/DB-CLIENT.md +814 -0
- package/docs/FLOW-PEN.md +1026 -0
- package/docs/FORMS-PEN.md +940 -0
- package/docs/JSLT-PEN.md +955 -0
- package/docs/LINQ-FORMAT.md +771 -383
- package/docs/MIGRATION-PEN.md +781 -0
- package/docs/MODEL-PEN.md +1083 -0
- package/docs/QUERY-PEN.md +1636 -0
- package/docs/SCHEMA-PEN.md +1218 -0
- package/package.json +57 -4
- package/src/app/action.js +255 -0
- package/src/app/capture.js +63 -0
- package/src/app/define.js +260 -0
- package/src/app/index.js +20 -0
- package/src/app/patch.js +277 -0
- package/src/app/sub.js +106 -0
- package/src/async.js +329 -75
- package/src/capture-root.js +82 -0
- package/src/concurrency.js +9 -4
- package/src/contract/define.js +269 -0
- package/src/contract/http.js +247 -0
- package/src/contract/index.js +23 -0
- package/src/contract/operation.js +342 -0
- package/src/db/handle.js +86 -0
- package/src/db/include.js +316 -0
- package/src/db/index.js +19 -0
- package/src/db/live.js +43 -0
- package/src/db/membership.js +37 -0
- package/src/db/open.js +82 -0
- package/src/document.js +143 -13
- package/src/effect.js +65 -0
- package/src/errors.js +69 -6
- package/src/expression.js +437 -36
- package/src/flow/capture.js +33 -0
- package/src/flow/dag.js +302 -0
- package/src/flow/fsm.js +328 -0
- package/src/flow/index.js +22 -0
- package/src/forms/index.js +43 -0
- package/src/forms/rules.js +170 -0
- package/src/forms/submit.js +177 -0
- package/src/index.js +4 -2
- package/src/jslt/body.js +226 -0
- package/src/jslt/index.js +18 -0
- package/src/jslt/rules.js +207 -0
- package/src/json-boundary.js +90 -0
- package/src/migration/define.js +323 -0
- package/src/migration/index.js +15 -0
- package/src/migration/steps.js +248 -0
- package/src/model/collection.js +171 -0
- package/src/model/define.js +125 -0
- package/src/model/entity.js +307 -0
- package/src/model/index.js +47 -0
- package/src/model/relation.js +85 -0
- package/src/provider.js +137 -20
- package/src/schema/brand.js +31 -0
- package/src/schema/builders.js +526 -0
- package/src/schema/check.js +29 -0
- package/src/schema/emit.js +394 -0
- package/src/schema/factories.js +239 -0
- package/src/schema/index.js +37 -0
- package/src/schema-of.js +24 -0
- package/src/sequence.js +233 -103
- package/src/sources.js +10 -3
- package/types/app.d.ts +293 -0
- package/types/contract.d.ts +371 -0
- package/types/db.d.ts +188 -0
- package/types/flow.d.ts +285 -0
- package/types/forms.d.ts +253 -0
- package/types/index.d.ts +231 -26
- package/types/jslt.d.ts +193 -0
- package/types/migration.d.ts +201 -0
- package/types/model.d.ts +493 -0
- package/types/schema.d.ts +494 -0
package/types/forms.d.ts
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hand-authored declarations for `@jarenjs/linq/forms` — the schema
|
|
3
|
+
* pen's every name, from subclasses that carry the `x-form` vocabulary,
|
|
4
|
+
* plus `assertOnSubmit()`.
|
|
5
|
+
*
|
|
6
|
+
* A rule is an ANNOTATION, so nothing here changes what a builder
|
|
7
|
+
* INFERS: `Infer<>`, `Input<>` and the flags read exactly as they do on
|
|
8
|
+
* the schema pen, and the subclasses exist only so `form()` survives
|
|
9
|
+
* every chained method. What the rules are typed against is the rule
|
|
10
|
+
* CONTEXT: `c.root` is the whole form document, typed by annotation
|
|
11
|
+
* (`(c: RuleContext<Invoice>) => …`) because a member builder is
|
|
12
|
+
* written before the object that will hold it exists — the same limit
|
|
13
|
+
* the flow pen's `context` meets, and TypeScript's own.
|
|
14
|
+
*
|
|
15
|
+
* Every claim here has a runtime twin in `test/linq/forms-pen.test.js`
|
|
16
|
+
* and a compile-level pin in `test/consumer/linq-app.ts`; FORMS-PEN.md
|
|
17
|
+
* is the normative mapping table.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { BoolExpr, DateTime, MemberExpr, StringExpr } from './index.js';
|
|
21
|
+
import type {
|
|
22
|
+
Annotations, BuilderLike, Flag, Infer, Input, Json, JsonSchema, NamedLike, Simplify,
|
|
23
|
+
SchemaBuilder, StringBuilder, NumberBuilder, BooleanBuilder, NullBuilder, ArrayBuilder,
|
|
24
|
+
TupleBuilder, ObjectBuilder, NamedBuilder, WhenBuilder, NeverBuilder,
|
|
25
|
+
} from './schema.js';
|
|
26
|
+
|
|
27
|
+
type AnyBuilder = BuilderLike<any, any, any>;
|
|
28
|
+
type Props = Record<string, AnyBuilder>;
|
|
29
|
+
type Nullify<T, N extends boolean> = N extends true ? T | null : T;
|
|
30
|
+
|
|
31
|
+
// ————— the rule context —————
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The three names a rule query binds (the forms README, "The rule query
|
|
35
|
+
* context"): the whole document at `$`, the field's own value as the
|
|
36
|
+
* `$value` external and its pointer as `$pointer`. `Doc` is the honest
|
|
37
|
+
* top until the callback is annotated.
|
|
38
|
+
*/
|
|
39
|
+
export interface RuleContext<Doc = unknown, Value = unknown> {
|
|
40
|
+
/** The whole form document (`$`) — cross-field is the point. */
|
|
41
|
+
readonly root: MemberExpr<Doc>;
|
|
42
|
+
/** The field's current value (`$value`); an absent field binds `null`. */
|
|
43
|
+
readonly value: MemberExpr<Value>;
|
|
44
|
+
/** The field's data pointer (`$pointer`), `'/vatId'`. */
|
|
45
|
+
readonly pointer: StringExpr;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** A rule: a callback captured over the context, or a query document. */
|
|
49
|
+
export type Rule<Doc = unknown, Value = unknown> =
|
|
50
|
+
| ((context: RuleContext<Doc, Value>) => unknown)
|
|
51
|
+
| { readonly [keyword: string]: unknown };
|
|
52
|
+
|
|
53
|
+
/** The message an `assert` failure renders: an inline template, or a
|
|
54
|
+
* catalog spec (the forms README, "MessageSpec in `x-form.message`"). */
|
|
55
|
+
export type MessageSpec =
|
|
56
|
+
| string
|
|
57
|
+
| { readonly $msgid?: string; readonly message?: string; readonly params?: Record<string, Json> };
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* What `form()` takes — exactly the members `x-form` defines. `preview`
|
|
61
|
+
* is absent on purpose: a field's preview hint is DERIVED from its
|
|
62
|
+
* format by the registry, never authored, and writing it is `JL0102`.
|
|
63
|
+
*/
|
|
64
|
+
export interface FormRules<Doc = unknown, Value = unknown> {
|
|
65
|
+
/** Should the field be shown? Asserted by effective boolean value; fails OPEN. */
|
|
66
|
+
readonly visible?: Rule<Doc, Value>;
|
|
67
|
+
/** Should the field accept input? EBV; fails OPEN. */
|
|
68
|
+
readonly enabled?: Rule<Doc, Value>;
|
|
69
|
+
/** A cross-field preemptive assertion. EBV; fails CLOSED. */
|
|
70
|
+
readonly assert?: Rule<Doc, Value>;
|
|
71
|
+
/** The field's derived value, mapped to plain JSON. */
|
|
72
|
+
readonly computed?: Rule<Doc, Value>;
|
|
73
|
+
/** Shown when `assert` fails. */
|
|
74
|
+
readonly message?: MessageSpec;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ————— the rule-aware builders —————
|
|
78
|
+
|
|
79
|
+
/** The base every untyped kind is built from, plus `form()`. */
|
|
80
|
+
export class FormBuilder<Out = unknown, In = Out, F extends Flag = never> extends SchemaBuilder<Out, In, F> {
|
|
81
|
+
optional(): FormBuilder<Out, In, F | 'optional'>;
|
|
82
|
+
nullable(): FormBuilder<Out | null, In | null, F>;
|
|
83
|
+
default(value: Out): FormBuilder<Out, In, F | 'defaulted'>;
|
|
84
|
+
/** One `x-form` annotation; a second call merges into the same one. */
|
|
85
|
+
form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
|
|
86
|
+
/** As in the schema pen, but `x-form` is owned here. */
|
|
87
|
+
meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export class FormStringBuilder<Out = string, In = Out, F extends Flag = never> extends StringBuilder<Out, In, F> {
|
|
91
|
+
optional(): FormStringBuilder<Out, In, F | 'optional'>;
|
|
92
|
+
nullable(): FormStringBuilder<Out | null, In | null, F>;
|
|
93
|
+
default(value: Out): FormStringBuilder<Out, In, F | 'defaulted'>;
|
|
94
|
+
coerce(): FormStringBuilder<Out, In | number | boolean, F>;
|
|
95
|
+
format(name: 'date-time' | 'date'): FormStringBuilder<DateTime, DateTime, F>;
|
|
96
|
+
format(name: string): this;
|
|
97
|
+
enumOf<const V extends readonly string[]>(values: V): FormStringBuilder<V[number], V[number], F>;
|
|
98
|
+
form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
|
|
99
|
+
meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export class FormNumberBuilder<Out = number, In = Out, F extends Flag = never> extends NumberBuilder<Out, In, F> {
|
|
103
|
+
optional(): FormNumberBuilder<Out, In, F | 'optional'>;
|
|
104
|
+
nullable(): FormNumberBuilder<Out | null, In | null, F>;
|
|
105
|
+
default(value: Out): FormNumberBuilder<Out, In, F | 'defaulted'>;
|
|
106
|
+
coerce(): FormNumberBuilder<Out, In | string, F>;
|
|
107
|
+
enumOf<const V extends readonly number[]>(values: V): FormNumberBuilder<V[number], V[number] | Exclude<In, number>, F>;
|
|
108
|
+
form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
|
|
109
|
+
meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
declare class FormBooleanBuilder<Out = boolean, In = Out, F extends Flag = never> extends BooleanBuilder<Out, In, F> {
|
|
113
|
+
optional(): FormBooleanBuilder<Out, In, F | 'optional'>;
|
|
114
|
+
nullable(): FormBooleanBuilder<Out | null, In | null, F>;
|
|
115
|
+
default(value: Out): FormBooleanBuilder<Out, In, F | 'defaulted'>;
|
|
116
|
+
coerce(): FormBooleanBuilder<Out, In | string, F>;
|
|
117
|
+
form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
|
|
118
|
+
meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
declare class FormNullBuilder<Out = null, In = Out, F extends Flag = never> extends NullBuilder<Out, In, F> {
|
|
122
|
+
optional(): FormNullBuilder<Out, In, F | 'optional'>;
|
|
123
|
+
default(value: Out): FormNullBuilder<Out, In, F | 'defaulted'>;
|
|
124
|
+
coerce(): FormNullBuilder<Out, In | string, F>;
|
|
125
|
+
form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
|
|
126
|
+
meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export class FormArrayBuilder<Out = unknown[], In = Out, F extends Flag = never> extends ArrayBuilder<Out, In, F> {
|
|
130
|
+
optional(): FormArrayBuilder<Out, In, F | 'optional'>;
|
|
131
|
+
nullable(): FormArrayBuilder<Out | null, In | null, F>;
|
|
132
|
+
default(value: Out): FormArrayBuilder<Out, In, F | 'defaulted'>;
|
|
133
|
+
form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
|
|
134
|
+
meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export class FormTupleBuilder<
|
|
138
|
+
T extends readonly AnyBuilder[], R = unknown, RIn = R,
|
|
139
|
+
N extends boolean = false, F extends Flag = never,
|
|
140
|
+
> extends TupleBuilder<T, R, RIn, N, F> {
|
|
141
|
+
optional(): FormTupleBuilder<T, R, RIn, N, F | 'optional'>;
|
|
142
|
+
nullable(): FormTupleBuilder<T, R, RIn, true, F>;
|
|
143
|
+
rest<B extends AnyBuilder>(builder: B): FormTupleBuilder<T, Infer<B>, Input<B>, N, F>;
|
|
144
|
+
form<Doc = unknown>(rules: FormRules<Doc, unknown>): this;
|
|
145
|
+
meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export class FormObjectBuilder<
|
|
149
|
+
P extends Props, Open extends boolean = false, PV = never, PVIn = PV,
|
|
150
|
+
N extends boolean = false, F extends Flag = never,
|
|
151
|
+
> extends ObjectBuilder<P, Open, PV, PVIn, N, F> {
|
|
152
|
+
optional(): FormObjectBuilder<P, Open, PV, PVIn, N, F | 'optional'>;
|
|
153
|
+
nullable(): FormObjectBuilder<P, Open, PV, PVIn, true, F>;
|
|
154
|
+
open(): FormObjectBuilder<P, true, PV, PVIn, N, F>;
|
|
155
|
+
patternProperties<M extends Props>(map: M): FormObjectBuilder<P, Open, Infer<M[keyof M]>, Input<M[keyof M]>, N, F>;
|
|
156
|
+
extend<Q extends Props>(props: Q): FormObjectBuilder<Simplify<Omit<P, keyof Q> & Q>, Open, PV, PVIn, N, F>;
|
|
157
|
+
pick<K extends keyof P & string>(keys: readonly K[]): FormObjectBuilder<Pick<P, K>, Open, PV, PVIn, N, F>;
|
|
158
|
+
omit<K extends keyof P & string>(keys: readonly K[]): FormObjectBuilder<Omit<P, K>, Open, PV, PVIn, N, F>;
|
|
159
|
+
/** A rule on the ROOT's `visible` is refused by `compileFormRules`:
|
|
160
|
+
* hiding the whole form would null the render tree and its summary. */
|
|
161
|
+
form<Doc = unknown>(rules: FormRules<Doc, unknown>): this;
|
|
162
|
+
meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
declare class FormNamedBuilder<Out, In = Out, F extends Flag = never> extends NamedBuilder<Out, In, F> {
|
|
166
|
+
optional(): FormNamedBuilder<Out, In, F | 'optional'>;
|
|
167
|
+
nullable(): FormNamedBuilder<Out | null, In | null, F>;
|
|
168
|
+
form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
|
|
169
|
+
meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* `when()` on this pen. A conditional carries a rule like any other
|
|
174
|
+
* node: `buildFormModel` reads `x-form` off whatever schema it builds a
|
|
175
|
+
* field for, so a `when()` used as an object MEMBER answers a field whose
|
|
176
|
+
* rules evaluate — the runtime twin is in `test/linq/forms-pen.test.js`.
|
|
177
|
+
* `Value` is `unknown` here, as on the object and tuple builders: the
|
|
178
|
+
* node describes a shape rather than a value.
|
|
179
|
+
*/
|
|
180
|
+
export class FormWhenBuilder<F extends Flag = never> extends WhenBuilder<F> {
|
|
181
|
+
optional(): FormWhenBuilder<F | 'optional'>;
|
|
182
|
+
then(builder: AnyBuilder): FormWhenBuilder<F>;
|
|
183
|
+
else(builder: AnyBuilder): FormWhenBuilder<F>;
|
|
184
|
+
form<Doc = unknown>(rules: FormRules<Doc, unknown>): this;
|
|
185
|
+
meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* `never()` on this pen — and `never()` ANSWERS one, so a caller meets
|
|
190
|
+
* this class without narrowing to it. A rule is an annotation and
|
|
191
|
+
* `false` carries no annotation, so `form()` and `meta()` both raise
|
|
192
|
+
* `JL0102` here: `form()` is not declared at all, and `meta()` is
|
|
193
|
+
* inherited from `NeverBuilder` with a `never` parameter, so neither
|
|
194
|
+
* call compiles either. `nullable()` widens the node and hands back this
|
|
195
|
+
* pen's base builder, where both are legal again.
|
|
196
|
+
*/
|
|
197
|
+
export class FormNeverBuilder<Out = never, In = Out, F extends Flag = never> extends NeverBuilder<Out, In, F> {
|
|
198
|
+
optional(): FormNeverBuilder<Out, In, F | 'optional'>;
|
|
199
|
+
/** As on the schema pen: widening to admit `null` is what makes a rule
|
|
200
|
+
* writable, so it answers this pen's base builder. */
|
|
201
|
+
nullable(): FormBuilder<Out | null, In | null, F>;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ————— the named factories —————
|
|
205
|
+
|
|
206
|
+
export function string(): FormStringBuilder;
|
|
207
|
+
export function number(): FormNumberBuilder;
|
|
208
|
+
export function integer(): FormNumberBuilder;
|
|
209
|
+
export function boolean(): FormBooleanBuilder;
|
|
210
|
+
export function nil(): FormNullBuilder;
|
|
211
|
+
export function literal<const V extends Json>(value: V): FormBuilder<V, V>;
|
|
212
|
+
export function enumOf<const V extends readonly Json[]>(values: V): FormBuilder<V[number], V[number]>;
|
|
213
|
+
export function object<P extends Props>(props: P): FormObjectBuilder<P>;
|
|
214
|
+
export function array<B extends AnyBuilder>(items: B): FormArrayBuilder<Infer<B>[], Input<B>[]>;
|
|
215
|
+
export function tuple<T extends readonly AnyBuilder[]>(items: readonly [...T]): FormTupleBuilder<T>;
|
|
216
|
+
export function record<B extends AnyBuilder>(values: B):
|
|
217
|
+
FormBuilder<{ [key: string]: Infer<B> }, { [key: string]: Input<B> }>;
|
|
218
|
+
export function union<T extends readonly AnyBuilder[]>(options: readonly [...T]):
|
|
219
|
+
FormBuilder<Infer<T[number]>, Input<T[number]>>;
|
|
220
|
+
export function discriminated<K extends string, T extends readonly BuilderLike<Record<K, unknown>, any, any>[]>(
|
|
221
|
+
key: K, options: readonly [...T]): FormBuilder<Infer<T[number]>, Input<T[number]>>;
|
|
222
|
+
export function intersection<T extends readonly AnyBuilder[]>(parts: readonly [...T]):
|
|
223
|
+
FormBuilder<Intersect<{ [I in keyof T]: Infer<T[I]> }>, Intersect<{ [I in keyof T]: Input<T[I]> }>>;
|
|
224
|
+
type Intersect<T extends readonly unknown[]> = T extends readonly [infer H, ...infer R] ? H & Intersect<R> : unknown;
|
|
225
|
+
export function named<B extends AnyBuilder>(name: string, builder: B): FormNamedBuilder<Infer<B>, Input<B>>;
|
|
226
|
+
export function ref<T = unknown>(name: string): FormBuilder<T, T>;
|
|
227
|
+
export function lazy<T, I = T>(thunk: () => NamedLike<T, I>): FormBuilder<T, I>;
|
|
228
|
+
export function any(): FormBuilder<unknown, unknown>;
|
|
229
|
+
export function never(): FormNeverBuilder;
|
|
230
|
+
export function when(cond: AnyBuilder): FormWhenBuilder;
|
|
231
|
+
export function from<T = unknown>(json: JsonSchema | boolean): FormBuilder<T, T>;
|
|
232
|
+
export function document(root: AnyBuilder, options?: { draft?: '2020-12' }): JsonSchema | boolean;
|
|
233
|
+
export function datetime(): FormStringBuilder<DateTime, DateTime>;
|
|
234
|
+
export function date(): FormStringBuilder<DateTime, DateTime>;
|
|
235
|
+
export function time(): FormStringBuilder;
|
|
236
|
+
export function duration(): FormStringBuilder;
|
|
237
|
+
|
|
238
|
+
/** The mixin the classes above are built with: a NEW class carrying `form()`. */
|
|
239
|
+
export function withForm<B extends new (...args: any[]) => any>(Base: B): B;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* The submit twin of a document's `x-form.assert` rules (the forms
|
|
243
|
+
* README's layer 3): every assert copied onto the ROOT as its own
|
|
244
|
+
* `allOf` branch `{ $query, errorMessage }`, so the rule an author wrote
|
|
245
|
+
* once for per-keystroke feedback is what the compiled validator
|
|
246
|
+
* enforces. A document with no assert answers itself.
|
|
247
|
+
*/
|
|
248
|
+
export function assertOnSubmit(root: AnyBuilder | JsonSchema): JsonSchema;
|
|
249
|
+
|
|
250
|
+
export const SCHEMA_BUILDER: unique symbol;
|
|
251
|
+
export function isSchemaBuilder(value: unknown): value is BuilderLike;
|
|
252
|
+
export function schemaOf(value: unknown): unknown;
|
|
253
|
+
export type { BoolExpr };
|
package/types/index.d.ts
CHANGED
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
* EVERY string a date. Purely a type-level marker — the runtime value is a plain
|
|
20
20
|
* RFC 3339 string; there is no constructor and no runtime cost.
|
|
21
21
|
*/
|
|
22
|
-
export type DateTime = string & {
|
|
22
|
+
export type DateTime = string & { __jarenTag: 'date-time' };
|
|
23
|
+
|
|
24
|
+
import type { SchemaBuilder } from './schema.js';
|
|
23
25
|
|
|
24
26
|
/** The phantom carrier every expression type extends: `__value` never
|
|
25
27
|
* exists at runtime; it lets projections infer their unwrapped shape. */
|
|
@@ -65,7 +67,7 @@ export interface NumberExpr extends ExprBase<number>, EqExpr<number> {
|
|
|
65
67
|
context?: CalendarContext): NumberExpr;
|
|
66
68
|
}
|
|
67
69
|
|
|
68
|
-
export interface StringExpr extends ExprBase<string>, EqExpr<string
|
|
70
|
+
export interface StringExpr extends ExprBase<string>, EqExpr<string>, SpatialMethods {
|
|
69
71
|
lt(value: string | StringExpr): BoolExpr;
|
|
70
72
|
le(value: string | StringExpr): BoolExpr;
|
|
71
73
|
gt(value: string | StringExpr): BoolExpr;
|
|
@@ -236,22 +238,82 @@ export interface SeriesMethods {
|
|
|
236
238
|
Expr<AsOfMatch[]> & AggregatableExpr;
|
|
237
239
|
}
|
|
238
240
|
|
|
239
|
-
|
|
241
|
+
/** A geometry operand: a GeoJSON geometry or position, a WKT string,
|
|
242
|
+
* or an expression yielding one. */
|
|
243
|
+
export type GeoOperand = ExprBase<unknown> | object | readonly number[] | string;
|
|
244
|
+
|
|
245
|
+
/** The §8.14 family, one method per operator, on every expression kind
|
|
246
|
+
* a geometry can be — a position or bbox array, a GeoJSON object, a WKT
|
|
247
|
+
* or geohash string — and on the honest top. Measurements are numbers,
|
|
248
|
+
* cells and text are strings, a bbox and a centroid are positions; a
|
|
249
|
+
* result that is a geometry stays `UnknownExpr`, because a GeoJSON
|
|
250
|
+
* shape is not a TypeScript type this surface can promise. */
|
|
251
|
+
export interface SpatialMethods {
|
|
252
|
+
/** `[west, south, east, north]` of the value's positions. */
|
|
253
|
+
bbox(): ArrayExpr<number>;
|
|
254
|
+
/** Square metres of the value's polygons (`$area`). */
|
|
255
|
+
geoArea(): NumberExpr;
|
|
256
|
+
/** Metres of the value's lines and ring perimeters (`$length`). */
|
|
257
|
+
geoLength(): NumberExpr;
|
|
258
|
+
/** The mean of the value's positions, as a position. */
|
|
259
|
+
centroid(): ArrayExpr<number>;
|
|
260
|
+
/** Metres between the two representative positions. */
|
|
261
|
+
distance(other: GeoOperand): NumberExpr;
|
|
262
|
+
/** Is this value's representative position inside `region`'s surface? */
|
|
263
|
+
within(region: GeoOperand): BoolExpr;
|
|
264
|
+
/** Do the two bounding boxes overlap? Touching edges count. */
|
|
265
|
+
bboxIntersects(other: GeoOperand): BoolExpr;
|
|
266
|
+
/** The base-32 geohash cell (precision 1–12, default 9). */
|
|
267
|
+
geohash(precision?: number | NumberExpr): StringExpr;
|
|
268
|
+
/** A Well-Known Text string → the geometry it denotes. */
|
|
269
|
+
geoParse(): UnknownExpr;
|
|
270
|
+
/** Any value → its Well-Known Text. */
|
|
271
|
+
geoText(): StringExpr;
|
|
272
|
+
/** A cell string → the `Polygon` covering that cell. */
|
|
273
|
+
geohashBounds(): UnknownExpr;
|
|
274
|
+
/** A cell string → the cell and its neighbours, a SEQUENCE of up to
|
|
275
|
+
* nine cell strings (aggregate it, or `at()` is not available). */
|
|
276
|
+
geohashNeighbours(): StringExpr & AggregatableExpr;
|
|
277
|
+
/** The same value with vertices dropped; the tolerance is in degrees. */
|
|
278
|
+
geoSimplify(tolerance: number | NumberExpr): UnknownExpr;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export interface ArrayExpr<E> extends ExprBase<E[]>, SeriesMethods, SpatialMethods {
|
|
240
282
|
eq(value: readonly E[] | ArrayExpr<E> | null): BoolExpr;
|
|
241
283
|
ne(value: readonly E[] | ArrayExpr<E> | null): BoolExpr;
|
|
242
284
|
/** Do two half-open `{start, end}` intervals share an instant?
|
|
243
285
|
* Touching spans do not. */
|
|
244
286
|
overlaps(other: Interval | ExprBase<unknown>): BoolExpr;
|
|
245
287
|
/** Fan the elements out (`[*]`) — a MANY-cardinality expression the
|
|
246
|
-
* aggregates
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
*
|
|
288
|
+
* aggregates and the §8.16 sequence operators apply to
|
|
289
|
+
* (`u.tags.all().count()`, `rows.all().resample(spec)`); an object
|
|
290
|
+
* element's members are fanned with it (`lines.all().amount.sum()`). */
|
|
291
|
+
all(): FannedExpr<E>;
|
|
292
|
+
/** The element at a 0-based index; negative counts from the end. A
|
|
293
|
+
* computed index is an expression — the engine's `$get` — which is
|
|
294
|
+
* what an app-pen patch path lowers to a `$concat` pointer. */
|
|
295
|
+
at(index: number | NumberExpr): Expr<E>;
|
|
296
|
+
/** `$count`. Over a GROUP — a `groupBy`'s `items`, a group-join's
|
|
297
|
+
* group — this is the number of rows, because the chain knows those
|
|
298
|
+
* are rows and fans them (QUERY-PEN.md §13.3). Over an array a caller
|
|
299
|
+
* stored, it counts the array as one item, because at capture time an
|
|
300
|
+
* array member and a scalar member are the same path: fan it first
|
|
301
|
+
* (`u.tags.all().count()`), or ask `exists()` what this would
|
|
302
|
+
* otherwise be answering. */
|
|
252
303
|
count(): NumberExpr;
|
|
304
|
+
/** Cosine similarity to another vector (§8.15): a captured array
|
|
305
|
+
* embeds as a literal, a `params()` binding stays an external. Only a
|
|
306
|
+
* numeric array is a vector. */
|
|
307
|
+
similarity(this: ArrayExpr<number>, other: readonly number[] | ArrayExpr<number>): NumberExpr;
|
|
253
308
|
}
|
|
254
309
|
|
|
310
|
+
/** A fanned path (`$.lines[*]`): the element's expression, aggregatable,
|
|
311
|
+
* and — for an object element — every member is a fanned path too
|
|
312
|
+
* (`$.lines[*].amount`), so it aggregates without a second `all()`. */
|
|
313
|
+
export type FannedExpr<E> = Expr<E> & AggregatableExpr & SeriesMethods &
|
|
314
|
+
([E] extends [readonly unknown[]] ? {} :
|
|
315
|
+
[E] extends [object] ? { readonly [K in keyof E & string]-?: MemberExpr<E[K]> & AggregatableExpr } : {});
|
|
316
|
+
|
|
255
317
|
/** Aggregates available on any expression (a fanned path, a group). */
|
|
256
318
|
export interface AggregatableExpr {
|
|
257
319
|
count(): NumberExpr;
|
|
@@ -262,16 +324,25 @@ export interface AggregatableExpr {
|
|
|
262
324
|
}
|
|
263
325
|
|
|
264
326
|
/** An object's expression: exactly its properties, recursively typed —
|
|
265
|
-
* which is what makes a misspelled member a compile error.
|
|
266
|
-
|
|
267
|
-
|
|
327
|
+
* which is what makes a misspelled member a compile error. A GeoJSON
|
|
328
|
+
* object carries the spatial family; a `{ start, end }` object the
|
|
329
|
+
* interval test. */
|
|
330
|
+
export type ObjectExpr<T> = ExprBase<T> & EqExpr<T> & SpatialMethods & {
|
|
331
|
+
/** Do two half-open `{start, end}` intervals share an instant? */
|
|
332
|
+
overlaps(other: Interval | ExprBase<unknown>): BoolExpr;
|
|
333
|
+
} & {
|
|
334
|
+
readonly [K in keyof T & string]-?: MemberExpr<T[K]>;
|
|
268
335
|
};
|
|
269
336
|
|
|
337
|
+
/** A member's expression: an `unknown` (or `any`) member is the honest
|
|
338
|
+
* top, never the first conditional arm `Expr<>` would pick for it. */
|
|
339
|
+
export type MemberExpr<V> = unknown extends V ? UnknownExpr : Expr<NonNullable<V>>;
|
|
340
|
+
|
|
270
341
|
/** The honest top: everything is available, nothing is precise. Used
|
|
271
342
|
* where inference ends (dynamic `get`, post-operator members, unknown
|
|
272
343
|
* elements) — wide, never wrong. */
|
|
273
344
|
export interface UnknownExpr
|
|
274
|
-
extends ExprBase<unknown>, AggregatableExpr, DateMethods, SeriesMethods {
|
|
345
|
+
extends ExprBase<unknown>, AggregatableExpr, DateMethods, SeriesMethods, SpatialMethods {
|
|
275
346
|
eq(value: unknown): BoolExpr;
|
|
276
347
|
ne(value: unknown): BoolExpr;
|
|
277
348
|
lt(value: unknown): BoolExpr;
|
|
@@ -299,9 +370,11 @@ export interface UnknownExpr
|
|
|
299
370
|
substring(start: number, length?: number): UnknownExpr;
|
|
300
371
|
replace(pattern: string, replacement: string): UnknownExpr;
|
|
301
372
|
all(): UnknownExpr;
|
|
302
|
-
at(index: number): UnknownExpr;
|
|
373
|
+
at(index: number | NumberExpr): UnknownExpr;
|
|
303
374
|
/** Do two half-open `{start, end}` intervals share an instant? */
|
|
304
375
|
overlaps(other: Interval | ExprBase<unknown>): BoolExpr;
|
|
376
|
+
/** Cosine similarity (§8.15) — wide, on the honest top. */
|
|
377
|
+
similarity(other: unknown): NumberExpr;
|
|
305
378
|
}
|
|
306
379
|
|
|
307
380
|
/** Value type → expression type. Order matters: the DateTime brand is
|
|
@@ -342,17 +415,90 @@ export interface OrderOptions {
|
|
|
342
415
|
collation?: string;
|
|
343
416
|
}
|
|
344
417
|
|
|
345
|
-
/**
|
|
418
|
+
/** One row of a provider's relation table (MODEL-FORMAT §10.1, as a
|
|
419
|
+
* store spells it): the declared relation as plain data a hop lowers
|
|
420
|
+
* from. A foreign-key relation names its key column (`via`), the entity
|
|
421
|
+
* holding it (`fkEntity`), the entity it references (`fkTargets`) and the
|
|
422
|
+
* key it references there (`targetKey`); `kind` says which side holds the
|
|
423
|
+
* key. A many-to-many names its `joinTable` and is refused (`JL0105`). */
|
|
424
|
+
export interface RelationEntry {
|
|
425
|
+
readonly to: string;
|
|
426
|
+
readonly kind: 'oneToOne' | 'oneToMany' | 'manyToMany';
|
|
427
|
+
readonly via?: string;
|
|
428
|
+
readonly fkEntity?: string;
|
|
429
|
+
readonly fkTargets?: string;
|
|
430
|
+
readonly joinTable?: string;
|
|
431
|
+
readonly targetKey: string;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/** A provider's relation table: one entry per relation member of the
|
|
435
|
+
* rows it serves. */
|
|
436
|
+
export type RelationTable = Readonly<Record<string, RelationEntry>>;
|
|
437
|
+
|
|
438
|
+
/** One relation hop a callback navigated (QUERY-PEN §4, relation
|
|
439
|
+
* navigation): the member read, the relation's kind, and the binding
|
|
440
|
+
* the lowered correlated phrase ranges over (`r1`, `r2`, …). */
|
|
441
|
+
export interface Hop {
|
|
442
|
+
member: string;
|
|
443
|
+
kind: 'oneToOne' | 'oneToMany';
|
|
444
|
+
binding: string;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** The provider contract (D2, QUERY-PEN §8): any object exposing
|
|
346
448
|
* `execute(document, options)`. The document arrives whole; the return
|
|
347
|
-
* value uses the engine's result mapping.
|
|
348
|
-
|
|
449
|
+
* value uses the engine's result mapping. `T` is the item type — read
|
|
450
|
+
* from the `__item` phantom a typed provider carries (a typed entity
|
|
451
|
+
* set), stated by the caller (`from<T>(provider)`), or `unknown`. */
|
|
452
|
+
export interface Provider<T = unknown> {
|
|
453
|
+
/** The item phantom: never present at runtime; what `from` infers `T` from. */
|
|
454
|
+
readonly __item?: T;
|
|
349
455
|
execute(document: unknown, options: { externals: Record<string, unknown> }): unknown;
|
|
456
|
+
/** The root expression the items are bound through (`'$.Post[*]'`);
|
|
457
|
+
* absent means the whole input, `'$[*]'`. */
|
|
458
|
+
readonly root?: string;
|
|
459
|
+
/** The entity roots a store-level provider serves when it has no root
|
|
460
|
+
* of its own — `from()` refuses it (`JL0007`) naming them. */
|
|
461
|
+
readonly roots?: readonly string[];
|
|
462
|
+
/** An identity two providers share when their documents may be joined
|
|
463
|
+
* (one store's entity sets). When it carries `relations` — the tables
|
|
464
|
+
* of every root of the scope, keyed by root name — a hop continues
|
|
465
|
+
* into another root (`p.author.posts`). */
|
|
466
|
+
readonly scope?: unknown;
|
|
467
|
+
/** The relation table of the rows this provider serves: a relation
|
|
468
|
+
* member on the chain then hops (§3), lowered to a correlated phrase. */
|
|
469
|
+
readonly relations?: RelationTable;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/** The asynchronous provider (D8, §12): the same members, and `execute`
|
|
473
|
+
* may answer a promise — `fromAsync(provider)` awaits it, and the whole
|
|
474
|
+
* chain up to a `mapAsync` arrives as ONE document. */
|
|
475
|
+
export interface AsyncProvider<T = unknown> {
|
|
476
|
+
readonly __item?: T;
|
|
477
|
+
execute(document: unknown, options: { externals: Record<string, unknown> }): unknown | Promise<unknown>;
|
|
478
|
+
readonly root?: string;
|
|
479
|
+
readonly roots?: readonly string[];
|
|
480
|
+
readonly scope?: unknown;
|
|
481
|
+
readonly relations?: RelationTable;
|
|
350
482
|
}
|
|
351
483
|
|
|
484
|
+
/** The engine's compile registries, under the engine's own option names
|
|
485
|
+
* (QUERY-PEN §8.1): what makes an expressible document executable in
|
|
486
|
+
* memory. Their shapes are the query engine's — wide here, never wrong. */
|
|
352
487
|
export interface LinqOptions {
|
|
353
488
|
/** Enables `ofType`/`cast` (schema operators); e.g.
|
|
354
489
|
* `createTypeTestCompiler()` from `@jarenjs/validate/query`. */
|
|
355
490
|
compileTypeTest?: (schema: unknown, docPath: string) => (value: unknown) => boolean;
|
|
491
|
+
/** Registered `$call` functions, for a hand-written or saved document. */
|
|
492
|
+
functions?: Readonly<Record<string, (...args: any[]) => unknown>>;
|
|
493
|
+
/** Named collations: `orderBy(…, { collation })` is `JQ0010` without one. */
|
|
494
|
+
collations?: Readonly<Record<string, (a: string, b: string) => number>>;
|
|
495
|
+
/** Custom RFC 9535 path function extensions. */
|
|
496
|
+
pathFunctions?: Readonly<Record<string, unknown>>;
|
|
497
|
+
/** Step, depth and sequence bounds — a SAVED document's guard. */
|
|
498
|
+
limits?: Readonly<Record<string, number>>;
|
|
499
|
+
/** An explicit cache-partition key, when the hooks above are rebuilt
|
|
500
|
+
* per call: compiled documents are shared per registry combination. */
|
|
501
|
+
registry?: object;
|
|
356
502
|
}
|
|
357
503
|
|
|
358
504
|
export interface Explanation {
|
|
@@ -364,6 +510,13 @@ export interface Explanation {
|
|
|
364
510
|
readonly functions: readonly string[];
|
|
365
511
|
readonly collations: readonly string[];
|
|
366
512
|
};
|
|
513
|
+
/** The relation hops the chain's callbacks navigated, in capture
|
|
514
|
+
* order; a join's inner sequence's hops precede the join's own. */
|
|
515
|
+
hops: Hop[];
|
|
516
|
+
/** The values `params()` bound, by name — what a provider receives as
|
|
517
|
+
* `externals` when the document runs, so a host handed the chain (a
|
|
518
|
+
* live registration) can carry them without a second spelling. */
|
|
519
|
+
bindings: Record<string, unknown>;
|
|
367
520
|
}
|
|
368
521
|
|
|
369
522
|
/** The deferred, immutable sequence of `T` with declared params `P`. */
|
|
@@ -389,6 +542,10 @@ export class Sequence<T = unknown, P = {}> {
|
|
|
389
542
|
result: (outer: Expr<T>, inner: Expr<U>, p: ParamsExpr<P>) => R,
|
|
390
543
|
): Sequence<Unwrap<R>, P>;
|
|
391
544
|
|
|
545
|
+
/** The matching inner group is bound as an ARRAY value: index it
|
|
546
|
+
* (`g.at(0)`), fan it (`g.all()`), place it in a member (`{ all: g }`),
|
|
547
|
+
* and aggregate over its MEMBERS (`g.count()` is the number of
|
|
548
|
+
* matches, `g.exists()` whether there are any). */
|
|
392
549
|
groupJoin<U, R extends ExprResult>(
|
|
393
550
|
inner: Sequence<U, any>,
|
|
394
551
|
outerKey: (it: Expr<T>, p: ParamsExpr<P>) => ExprResult,
|
|
@@ -406,13 +563,21 @@ export class Sequence<T = unknown, P = {}> {
|
|
|
406
563
|
concat(other: Sequence<T, any> | readonly T[]): Sequence<T, P>;
|
|
407
564
|
defaultIfEmpty(fallback?: T | null): Sequence<T | null, P>;
|
|
408
565
|
|
|
409
|
-
/** Keep items the schema accepts.
|
|
410
|
-
*
|
|
566
|
+
/** Keep items the schema accepts. A schema-pen builder carries its
|
|
567
|
+
* own shape (`Infer<>`); for a hand-written document `S` is
|
|
568
|
+
* caller-asserted (a JSON Schema is not a TypeScript type) and the
|
|
569
|
+
* default is honest `unknown`. */
|
|
570
|
+
ofType<S>(schema: SchemaBuilder<S, any, any>): Sequence<S, P>;
|
|
411
571
|
ofType<S = unknown>(schema: object): Sequence<S, P>;
|
|
572
|
+
cast<S>(schema: SchemaBuilder<S, any, any>): Sequence<S, P>;
|
|
412
573
|
cast<S = unknown>(schema: object): Sequence<S, P>;
|
|
413
574
|
|
|
414
|
-
/** Recorded unsupported:
|
|
415
|
-
|
|
575
|
+
/** Recorded unsupported (§4, §16): the grammar has no positional
|
|
576
|
+
* co-iteration. The parameter is `never`, not just the return type:
|
|
577
|
+
* a rest parameter accepts zero arguments, so `q.zip()` — the one
|
|
578
|
+
* spelling a caller would actually write — type-checked and failed at
|
|
579
|
+
* run time instead. JavaScript callers still get `JL0006`. */
|
|
580
|
+
zip(unsupported: never): never;
|
|
416
581
|
|
|
417
582
|
params<Q extends Record<string, unknown>>(bindings: Q): Sequence<T, P & Q>;
|
|
418
583
|
|
|
@@ -445,7 +610,7 @@ export class Sequence<T = unknown, P = {}> {
|
|
|
445
610
|
any(predicate?: (it: Expr<T>, p: ParamsExpr<P>) => BoolExpr | boolean): boolean;
|
|
446
611
|
all(predicate: (it: Expr<T>, p: ParamsExpr<P>) => BoolExpr | boolean): boolean;
|
|
447
612
|
|
|
448
|
-
/** Cross into the async surface (
|
|
613
|
+
/** Cross into the async surface (QUERY-PEN.md §11): the sync chain
|
|
449
614
|
* becomes the pushed prefix; the element re-types to the callback's
|
|
450
615
|
* RESOLVED type. */
|
|
451
616
|
mapAsync<R>(fn: (item: T, signal: AbortSignal) => R, options: MapAsyncOptions):
|
|
@@ -453,7 +618,9 @@ export class Sequence<T = unknown, P = {}> {
|
|
|
453
618
|
}
|
|
454
619
|
|
|
455
620
|
export function from<T>(source: Iterable<T>, options?: LinqOptions): Sequence<T, {}>;
|
|
456
|
-
|
|
621
|
+
/** A provider: `T` from its `__item` phantom (a typed entity set infers
|
|
622
|
+
* without a cast), or as the caller states it, or `unknown`. */
|
|
623
|
+
export function from<T = unknown>(source: Provider<T>, options?: LinqOptions): Sequence<T, {}>;
|
|
457
624
|
|
|
458
625
|
export function fromDocument<T = unknown>(
|
|
459
626
|
source: Iterable<unknown> | Provider,
|
|
@@ -461,7 +628,7 @@ export function fromDocument<T = unknown>(
|
|
|
461
628
|
options?: LinqOptions,
|
|
462
629
|
): Sequence<T, {}>;
|
|
463
630
|
|
|
464
|
-
/** The runtime code table, synced to
|
|
631
|
+
/** The runtime code table, synced to QUERY-PEN.md §9 by a test. */
|
|
465
632
|
export const LINQ_CODES: Readonly<Record<string, string>>;
|
|
466
633
|
|
|
467
634
|
export class LinqBuildError extends Error {
|
|
@@ -476,7 +643,7 @@ export class LinqRuntimeError extends Error {
|
|
|
476
643
|
readonly docPath: string | undefined;
|
|
477
644
|
}
|
|
478
645
|
|
|
479
|
-
// ————— The asynchronous surface (
|
|
646
|
+
// ————— The asynchronous surface (QUERY-PEN.md §§10–12) —————
|
|
480
647
|
|
|
481
648
|
export interface MapAsyncOptions {
|
|
482
649
|
/** REQUIRED: the in-flight bound (a positive integer, `JL0005`
|
|
@@ -490,6 +657,10 @@ export interface MapAsyncOptions {
|
|
|
490
657
|
|
|
491
658
|
export interface AsyncExplanation {
|
|
492
659
|
barriers: { operator: string, reason: string }[];
|
|
660
|
+
/** The relation hops the chain's callbacks navigated (as `Explanation`). */
|
|
661
|
+
hops: Hop[];
|
|
662
|
+
/** The values `params()` bound, by name (as `Explanation`). */
|
|
663
|
+
bindings: Record<string, unknown>;
|
|
493
664
|
/** Present when the chain is document-representable (no mapAsync). */
|
|
494
665
|
document?: unknown;
|
|
495
666
|
/** Present when a mapAsync splits the chain. */
|
|
@@ -517,6 +688,24 @@ export class AsyncSequence<T = unknown, P = {}> {
|
|
|
517
688
|
groupBy<R extends ExprResult>(key: (it: Expr<T>, p: ParamsExpr<P>) => R):
|
|
518
689
|
AsyncSequence<{ key: Unwrap<R> | null, items: T[] }, P>;
|
|
519
690
|
aggregate<A>(seed: A, step: (acc: Expr<A>, it: Expr<T>, p: ParamsExpr<P>) => ExprResult): AsyncSequence<A, P>;
|
|
691
|
+
|
|
692
|
+
/** Equi-join, pushed WHOLE: only over a provider origin, before any
|
|
693
|
+
* `mapAsync`, with an inner async sequence over the same provider or
|
|
694
|
+
* one sharing its scope (`JL0005` otherwise — a single-pass source
|
|
695
|
+
* cannot be joined; QUERY-PEN §10). */
|
|
696
|
+
join<U, R extends ExprResult>(
|
|
697
|
+
inner: AsyncSequence<U, any>,
|
|
698
|
+
outerKey: (it: Expr<T>, p: ParamsExpr<P>) => ExprResult,
|
|
699
|
+
innerKey: (it: Expr<U>, p: ParamsExpr<P>) => ExprResult,
|
|
700
|
+
result: (outer: Expr<T>, inner: Expr<U>, p: ParamsExpr<P>) => R,
|
|
701
|
+
): AsyncSequence<Unwrap<R>, P>;
|
|
702
|
+
/** Group-join, pushed WHOLE under the same rule as `join`. */
|
|
703
|
+
groupJoin<U, R extends ExprResult>(
|
|
704
|
+
inner: AsyncSequence<U, any>,
|
|
705
|
+
outerKey: (it: Expr<T>, p: ParamsExpr<P>) => ExprResult,
|
|
706
|
+
innerKey: (it: Expr<U>, p: ParamsExpr<P>) => ExprResult,
|
|
707
|
+
result: (outer: Expr<T>, group: ArrayExpr<U> & AggregatableExpr, p: ParamsExpr<P>) => R,
|
|
708
|
+
): AsyncSequence<Unwrap<R>, P>;
|
|
520
709
|
skip(count: number): AsyncSequence<T, P>;
|
|
521
710
|
take(count: number): AsyncSequence<T, P>;
|
|
522
711
|
distinct(): AsyncSequence<T, P>;
|
|
@@ -524,9 +713,12 @@ export class AsyncSequence<T = unknown, P = {}> {
|
|
|
524
713
|
/** Only a CONSTANT array can join an async stream (§10). */
|
|
525
714
|
concat(other: readonly T[]): AsyncSequence<T, P>;
|
|
526
715
|
defaultIfEmpty(fallback?: T | null): AsyncSequence<T | null, P>;
|
|
716
|
+
ofType<S>(schema: SchemaBuilder<S, any, any>): AsyncSequence<S, P>;
|
|
527
717
|
ofType<S = unknown>(schema: object): AsyncSequence<S, P>;
|
|
718
|
+
cast<S>(schema: SchemaBuilder<S, any, any>): AsyncSequence<S, P>;
|
|
528
719
|
cast<S = unknown>(schema: object): AsyncSequence<S, P>;
|
|
529
|
-
|
|
720
|
+
/** Recorded unsupported, as on the synchronous surface. */
|
|
721
|
+
zip(unsupported: never): never;
|
|
530
722
|
params<Q extends Record<string, unknown>>(bindings: Q): AsyncSequence<T, P & Q>;
|
|
531
723
|
|
|
532
724
|
/** The bounded-concurrency boundary (§11): re-types the element to
|
|
@@ -560,6 +752,19 @@ export class AsyncSequence<T = unknown, P = {}> {
|
|
|
560
752
|
all(predicate: (it: Expr<T>, p: ParamsExpr<P>) => BoolExpr | boolean): Promise<boolean>;
|
|
561
753
|
}
|
|
562
754
|
|
|
755
|
+
/** Build an async sequence over a provider (an `execute` duck, asked for
|
|
756
|
+
* before the iterable shapes): the document arrives whole and `execute`
|
|
757
|
+
* may answer a promise; `T` from the `__item` phantom, the caller, or
|
|
758
|
+
* `unknown`. */
|
|
759
|
+
export function fromAsync<T = unknown>(
|
|
760
|
+
source: AsyncProvider<T>,
|
|
761
|
+
options?: LinqOptions,
|
|
762
|
+
): AsyncSequence<T, {}>;
|
|
763
|
+
/** Build an async sequence over an async iterable, a sync iterable, a
|
|
764
|
+
* cursor or a push queue. A STRING is refused (`JL0001`): on this
|
|
765
|
+
* surface a string is a chunk source — feed it through a push queue —
|
|
766
|
+
* never a character stream, which is where the twins deliberately
|
|
767
|
+
* differ from `from('abc')`. */
|
|
563
768
|
export function fromAsync<T>(
|
|
564
769
|
source: AsyncIterable<T> | Iterable<T> | AsyncCursor<T>,
|
|
565
770
|
options?: LinqOptions,
|