tyneq 1.0.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/LICENSE +21 -0
- package/README.md +319 -0
- package/dist/Lazy.cjs +762 -0
- package/dist/Lazy.cjs.map +1 -0
- package/dist/Lazy.js +691 -0
- package/dist/Lazy.js.map +1 -0
- package/dist/TyneqCachedTerminalOperator.cjs +4950 -0
- package/dist/TyneqCachedTerminalOperator.cjs.map +1 -0
- package/dist/TyneqCachedTerminalOperator.d.cts +724 -0
- package/dist/TyneqCachedTerminalOperator.d.cts.map +1 -0
- package/dist/TyneqCachedTerminalOperator.d.ts +724 -0
- package/dist/TyneqCachedTerminalOperator.d.ts.map +1 -0
- package/dist/TyneqCachedTerminalOperator.js +4741 -0
- package/dist/TyneqCachedTerminalOperator.js.map +1 -0
- package/dist/ValidationBuilder.cjs +80 -0
- package/dist/ValidationBuilder.cjs.map +1 -0
- package/dist/ValidationBuilder.d.cts +319 -0
- package/dist/ValidationBuilder.d.cts.map +1 -0
- package/dist/ValidationBuilder.d.ts +319 -0
- package/dist/ValidationBuilder.d.ts.map +1 -0
- package/dist/ValidationBuilder.js +69 -0
- package/dist/ValidationBuilder.js.map +1 -0
- package/dist/core.d.cts +1393 -0
- package/dist/core.d.cts.map +1 -0
- package/dist/core.d.ts +1393 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/index.cjs +863 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1038 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +1038 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +809 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin/index.cjs +24 -0
- package/dist/plugin/index.d.cts +89 -0
- package/dist/plugin/index.d.cts.map +1 -0
- package/dist/plugin/index.d.ts +89 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +2 -0
- package/dist/utility/index.cjs +9 -0
- package/dist/utility/index.d.cts +2 -0
- package/dist/utility/index.d.ts +2 -0
- package/dist/utility/index.js +3 -0
- package/package.json +96 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1038 @@
|
|
|
1
|
+
import { $ as Predicate, A as SourceKind, B as Func, C as QueryNode, D as QueryPlanTraversalDirection, E as QueryPlanPrinterOptions, F as BoundMethod, G as ItemPredicate, H as HasLength, I as Cast, J as Method, K as ItemSelector, L as Constructor, M as tyneqQueryNode, N as Action, O as QueryPlanVisitor, P as Assume, Q as Optional, R as Factory, T as QueryPlanNode, U as InstanceOf, V as GenericFunction, W as ItemAction, X as NoInfer, Y as MethodKeys, Z as Nullable, _ as TyneqCachedSequence, a as Enumerator, b as TyneqSequence, c as IteratorFactory, d as OperatorEntry, et as WithProperties, f as OperatorKind, g as SequenceFactory, h as SequenceConstructor, i as Enumerable, j as isSourceNode, k as QueryPlanWalkerOptions, l as KeyValuePair, m as OrderedEnumerable, n as CachedEnumerable, o as EnumeratorFactory, p as OperatorSource, q as Maybe, r as Comparer, s as EqualityComparer, t as CacheResult, u as MinMaxResult, v as TyneqEnumerableFactory, w as OperatorCategory, x as OperatorMetadata, y as TyneqOrderedSequence, z as FieldKeys } from "./core.js";
|
|
2
|
+
import { a as reflect, c as MemberDescriptor, d as ArgumentUtility, i as ReflectionContext, l as MethodDescriptor, n as Lazy, o as AccessorDescriptor, r as TypeGuardUtility, s as DataDescriptor, t as ValidationBuilder, u as ReflectOptions } from "./ValidationBuilder.js";
|
|
3
|
+
import { S as operator, _ as cachedTerminal, a as TyneqOrderedEnumerator, b as cachedOperator, c as createCachedTerminalOperator, d as createCachedOperator, f as TyneqCachedEnumerable, g as createOperator, h as createGeneratorOperator, i as TyneqCachedEnumerator, l as createOrderedTerminalOperator, m as TyneqOrderedEnumerable, n as TyneqOrderedTerminalOperator, o as TyneqEnumerator, p as createOrderedOperator, r as TyneqTerminalOperator, s as TyneqBaseEnumerator, t as TyneqCachedTerminalOperator, u as createTerminalOperator, v as orderedTerminal, x as orderedOperator, y as terminal } from "./TyneqCachedTerminalOperator.js";
|
|
4
|
+
|
|
5
|
+
//#region src/core/tyneq.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Entry point for creating Tyneq sequences.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { Tyneq } from "tyneq";
|
|
12
|
+
*
|
|
13
|
+
* const sum = Tyneq.from([1, 2, 3, 4, 5])
|
|
14
|
+
* .where((x) => x % 2 === 0)
|
|
15
|
+
* .sum((x) => x); // -> 6
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @group Classes
|
|
19
|
+
*/
|
|
20
|
+
declare class Tyneq {
|
|
21
|
+
/**
|
|
22
|
+
* Creates a lazy sequence from any `Iterable<T>` (arrays, sets, generators, etc.).
|
|
23
|
+
*
|
|
24
|
+
* @throws {ArgumentNullError} When `source` is null or undefined.
|
|
25
|
+
* @throws {ArgumentTypeError} When `source` is not iterable.
|
|
26
|
+
*/
|
|
27
|
+
static from<TSource>(source: Iterable<TSource>): TyneqSequence<TSource>;
|
|
28
|
+
private static resolveSourceKind;
|
|
29
|
+
/**
|
|
30
|
+
* Creates a sequence of `count` elements produced by calling `randomizer` once per element.
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* Returns an empty sequence when `count === 0`.
|
|
34
|
+
*
|
|
35
|
+
* @throws {ArgumentOutOfRangeError} When `count` is negative.
|
|
36
|
+
* @throws {ArgumentNullError} When `randomizer` is null or undefined.
|
|
37
|
+
*/
|
|
38
|
+
static random<TSource>(count: number, randomizer: () => TSource): TyneqSequence<TSource>;
|
|
39
|
+
/**
|
|
40
|
+
* Returns `true` if `source` is `null`, `undefined`, or an iterable whose first element is `null` or `undefined`.
|
|
41
|
+
*/
|
|
42
|
+
static isNullOrEmpty<TSource>(source: Optional<Iterable<TSource>>): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Creates a sequence of `count` integers starting from `start`.
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* Returns an empty sequence when `count === 0`.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* Tyneq.range(1, 5).toArray(); // -> [1, 2, 3, 4, 5]
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @throws {ArgumentOutOfRangeError} When `count` is negative.
|
|
55
|
+
* @throws {ArgumentError} When `count` is not an integer.
|
|
56
|
+
*/
|
|
57
|
+
static range(start: number, count: number): TyneqSequence<number>;
|
|
58
|
+
/** Returns an empty sequence with zero elements. */
|
|
59
|
+
static empty<TSource>(): TyneqSequence<TSource>;
|
|
60
|
+
/**
|
|
61
|
+
* Creates a sequence that yields `value` exactly `count` times.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* Tyneq.repeat("x", 3).toArray(); // -> ["x", "x", "x"]
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @throws {ArgumentOutOfRangeError} When `count` is negative.
|
|
69
|
+
* @throws {ArgumentError} When `count` is not an integer.
|
|
70
|
+
*/
|
|
71
|
+
static repeat<TSource>(value: TSource, count: number): TyneqSequence<TSource>;
|
|
72
|
+
/**
|
|
73
|
+
* Creates a sequence by repeatedly applying `next` to produce each element from the previous one.
|
|
74
|
+
*
|
|
75
|
+
* @remarks
|
|
76
|
+
* The selector receives `(currentValue, index)`. Each call's return value becomes the input
|
|
77
|
+
* for the next call. Omit `count` for an infinite sequence; pair with `take` to bound it.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* Tyneq.generate(1, (x) => x * 2, 4).toArray(); // -> [2, 4, 8, 16]
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @throws {ArgumentNullError} When `next` is null or undefined.
|
|
85
|
+
* @throws {ArgumentOutOfRangeError} When `count` is negative.
|
|
86
|
+
* @throws {ArgumentError} When `count` is not an integer.
|
|
87
|
+
*/
|
|
88
|
+
static generate<TSource, TResult extends TSource>(seed: TSource, next: ItemSelector<TSource, TResult>, count?: number): TyneqSequence<TResult>;
|
|
89
|
+
/**
|
|
90
|
+
* Creates a sequence that yields all elements from each source in order.
|
|
91
|
+
*
|
|
92
|
+
* @remarks
|
|
93
|
+
* Returns an empty sequence when called with no arguments.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* Tyneq.concat([1, 2], [3, 4], [5]).toArray(); // -> [1, 2, 3, 4, 5]
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @throws {ArgumentNullError} When any `source` is null or undefined.
|
|
101
|
+
* @throws {ArgumentTypeError} When any `source` is not iterable.
|
|
102
|
+
*/
|
|
103
|
+
static concat<TSource>(...sources: Iterable<TSource>[]): TyneqSequence<TSource>;
|
|
104
|
+
/**
|
|
105
|
+
* Pairs each element with its zero-based index.
|
|
106
|
+
*
|
|
107
|
+
* @remarks
|
|
108
|
+
* Each iteration produces independent index counters - safe to re-enumerate.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* Tyneq.enumerate(["a", "b", "c"]).toArray();
|
|
113
|
+
* // -> [[0, "a"], [1, "b"], [2, "c"]]
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @throws {ArgumentNullError} When `source` is null or undefined.
|
|
117
|
+
* @throws {ArgumentTypeError} When `source` is not iterable.
|
|
118
|
+
*/
|
|
119
|
+
static enumerate<TSource>(source: Iterable<TSource>): TyneqSequence<[number, TSource]>;
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/core/TyneqComparer.d.ts
|
|
123
|
+
/**
|
|
124
|
+
* Built-in comparers and equality comparers used by ordering and equality operators.
|
|
125
|
+
*
|
|
126
|
+
* @remarks
|
|
127
|
+
* All members are static. This class cannot be instantiated.
|
|
128
|
+
*
|
|
129
|
+
* @group Utilities
|
|
130
|
+
*/
|
|
131
|
+
declare class TyneqComparer {
|
|
132
|
+
private constructor();
|
|
133
|
+
/**
|
|
134
|
+
* Natural-order comparer using `<` and `>`.
|
|
135
|
+
*
|
|
136
|
+
* @remarks
|
|
137
|
+
* Works correctly for numbers, strings, dates, and any type that supports the relational operators.
|
|
138
|
+
*
|
|
139
|
+
* @returns Negative if `a < b`, positive if `a > b`, `0` if equal.
|
|
140
|
+
*/
|
|
141
|
+
static defaultComparer<T>(a: T, b: T): number;
|
|
142
|
+
/** Strict equality comparer using `===`. */
|
|
143
|
+
static defaultEqualityComparer<T>(a: T, b: T): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Returns a comparer that reverses the order of `comparer`.
|
|
146
|
+
*
|
|
147
|
+
* @remarks
|
|
148
|
+
* Use this to invert any custom comparer - for example, to sort by a locale-aware comparer
|
|
149
|
+
* in descending order without rewriting it.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* const desc = TyneqComparer.reverse(TyneqComparer.createLocaleComparer("en"));
|
|
154
|
+
* seq.orderBy((s) => s, desc);
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
static reverse<T>(comparer: Comparer<T>): Comparer<T>;
|
|
158
|
+
/**
|
|
159
|
+
* Returns a locale-aware string comparer backed by `Intl.Collator`.
|
|
160
|
+
*
|
|
161
|
+
* @remarks
|
|
162
|
+
* Pass a `locale` and optional `options` for deterministic cross-environment ordering.
|
|
163
|
+
* Without arguments the comparer uses the runtime locale, which may vary across environments.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```ts
|
|
167
|
+
* seq.orderBy((s) => s, TyneqComparer.createLocaleComparer("en"));
|
|
168
|
+
* ```
|
|
169
|
+
*
|
|
170
|
+
* @param locale - BCP 47 language tag(s) passed to `Intl.Collator`.
|
|
171
|
+
* @param options - `Intl.CollatorOptions` passed to `Intl.Collator`.
|
|
172
|
+
*
|
|
173
|
+
* @see {@link caseInsensitiveComparer} for a locale-independent case-insensitive ordering comparer.
|
|
174
|
+
*/
|
|
175
|
+
static createLocaleComparer(locale?: string | string[], options?: Intl.CollatorOptions): Comparer<string>;
|
|
176
|
+
/**
|
|
177
|
+
* Case-insensitive string equality comparer.
|
|
178
|
+
*
|
|
179
|
+
* @remarks
|
|
180
|
+
* Converts both values to lower-case with `toLowerCase()` before comparing with `===`.
|
|
181
|
+
* Locale-independent: results are consistent across environments.
|
|
182
|
+
*
|
|
183
|
+
* Use {@link createLocaleComparer} with `{ sensitivity: "base" }` for locale-aware
|
|
184
|
+
* case-insensitive equality.
|
|
185
|
+
*
|
|
186
|
+
* @see {@link caseInsensitiveComparer} for the ordering (negative/zero/positive) counterpart.
|
|
187
|
+
*/
|
|
188
|
+
static caseInsensitiveEqualityComparer(a: string, b: string): boolean;
|
|
189
|
+
/**
|
|
190
|
+
* Case-insensitive ordering comparer.
|
|
191
|
+
*
|
|
192
|
+
* @remarks
|
|
193
|
+
* Converts both values to lower-case with `toLowerCase()` and compares with `<` / `>`.
|
|
194
|
+
* Locale-independent: results are consistent across environments and match
|
|
195
|
+
* {@link caseInsensitiveEqualityComparer} - strings that compare equal here return `true`
|
|
196
|
+
* there, and vice versa.
|
|
197
|
+
*
|
|
198
|
+
* Use {@link createLocaleComparer} when you need locale-aware case-insensitive ordering.
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```ts
|
|
202
|
+
* seq.orderBy((s) => s, TyneqComparer.caseInsensitiveComparer)
|
|
203
|
+
* ```
|
|
204
|
+
*
|
|
205
|
+
* @see {@link caseInsensitiveEqualityComparer} for the boolean equality counterpart.
|
|
206
|
+
* @see {@link createLocaleComparer} for locale-aware ordering.
|
|
207
|
+
*/
|
|
208
|
+
static caseInsensitiveComparer(a: string, b: string): number;
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/core/errors/TyneqError.d.ts
|
|
212
|
+
/**
|
|
213
|
+
* Base class for all errors thrown by Tyneq.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* try { Tyneq.from([]).first(); }
|
|
218
|
+
* catch (e) { if (e instanceof TyneqError) { console.log(e.message); } }
|
|
219
|
+
* ```
|
|
220
|
+
*
|
|
221
|
+
* @group Errors
|
|
222
|
+
*/
|
|
223
|
+
declare class TyneqError extends Error {
|
|
224
|
+
/** The underlying error that caused this error, if any. */
|
|
225
|
+
inner: Maybe<Error>;
|
|
226
|
+
constructor(message: string, options?: {
|
|
227
|
+
inner?: Error;
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
//#endregion
|
|
231
|
+
//#region src/core/errors/InvalidOperationError.d.ts
|
|
232
|
+
/**
|
|
233
|
+
* Thrown when a method call is invalid for the current state of the object.
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```ts
|
|
237
|
+
* try { Tyneq.from([1, 2]).single(); }
|
|
238
|
+
* catch (e) { if (e instanceof InvalidOperationError) { ... } }
|
|
239
|
+
* ```
|
|
240
|
+
*
|
|
241
|
+
* @see {@link TyneqError}
|
|
242
|
+
* @group Errors
|
|
243
|
+
*/
|
|
244
|
+
declare class InvalidOperationError extends TyneqError {
|
|
245
|
+
constructor(message?: string, inner?: Error);
|
|
246
|
+
}
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/core/errors/KeyNotFoundError.d.ts
|
|
249
|
+
/**
|
|
250
|
+
* Thrown when a lookup is performed with a key that does not exist in the collection.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* try { seq.toMap((x) => x.id).get(999); }
|
|
255
|
+
* catch (e) { if (e instanceof KeyNotFoundError) { ... } }
|
|
256
|
+
* ```
|
|
257
|
+
*
|
|
258
|
+
* @see {@link TyneqError}
|
|
259
|
+
* @group Errors
|
|
260
|
+
*/
|
|
261
|
+
declare class KeyNotFoundError extends TyneqError {
|
|
262
|
+
constructor(message?: string, inner?: Error);
|
|
263
|
+
}
|
|
264
|
+
//#endregion
|
|
265
|
+
//#region src/core/errors/NotSupportedError.d.ts
|
|
266
|
+
/**
|
|
267
|
+
* Thrown when a requested operation is not supported.
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* ```ts
|
|
271
|
+
* try { iterator.throw?.(new Error()); }
|
|
272
|
+
* catch (e) { if (e instanceof NotSupportedError) { ... } }
|
|
273
|
+
* ```
|
|
274
|
+
*
|
|
275
|
+
* @see {@link TyneqError}
|
|
276
|
+
* @group Errors
|
|
277
|
+
*/
|
|
278
|
+
declare class NotSupportedError extends TyneqError {
|
|
279
|
+
constructor(message?: string, inner?: Error);
|
|
280
|
+
}
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region src/core/errors/SequenceContainsNoElementsError.d.ts
|
|
283
|
+
/**
|
|
284
|
+
* Thrown when an element is required from a sequence that contains no elements.
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```ts
|
|
288
|
+
* try { Tyneq.from([]).first(); }
|
|
289
|
+
* catch (e) { if (e instanceof SequenceContainsNoElementsError) { ... } }
|
|
290
|
+
* ```
|
|
291
|
+
*
|
|
292
|
+
* @see {@link InvalidOperationError}
|
|
293
|
+
* @group Errors
|
|
294
|
+
*/
|
|
295
|
+
declare class SequenceContainsNoElementsError extends InvalidOperationError {
|
|
296
|
+
readonly operatorName: Maybe<string>;
|
|
297
|
+
constructor(operatorName?: string, inner?: Error);
|
|
298
|
+
}
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region src/core/errors/argument/ArgumentError.d.ts
|
|
301
|
+
/**
|
|
302
|
+
* Thrown when a method argument fails validation.
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```ts
|
|
306
|
+
* try { Tyneq.from([]).take(-1); }
|
|
307
|
+
* catch (e) { if (e instanceof ArgumentError) { console.log(e.paramName); } }
|
|
308
|
+
* ```
|
|
309
|
+
*
|
|
310
|
+
* @see {@link TyneqError}
|
|
311
|
+
* @group Errors
|
|
312
|
+
*/
|
|
313
|
+
declare class ArgumentError extends TyneqError {
|
|
314
|
+
/** The name of the parameter that caused the error. */
|
|
315
|
+
readonly paramName?: string;
|
|
316
|
+
constructor(message: string, paramName?: string, inner?: Error);
|
|
317
|
+
}
|
|
318
|
+
//#endregion
|
|
319
|
+
//#region src/core/errors/argument/ArgumentNullError.d.ts
|
|
320
|
+
/**
|
|
321
|
+
* Thrown when a required argument is `null`.
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* ```ts
|
|
325
|
+
* try { Tyneq.from([1, 2]).select(null as any); }
|
|
326
|
+
* catch (e) { if (e instanceof ArgumentNullError) { console.log(e.paramName); } }
|
|
327
|
+
* ```
|
|
328
|
+
*
|
|
329
|
+
* @see {@link ArgumentError}
|
|
330
|
+
* @group Errors
|
|
331
|
+
*/
|
|
332
|
+
declare class ArgumentNullError extends ArgumentError {
|
|
333
|
+
constructor(paramName: string, inner?: Error);
|
|
334
|
+
}
|
|
335
|
+
//#endregion
|
|
336
|
+
//#region src/core/errors/argument/ArgumentOutOfRangeError.d.ts
|
|
337
|
+
/**
|
|
338
|
+
* Thrown when an argument is outside the valid range.
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```ts
|
|
342
|
+
* try { Tyneq.from([1, 2]).take(-1); }
|
|
343
|
+
* catch (e) { if (e instanceof ArgumentOutOfRangeError) { console.log(e.actualValue); } }
|
|
344
|
+
* ```
|
|
345
|
+
*
|
|
346
|
+
* @see {@link ArgumentError}
|
|
347
|
+
* @group Errors
|
|
348
|
+
*/
|
|
349
|
+
declare class ArgumentOutOfRangeError extends ArgumentError {
|
|
350
|
+
/** The actual value that was out of range. */
|
|
351
|
+
readonly actualValue?: unknown;
|
|
352
|
+
constructor(paramName: string, message?: string, actualValue?: unknown, inner?: Error);
|
|
353
|
+
}
|
|
354
|
+
//#endregion
|
|
355
|
+
//#region src/core/errors/argument/ArgumentTypeError.d.ts
|
|
356
|
+
/**
|
|
357
|
+
* Thrown when an argument has the wrong type.
|
|
358
|
+
*
|
|
359
|
+
* @example
|
|
360
|
+
* ```ts
|
|
361
|
+
* try { Tyneq.from([1, 2]).where("not a function" as any); }
|
|
362
|
+
* catch (e) { if (e instanceof ArgumentTypeError) { console.log(e.expectedType, e.actualType); } }
|
|
363
|
+
* ```
|
|
364
|
+
*
|
|
365
|
+
* @see {@link ArgumentError}
|
|
366
|
+
* @group Errors
|
|
367
|
+
*/
|
|
368
|
+
declare class ArgumentTypeError extends ArgumentError {
|
|
369
|
+
/** The expected type name. */
|
|
370
|
+
readonly expectedType?: string;
|
|
371
|
+
/** The actual type name received. */
|
|
372
|
+
readonly actualType?: string;
|
|
373
|
+
constructor(paramName: string, expectedType?: string, actualType?: string, message?: string, inner?: Error);
|
|
374
|
+
}
|
|
375
|
+
//#endregion
|
|
376
|
+
//#region src/core/errors/argument/ValidationError.d.ts
|
|
377
|
+
/**
|
|
378
|
+
* Thrown when multiple argument validations fail simultaneously.
|
|
379
|
+
*
|
|
380
|
+
* @remarks
|
|
381
|
+
* `errors` contains one message per failed validation.
|
|
382
|
+
* Thrown by `ValidationBuilder.throwIfAny()` when at least one check failed.
|
|
383
|
+
*
|
|
384
|
+
* @example
|
|
385
|
+
* ```ts
|
|
386
|
+
* try { seq.someOperator(badArg1, badArg2); }
|
|
387
|
+
* catch (e) { if (e instanceof ValidationError) { console.log(e.errors); } }
|
|
388
|
+
* ```
|
|
389
|
+
*
|
|
390
|
+
* @see {@link ArgumentError}
|
|
391
|
+
* @group Errors
|
|
392
|
+
*/
|
|
393
|
+
declare class ValidationError extends ArgumentError {
|
|
394
|
+
/** The individual validation failure messages. */
|
|
395
|
+
readonly errors: readonly string[];
|
|
396
|
+
constructor(errors: readonly string[]);
|
|
397
|
+
}
|
|
398
|
+
//#endregion
|
|
399
|
+
//#region src/core/errors/CompilerError.d.ts
|
|
400
|
+
/**
|
|
401
|
+
* Thrown when the query plan compiler encounters a structural or semantic error
|
|
402
|
+
* while compiling a query plan into an executable sequence.
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```ts
|
|
406
|
+
* try { compiler.compile(plan); }
|
|
407
|
+
* catch (e) {
|
|
408
|
+
* if (e instanceof CompilerError) {
|
|
409
|
+
* console.log(e.operatorName, e.phase, e.message);
|
|
410
|
+
* }
|
|
411
|
+
* }
|
|
412
|
+
* ```
|
|
413
|
+
*
|
|
414
|
+
* @see {@link TyneqError}
|
|
415
|
+
* @group Errors
|
|
416
|
+
*/
|
|
417
|
+
declare class CompilerError extends TyneqError {
|
|
418
|
+
/** The name of the operator being compiled when the error occurred, if known. */
|
|
419
|
+
readonly operatorName: Maybe<string>;
|
|
420
|
+
/**
|
|
421
|
+
* The compilation phase in which the error occurred.
|
|
422
|
+
* - `"transform"` - during query plan transformation (pre-compile)
|
|
423
|
+
* - `"source"` - while compiling a source node
|
|
424
|
+
* - `"operator"` - while applying an operator node
|
|
425
|
+
*/
|
|
426
|
+
readonly phase: "transform" | "source" | "operator";
|
|
427
|
+
constructor(message: string, phase: "transform" | "source" | "operator", operatorName?: string, inner?: Error);
|
|
428
|
+
}
|
|
429
|
+
//#endregion
|
|
430
|
+
//#region src/core/errors/RegistryError.d.ts
|
|
431
|
+
/**
|
|
432
|
+
* Thrown when the operator registry encounters a conflict or invalid state
|
|
433
|
+
* during operator registration or invocation.
|
|
434
|
+
*
|
|
435
|
+
* @example
|
|
436
|
+
* ```ts
|
|
437
|
+
* try { OperatorRegistry.register(entry); }
|
|
438
|
+
* catch (e) {
|
|
439
|
+
* if (e instanceof RegistryError) {
|
|
440
|
+
* console.log(e.operatorName, e.conflictingKind, e.message);
|
|
441
|
+
* }
|
|
442
|
+
* }
|
|
443
|
+
* ```
|
|
444
|
+
*
|
|
445
|
+
* @see {@link TyneqError}
|
|
446
|
+
* @group Errors
|
|
447
|
+
*/
|
|
448
|
+
declare class RegistryError extends TyneqError {
|
|
449
|
+
/** The name of the operator involved in the error. */
|
|
450
|
+
readonly operatorName: string;
|
|
451
|
+
/**
|
|
452
|
+
* The kind of the operator that was being registered or invoked.
|
|
453
|
+
* `undefined` if the kind is not applicable to this error.
|
|
454
|
+
*/
|
|
455
|
+
readonly kind: Maybe<OperatorMetadata["kind"]>;
|
|
456
|
+
/**
|
|
457
|
+
* The kind already present in the registry for this name, when there is a conflict.
|
|
458
|
+
* `undefined` when the error is not a duplicate-registration conflict.
|
|
459
|
+
*/
|
|
460
|
+
readonly conflictingKind: Maybe<OperatorMetadata["kind"]>;
|
|
461
|
+
/**
|
|
462
|
+
* The source that originally registered the conflicting operator.
|
|
463
|
+
* `undefined` when the error is not a duplicate-registration conflict.
|
|
464
|
+
*/
|
|
465
|
+
readonly conflictingSource: Maybe<OperatorMetadata["source"]>;
|
|
466
|
+
constructor(message: string, operatorName: string, kind?: OperatorMetadata["kind"], conflict?: {
|
|
467
|
+
kind: OperatorMetadata["kind"];
|
|
468
|
+
source: OperatorMetadata["source"];
|
|
469
|
+
}, inner?: Error);
|
|
470
|
+
}
|
|
471
|
+
//#endregion
|
|
472
|
+
//#region src/core/errors/PluginError.d.ts
|
|
473
|
+
/**
|
|
474
|
+
* Thrown when a plugin, decorator (`@operator`, `@terminal`), or factory
|
|
475
|
+
* (`createOperator`, `createTerminalOperator`) is used incorrectly.
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* ```ts
|
|
479
|
+
* // @operator('myOp') applied to a class that doesn't extend TyneqEnumerator
|
|
480
|
+
* // throws PluginError with decoratorName = "operator" and targetName = "MyOp"
|
|
481
|
+
* ```
|
|
482
|
+
*
|
|
483
|
+
* @see {@link TyneqError}
|
|
484
|
+
* @group Errors
|
|
485
|
+
*/
|
|
486
|
+
declare class PluginError extends TyneqError {
|
|
487
|
+
/**
|
|
488
|
+
* The name of the decorator or factory that produced the error.
|
|
489
|
+
* e.g. `"operator"`, `"terminal"`, `"createOperator"`.
|
|
490
|
+
*/
|
|
491
|
+
readonly decoratorName: string;
|
|
492
|
+
/**
|
|
493
|
+
* The name of the class or function the decorator was applied to, if available.
|
|
494
|
+
*/
|
|
495
|
+
readonly targetName: Maybe<string>;
|
|
496
|
+
constructor(message: string, decoratorName: string, targetName?: string, inner?: Error);
|
|
497
|
+
}
|
|
498
|
+
//#endregion
|
|
499
|
+
//#region src/core/errors/ReflectionError.d.ts
|
|
500
|
+
/**
|
|
501
|
+
* Thrown when a prototype reflection operation fails - for example, when a
|
|
502
|
+
* method that is expected to exist on a prototype cannot be found.
|
|
503
|
+
*
|
|
504
|
+
* @example
|
|
505
|
+
* ```ts
|
|
506
|
+
* try { reflect(proto).getMethod("missing"); }
|
|
507
|
+
* catch (e) {
|
|
508
|
+
* if (e instanceof ReflectionError) {
|
|
509
|
+
* console.log(e.methodName, e.prototypeName, e.message);
|
|
510
|
+
* }
|
|
511
|
+
* }
|
|
512
|
+
* ```
|
|
513
|
+
*
|
|
514
|
+
* @see {@link TyneqError}
|
|
515
|
+
* @group Errors
|
|
516
|
+
*/
|
|
517
|
+
declare class ReflectionError extends TyneqError {
|
|
518
|
+
/** The name of the method that could not be found. */
|
|
519
|
+
readonly methodName: string;
|
|
520
|
+
/** The name of the prototype/class that was searched. */
|
|
521
|
+
readonly prototypeName: Maybe<string>;
|
|
522
|
+
constructor(message: string, methodName: string, prototypeName?: string, inner?: Error);
|
|
523
|
+
}
|
|
524
|
+
//#endregion
|
|
525
|
+
//#region src/core/registry/TyneqOperatorRegistry.d.ts
|
|
526
|
+
/**
|
|
527
|
+
* Central registry for all Tyneq operators.
|
|
528
|
+
*
|
|
529
|
+
* Every registration path - `@operator`, `@terminal`, `createOperator`,
|
|
530
|
+
* `createGeneratorOperator`, `createTerminalOperator` - flows through this class.
|
|
531
|
+
* It is the single source of truth for which operators exist, their kind, and their
|
|
532
|
+
* prototype-level implementation.
|
|
533
|
+
*
|
|
534
|
+
* Internally the registry maintains two separate namespaces:
|
|
535
|
+
* - Source factories (`Tyneq.from`, `Tyneq.range`, etc.) - keyed by name alone.
|
|
536
|
+
* - Instance operators (`.where`, `.select`, etc.) - keyed by (name, targetClass).
|
|
537
|
+
*
|
|
538
|
+
* This means a source factory and an instance method can share a name without
|
|
539
|
+
* conflict (e.g. `Tyneq.concat` and `seq.concat`), and two instance operators
|
|
540
|
+
* with the same name on different prototype chains (e.g. `ordered.foo` and
|
|
541
|
+
* `cached.foo`) also coexist without conflict.
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* ```ts
|
|
545
|
+
* import { OperatorRegistry } from "tyneq/plugin";
|
|
546
|
+
*
|
|
547
|
+
* OperatorRegistry.has("where"); // -> true
|
|
548
|
+
* OperatorRegistry.list(); // -> OperatorMetadata[]
|
|
549
|
+
* ```
|
|
550
|
+
*
|
|
551
|
+
* @group Classes
|
|
552
|
+
*/
|
|
553
|
+
declare class OperatorRegistry {
|
|
554
|
+
private static readonly _sources;
|
|
555
|
+
private static readonly _operators;
|
|
556
|
+
private static readonly _registrationHooks;
|
|
557
|
+
private static readonly _registrationGuards;
|
|
558
|
+
/**
|
|
559
|
+
* Registers an operator entry and patches the method onto `entry.metadata.targetClass.prototype`.
|
|
560
|
+
*
|
|
561
|
+
* @throws {RegistryError} When an operator with the same name is already registered on the same targetClass.
|
|
562
|
+
*/
|
|
563
|
+
static register(input: OperatorEntry): void;
|
|
564
|
+
/**
|
|
565
|
+
* Removes an operator registration and deletes the prototype method for external operators.
|
|
566
|
+
*
|
|
567
|
+
* Checks the instance operator namespace first, then the source namespace.
|
|
568
|
+
*
|
|
569
|
+
* @returns `true` if the operator was found and removed; `false` if no operator with that name existed.
|
|
570
|
+
* @remarks
|
|
571
|
+
* Internal operators (source `"internal"`) are not removed from the prototype - only
|
|
572
|
+
* their registry entry is deleted.
|
|
573
|
+
*
|
|
574
|
+
* For targeted removal use {@link unregisterOperator} or {@link unregisterSource}.
|
|
575
|
+
*/
|
|
576
|
+
static unregister(name: string): boolean;
|
|
577
|
+
/**
|
|
578
|
+
* Removes a specific instance operator registration for a given (name, targetClass) pair
|
|
579
|
+
* and deletes the prototype method for external operators.
|
|
580
|
+
*
|
|
581
|
+
* @returns `true` if the entry was found and removed; `false` otherwise.
|
|
582
|
+
*/
|
|
583
|
+
static unregisterOperator(name: string, targetClass: SequenceConstructor): boolean;
|
|
584
|
+
/**
|
|
585
|
+
* Removes a source factory registration.
|
|
586
|
+
*
|
|
587
|
+
* @returns `true` if the source was found and removed; `false` otherwise.
|
|
588
|
+
*/
|
|
589
|
+
static unregisterSource(name: string): boolean;
|
|
590
|
+
/**
|
|
591
|
+
* Registers a hook called after every successful operator registration (both namespaces).
|
|
592
|
+
*
|
|
593
|
+
* @returns A function that removes the hook when called.
|
|
594
|
+
*/
|
|
595
|
+
static onRegister(hook: (entry: OperatorEntry) => void): () => void;
|
|
596
|
+
/**
|
|
597
|
+
* Registers a guard called before every registration (both namespaces).
|
|
598
|
+
* Throw from the guard to reject the registration.
|
|
599
|
+
*
|
|
600
|
+
* @returns A function that removes the guard when called.
|
|
601
|
+
*/
|
|
602
|
+
static addGuard(guard: (entry: OperatorEntry) => void): () => void;
|
|
603
|
+
/**
|
|
604
|
+
* Returns `true` if a name exists in either the source or instance operator namespace.
|
|
605
|
+
* Use {@link hasSource} or {@link hasOperator} for namespace-specific checks.
|
|
606
|
+
*/
|
|
607
|
+
static has(name: string): boolean;
|
|
608
|
+
/**
|
|
609
|
+
* Returns `true` if a source factory with `name` is registered.
|
|
610
|
+
*/
|
|
611
|
+
static hasSource(name: string): boolean;
|
|
612
|
+
/**
|
|
613
|
+
* Returns `true` if an instance operator with `name` is registered.
|
|
614
|
+
* When `targetClass` is provided, checks only that specific (name, targetClass) pair.
|
|
615
|
+
* When omitted, returns `true` if any target has an operator with that name.
|
|
616
|
+
*/
|
|
617
|
+
static hasOperator(name: string, targetClass?: SequenceConstructor): boolean;
|
|
618
|
+
/**
|
|
619
|
+
* Returns the operator entry for `name` from either namespace, or `undefined` if not found.
|
|
620
|
+
* Checks the instance operator namespace first, then the source namespace.
|
|
621
|
+
* For namespace-specific retrieval use {@link getSource} or {@link getOperator}.
|
|
622
|
+
*/
|
|
623
|
+
static get(name: string): Maybe<OperatorEntry>;
|
|
624
|
+
/**
|
|
625
|
+
* Returns the source factory entry for `name`, or `undefined` if not registered.
|
|
626
|
+
*/
|
|
627
|
+
static getSource(name: string): Maybe<OperatorEntry>;
|
|
628
|
+
/**
|
|
629
|
+
* Returns the instance operator entry for `name` on `targetClass`, or `undefined`.
|
|
630
|
+
* When `targetClass` is omitted, returns the first entry found across all targets.
|
|
631
|
+
*/
|
|
632
|
+
static getOperator(name: string, targetClass?: SequenceConstructor): Maybe<OperatorEntry>;
|
|
633
|
+
/**
|
|
634
|
+
* Returns the metadata for `name` from either namespace, or `undefined` if not found.
|
|
635
|
+
* Checks instance operators first, then sources.
|
|
636
|
+
*/
|
|
637
|
+
static getMetadata(name: string): Maybe<OperatorMetadata>;
|
|
638
|
+
/**
|
|
639
|
+
* Returns metadata for all registered operators and source factories.
|
|
640
|
+
* Use {@link listOperators} or {@link listSources} for namespace-specific lists.
|
|
641
|
+
*/
|
|
642
|
+
static list(): readonly OperatorMetadata[];
|
|
643
|
+
/**
|
|
644
|
+
* Returns metadata for all registered source factories.
|
|
645
|
+
*/
|
|
646
|
+
static listSources(): readonly OperatorMetadata[];
|
|
647
|
+
/**
|
|
648
|
+
* Returns metadata for all registered instance operators.
|
|
649
|
+
* When `targetClass` is provided, returns only entries for that specific target class.
|
|
650
|
+
*/
|
|
651
|
+
static listOperators(targetClass?: SequenceConstructor): readonly OperatorMetadata[];
|
|
652
|
+
/** Returns metadata for all operators of `kind` across both namespaces. */
|
|
653
|
+
static listByKind(kind: OperatorMetadata["kind"]): readonly OperatorMetadata[];
|
|
654
|
+
/** Returns metadata for all operators from `source` across both namespaces. */
|
|
655
|
+
static listBySource(source: OperatorMetadata["source"]): readonly OperatorMetadata[];
|
|
656
|
+
/** Returns the total number of registered operators across both namespaces. */
|
|
657
|
+
static count(): number;
|
|
658
|
+
/**
|
|
659
|
+
* Registers a source operator (a static factory, not a prototype method).
|
|
660
|
+
*
|
|
661
|
+
* @remarks
|
|
662
|
+
* Source operators differ from prototype operators in two ways:
|
|
663
|
+
* - They are called with `null` as `this` - they have no instance.
|
|
664
|
+
* - They are looked up by the compiler via {@link getSource} rather than
|
|
665
|
+
* being patched onto a prototype.
|
|
666
|
+
*
|
|
667
|
+
* The entry is stored in the source namespace and is never patched onto any prototype.
|
|
668
|
+
* Registration guards run for `"external"` sources (same policy as {@link register}).
|
|
669
|
+
* Guards are skipped for `"internal"` sources (same policy used for internal builtins).
|
|
670
|
+
*
|
|
671
|
+
* Third-party source operators registered here are automatically compiled by
|
|
672
|
+
* `QueryPlanCompiler` without any changes to the compiler.
|
|
673
|
+
*
|
|
674
|
+
* @param name - The operator name, matching the `operatorName` on the `QueryPlanNode`.
|
|
675
|
+
* @param factory - The factory function; receives the node args in order, `this` is `null`.
|
|
676
|
+
* @param source - Whether this is a built-in or external source operator. Defaults to `"external"`.
|
|
677
|
+
*
|
|
678
|
+
* @example
|
|
679
|
+
* ```ts
|
|
680
|
+
* import { OperatorRegistry } from "tyneq/plugin";
|
|
681
|
+
* import { Tyneq } from "tyneq";
|
|
682
|
+
*
|
|
683
|
+
* OperatorRegistry.registerSource("fibonacci", (count) => {
|
|
684
|
+
* // return a Tyneq sequence of fibonacci numbers
|
|
685
|
+
* });
|
|
686
|
+
* ```
|
|
687
|
+
*
|
|
688
|
+
* @group Classes
|
|
689
|
+
*/
|
|
690
|
+
static registerSource(name: string, factory: (...args: unknown[]) => unknown, source?: OperatorSource): void;
|
|
691
|
+
/**
|
|
692
|
+
* Records a built-in operator in the instance operator namespace without patching the prototype.
|
|
693
|
+
* Built-in operators already live as direct methods on their target class.
|
|
694
|
+
*
|
|
695
|
+
* @remarks
|
|
696
|
+
* Registration guards are intentionally skipped - builtins are internal and
|
|
697
|
+
* trusted; guards exist to validate external plugin registrations only.
|
|
698
|
+
*
|
|
699
|
+
* @internal
|
|
700
|
+
*/
|
|
701
|
+
static registerBuiltin(name: string, kind: OperatorMetadata["kind"], targetClass: SequenceConstructor): void;
|
|
702
|
+
}
|
|
703
|
+
//#endregion
|
|
704
|
+
//#region src/queryplan/QueryPlanPrinter.d.ts
|
|
705
|
+
/**
|
|
706
|
+
* Converts a query plan tree into a human-readable multi-line string.
|
|
707
|
+
*
|
|
708
|
+
* Implements `QueryPlanVisitor<string>`. The output lists operators from source to
|
|
709
|
+
* terminal, one per line, with indentation showing the pipeline depth.
|
|
710
|
+
*
|
|
711
|
+
* @example
|
|
712
|
+
* ```ts
|
|
713
|
+
* import { QueryPlanPrinter } from "tyneq/queryplan";
|
|
714
|
+
*
|
|
715
|
+
* const seq = Tyneq.range(1, 10).where(x => x % 2 === 0).select(x => x * x);
|
|
716
|
+
* console.log(QueryPlanPrinter.print(seq[tyneqQueryNode]!));
|
|
717
|
+
* // range(1, 10)
|
|
718
|
+
* // -> where(<fn>)
|
|
719
|
+
* // -> select(<fn>)
|
|
720
|
+
* ```
|
|
721
|
+
*
|
|
722
|
+
* @group QueryPlan
|
|
723
|
+
*/
|
|
724
|
+
declare class QueryPlanPrinter implements QueryPlanVisitor<string> {
|
|
725
|
+
protected readonly indent: string;
|
|
726
|
+
protected readonly arrow: string;
|
|
727
|
+
protected readonly maxInlineArrayItems: number;
|
|
728
|
+
constructor(options?: QueryPlanPrinterOptions);
|
|
729
|
+
/** Renders the full query plan rooted at `node` as a multi-line string. */
|
|
730
|
+
visit(node: QueryPlanNode): string;
|
|
731
|
+
/** Convenience static: creates a printer with `options` and calls `visit(node)`. */
|
|
732
|
+
static print(node: QueryPlanNode, options?: QueryPlanPrinterOptions): string;
|
|
733
|
+
/**
|
|
734
|
+
* Formats a single operator argument for display.
|
|
735
|
+
* Override to customise how arguments appear in printed plans.
|
|
736
|
+
*/
|
|
737
|
+
protected formatArg(arg: unknown): string;
|
|
738
|
+
/**
|
|
739
|
+
* Formats one line of the plan output.
|
|
740
|
+
* Override to customise indentation or arrow style beyond what `QueryPlanPrinterOptions` allows.
|
|
741
|
+
*/
|
|
742
|
+
protected formatLine(name: string, argStr: string, isRoot: boolean): string;
|
|
743
|
+
private buildPlan;
|
|
744
|
+
private collectNodes;
|
|
745
|
+
}
|
|
746
|
+
//#endregion
|
|
747
|
+
//#region src/queryplan/QueryPlanWalker.d.ts
|
|
748
|
+
/**
|
|
749
|
+
* Concrete base class for side-effect query plan visitors.
|
|
750
|
+
*
|
|
751
|
+
* @remarks
|
|
752
|
+
* Traverses the node chain calling {@link QueryPlanWalker.visitNode} once per node.
|
|
753
|
+
* The traversal direction defaults to `"source-to-terminal"` (bottom-up: `from` before
|
|
754
|
+
* `where` before `select`) and can be changed to `"terminal-to-source"` (top-down) via
|
|
755
|
+
* the options object.
|
|
756
|
+
*
|
|
757
|
+
* ### Usage patterns
|
|
758
|
+
*
|
|
759
|
+
* **Direct instantiation with a callback** - no subclass needed for simple traversals:
|
|
760
|
+
* ```ts
|
|
761
|
+
* const names: string[] = [];
|
|
762
|
+
* new QueryPlanWalker({ callback: node => names.push(node.operatorName) }).visit(plan);
|
|
763
|
+
* ```
|
|
764
|
+
*
|
|
765
|
+
* **Subclass** - for stateful walkers that accumulate results across nodes:
|
|
766
|
+
* ```ts
|
|
767
|
+
* class NodeCounter extends QueryPlanWalker {
|
|
768
|
+
* public count = 0;
|
|
769
|
+
* protected override visitNode(_node: QueryPlanNode): void { this.count++; }
|
|
770
|
+
* }
|
|
771
|
+
*
|
|
772
|
+
* const counter = new NodeCounter();
|
|
773
|
+
* counter.visit(seq[tyneqQueryNode]!);
|
|
774
|
+
* console.log(counter.count); // number of operators in the pipeline
|
|
775
|
+
* ```
|
|
776
|
+
*
|
|
777
|
+
* **Top-down traversal:**
|
|
778
|
+
* ```ts
|
|
779
|
+
* new QueryPlanWalker({
|
|
780
|
+
* callback: node => console.log(node.operatorName),
|
|
781
|
+
* direction: "terminal-to-source",
|
|
782
|
+
* }).visit(plan);
|
|
783
|
+
* ```
|
|
784
|
+
*
|
|
785
|
+
* **Subclass with direction override** - pass options to `super`:
|
|
786
|
+
* ```ts
|
|
787
|
+
* class ReverseCollector extends QueryPlanWalker {
|
|
788
|
+
* public readonly names: string[] = [];
|
|
789
|
+
* public constructor() { super({ direction: "terminal-to-source" }); }
|
|
790
|
+
* protected override visitNode(node: QueryPlanNode): void {
|
|
791
|
+
* this.names.push(node.operatorName);
|
|
792
|
+
* }
|
|
793
|
+
* }
|
|
794
|
+
* ```
|
|
795
|
+
*
|
|
796
|
+
* @group QueryPlan
|
|
797
|
+
*/
|
|
798
|
+
declare class QueryPlanWalker implements QueryPlanVisitor<void> {
|
|
799
|
+
private readonly callback;
|
|
800
|
+
private readonly direction;
|
|
801
|
+
/**
|
|
802
|
+
* @param options - Optional configuration for the walker.
|
|
803
|
+
*/
|
|
804
|
+
constructor(options?: QueryPlanWalkerOptions);
|
|
805
|
+
/**
|
|
806
|
+
* Walks the full chain rooted at `node`, calling {@link visitNode} for each node
|
|
807
|
+
* in the configured direction.
|
|
808
|
+
*/
|
|
809
|
+
visit(node: QueryPlanNode): void;
|
|
810
|
+
/**
|
|
811
|
+
* Called once per node during traversal.
|
|
812
|
+
*
|
|
813
|
+
* @remarks
|
|
814
|
+
* The default implementation fires the callback passed via options (if any).
|
|
815
|
+
* Override this method in a subclass to provide custom behaviour. Subclasses that
|
|
816
|
+
* override this method decide whether to call `super.visitNode(node)` to also fire
|
|
817
|
+
* the options callback.
|
|
818
|
+
*
|
|
819
|
+
* @param node - The current node being visited.
|
|
820
|
+
*/
|
|
821
|
+
protected visitNode(node: QueryPlanNode): void;
|
|
822
|
+
}
|
|
823
|
+
//#endregion
|
|
824
|
+
//#region src/queryplan/QueryPlanTransformer.d.ts
|
|
825
|
+
/**
|
|
826
|
+
* Base class for immutable query plan rewriting.
|
|
827
|
+
*
|
|
828
|
+
* @remarks
|
|
829
|
+
* Recursively rebuilds the node chain, calling {@link QueryPlanTransformer.transformNode}
|
|
830
|
+
* once per node. The default implementation is an **identity transform** - every node is
|
|
831
|
+
* reconstructed with the same data, producing a structurally equivalent copy.
|
|
832
|
+
*
|
|
833
|
+
* Subclasses override `transformNode` to intercept specific operators. Three rewrite
|
|
834
|
+
* patterns are possible:
|
|
835
|
+
*
|
|
836
|
+
* - **Rewrite a node** - return a new `QueryNode` with different `operatorName` or `args`
|
|
837
|
+
* - **Remove a node** - return `source` directly, skipping this node
|
|
838
|
+
* - **Collapse two nodes into one** - use `source` as the new node's `source` (fusing
|
|
839
|
+
* the current node with its already-transformed predecessor)
|
|
840
|
+
*
|
|
841
|
+
* @example
|
|
842
|
+
* ```ts
|
|
843
|
+
* // Rename all 'where' nodes to 'filter' in the plan view
|
|
844
|
+
* class RenameWhere extends QueryPlanTransformer {
|
|
845
|
+
* protected override transformNode(node: QueryPlanNode, source: QueryPlanNode | null): QueryPlanNode {
|
|
846
|
+
* if (node.operatorName === "where") {
|
|
847
|
+
* return new QueryNode("filter", node.args, source, node.category);
|
|
848
|
+
* }
|
|
849
|
+
* return super.transformNode(node, source);
|
|
850
|
+
* }
|
|
851
|
+
* }
|
|
852
|
+
* ```
|
|
853
|
+
*
|
|
854
|
+
* @group QueryPlan
|
|
855
|
+
*/
|
|
856
|
+
declare class QueryPlanTransformer implements QueryPlanVisitor<QueryPlanNode> {
|
|
857
|
+
/**
|
|
858
|
+
* Transforms the full chain rooted at `node` and returns the new root node.
|
|
859
|
+
*
|
|
860
|
+
* @remarks
|
|
861
|
+
* Processes source-first (bottom-up): the source chain is fully transformed before
|
|
862
|
+
* `transformNode` is called for the current node. This means `source` passed to
|
|
863
|
+
* `transformNode` is always already the transformed predecessor.
|
|
864
|
+
*/
|
|
865
|
+
visit(node: QueryPlanNode): QueryPlanNode;
|
|
866
|
+
/**
|
|
867
|
+
* Transforms a single node. Override to intercept specific operators.
|
|
868
|
+
*
|
|
869
|
+
* @remarks
|
|
870
|
+
* The default implementation reconstructs the node with identical data (identity transform).
|
|
871
|
+
* `source` is the already-transformed predecessor - use it as the `source` of any returned
|
|
872
|
+
* node to preserve chain continuity.
|
|
873
|
+
*
|
|
874
|
+
* @param node - The original node (unmodified).
|
|
875
|
+
* @param source - The transformed predecessor, or `null` for source nodes.
|
|
876
|
+
*/
|
|
877
|
+
protected transformNode(node: QueryPlanNode, source: Nullable<QueryPlanNode>): QueryPlanNode;
|
|
878
|
+
}
|
|
879
|
+
//#endregion
|
|
880
|
+
//#region src/queryplan/QueryPlanOptimizer.d.ts
|
|
881
|
+
/**
|
|
882
|
+
* A built-in {@link QueryPlanTransformer} that fuses redundant consecutive operators.
|
|
883
|
+
*
|
|
884
|
+
* @remarks
|
|
885
|
+
* **This optimizer rewrites the query plan tree only - it does not affect execution of the
|
|
886
|
+
* original sequence.** The returned `QueryPlanNode` reflects what an optimized pipeline would
|
|
887
|
+
* look like; the live sequence that produced the original plan is unchanged.
|
|
888
|
+
*
|
|
889
|
+
* **Fusion is only semantics-preserving for pure, side-effect-free functions.**
|
|
890
|
+
* If a predicate or projection has side effects (e.g. logging, mutation), fusing two nodes into
|
|
891
|
+
* one changes when and how many times those effects fire. For example, in a fused `where`, the
|
|
892
|
+
* second predicate is never called for items that fail the first - any mutation inside the second
|
|
893
|
+
* predicate is skipped for those items. Do not use this optimizer on pipelines with impure
|
|
894
|
+
* predicates or projections.
|
|
895
|
+
*
|
|
896
|
+
* ### Fusions applied
|
|
897
|
+
*
|
|
898
|
+
* | Pattern | Result |
|
|
899
|
+
* |---------|--------|
|
|
900
|
+
* | `where(a) -> where(b)` | `where(x => a(x) && b(x))` |
|
|
901
|
+
* | `select(a) -> select(b)` | `select(x => b(a(x)))` |
|
|
902
|
+
*
|
|
903
|
+
* Additional fusions can be added by subclassing and overriding
|
|
904
|
+
* {@link QueryPlanTransformer.transformNode}.
|
|
905
|
+
*
|
|
906
|
+
* @example
|
|
907
|
+
* ```ts
|
|
908
|
+
* import { Tyneq, tyneqQueryNode, QueryPlanOptimizer, QueryPlanPrinter } from "tyneq";
|
|
909
|
+
*
|
|
910
|
+
* const seq = Tyneq.from([1, 2, 3])
|
|
911
|
+
* .where(x => x > 1)
|
|
912
|
+
* .where(x => x < 3)
|
|
913
|
+
* .select(x => x * 2)
|
|
914
|
+
* .select(x => x + 1);
|
|
915
|
+
*
|
|
916
|
+
* const original = seq[tyneqQueryNode]!;
|
|
917
|
+
* const optimized = new QueryPlanOptimizer().visit(original);
|
|
918
|
+
*
|
|
919
|
+
* console.log(QueryPlanPrinter.print(original));
|
|
920
|
+
* // from([...])
|
|
921
|
+
* // -> where(<fn>)
|
|
922
|
+
* // -> where(<fn>)
|
|
923
|
+
* // -> select(<fn>)
|
|
924
|
+
* // -> select(<fn>)
|
|
925
|
+
*
|
|
926
|
+
* console.log(QueryPlanPrinter.print(optimized));
|
|
927
|
+
* // from([...])
|
|
928
|
+
* // -> where(<fn>)
|
|
929
|
+
* // -> select(<fn>)
|
|
930
|
+
* ```
|
|
931
|
+
*
|
|
932
|
+
* @group QueryPlan
|
|
933
|
+
*/
|
|
934
|
+
declare class QueryPlanOptimizer extends QueryPlanTransformer {
|
|
935
|
+
protected transformNode(node: QueryPlanNode, source: Nullable<QueryPlanNode>): QueryPlanNode;
|
|
936
|
+
/**
|
|
937
|
+
* @remarks Fusion is only semantics-preserving for pure, side-effect-free predicates.
|
|
938
|
+
*/
|
|
939
|
+
private fuseWhere;
|
|
940
|
+
/**
|
|
941
|
+
* @remarks Fusion is only semantics-preserving for pure, side-effect-free projections.
|
|
942
|
+
*/
|
|
943
|
+
private fuseSelect;
|
|
944
|
+
}
|
|
945
|
+
//#endregion
|
|
946
|
+
//#region src/queryplan/compiler/QueryPlanCompiler.d.ts
|
|
947
|
+
/**
|
|
948
|
+
* Options for {@link QueryPlanCompiler.compile} and {@link QueryPlanCompiler.compileRaw}.
|
|
949
|
+
*
|
|
950
|
+
* @group QueryPlan
|
|
951
|
+
*/
|
|
952
|
+
interface CompileOptions {
|
|
953
|
+
/**
|
|
954
|
+
* Replaces the source data when compiling.
|
|
955
|
+
*
|
|
956
|
+
* When provided, the compiler passes this value as the first argument to the source
|
|
957
|
+
* operator instead of the value stored in the plan node's `args`. This lets you reuse
|
|
958
|
+
* the same pipeline structure (operators, predicates, projections) against a different
|
|
959
|
+
* data set without rebuilding the sequence.
|
|
960
|
+
*
|
|
961
|
+
* @example
|
|
962
|
+
* ```ts
|
|
963
|
+
* const plan = Tyneq.from([1, 2, 3]).where(x => x > 1).select(x => x * 2)[tyneqQueryNode]!;
|
|
964
|
+
* const compiler = new QueryPlanCompiler();
|
|
965
|
+
*
|
|
966
|
+
* compiler.compile(plan).toArray(); // -> [4, 6]
|
|
967
|
+
* compiler.compile(plan, { source: [10, 20, 30] }).toArray(); // -> [40, 60]
|
|
968
|
+
* ```
|
|
969
|
+
*
|
|
970
|
+
* @remarks
|
|
971
|
+
* Only affects source nodes (the root of the plan). All operator nodes are replayed
|
|
972
|
+
* exactly as recorded. If the plan has no source node (e.g. it starts from an operator
|
|
973
|
+
* node with a missing parent), this option has no effect.
|
|
974
|
+
*/
|
|
975
|
+
readonly source?: Iterable<unknown>;
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Compiles a query plan tree into an executable `TyneqSequence`.
|
|
979
|
+
*
|
|
980
|
+
* @remarks
|
|
981
|
+
* Walks the `QueryPlanNode` chain from source to terminal, reconstructing each operator by
|
|
982
|
+
* looking it up in the `OperatorRegistry` and applying it to the compiled source.
|
|
983
|
+
* An optional list of `QueryPlanTransformer` instances runs before compilation, allowing
|
|
984
|
+
* optimization or rewriting of the plan.
|
|
985
|
+
*
|
|
986
|
+
* @example
|
|
987
|
+
* ```ts
|
|
988
|
+
* import { Tyneq, tyneqQueryNode, QueryPlanCompiler, QueryPlanOptimizer } from "tyneq";
|
|
989
|
+
*
|
|
990
|
+
* const seq = Tyneq.from([1, 2, 3]).where(x => x > 1).select(x => x * 2);
|
|
991
|
+
* const compiler = new QueryPlanCompiler([new QueryPlanOptimizer()]);
|
|
992
|
+
* const result = compiler.compile(seq[tyneqQueryNode]!);
|
|
993
|
+
* result.toArray(); // -> [4, 6]
|
|
994
|
+
* ```
|
|
995
|
+
*
|
|
996
|
+
* @group QueryPlan
|
|
997
|
+
*/
|
|
998
|
+
declare class QueryPlanCompiler {
|
|
999
|
+
private readonly transformers;
|
|
1000
|
+
constructor(transformers?: Iterable<QueryPlanTransformer>);
|
|
1001
|
+
/**
|
|
1002
|
+
* Compile a query plan into an executable sequence.
|
|
1003
|
+
*
|
|
1004
|
+
* Runs all registered transformers before compiling. Use {@link compileRaw} to skip
|
|
1005
|
+
* the transform phase when the plan is already optimised.
|
|
1006
|
+
*
|
|
1007
|
+
* @param node - The root node of the query plan to compile.
|
|
1008
|
+
* @param options - Optional compile-time overrides. Use `options.source` to supply a
|
|
1009
|
+
* different data source than the one stored in the plan.
|
|
1010
|
+
* @returns The compiled sequence typed as `TyneqSequence<T>` by default.
|
|
1011
|
+
* If you know the plan ends in an operator that returns a subtype (e.g. `orderBy` ->
|
|
1012
|
+
* `TyneqOrderedSequence`, `memoize` -> `TyneqCachedSequence`), supply `TResult` explicitly:
|
|
1013
|
+
* `compiler.compile<number, TyneqOrderedSequence<number>>(node)`.
|
|
1014
|
+
*/
|
|
1015
|
+
compile<T = unknown, TResult extends TyneqSequence<T> = TyneqSequence<T>>(node: QueryPlanNode, options?: CompileOptions): TResult;
|
|
1016
|
+
/**
|
|
1017
|
+
* Compile a pre-optimised query plan into an executable sequence, skipping the
|
|
1018
|
+
* transform phase.
|
|
1019
|
+
*
|
|
1020
|
+
* @remarks
|
|
1021
|
+
* Use this overload when you have already run transformers externally (or deliberately
|
|
1022
|
+
* want to bypass them) and want to compile the node as-is. Equivalent to constructing
|
|
1023
|
+
* a `QueryPlanCompiler` with no transformers and calling `compile()`.
|
|
1024
|
+
*
|
|
1025
|
+
* @param node - The root node of the already-transformed query plan to compile.
|
|
1026
|
+
* @param options - Optional compile-time overrides. Use `options.source` to supply a
|
|
1027
|
+
* different data source than the one stored in the plan.
|
|
1028
|
+
*/
|
|
1029
|
+
compileRaw<T = unknown, TResult extends TyneqSequence<T> = TyneqSequence<T>>(node: QueryPlanNode, options?: CompileOptions): TResult;
|
|
1030
|
+
private transform;
|
|
1031
|
+
private compileNode;
|
|
1032
|
+
private compileSource;
|
|
1033
|
+
private applyOperator;
|
|
1034
|
+
private findOperatorEntry;
|
|
1035
|
+
}
|
|
1036
|
+
//#endregion
|
|
1037
|
+
export { type AccessorDescriptor, Action, ArgumentError, ArgumentNullError, ArgumentOutOfRangeError, ArgumentTypeError, ArgumentUtility, Assume, BoundMethod, CacheResult, CachedEnumerable, Cast, Comparer, type CompileOptions, CompilerError, Constructor, type DataDescriptor, Enumerable, Enumerator, EnumeratorFactory, EqualityComparer, Factory, FieldKeys, Func, GenericFunction, HasLength, type QueryPlanNode as IQueryNode, InstanceOf, InvalidOperationError, ItemAction, ItemPredicate, ItemSelector, IteratorFactory, KeyNotFoundError, KeyValuePair, Lazy, Maybe, type MemberDescriptor, Method, type MethodDescriptor, MethodKeys, MinMaxResult, NoInfer, NotSupportedError, Nullable, type OperatorCategory, type OperatorEntry, OperatorKind, OperatorMetadata, OperatorRegistry, OperatorSource, Optional, OrderedEnumerable, PluginError, Predicate, QueryNode, QueryPlanCompiler, QueryPlanOptimizer, QueryPlanPrinter, type QueryPlanPrinterOptions, QueryPlanTransformer, type QueryPlanTraversalDirection, type QueryPlanVisitor, QueryPlanWalker, type QueryPlanWalkerOptions, type ReflectOptions, ReflectionContext, ReflectionError, RegistryError, SequenceConstructor, SequenceContainsNoElementsError, SequenceFactory, type SourceKind, Tyneq, TyneqBaseEnumerator, TyneqCachedEnumerable, TyneqCachedEnumerator, TyneqCachedSequence, TyneqCachedTerminalOperator, TyneqComparer, TyneqEnumerableFactory, TyneqEnumerator, TyneqError, TyneqOrderedEnumerable, TyneqOrderedEnumerator, TyneqOrderedSequence, TyneqOrderedTerminalOperator, TyneqSequence, TyneqTerminalOperator, TypeGuardUtility, ValidationBuilder, ValidationError, WithProperties, cachedOperator, cachedTerminal, createCachedOperator, createCachedTerminalOperator, createGeneratorOperator, createOperator, createOrderedOperator, createOrderedTerminalOperator, createTerminalOperator, isSourceNode, operator, orderedOperator, orderedTerminal, reflect, terminal, tyneqQueryNode };
|
|
1038
|
+
//# sourceMappingURL=index.d.ts.map
|