@dxos/echo-query 0.10.0 → 0.11.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/dist/lib/index.mjs +641 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/sandbox.mjs +137 -0
- package/dist/lib/sandbox.mjs.map +1 -0
- package/dist/query-lite/index.d.ts +2315 -1764
- package/dist/query-lite/index.d.ts.map +1 -1
- package/dist/query-lite/index.js +131 -69
- package/dist/query-lite/index.js.map +1 -1
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/query-lite/query-lite.d.ts.map +1 -1
- package/dist/types/src/sandbox/query-sandbox.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -11
- package/src/index.ts +4 -1
- package/src/query-lite/query-lite.ts +148 -77
- package/src/sandbox/query-sandbox.ts +2 -2
- package/dist/lib/neutral/index.mjs +0 -918
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/echo-query",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "ECHO queries.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -19,7 +19,12 @@
|
|
|
19
19
|
".": {
|
|
20
20
|
"source": "./src/index.ts",
|
|
21
21
|
"types": "./dist/types/src/index.d.ts",
|
|
22
|
-
"
|
|
22
|
+
"import": "./dist/lib/index.mjs"
|
|
23
|
+
},
|
|
24
|
+
"./sandbox": {
|
|
25
|
+
"source": "./src/sandbox/index.ts",
|
|
26
|
+
"types": "./dist/types/src/sandbox/index.d.ts",
|
|
27
|
+
"import": "./dist/lib/sandbox.mjs"
|
|
23
28
|
},
|
|
24
29
|
"./api.d.ts": "./dist/query-lite/index.d.ts"
|
|
25
30
|
},
|
|
@@ -31,20 +36,20 @@
|
|
|
31
36
|
"dependencies": {
|
|
32
37
|
"@lezer/common": "^1.5.2",
|
|
33
38
|
"@lezer/lr": "^1.4.10",
|
|
34
|
-
"@dxos/context": "0.
|
|
35
|
-
"@dxos/echo": "0.
|
|
36
|
-
"@dxos/echo-protocol": "0.
|
|
37
|
-
"@dxos/node-std": "0.
|
|
38
|
-
"@dxos/
|
|
39
|
-
"@dxos/
|
|
40
|
-
"@dxos/invariant": "0.
|
|
39
|
+
"@dxos/context": "0.11.0",
|
|
40
|
+
"@dxos/echo": "0.11.0",
|
|
41
|
+
"@dxos/echo-protocol": "0.11.0",
|
|
42
|
+
"@dxos/node-std": "0.11.0",
|
|
43
|
+
"@dxos/util": "0.11.0",
|
|
44
|
+
"@dxos/vendor-quickjs": "0.11.0",
|
|
45
|
+
"@dxos/invariant": "0.11.0"
|
|
41
46
|
},
|
|
42
47
|
"devDependencies": {
|
|
43
48
|
"@lezer/generator": "^1.8.0",
|
|
44
49
|
"tsdown": "^0.16.7",
|
|
45
50
|
"typescript": "^6.0.3",
|
|
46
|
-
"@dxos/echo-generator": "0.
|
|
47
|
-
"@dxos/random": "0.
|
|
51
|
+
"@dxos/echo-generator": "0.11.0",
|
|
52
|
+
"@dxos/random": "0.11.0"
|
|
48
53
|
},
|
|
49
54
|
"publishConfig": {
|
|
50
55
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -3,4 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
export * from './parser';
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
// NOTE: `./sandbox` (QuerySandbox) is intentionally NOT re-exported here. It runtime-imports the
|
|
8
|
+
// vendored QuickJS wasm runtime (`@dxos/vendor-quickjs`), which every barrel consumer would then
|
|
9
|
+
// pull into its bundle even though only sandbox users need it. Import it from `@dxos/echo-query/sandbox`.
|
|
@@ -4,7 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
import type * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
Ref,
|
|
9
|
+
Aggregate as Aggregate$,
|
|
10
|
+
Filter as Filter$,
|
|
11
|
+
Obj as Obj$,
|
|
12
|
+
Order as Order$,
|
|
13
|
+
Query as Query$,
|
|
14
|
+
Type as Type$,
|
|
15
|
+
} from '@dxos/echo';
|
|
8
16
|
import type { ForeignKey, QueryAST } from '@dxos/echo-protocol';
|
|
9
17
|
import { assertArgument } from '@dxos/invariant';
|
|
10
18
|
// `DXN`/`EID` are type-only imports to keep the `query-lite` bundle free of
|
|
@@ -17,20 +25,30 @@ import type { DXN, EID, EntityId, URI } from '@dxos/keys';
|
|
|
17
25
|
|
|
18
26
|
// TODO(wittjosiah): The `export * as ...` syntax causes tsdown to genereate multiple files which breaks the sandbox.
|
|
19
27
|
|
|
28
|
+
// The TypeId brand keys mirror the constants in `@dxos/echo`. They are declared locally (typed by the
|
|
29
|
+
// type-only imports) rather than imported as runtime values to keep this sandbox bundle free of the
|
|
30
|
+
// `@dxos/echo` runtime graph.
|
|
31
|
+
const OrderTypeId: Order$.OrderTypeId = '~@dxos/echo/Order';
|
|
32
|
+
const FilterTypeId: Filter$.FilterTypeId = '~@dxos/echo/Filter';
|
|
33
|
+
const QueryTypeId: Query$.QueryTypeId = '~@dxos/echo/Query';
|
|
34
|
+
const ProjectionTypeId: Query$.ProjectionTypeId = '~@dxos/echo/Query.Projection';
|
|
35
|
+
|
|
20
36
|
class OrderClass implements Order$.Any {
|
|
21
|
-
private static 'variance': Order$.Any[
|
|
37
|
+
private static 'variance': Order$.Any[typeof OrderTypeId] = {} as Order$.Any[typeof OrderTypeId];
|
|
22
38
|
|
|
23
|
-
static
|
|
24
|
-
return typeof value === 'object' && value !== null &&
|
|
39
|
+
static is(value: unknown): value is Order$.Any {
|
|
40
|
+
return typeof value === 'object' && value !== null && OrderTypeId in value;
|
|
25
41
|
}
|
|
26
42
|
|
|
27
|
-
|
|
43
|
+
constructor(public readonly ast: QueryAST.Order) {}
|
|
28
44
|
|
|
29
|
-
|
|
45
|
+
[OrderTypeId] = OrderClass.variance;
|
|
30
46
|
}
|
|
31
47
|
|
|
32
48
|
namespace Order1 {
|
|
33
|
-
export const
|
|
49
|
+
export const OrderTypeId: Order$.OrderTypeId = '~@dxos/echo/Order';
|
|
50
|
+
export const natural = (direction: QueryAST.OrderDirection = 'asc'): Order$.Order<any> =>
|
|
51
|
+
new OrderClass({ kind: 'natural', direction });
|
|
34
52
|
export const property = <T>(property: keyof T & string, direction: QueryAST.OrderDirection): Order$.Order<T> =>
|
|
35
53
|
new OrderClass({
|
|
36
54
|
kind: 'property',
|
|
@@ -96,6 +114,10 @@ const _filterMatchValueLocal = (filter: QueryAST.Filter, value: unknown): boolea
|
|
|
96
114
|
}
|
|
97
115
|
case 'in':
|
|
98
116
|
return filter.values.includes(value);
|
|
117
|
+
case 'in-query':
|
|
118
|
+
// The QuickJS sandbox has no database access to run a subquery — a semi-join predicate
|
|
119
|
+
// must be resolved to a literal `in` by the query executor before reaching this matcher.
|
|
120
|
+
throw new Error('in-query filters are not supported in the sandboxed toPredicate matcher.');
|
|
99
121
|
case 'range':
|
|
100
122
|
return (value as any) >= filter.from && (value as any) <= filter.to;
|
|
101
123
|
case 'not':
|
|
@@ -145,17 +167,19 @@ const _filterMatchEntityLocal = (filter: QueryAST.Filter, entity: any): boolean
|
|
|
145
167
|
};
|
|
146
168
|
|
|
147
169
|
class FilterClass implements Filter$.Any {
|
|
148
|
-
|
|
170
|
+
static 'FilterTypeId': Filter$.FilterTypeId = FilterTypeId;
|
|
171
|
+
|
|
172
|
+
private static 'variance': Filter$.Any[typeof FilterTypeId] = {} as Filter$.Any[typeof FilterTypeId];
|
|
149
173
|
|
|
150
|
-
static
|
|
151
|
-
return typeof value === 'object' && value !== null &&
|
|
174
|
+
static is(value: unknown): value is Filter$.Any {
|
|
175
|
+
return typeof value === 'object' && value !== null && FilterTypeId in value;
|
|
152
176
|
}
|
|
153
177
|
|
|
154
|
-
static
|
|
178
|
+
static fromAst(ast: QueryAST.Filter): Filter$.Any {
|
|
155
179
|
return new FilterClass(ast);
|
|
156
180
|
}
|
|
157
181
|
|
|
158
|
-
static
|
|
182
|
+
static everything(): FilterClass {
|
|
159
183
|
return new FilterClass({
|
|
160
184
|
type: 'object',
|
|
161
185
|
typename: null,
|
|
@@ -163,7 +187,7 @@ class FilterClass implements Filter$.Any {
|
|
|
163
187
|
});
|
|
164
188
|
}
|
|
165
189
|
|
|
166
|
-
static
|
|
190
|
+
static nothing(): FilterClass {
|
|
167
191
|
return new FilterClass({
|
|
168
192
|
type: 'not',
|
|
169
193
|
filter: {
|
|
@@ -174,7 +198,7 @@ class FilterClass implements Filter$.Any {
|
|
|
174
198
|
});
|
|
175
199
|
}
|
|
176
200
|
|
|
177
|
-
static
|
|
201
|
+
static relation() {
|
|
178
202
|
return new FilterClass({
|
|
179
203
|
type: 'object',
|
|
180
204
|
typename: null,
|
|
@@ -182,7 +206,7 @@ class FilterClass implements Filter$.Any {
|
|
|
182
206
|
});
|
|
183
207
|
}
|
|
184
208
|
|
|
185
|
-
static
|
|
209
|
+
static id(...ids: EntityId[]): Filter$.Any {
|
|
186
210
|
// assertArgument(
|
|
187
211
|
// ids.every((id) => EntityId.isValid(id)),
|
|
188
212
|
// 'ids',
|
|
@@ -201,12 +225,12 @@ class FilterClass implements Filter$.Any {
|
|
|
201
225
|
});
|
|
202
226
|
}
|
|
203
227
|
|
|
204
|
-
static
|
|
228
|
+
static type<T extends Type$.AnyEntity>(
|
|
205
229
|
type: T,
|
|
206
230
|
props?: Filter$.Props<Type$.InstanceType<T>>,
|
|
207
231
|
): Filter$.Filter<Type$.InstanceType<T>>;
|
|
208
|
-
static
|
|
209
|
-
static
|
|
232
|
+
static type(schema: string, props?: Filter$.Props<unknown>): Filter$.Filter<any>;
|
|
233
|
+
static type(schema: Type$.AnyEntity | string, props?: Filter$.Props<unknown>): Filter$.Filter<unknown> {
|
|
210
234
|
if (typeof schema !== 'string') {
|
|
211
235
|
throw new TypeError('expected typename as the first paramter');
|
|
212
236
|
}
|
|
@@ -217,7 +241,7 @@ class FilterClass implements Filter$.Any {
|
|
|
217
241
|
});
|
|
218
242
|
}
|
|
219
243
|
|
|
220
|
-
static
|
|
244
|
+
static typename(typename: string): Filter$.Any {
|
|
221
245
|
return new FilterClass({
|
|
222
246
|
type: 'object',
|
|
223
247
|
typename: makeTypeDxn(typename),
|
|
@@ -225,7 +249,7 @@ class FilterClass implements Filter$.Any {
|
|
|
225
249
|
});
|
|
226
250
|
}
|
|
227
251
|
|
|
228
|
-
static
|
|
252
|
+
static typeURI(uri: URI.URI): Filter$.Any {
|
|
229
253
|
return new FilterClass({
|
|
230
254
|
type: 'object',
|
|
231
255
|
typename: uri,
|
|
@@ -233,14 +257,14 @@ class FilterClass implements Filter$.Any {
|
|
|
233
257
|
});
|
|
234
258
|
}
|
|
235
259
|
|
|
236
|
-
static
|
|
260
|
+
static tag(tag: string): Filter$.Any {
|
|
237
261
|
return new FilterClass({
|
|
238
262
|
type: 'tag',
|
|
239
263
|
tag,
|
|
240
264
|
});
|
|
241
265
|
}
|
|
242
266
|
|
|
243
|
-
static
|
|
267
|
+
static key(key: string, options?: Filter$.KeyFilterOptions): Filter$.Any {
|
|
244
268
|
return new FilterClass({
|
|
245
269
|
type: 'object',
|
|
246
270
|
typename: null,
|
|
@@ -250,7 +274,7 @@ class FilterClass implements Filter$.Any {
|
|
|
250
274
|
});
|
|
251
275
|
}
|
|
252
276
|
|
|
253
|
-
static
|
|
277
|
+
static props<T>(props: Filter$.Props<T>): Filter$.Filter<T> {
|
|
254
278
|
return new FilterClass({
|
|
255
279
|
type: 'object',
|
|
256
280
|
typename: null,
|
|
@@ -258,7 +282,7 @@ class FilterClass implements Filter$.Any {
|
|
|
258
282
|
});
|
|
259
283
|
}
|
|
260
284
|
|
|
261
|
-
static
|
|
285
|
+
static text(text: string, options?: Filter$.TextSearchOptions): Filter$.Any {
|
|
262
286
|
return new FilterClass({
|
|
263
287
|
type: 'text-search',
|
|
264
288
|
text,
|
|
@@ -266,7 +290,7 @@ class FilterClass implements Filter$.Any {
|
|
|
266
290
|
});
|
|
267
291
|
}
|
|
268
292
|
|
|
269
|
-
static
|
|
293
|
+
static foreignKeys<S extends Type$.AnyEntity | string>(
|
|
270
294
|
schema: S,
|
|
271
295
|
keys: ForeignKey[],
|
|
272
296
|
): Filter$.Filter<S extends Type$.AnyEntity ? Type$.InstanceType<S> : unknown> {
|
|
@@ -280,7 +304,7 @@ class FilterClass implements Filter$.Any {
|
|
|
280
304
|
});
|
|
281
305
|
}
|
|
282
306
|
|
|
283
|
-
static
|
|
307
|
+
static eq<T>(value: T): Filter$.Filter<T | undefined> {
|
|
284
308
|
if (!isRef(value) && typeof value === 'object' && value !== null) {
|
|
285
309
|
throw new TypeError('Cannot use object as a value for eq filter');
|
|
286
310
|
}
|
|
@@ -292,7 +316,7 @@ class FilterClass implements Filter$.Any {
|
|
|
292
316
|
});
|
|
293
317
|
}
|
|
294
318
|
|
|
295
|
-
static
|
|
319
|
+
static neq<T>(value: T): Filter$.Filter<T | undefined> {
|
|
296
320
|
return new FilterClass({
|
|
297
321
|
type: 'compare',
|
|
298
322
|
operator: 'neq',
|
|
@@ -300,7 +324,7 @@ class FilterClass implements Filter$.Any {
|
|
|
300
324
|
});
|
|
301
325
|
}
|
|
302
326
|
|
|
303
|
-
static
|
|
327
|
+
static gt<T>(value: T): Filter$.Filter<T | undefined> {
|
|
304
328
|
return new FilterClass({
|
|
305
329
|
type: 'compare',
|
|
306
330
|
operator: 'gt',
|
|
@@ -308,7 +332,7 @@ class FilterClass implements Filter$.Any {
|
|
|
308
332
|
});
|
|
309
333
|
}
|
|
310
334
|
|
|
311
|
-
static
|
|
335
|
+
static gte<T>(value: T): Filter$.Filter<T | undefined> {
|
|
312
336
|
return new FilterClass({
|
|
313
337
|
type: 'compare',
|
|
314
338
|
operator: 'gte',
|
|
@@ -316,7 +340,7 @@ class FilterClass implements Filter$.Any {
|
|
|
316
340
|
});
|
|
317
341
|
}
|
|
318
342
|
|
|
319
|
-
static
|
|
343
|
+
static lt<T>(value: T): Filter$.Filter<T | undefined> {
|
|
320
344
|
return new FilterClass({
|
|
321
345
|
type: 'compare',
|
|
322
346
|
operator: 'lt',
|
|
@@ -324,7 +348,7 @@ class FilterClass implements Filter$.Any {
|
|
|
324
348
|
});
|
|
325
349
|
}
|
|
326
350
|
|
|
327
|
-
static
|
|
351
|
+
static lte<T>(value: T): Filter$.Filter<T | undefined> {
|
|
328
352
|
return new FilterClass({
|
|
329
353
|
type: 'compare',
|
|
330
354
|
operator: 'lte',
|
|
@@ -332,21 +356,21 @@ class FilterClass implements Filter$.Any {
|
|
|
332
356
|
});
|
|
333
357
|
}
|
|
334
358
|
|
|
335
|
-
static
|
|
359
|
+
static in<T>(...values: T[]): Filter$.Filter<T> {
|
|
336
360
|
return new FilterClass({
|
|
337
361
|
type: 'in',
|
|
338
362
|
values,
|
|
339
363
|
});
|
|
340
364
|
}
|
|
341
365
|
|
|
342
|
-
static
|
|
366
|
+
static contains<T>(value: T): Filter$.Filter<readonly T[] | undefined> {
|
|
343
367
|
return new FilterClass({
|
|
344
368
|
type: 'contains',
|
|
345
369
|
value,
|
|
346
370
|
});
|
|
347
371
|
}
|
|
348
372
|
|
|
349
|
-
static
|
|
373
|
+
static between<T>(from: T, to: T): Filter$.Filter<T> {
|
|
350
374
|
return new FilterClass({
|
|
351
375
|
type: 'range',
|
|
352
376
|
from,
|
|
@@ -354,15 +378,15 @@ class FilterClass implements Filter$.Any {
|
|
|
354
378
|
});
|
|
355
379
|
}
|
|
356
380
|
|
|
357
|
-
static
|
|
381
|
+
static updated(range: { after?: Date | number; before?: Date | number }): Filter$.Any {
|
|
358
382
|
return FilterClass._timeRangeFilter('updatedAt', range);
|
|
359
383
|
}
|
|
360
384
|
|
|
361
|
-
static
|
|
385
|
+
static created(range: { after?: Date | number; before?: Date | number }): Filter$.Any {
|
|
362
386
|
return FilterClass._timeRangeFilter('createdAt', range);
|
|
363
387
|
}
|
|
364
388
|
|
|
365
|
-
static
|
|
389
|
+
static childOf(parents: unknown | unknown[], options?: { transitive?: boolean }): Filter$.Any {
|
|
366
390
|
const items = Array.isArray(parents) ? parents : [parents];
|
|
367
391
|
const dxns = items.map((item) => {
|
|
368
392
|
if (isEchoUriLike(item)) {
|
|
@@ -377,7 +401,7 @@ class FilterClass implements Filter$.Any {
|
|
|
377
401
|
});
|
|
378
402
|
}
|
|
379
403
|
|
|
380
|
-
private static
|
|
404
|
+
private static _timeRangeFilter(
|
|
381
405
|
field: 'updatedAt' | 'createdAt',
|
|
382
406
|
range: { after?: Date | number; before?: Date | number },
|
|
383
407
|
): Filter$.Any {
|
|
@@ -395,33 +419,33 @@ class FilterClass implements Filter$.Any {
|
|
|
395
419
|
return filters.length === 1 ? filters[0] : FilterClass.and(...filters);
|
|
396
420
|
}
|
|
397
421
|
|
|
398
|
-
static
|
|
422
|
+
static not<F extends Filter$.Any>(filter: F): Filter$.Filter<Filter$.Type<F>> {
|
|
399
423
|
return new FilterClass({
|
|
400
424
|
type: 'not',
|
|
401
425
|
filter: filter.ast,
|
|
402
426
|
});
|
|
403
427
|
}
|
|
404
428
|
|
|
405
|
-
static
|
|
429
|
+
static and<Filters extends readonly Filter$.Any[]>(
|
|
406
430
|
...filters: Filters
|
|
407
431
|
): Filter$.Filter<Filter$.Type<Filters[number]>> {
|
|
408
432
|
return new FilterClass({
|
|
409
433
|
type: 'and',
|
|
410
|
-
filters: filters.map((
|
|
434
|
+
filters: filters.map((filter) => filter.ast),
|
|
411
435
|
});
|
|
412
436
|
}
|
|
413
437
|
|
|
414
|
-
static
|
|
438
|
+
static or<Filters extends readonly Filter$.Any[]>(
|
|
415
439
|
...filters: Filters
|
|
416
440
|
): Filter$.Filter<Filter$.Type<Filters[number]>> {
|
|
417
441
|
return new FilterClass({
|
|
418
442
|
type: 'or',
|
|
419
|
-
filters: filters.map((
|
|
443
|
+
filters: filters.map((filter) => filter.ast),
|
|
420
444
|
});
|
|
421
445
|
}
|
|
422
446
|
|
|
423
447
|
/** Returns a human-readable string representation of a Filter AST. */
|
|
424
|
-
static
|
|
448
|
+
static pretty(filter: Filter$.Any): string {
|
|
425
449
|
return prettyFilter(filter.ast);
|
|
426
450
|
}
|
|
427
451
|
|
|
@@ -435,9 +459,9 @@ class FilterClass implements Filter$.Any {
|
|
|
435
459
|
return _filterMatchEntityLocal(filter.ast, entityOrFilter);
|
|
436
460
|
}) as typeof Filter$.toPredicate;
|
|
437
461
|
|
|
438
|
-
private
|
|
462
|
+
private constructor(public readonly ast: QueryAST.Filter) {}
|
|
439
463
|
|
|
440
|
-
|
|
464
|
+
[FilterTypeId] = FilterClass.variance;
|
|
441
465
|
}
|
|
442
466
|
|
|
443
467
|
export const Filter1: typeof Filter$ = FilterClass;
|
|
@@ -495,24 +519,29 @@ const processPredicate = (predicate: any): QueryAST.Filter => {
|
|
|
495
519
|
};
|
|
496
520
|
|
|
497
521
|
class QueryClass implements Query$.Any {
|
|
498
|
-
|
|
522
|
+
static 'QueryTypeId': Query$.QueryTypeId = QueryTypeId;
|
|
523
|
+
|
|
524
|
+
private static 'variance': Query$.Any[typeof QueryTypeId] = {} as Query$.Any[typeof QueryTypeId];
|
|
499
525
|
|
|
500
|
-
static '
|
|
501
|
-
|
|
526
|
+
private static 'projectionVariance': Query$.Projection<any>[typeof ProjectionTypeId] =
|
|
527
|
+
{} as Query$.Projection<any>[typeof ProjectionTypeId];
|
|
528
|
+
|
|
529
|
+
static is(value: unknown): value is Query$.Any {
|
|
530
|
+
return typeof value === 'object' && value !== null && QueryTypeId in value;
|
|
502
531
|
}
|
|
503
532
|
|
|
504
|
-
static
|
|
533
|
+
static fromAst(ast: QueryAST.Query): Query$.Any {
|
|
505
534
|
return new QueryClass(ast);
|
|
506
535
|
}
|
|
507
536
|
|
|
508
|
-
static
|
|
537
|
+
static select<F extends Filter$.Any>(filter: F): Query$.Query<Filter$.Type<F>> {
|
|
509
538
|
return new QueryClass({
|
|
510
539
|
type: 'select',
|
|
511
540
|
filter: filter.ast,
|
|
512
541
|
});
|
|
513
542
|
}
|
|
514
543
|
|
|
515
|
-
|
|
544
|
+
select(filter: Filter$.Any | Filter$.Props<any>): Query$.Any {
|
|
516
545
|
if (FilterClass.is(filter)) {
|
|
517
546
|
return new QueryClass({
|
|
518
547
|
type: 'filter',
|
|
@@ -528,13 +557,17 @@ class QueryClass implements Query$.Any {
|
|
|
528
557
|
}
|
|
529
558
|
}
|
|
530
559
|
|
|
531
|
-
|
|
560
|
+
project(property: string): Query$.Projection<any> {
|
|
561
|
+
return { [ProjectionTypeId]: QueryClass.projectionVariance, query: this.ast, property };
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
static type<S extends Schema.Schema.All>(
|
|
532
565
|
schema: S,
|
|
533
566
|
predicates?: Filter$.Props<Schema.Schema.Type<S>>,
|
|
534
567
|
): Query$.Query<Schema.Schema.Type<S>>;
|
|
535
|
-
static
|
|
536
|
-
static
|
|
537
|
-
static
|
|
568
|
+
static type(type: Type$.Type, predicates?: Filter$.Props<Obj$.Unknown>): Query$.Query<Obj$.Unknown>;
|
|
569
|
+
static type(schema: string, predicates?: Filter$.Props<unknown>): Query$.Query<any>;
|
|
570
|
+
static type(schema: Schema.Schema.All | Type$.Type | string, predicates?: Filter$.Props<unknown>): Query$.Any {
|
|
538
571
|
if (typeof schema !== 'string') {
|
|
539
572
|
throw new TypeError('expected typename as the first paramter');
|
|
540
573
|
}
|
|
@@ -544,7 +577,7 @@ class QueryClass implements Query$.Any {
|
|
|
544
577
|
});
|
|
545
578
|
}
|
|
546
579
|
|
|
547
|
-
static
|
|
580
|
+
static all(...queries: Query$.Any[]): Query$.Any {
|
|
548
581
|
if (queries.length === 0) {
|
|
549
582
|
throw new TypeError(
|
|
550
583
|
'Query.all combines results of multiple queries, to query all objects use Query.select(Filter.everything())',
|
|
@@ -556,7 +589,7 @@ class QueryClass implements Query$.Any {
|
|
|
556
589
|
});
|
|
557
590
|
}
|
|
558
591
|
|
|
559
|
-
static
|
|
592
|
+
static without<T>(source: Query$.Query<T>, exclude: Query$.Query<T>): Query$.Query<T> {
|
|
560
593
|
return new QueryClass({
|
|
561
594
|
type: 'set-difference',
|
|
562
595
|
source: source.ast,
|
|
@@ -564,7 +597,11 @@ class QueryClass implements Query$.Any {
|
|
|
564
597
|
});
|
|
565
598
|
}
|
|
566
599
|
|
|
567
|
-
static
|
|
600
|
+
static project(query: Query$.Any, property: string): Query$.Projection<any> {
|
|
601
|
+
return { [ProjectionTypeId]: QueryClass.projectionVariance, query: query.ast, property };
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
static from(...args: any[]): Query$.Any {
|
|
568
605
|
const baseQuery: QueryAST.Query = {
|
|
569
606
|
type: 'select',
|
|
570
607
|
filter: FilterClass.everything().ast,
|
|
@@ -573,7 +610,7 @@ class QueryClass implements Query$.Any {
|
|
|
573
610
|
return (wrapper.from as (...args: any[]) => Query$.Any)(...args);
|
|
574
611
|
}
|
|
575
612
|
|
|
576
|
-
|
|
613
|
+
from(...args: any[]): Query$.Any {
|
|
577
614
|
// Variadic raw scopes: `.from(Scope.space(), Scope.registry())`.
|
|
578
615
|
if (args.length > 1 && args.every((arg) => _isScopeLike(arg))) {
|
|
579
616
|
return new QueryClass({
|
|
@@ -604,15 +641,15 @@ class QueryClass implements Query$.Any {
|
|
|
604
641
|
}
|
|
605
642
|
|
|
606
643
|
/** Returns a human-readable string representation of a Query AST. */
|
|
607
|
-
static
|
|
644
|
+
static pretty(query: Query$.Any): string {
|
|
608
645
|
return prettyQuery(query.ast);
|
|
609
646
|
}
|
|
610
647
|
|
|
611
|
-
|
|
648
|
+
constructor(public readonly ast: QueryAST.Query) {}
|
|
612
649
|
|
|
613
|
-
|
|
650
|
+
[QueryTypeId] = QueryClass.variance;
|
|
614
651
|
|
|
615
|
-
|
|
652
|
+
reference(key: string): Query$.Any {
|
|
616
653
|
return new QueryClass({
|
|
617
654
|
type: 'reference-traversal',
|
|
618
655
|
anchor: this.ast,
|
|
@@ -620,7 +657,7 @@ class QueryClass implements Query$.Any {
|
|
|
620
657
|
});
|
|
621
658
|
}
|
|
622
659
|
|
|
623
|
-
|
|
660
|
+
referencedBy(target?: Type$.AnyEntity | string, key?: string): Query$.Any {
|
|
624
661
|
if (target !== undefined && typeof target !== 'string') {
|
|
625
662
|
throw new TypeError('referencedBy requires a typename string in query-lite');
|
|
626
663
|
}
|
|
@@ -633,7 +670,7 @@ class QueryClass implements Query$.Any {
|
|
|
633
670
|
});
|
|
634
671
|
}
|
|
635
672
|
|
|
636
|
-
|
|
673
|
+
sourceOf(
|
|
637
674
|
relation?: Type$.Relation<any, any, any, any> | string,
|
|
638
675
|
predicates?: Filter$.Props<unknown> | undefined,
|
|
639
676
|
): Query$.Any {
|
|
@@ -650,7 +687,7 @@ class QueryClass implements Query$.Any {
|
|
|
650
687
|
});
|
|
651
688
|
}
|
|
652
689
|
|
|
653
|
-
|
|
690
|
+
targetOf(
|
|
654
691
|
relation?: Type$.Relation<any, any, any, any> | string,
|
|
655
692
|
predicates?: Filter$.Props<unknown> | undefined,
|
|
656
693
|
): Query$.Any {
|
|
@@ -667,7 +704,7 @@ class QueryClass implements Query$.Any {
|
|
|
667
704
|
});
|
|
668
705
|
}
|
|
669
706
|
|
|
670
|
-
|
|
707
|
+
source(): Query$.Any {
|
|
671
708
|
return new QueryClass({
|
|
672
709
|
type: 'relation-traversal',
|
|
673
710
|
anchor: this.ast,
|
|
@@ -675,7 +712,7 @@ class QueryClass implements Query$.Any {
|
|
|
675
712
|
});
|
|
676
713
|
}
|
|
677
714
|
|
|
678
|
-
|
|
715
|
+
target(): Query$.Any {
|
|
679
716
|
return new QueryClass({
|
|
680
717
|
type: 'relation-traversal',
|
|
681
718
|
anchor: this.ast,
|
|
@@ -683,7 +720,7 @@ class QueryClass implements Query$.Any {
|
|
|
683
720
|
});
|
|
684
721
|
}
|
|
685
722
|
|
|
686
|
-
|
|
723
|
+
parent(): Query$.Any {
|
|
687
724
|
return new QueryClass({
|
|
688
725
|
type: 'hierarchy-traversal',
|
|
689
726
|
anchor: this.ast,
|
|
@@ -691,7 +728,7 @@ class QueryClass implements Query$.Any {
|
|
|
691
728
|
});
|
|
692
729
|
}
|
|
693
730
|
|
|
694
|
-
|
|
731
|
+
children(): Query$.Any {
|
|
695
732
|
return new QueryClass({
|
|
696
733
|
type: 'hierarchy-traversal',
|
|
697
734
|
anchor: this.ast,
|
|
@@ -699,15 +736,15 @@ class QueryClass implements Query$.Any {
|
|
|
699
736
|
});
|
|
700
737
|
}
|
|
701
738
|
|
|
702
|
-
|
|
739
|
+
orderBy(...order: Order$.Any[]): Query$.Any {
|
|
703
740
|
return new QueryClass({
|
|
704
741
|
type: 'order',
|
|
705
742
|
query: this.ast,
|
|
706
|
-
order: order.map((
|
|
743
|
+
order: order.map((orderItem) => orderItem.ast),
|
|
707
744
|
});
|
|
708
745
|
}
|
|
709
746
|
|
|
710
|
-
|
|
747
|
+
limit(limit: number): Query$.Any {
|
|
711
748
|
return new QueryClass({
|
|
712
749
|
type: 'limit',
|
|
713
750
|
query: this.ast,
|
|
@@ -715,7 +752,23 @@ class QueryClass implements Query$.Any {
|
|
|
715
752
|
});
|
|
716
753
|
}
|
|
717
754
|
|
|
718
|
-
|
|
755
|
+
skip(skip: number): Query$.Any {
|
|
756
|
+
return new QueryClass({
|
|
757
|
+
type: 'skip',
|
|
758
|
+
query: this.ast,
|
|
759
|
+
skip,
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
aggregate(aggregates: Record<string, Aggregate$.Any>): Query$.Any {
|
|
764
|
+
return new QueryClass({
|
|
765
|
+
type: 'aggregate',
|
|
766
|
+
query: this.ast,
|
|
767
|
+
aggregates: Object.entries(aggregates).map(([name, aggregate]) => ({ name, ...aggregate.spec })),
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
options(options: QueryAST.QueryOptions): Query$.Any {
|
|
719
772
|
return new QueryClass({
|
|
720
773
|
type: 'options',
|
|
721
774
|
query: this.ast,
|
|
@@ -723,7 +776,7 @@ class QueryClass implements Query$.Any {
|
|
|
723
776
|
});
|
|
724
777
|
}
|
|
725
778
|
|
|
726
|
-
|
|
779
|
+
debugLabel(label: string): Query$.Any {
|
|
727
780
|
if (this.ast.type === 'options') {
|
|
728
781
|
return new QueryClass({
|
|
729
782
|
type: 'options',
|
|
@@ -821,6 +874,8 @@ const prettyFilter = (filter: QueryAST.Filter): string => {
|
|
|
821
874
|
return `Filter.${filter.operator}(${JSON.stringify(filter.value)})`;
|
|
822
875
|
case 'in':
|
|
823
876
|
return `Filter.in(${filter.values.map((v) => JSON.stringify(v)).join(', ')})`;
|
|
877
|
+
case 'in-query':
|
|
878
|
+
return `Filter.in(${prettyQuery(filter.subquery)}.project(${JSON.stringify(filter.property)}))`;
|
|
824
879
|
case 'contains':
|
|
825
880
|
return `Filter.contains(${JSON.stringify(filter.value)})`;
|
|
826
881
|
case 'range':
|
|
@@ -879,7 +934,7 @@ const prettyQuery = (query: QueryAST.Query): string => {
|
|
|
879
934
|
case 'order': {
|
|
880
935
|
const orders = query.order.map((o) => {
|
|
881
936
|
if (o.kind === 'natural') {
|
|
882
|
-
return
|
|
937
|
+
return `Order.natural(${JSON.stringify(o.direction)})`;
|
|
883
938
|
}
|
|
884
939
|
if (o.kind === 'rank') {
|
|
885
940
|
return `Order.rank(${JSON.stringify(o.direction)})`;
|
|
@@ -924,5 +979,21 @@ const prettyQuery = (query: QueryAST.Query): string => {
|
|
|
924
979
|
}
|
|
925
980
|
case 'limit':
|
|
926
981
|
return `${prettyQuery(query.query)}.limit(${query.limit})`;
|
|
982
|
+
case 'skip':
|
|
983
|
+
return `${prettyQuery(query.query)}.skip(${query.skip})`;
|
|
984
|
+
case 'aggregate': {
|
|
985
|
+
const aggregates = query.aggregates.map((aggregate) => {
|
|
986
|
+
const arg =
|
|
987
|
+
aggregate.kind === 'items'
|
|
988
|
+
? aggregate.limit !== undefined
|
|
989
|
+
? `{ limit: ${aggregate.limit} }`
|
|
990
|
+
: ''
|
|
991
|
+
: aggregate.kind === 'count'
|
|
992
|
+
? ''
|
|
993
|
+
: JSON.stringify(aggregate.property);
|
|
994
|
+
return `${JSON.stringify(aggregate.name)}: Aggregate.${aggregate.kind}(${arg})`;
|
|
995
|
+
});
|
|
996
|
+
return `${prettyQuery(query.query)}.aggregate({ ${aggregates.join(', ')} })`;
|
|
997
|
+
}
|
|
927
998
|
}
|
|
928
999
|
};
|