@dxos/echo-query 0.8.4-main.c4373fc → 0.8.4-main.d05673bc65
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/{browser → neutral}/index.mjs +257 -68
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/query-lite/index.d.ts +9895 -0
- package/dist/query-lite/index.d.ts.map +1 -0
- package/dist/query-lite/index.js +415 -0
- package/dist/query-lite/index.js.map +1 -0
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/parser/gen/query.terms.d.ts +1 -1
- package/dist/types/src/parser/gen/query.terms.d.ts.map +1 -1
- package/dist/types/src/parser/query-builder.d.ts +12 -4
- package/dist/types/src/parser/query-builder.d.ts.map +1 -1
- package/dist/types/src/query-lite/index.d.ts +2 -0
- package/dist/types/src/query-lite/index.d.ts.map +1 -0
- package/dist/types/src/query-lite/query-lite.d.ts +8 -0
- package/dist/types/src/query-lite/query-lite.d.ts.map +1 -0
- package/dist/types/src/sandbox/index.d.ts +2 -0
- package/dist/types/src/sandbox/index.d.ts.map +1 -0
- package/dist/types/src/sandbox/query-sandbox.d.ts +1 -1
- package/dist/types/src/sandbox/quickjs.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +22 -17
- package/src/env.d.ts +1 -1
- package/src/index.ts +1 -0
- package/src/parser/gen/query.terms.ts +24 -23
- package/src/parser/gen/query.ts +8 -8
- package/src/parser/query-builder.ts +65 -12
- package/src/parser/query.grammar +8 -2
- package/src/parser/query.test.ts +96 -43
- package/src/query-lite/index.ts +5 -0
- package/src/{query-env/index.ts → query-lite/query-lite.ts} +145 -59
- package/src/sandbox/index.ts +5 -0
- package/src/sandbox/query-sandbox.test.ts +15 -14
- package/src/sandbox/query-sandbox.ts +4 -4
- package/src/sandbox/quickjs.ts +1 -2
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/node-esm/index.mjs +0 -530
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/query-env/index.js +0 -387
- package/dist/types/src/query-env/index.d.ts +0 -8
- package/dist/types/src/query-env/index.d.ts.map +0 -1
|
@@ -4,16 +4,21 @@
|
|
|
4
4
|
|
|
5
5
|
import type * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
|
-
import type { Filter
|
|
8
|
-
import type * as Echo from '@dxos/echo';
|
|
7
|
+
import type { Filter as Filter$, Order as Order$, Query as Query$, Ref } from '@dxos/echo';
|
|
9
8
|
import type { ForeignKey, QueryAST } from '@dxos/echo-protocol';
|
|
10
9
|
import { assertArgument } from '@dxos/invariant';
|
|
11
10
|
import type { DXN, ObjectId } from '@dxos/keys';
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
//
|
|
13
|
+
// Light-weight implementation of query execution.
|
|
14
|
+
//
|
|
15
|
+
|
|
16
|
+
// TODO(wittjosiah): The `export * as ...` syntax causes tsdown to genereate multiple files which breaks the sandbox.
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
class OrderClass implements Order$.Any {
|
|
19
|
+
private static 'variance': Order$.Any['~Order'] = {} as Order$.Any['~Order'];
|
|
20
|
+
|
|
21
|
+
static is(value: unknown): value is Order$.Any {
|
|
17
22
|
return typeof value === 'object' && value !== null && '~Order' in value;
|
|
18
23
|
}
|
|
19
24
|
|
|
@@ -21,27 +26,33 @@ class OrderClass implements Echo.Order<any> {
|
|
|
21
26
|
|
|
22
27
|
'~Order' = OrderClass.variance;
|
|
23
28
|
}
|
|
29
|
+
|
|
24
30
|
namespace Order1 {
|
|
25
|
-
export const natural:
|
|
26
|
-
export const property = <T>(property: keyof T & string, direction: QueryAST.OrderDirection):
|
|
31
|
+
export const natural: Order$.Any = new OrderClass({ kind: 'natural' });
|
|
32
|
+
export const property = <T>(property: keyof T & string, direction: QueryAST.OrderDirection): Order$.Order<T> =>
|
|
27
33
|
new OrderClass({
|
|
28
34
|
kind: 'property',
|
|
29
35
|
property,
|
|
30
36
|
direction,
|
|
31
37
|
});
|
|
38
|
+
export const rank = <T>(direction: QueryAST.OrderDirection = 'desc'): Order$.Order<T> =>
|
|
39
|
+
new OrderClass({
|
|
40
|
+
kind: 'rank',
|
|
41
|
+
direction,
|
|
42
|
+
});
|
|
32
43
|
}
|
|
33
44
|
|
|
34
|
-
const Order2: typeof
|
|
45
|
+
const Order2: typeof Order$ = Order1;
|
|
35
46
|
export { Order2 as Order };
|
|
36
47
|
|
|
37
|
-
class FilterClass implements
|
|
38
|
-
private static variance:
|
|
48
|
+
class FilterClass implements Filter$.Any {
|
|
49
|
+
private static 'variance': Filter$.Any['~Filter'] = {} as Filter$.Any['~Filter'];
|
|
39
50
|
|
|
40
|
-
static is(value: unknown): value is
|
|
51
|
+
static is(value: unknown): value is Filter$.Any {
|
|
41
52
|
return typeof value === 'object' && value !== null && '~Filter' in value;
|
|
42
53
|
}
|
|
43
54
|
|
|
44
|
-
static fromAst(ast: QueryAST.Filter): Filter
|
|
55
|
+
static fromAst(ast: QueryAST.Filter): Filter$.Any {
|
|
45
56
|
return new FilterClass(ast);
|
|
46
57
|
}
|
|
47
58
|
|
|
@@ -72,7 +83,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
72
83
|
});
|
|
73
84
|
}
|
|
74
85
|
|
|
75
|
-
static
|
|
86
|
+
static id(...ids: ObjectId[]): Filter$.Any {
|
|
76
87
|
// assertArgument(
|
|
77
88
|
// ids.every((id) => ObjectId.isValid(id)),
|
|
78
89
|
// 'ids',
|
|
@@ -93,8 +104,8 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
93
104
|
|
|
94
105
|
static type<S extends Schema.Schema.All>(
|
|
95
106
|
schema: S | string,
|
|
96
|
-
props?:
|
|
97
|
-
):
|
|
107
|
+
props?: Filter$.Props<Schema.Schema.Type<S>>,
|
|
108
|
+
): Filter$.Filter<Schema.Schema.Type<S>> {
|
|
98
109
|
if (typeof schema !== 'string') {
|
|
99
110
|
throw new TypeError('expected typename as the first paramter');
|
|
100
111
|
}
|
|
@@ -105,7 +116,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
105
116
|
});
|
|
106
117
|
}
|
|
107
118
|
|
|
108
|
-
static typename(typename: string):
|
|
119
|
+
static typename(typename: string): Filter$.Any {
|
|
109
120
|
return new FilterClass({
|
|
110
121
|
type: 'object',
|
|
111
122
|
typename: makeTypeDxn(typename),
|
|
@@ -113,7 +124,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
113
124
|
});
|
|
114
125
|
}
|
|
115
126
|
|
|
116
|
-
static typeDXN(dxn: DXN):
|
|
127
|
+
static typeDXN(dxn: DXN): Filter$.Any {
|
|
117
128
|
return new FilterClass({
|
|
118
129
|
type: 'object',
|
|
119
130
|
typename: dxn.toString(),
|
|
@@ -121,14 +132,14 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
121
132
|
});
|
|
122
133
|
}
|
|
123
134
|
|
|
124
|
-
static tag(tag: string):
|
|
135
|
+
static tag(tag: string): Filter$.Any {
|
|
125
136
|
return new FilterClass({
|
|
126
137
|
type: 'tag',
|
|
127
138
|
tag,
|
|
128
139
|
});
|
|
129
140
|
}
|
|
130
141
|
|
|
131
|
-
static props<T>(props:
|
|
142
|
+
static props<T>(props: Filter$.Props<T>): Filter$.Filter<T> {
|
|
132
143
|
return new FilterClass({
|
|
133
144
|
type: 'object',
|
|
134
145
|
typename: null,
|
|
@@ -136,7 +147,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
136
147
|
});
|
|
137
148
|
}
|
|
138
149
|
|
|
139
|
-
static text(text: string, options?:
|
|
150
|
+
static text(text: string, options?: Filter$.TextSearchOptions): Filter$.Any {
|
|
140
151
|
return new FilterClass({
|
|
141
152
|
type: 'text-search',
|
|
142
153
|
text,
|
|
@@ -147,7 +158,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
147
158
|
static foreignKeys<S extends Schema.Schema.All>(
|
|
148
159
|
schema: S | string,
|
|
149
160
|
keys: ForeignKey[],
|
|
150
|
-
):
|
|
161
|
+
): Filter$.Filter<Schema.Schema.Type<S>> {
|
|
151
162
|
assertArgument(typeof schema === 'string', 'schema');
|
|
152
163
|
assertArgument(!schema.startsWith('dxn:'), 'schema');
|
|
153
164
|
return new FilterClass({
|
|
@@ -158,7 +169,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
158
169
|
});
|
|
159
170
|
}
|
|
160
171
|
|
|
161
|
-
static eq<T>(value: T):
|
|
172
|
+
static eq<T>(value: T): Filter$.Filter<T | undefined> {
|
|
162
173
|
if (!isRef(value) && typeof value === 'object' && value !== null) {
|
|
163
174
|
throw new TypeError('Cannot use object as a value for eq filter');
|
|
164
175
|
}
|
|
@@ -170,7 +181,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
170
181
|
});
|
|
171
182
|
}
|
|
172
183
|
|
|
173
|
-
static neq<T>(value: T):
|
|
184
|
+
static neq<T>(value: T): Filter$.Filter<T | undefined> {
|
|
174
185
|
return new FilterClass({
|
|
175
186
|
type: 'compare',
|
|
176
187
|
operator: 'neq',
|
|
@@ -178,7 +189,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
178
189
|
});
|
|
179
190
|
}
|
|
180
191
|
|
|
181
|
-
static gt<T>(value: T):
|
|
192
|
+
static gt<T>(value: T): Filter$.Filter<T | undefined> {
|
|
182
193
|
return new FilterClass({
|
|
183
194
|
type: 'compare',
|
|
184
195
|
operator: 'gt',
|
|
@@ -186,7 +197,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
186
197
|
});
|
|
187
198
|
}
|
|
188
199
|
|
|
189
|
-
static gte<T>(value: T):
|
|
200
|
+
static gte<T>(value: T): Filter$.Filter<T | undefined> {
|
|
190
201
|
return new FilterClass({
|
|
191
202
|
type: 'compare',
|
|
192
203
|
operator: 'gte',
|
|
@@ -194,7 +205,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
194
205
|
});
|
|
195
206
|
}
|
|
196
207
|
|
|
197
|
-
static lt<T>(value: T):
|
|
208
|
+
static lt<T>(value: T): Filter$.Filter<T | undefined> {
|
|
198
209
|
return new FilterClass({
|
|
199
210
|
type: 'compare',
|
|
200
211
|
operator: 'lt',
|
|
@@ -202,7 +213,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
202
213
|
});
|
|
203
214
|
}
|
|
204
215
|
|
|
205
|
-
static lte<T>(value: T):
|
|
216
|
+
static lte<T>(value: T): Filter$.Filter<T | undefined> {
|
|
206
217
|
return new FilterClass({
|
|
207
218
|
type: 'compare',
|
|
208
219
|
operator: 'lte',
|
|
@@ -210,21 +221,21 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
210
221
|
});
|
|
211
222
|
}
|
|
212
223
|
|
|
213
|
-
static in<T>(...values: T[]):
|
|
224
|
+
static in<T>(...values: T[]): Filter$.Filter<T | undefined> {
|
|
214
225
|
return new FilterClass({
|
|
215
226
|
type: 'in',
|
|
216
227
|
values,
|
|
217
228
|
});
|
|
218
229
|
}
|
|
219
230
|
|
|
220
|
-
static contains<T>(value: T):
|
|
231
|
+
static contains<T>(value: T): Filter$.Filter<readonly T[] | undefined> {
|
|
221
232
|
return new FilterClass({
|
|
222
233
|
type: 'contains',
|
|
223
234
|
value,
|
|
224
235
|
});
|
|
225
236
|
}
|
|
226
237
|
|
|
227
|
-
static between<T>(from: T, to: T):
|
|
238
|
+
static between<T>(from: T, to: T): Filter$.Filter<unknown> {
|
|
228
239
|
return new FilterClass({
|
|
229
240
|
type: 'range',
|
|
230
241
|
from,
|
|
@@ -232,21 +243,25 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
232
243
|
});
|
|
233
244
|
}
|
|
234
245
|
|
|
235
|
-
static not<F extends
|
|
246
|
+
static not<F extends Filter$.Any>(filter: F): Filter$.Filter<Filter$.Type<F>> {
|
|
236
247
|
return new FilterClass({
|
|
237
248
|
type: 'not',
|
|
238
249
|
filter: filter.ast,
|
|
239
250
|
});
|
|
240
251
|
}
|
|
241
252
|
|
|
242
|
-
static and<
|
|
253
|
+
static and<Filters extends readonly Filter$.Any[]>(
|
|
254
|
+
...filters: Filters
|
|
255
|
+
): Filter$.Filter<Filter$.Type<Filters[number]>> {
|
|
243
256
|
return new FilterClass({
|
|
244
257
|
type: 'and',
|
|
245
258
|
filters: filters.map((f) => f.ast),
|
|
246
259
|
});
|
|
247
260
|
}
|
|
248
261
|
|
|
249
|
-
static or<
|
|
262
|
+
static or<Filters extends readonly Filter$.Any[]>(
|
|
263
|
+
...filters: Filters
|
|
264
|
+
): Filter$.Filter<Filter$.Type<Filters[number]>> {
|
|
250
265
|
return new FilterClass({
|
|
251
266
|
type: 'or',
|
|
252
267
|
filters: filters.map((f) => f.ast),
|
|
@@ -258,7 +273,7 @@ class FilterClass implements Echo.Filter<any> {
|
|
|
258
273
|
'~Filter' = FilterClass.variance;
|
|
259
274
|
}
|
|
260
275
|
|
|
261
|
-
export const Filter1: typeof
|
|
276
|
+
export const Filter1: typeof Filter$ = FilterClass;
|
|
262
277
|
export { Filter1 as Filter };
|
|
263
278
|
|
|
264
279
|
/**
|
|
@@ -267,7 +282,7 @@ export { Filter1 as Filter };
|
|
|
267
282
|
// TODO(dmaretskyi): Filter only properties that are references (or optional references, or unions that include references).
|
|
268
283
|
type RefPropKey<T> = keyof T & string;
|
|
269
284
|
|
|
270
|
-
const propsFilterToAst = (predicates:
|
|
285
|
+
const propsFilterToAst = (predicates: Filter$.Props<any>): Pick<QueryAST.FilterObject, 'id' | 'props'> => {
|
|
271
286
|
let idFilter: readonly ObjectId[] | undefined;
|
|
272
287
|
if ('id' in predicates) {
|
|
273
288
|
assertArgument(
|
|
@@ -312,32 +327,32 @@ const processPredicate = (predicate: any): QueryAST.Filter => {
|
|
|
312
327
|
return FilterClass.eq(predicate).ast;
|
|
313
328
|
};
|
|
314
329
|
|
|
315
|
-
class QueryClass implements
|
|
316
|
-
private static variance:
|
|
330
|
+
class QueryClass implements Query$.Any {
|
|
331
|
+
private static 'variance': Query$.Any['~Query'] = {} as Query$.Any['~Query'];
|
|
317
332
|
|
|
318
|
-
static is(value: unknown): value is
|
|
333
|
+
static is(value: unknown): value is Query$.Any {
|
|
319
334
|
return typeof value === 'object' && value !== null && '~Query' in value;
|
|
320
335
|
}
|
|
321
336
|
|
|
322
|
-
static fromAst(ast: QueryAST.Query):
|
|
337
|
+
static fromAst(ast: QueryAST.Query): Query$.Any {
|
|
323
338
|
return new QueryClass(ast);
|
|
324
339
|
}
|
|
325
340
|
|
|
326
|
-
static select<F extends
|
|
341
|
+
static select<F extends Filter$.Any>(filter: F): Query$.Query<Filter$.Type<F>> {
|
|
327
342
|
return new QueryClass({
|
|
328
343
|
type: 'select',
|
|
329
344
|
filter: filter.ast,
|
|
330
345
|
});
|
|
331
346
|
}
|
|
332
347
|
|
|
333
|
-
static type(schema: Schema.Schema.All | string, predicates?:
|
|
348
|
+
static type(schema: Schema.Schema.All | string, predicates?: Filter$.Props<unknown>): Query$.Any {
|
|
334
349
|
return new QueryClass({
|
|
335
350
|
type: 'select',
|
|
336
351
|
filter: FilterClass.type(schema, predicates).ast,
|
|
337
352
|
});
|
|
338
353
|
}
|
|
339
354
|
|
|
340
|
-
static all(...queries: Query
|
|
355
|
+
static all(...queries: Query$.Any[]): Query$.Any {
|
|
341
356
|
if (queries.length === 0) {
|
|
342
357
|
throw new TypeError(
|
|
343
358
|
'Query.all combines results of multiple queries, to query all objects use Query.select(Filter.everything())',
|
|
@@ -349,7 +364,7 @@ class QueryClass implements Echo.Query<any> {
|
|
|
349
364
|
});
|
|
350
365
|
}
|
|
351
366
|
|
|
352
|
-
static without<T>(source: Query<T>, exclude: Query<T>): Query<T> {
|
|
367
|
+
static without<T>(source: Query$.Query<T>, exclude: Query$.Query<T>): Query$.Query<T> {
|
|
353
368
|
return new QueryClass({
|
|
354
369
|
type: 'set-difference',
|
|
355
370
|
source: source.ast,
|
|
@@ -357,11 +372,20 @@ class QueryClass implements Echo.Query<any> {
|
|
|
357
372
|
});
|
|
358
373
|
}
|
|
359
374
|
|
|
375
|
+
static from(source: any, options?: { includeFeeds?: boolean }): Query$.Any {
|
|
376
|
+
const baseQuery: QueryAST.Query = {
|
|
377
|
+
type: 'select',
|
|
378
|
+
filter: FilterClass.everything().ast,
|
|
379
|
+
};
|
|
380
|
+
const wrapper = new QueryClass(baseQuery);
|
|
381
|
+
return wrapper.from(source, options);
|
|
382
|
+
}
|
|
383
|
+
|
|
360
384
|
constructor(public readonly ast: QueryAST.Query) {}
|
|
361
385
|
|
|
362
386
|
'~Query' = QueryClass.variance;
|
|
363
387
|
|
|
364
|
-
select(filter: Filter
|
|
388
|
+
select(filter: Filter$.Any | Filter$.Props<any>): Query$.Any {
|
|
365
389
|
if (FilterClass.is(filter)) {
|
|
366
390
|
return new QueryClass({
|
|
367
391
|
type: 'filter',
|
|
@@ -377,7 +401,7 @@ class QueryClass implements Echo.Query<any> {
|
|
|
377
401
|
}
|
|
378
402
|
}
|
|
379
403
|
|
|
380
|
-
reference(key: string): Query
|
|
404
|
+
reference(key: string): Query$.Any {
|
|
381
405
|
return new QueryClass({
|
|
382
406
|
type: 'reference-traversal',
|
|
383
407
|
anchor: this.ast,
|
|
@@ -385,36 +409,40 @@ class QueryClass implements Echo.Query<any> {
|
|
|
385
409
|
});
|
|
386
410
|
}
|
|
387
411
|
|
|
388
|
-
referencedBy(target
|
|
389
|
-
|
|
390
|
-
|
|
412
|
+
referencedBy(target?: Schema.Schema.All | string, key?: string): Query$.Any {
|
|
413
|
+
const typename =
|
|
414
|
+
target !== undefined
|
|
415
|
+
? (assertArgument(typeof target === 'string', 'target'),
|
|
416
|
+
assertArgument(!target.startsWith('dxn:'), 'target'),
|
|
417
|
+
target)
|
|
418
|
+
: null;
|
|
391
419
|
return new QueryClass({
|
|
392
420
|
type: 'incoming-references',
|
|
393
421
|
anchor: this.ast,
|
|
394
|
-
property: key,
|
|
395
|
-
typename
|
|
422
|
+
property: key ?? null,
|
|
423
|
+
typename,
|
|
396
424
|
});
|
|
397
425
|
}
|
|
398
426
|
|
|
399
|
-
sourceOf(relation
|
|
427
|
+
sourceOf(relation?: Schema.Schema.All | string, predicates?: Filter$.Props<unknown> | undefined): Query$.Any {
|
|
400
428
|
return new QueryClass({
|
|
401
429
|
type: 'relation',
|
|
402
430
|
anchor: this.ast,
|
|
403
431
|
direction: 'outgoing',
|
|
404
|
-
filter: FilterClass.type(relation, predicates).ast,
|
|
432
|
+
filter: relation !== undefined ? FilterClass.type(relation, predicates).ast : undefined,
|
|
405
433
|
});
|
|
406
434
|
}
|
|
407
435
|
|
|
408
|
-
targetOf(relation
|
|
436
|
+
targetOf(relation?: Schema.Schema.All | string, predicates?: Filter$.Props<unknown> | undefined): Query$.Any {
|
|
409
437
|
return new QueryClass({
|
|
410
438
|
type: 'relation',
|
|
411
439
|
anchor: this.ast,
|
|
412
440
|
direction: 'incoming',
|
|
413
|
-
filter: FilterClass.type(relation, predicates).ast,
|
|
441
|
+
filter: relation !== undefined ? FilterClass.type(relation, predicates).ast : undefined,
|
|
414
442
|
});
|
|
415
443
|
}
|
|
416
444
|
|
|
417
|
-
source(): Query
|
|
445
|
+
source(): Query$.Any {
|
|
418
446
|
return new QueryClass({
|
|
419
447
|
type: 'relation-traversal',
|
|
420
448
|
anchor: this.ast,
|
|
@@ -422,7 +450,7 @@ class QueryClass implements Echo.Query<any> {
|
|
|
422
450
|
});
|
|
423
451
|
}
|
|
424
452
|
|
|
425
|
-
target(): Query
|
|
453
|
+
target(): Query$.Any {
|
|
426
454
|
return new QueryClass({
|
|
427
455
|
type: 'relation-traversal',
|
|
428
456
|
anchor: this.ast,
|
|
@@ -430,7 +458,23 @@ class QueryClass implements Echo.Query<any> {
|
|
|
430
458
|
});
|
|
431
459
|
}
|
|
432
460
|
|
|
433
|
-
|
|
461
|
+
parent(): Query$.Any {
|
|
462
|
+
return new QueryClass({
|
|
463
|
+
type: 'hierarchy-traversal',
|
|
464
|
+
anchor: this.ast,
|
|
465
|
+
direction: 'to-parent',
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
children(): Query$.Any {
|
|
470
|
+
return new QueryClass({
|
|
471
|
+
type: 'hierarchy-traversal',
|
|
472
|
+
anchor: this.ast,
|
|
473
|
+
direction: 'to-children',
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
orderBy(...order: Order$.Any[]): Query$.Any {
|
|
434
478
|
return new QueryClass({
|
|
435
479
|
type: 'order',
|
|
436
480
|
query: this.ast,
|
|
@@ -438,7 +482,40 @@ class QueryClass implements Echo.Query<any> {
|
|
|
438
482
|
});
|
|
439
483
|
}
|
|
440
484
|
|
|
441
|
-
|
|
485
|
+
limit(limit: number): Query$.Any {
|
|
486
|
+
return new QueryClass({
|
|
487
|
+
type: 'limit',
|
|
488
|
+
query: this.ast,
|
|
489
|
+
limit,
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
from(arg: any, options?: { includeFeeds?: boolean }): Query$.Any {
|
|
494
|
+
if (arg === 'all-accessible-spaces') {
|
|
495
|
+
return new QueryClass({
|
|
496
|
+
type: 'from',
|
|
497
|
+
query: this.ast,
|
|
498
|
+
from: {
|
|
499
|
+
_tag: 'scope',
|
|
500
|
+
scope: {
|
|
501
|
+
...(options?.includeFeeds ? { allQueuesFromSpaces: true } : {}),
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (_isScopeLike(arg)) {
|
|
508
|
+
return new QueryClass({
|
|
509
|
+
type: 'from',
|
|
510
|
+
query: this.ast,
|
|
511
|
+
from: { _tag: 'scope', scope: arg },
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
throw new TypeError('Database and Feed objects are not supported in query-lite sandbox');
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
options(options: QueryAST.QueryOptions): Query$.Any {
|
|
442
519
|
return new QueryClass({
|
|
443
520
|
type: 'options',
|
|
444
521
|
query: this.ast,
|
|
@@ -447,7 +524,7 @@ class QueryClass implements Echo.Query<any> {
|
|
|
447
524
|
}
|
|
448
525
|
}
|
|
449
526
|
|
|
450
|
-
export const Query1: typeof
|
|
527
|
+
export const Query1: typeof Query$ = QueryClass;
|
|
451
528
|
export { Query1 as Query };
|
|
452
529
|
|
|
453
530
|
const RefTypeId: unique symbol = Symbol('@dxos/echo-query/Ref');
|
|
@@ -460,3 +537,12 @@ const makeTypeDxn = (typename: string) => {
|
|
|
460
537
|
assertArgument(!typename.startsWith('dxn:'), 'typename');
|
|
461
538
|
return `dxn:type:${typename}`;
|
|
462
539
|
};
|
|
540
|
+
|
|
541
|
+
const SCOPE_KEYS = new Set(['spaceIds', 'queues', 'allQueuesFromSpaces']);
|
|
542
|
+
|
|
543
|
+
const _isScopeLike = (value: unknown): value is QueryAST.Scope => {
|
|
544
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
return Object.keys(value).every((key) => SCOPE_KEYS.has(key));
|
|
548
|
+
};
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { afterAll, beforeAll, describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { Filter, Order, Query } from '@dxos/echo';
|
|
8
|
+
import { trim } from '@dxos/util';
|
|
8
9
|
|
|
9
10
|
import { QuerySandbox } from './query-sandbox';
|
|
10
11
|
|
|
@@ -14,38 +15,38 @@ describe('QuerySandbox', () => {
|
|
|
14
15
|
afterAll(() => sandbox.close());
|
|
15
16
|
|
|
16
17
|
test('works', { timeout: 10_000 }, async () => {
|
|
17
|
-
const ast = sandbox.eval(`
|
|
18
|
-
Query.select(Filter.typename('dxos.
|
|
18
|
+
const ast = sandbox.eval(trim`
|
|
19
|
+
Query.select(Filter.typename('org.dxos.type.person'))
|
|
19
20
|
`);
|
|
20
|
-
expect(ast).toEqual(Query.select(Filter.typename('dxos.
|
|
21
|
+
expect(ast).toEqual(Query.select(Filter.typename('org.dxos.type.person')).ast);
|
|
21
22
|
});
|
|
22
23
|
|
|
23
24
|
test('works with just Filter passed in', () => {
|
|
24
|
-
const ast = sandbox.eval(`
|
|
25
|
-
Filter.typename('dxos.
|
|
25
|
+
const ast = sandbox.eval(trim`
|
|
26
|
+
Filter.typename('org.dxos.type.person')
|
|
26
27
|
`);
|
|
27
|
-
expect(ast).toEqual(Query.select(Filter.typename('dxos.
|
|
28
|
+
expect(ast).toEqual(Query.select(Filter.typename('org.dxos.type.person')).ast);
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
test('Order', () => {
|
|
31
|
-
const ast = sandbox.eval(`
|
|
32
|
-
Query.type('dxos.
|
|
32
|
+
const ast = sandbox.eval(trim`
|
|
33
|
+
Query.type('org.dxos.type.person').orderBy(Order.property('name', 'desc'))
|
|
33
34
|
`);
|
|
34
|
-
expect(ast).toEqual(Query.type('dxos.
|
|
35
|
+
expect(ast).toEqual(Query.type('org.dxos.type.person').orderBy(Order.property('name', 'desc')).ast);
|
|
35
36
|
});
|
|
36
37
|
|
|
37
38
|
test('traversal', () => {
|
|
38
|
-
const ast = sandbox.eval(`
|
|
39
|
-
Query.select(Filter.type('
|
|
39
|
+
const ast = sandbox.eval(trim`
|
|
40
|
+
Query.select(Filter.type('org.dxos.type.person', { jobTitle: 'investor' }))
|
|
40
41
|
.reference('organization')
|
|
41
|
-
.targetOf('
|
|
42
|
+
.targetOf('org.dxos.relation.has-subject')
|
|
42
43
|
.source()
|
|
43
44
|
`);
|
|
44
45
|
|
|
45
46
|
expect(ast).toEqual(
|
|
46
|
-
Query.select(Filter.type('
|
|
47
|
+
Query.select(Filter.type('org.dxos.type.person', { jobTitle: 'investor' }))
|
|
47
48
|
.reference('organization')
|
|
48
|
-
.targetOf('
|
|
49
|
+
.targetOf('org.dxos.relation.has-subject')
|
|
49
50
|
.source().ast,
|
|
50
51
|
);
|
|
51
52
|
});
|
|
@@ -7,7 +7,7 @@ import { Query, type QueryAST } from '@dxos/echo';
|
|
|
7
7
|
import { trim } from '@dxos/util';
|
|
8
8
|
import { type QuickJSRuntime, type QuickJSWASMModule, createQuickJS } from '@dxos/vendor-quickjs';
|
|
9
9
|
|
|
10
|
-
import envCode from '#query-
|
|
10
|
+
import envCode from '#query-lite?raw';
|
|
11
11
|
|
|
12
12
|
import { unwrapResult } from './quickjs';
|
|
13
13
|
|
|
@@ -34,7 +34,7 @@ export class QuerySandbox extends Resource {
|
|
|
34
34
|
this.#runtime = quickJS.newRuntime({
|
|
35
35
|
moduleLoader: (moduleName, _context) => {
|
|
36
36
|
switch (moduleName) {
|
|
37
|
-
case 'dxos:query-
|
|
37
|
+
case 'dxos:query-lite':
|
|
38
38
|
return envCode;
|
|
39
39
|
default:
|
|
40
40
|
throw new Error(`Module not found: ${moduleName}`);
|
|
@@ -49,12 +49,12 @@ export class QuerySandbox extends Resource {
|
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Evaluates the query code.
|
|
52
|
-
* @param queryCode Example: `Query.select(Filter.typename('dxos.
|
|
52
|
+
* @param queryCode Example: `Query.select(Filter.typename('org.dxos.type.person'))`
|
|
53
53
|
*/
|
|
54
54
|
eval(queryCode: string): QueryAST.Query {
|
|
55
55
|
using context = this.#runtime.newContext();
|
|
56
56
|
const globals = trim`
|
|
57
|
-
import { Filter, Order, Query } from 'dxos:query-
|
|
57
|
+
import { Filter, Order, Query } from 'dxos:query-lite';
|
|
58
58
|
globalThis.Filter = Filter;
|
|
59
59
|
globalThis.Order = Order;
|
|
60
60
|
globalThis.Query = Query;
|
package/src/sandbox/quickjs.ts
CHANGED
|
@@ -17,8 +17,7 @@ export const unwrapResult = <T>(context: QuickJSContext, result: SuccessOrFail<T
|
|
|
17
17
|
if (
|
|
18
18
|
typeof contextError === 'object' &&
|
|
19
19
|
typeof contextError.name === 'string' &&
|
|
20
|
-
typeof contextError.message === 'string'
|
|
21
|
-
typeof contextError.stack === 'string'
|
|
20
|
+
typeof contextError.message === 'string'
|
|
22
21
|
) {
|
|
23
22
|
const error = new Error(contextError.message);
|
|
24
23
|
Object.defineProperty(error, 'name', { value: contextError.name });
|