@dxos/echo-protocol 0.8.4-main.72ec0f3 → 0.8.4-main.74a063c4e0
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 +250 -34
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/types/src/document-structure.d.ts +7 -1
- package/dist/types/src/document-structure.d.ts.map +1 -1
- package/dist/types/src/echo-feed-codec.d.ts +17 -0
- package/dist/types/src/echo-feed-codec.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +4 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/query/ast.d.ts +113 -29
- package/dist/types/src/query/ast.d.ts.map +1 -1
- package/dist/types/src/reference.d.ts +1 -0
- package/dist/types/src/reference.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -11
- package/src/document-structure.ts +11 -1
- package/src/echo-feed-codec.ts +67 -0
- package/src/index.ts +4 -3
- package/src/query/ast.ts +163 -10
- package/src/reference.ts +4 -1
- 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 -604
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
package/package.json
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/echo-protocol",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.74a063c4e0",
|
|
4
4
|
"description": "Core ECHO APIs.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
-
"repository":
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dxos/dxos"
|
|
10
|
+
},
|
|
8
11
|
"license": "MIT",
|
|
9
12
|
"author": "DXOS.org",
|
|
10
|
-
"sideEffects":
|
|
13
|
+
"sideEffects": false,
|
|
11
14
|
"type": "module",
|
|
12
15
|
"exports": {
|
|
13
16
|
".": {
|
|
14
17
|
"source": "./src/index.ts",
|
|
15
18
|
"types": "./dist/types/src/index.d.ts",
|
|
16
|
-
"
|
|
17
|
-
"node": "./dist/lib/node-esm/index.mjs"
|
|
19
|
+
"default": "./dist/lib/neutral/index.mjs"
|
|
18
20
|
}
|
|
19
21
|
},
|
|
20
22
|
"types": "dist/types/src/index.d.ts",
|
|
@@ -26,12 +28,12 @@
|
|
|
26
28
|
"src"
|
|
27
29
|
],
|
|
28
30
|
"dependencies": {
|
|
29
|
-
"effect": "3.
|
|
30
|
-
"@dxos/crypto": "0.8.4-main.
|
|
31
|
-
"@dxos/keys": "0.8.4-main.
|
|
32
|
-
"@dxos/invariant": "0.8.4-main.
|
|
33
|
-
"@dxos/
|
|
34
|
-
"@dxos/
|
|
31
|
+
"effect": "3.20.0",
|
|
32
|
+
"@dxos/crypto": "0.8.4-main.74a063c4e0",
|
|
33
|
+
"@dxos/keys": "0.8.4-main.74a063c4e0",
|
|
34
|
+
"@dxos/invariant": "0.8.4-main.74a063c4e0",
|
|
35
|
+
"@dxos/protocols": "0.8.4-main.74a063c4e0",
|
|
36
|
+
"@dxos/util": "0.8.4-main.74a063c4e0"
|
|
35
37
|
},
|
|
36
38
|
"publishConfig": {
|
|
37
39
|
"access": "public"
|
|
@@ -137,6 +137,10 @@ export const ObjectStructure = Object.freeze({
|
|
|
137
137
|
return object.system?.target;
|
|
138
138
|
},
|
|
139
139
|
|
|
140
|
+
getParent: (object: ObjectStructure): EncodedReference | undefined => {
|
|
141
|
+
return object.system?.parent;
|
|
142
|
+
},
|
|
143
|
+
|
|
140
144
|
/**
|
|
141
145
|
* @returns All references in the data section of the object.
|
|
142
146
|
*/
|
|
@@ -248,13 +252,19 @@ export type ObjectSystem = {
|
|
|
248
252
|
*/
|
|
249
253
|
deleted?: boolean;
|
|
250
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Object parent.
|
|
257
|
+
* Objects with no parent are at the top level of the object hierarchy in the space.
|
|
258
|
+
*/
|
|
259
|
+
parent?: EncodedReference;
|
|
260
|
+
|
|
251
261
|
/**
|
|
252
262
|
* Only for relations.
|
|
253
263
|
*/
|
|
254
264
|
source?: EncodedReference;
|
|
255
265
|
|
|
256
266
|
/**
|
|
257
|
-
* Only for relations.
|
|
267
|
+
* Only for relations.
|
|
258
268
|
*/
|
|
259
269
|
target?: EncodedReference;
|
|
260
270
|
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { FeedProtocol } from '@dxos/protocols';
|
|
6
|
+
|
|
7
|
+
import type { ForeignKey } from './foreign-key';
|
|
8
|
+
|
|
9
|
+
/** Property name for meta when object is serialized to JSON. Matches @dxos/echo/internal ATTR_META. */
|
|
10
|
+
const ATTR_META = '@meta';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Codec for ECHO objects in feed block payload: JSON object ↔ UTF-8 bytes.
|
|
14
|
+
* Encodes with queue position stripped; decodes with optional position injection.
|
|
15
|
+
*/
|
|
16
|
+
export class EchoFeedCodec {
|
|
17
|
+
static readonly #encoder = new TextEncoder();
|
|
18
|
+
static readonly #decoder = new TextDecoder();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Prepares a value for feed storage (strips queue position from metadata) and encodes to bytes.
|
|
22
|
+
*/
|
|
23
|
+
static encode(value: Record<string, unknown>): Uint8Array {
|
|
24
|
+
const prepared = EchoFeedCodec.#stripQueuePosition(value);
|
|
25
|
+
return EchoFeedCodec.#encoder.encode(JSON.stringify(prepared));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Decodes feed block bytes to a JSON value.
|
|
30
|
+
* If position is provided, injects queue position into the decoded object's metadata.
|
|
31
|
+
*/
|
|
32
|
+
static decode(data: Uint8Array, position?: number): Record<string, unknown> {
|
|
33
|
+
const decoded = JSON.parse(EchoFeedCodec.#decoder.decode(data));
|
|
34
|
+
if (position !== undefined && typeof decoded === 'object' && decoded !== null) {
|
|
35
|
+
EchoFeedCodec.#setQueuePosition(decoded, position);
|
|
36
|
+
}
|
|
37
|
+
return decoded;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static #stripQueuePosition(value: Record<string, unknown>): Record<string, unknown> {
|
|
41
|
+
if (typeof value !== 'object' || value === null) {
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
const obj = structuredClone(value);
|
|
45
|
+
const meta = obj[ATTR_META] as { keys?: ForeignKey[] } | undefined;
|
|
46
|
+
if (meta?.keys?.some((key: ForeignKey) => key.source === FeedProtocol.KEY_QUEUE_POSITION)) {
|
|
47
|
+
meta.keys = meta.keys.filter((key: ForeignKey) => key.source !== FeedProtocol.KEY_QUEUE_POSITION);
|
|
48
|
+
}
|
|
49
|
+
return obj;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static #setQueuePosition(obj: Record<string, any>, position: number): void {
|
|
53
|
+
obj[ATTR_META] ??= { keys: [] };
|
|
54
|
+
obj[ATTR_META]!.keys ??= [];
|
|
55
|
+
const keys = obj[ATTR_META]!.keys!;
|
|
56
|
+
for (let i = 0; i < keys.length; i++) {
|
|
57
|
+
if (keys[i].source === FeedProtocol.KEY_QUEUE_POSITION) {
|
|
58
|
+
keys.splice(i, 1);
|
|
59
|
+
i--;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
keys.push({
|
|
63
|
+
source: FeedProtocol.KEY_QUEUE_POSITION,
|
|
64
|
+
id: position.toString(),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
export type * from './collection-sync';
|
|
5
6
|
export * from './document-structure';
|
|
7
|
+
export * from './echo-feed-codec';
|
|
8
|
+
export * from './foreign-key';
|
|
9
|
+
export * from './query';
|
|
6
10
|
export * from './reference';
|
|
7
11
|
export * from './space-doc-version';
|
|
8
|
-
export type * from './collection-sync';
|
|
9
12
|
export * from './space-id';
|
|
10
|
-
export * from './foreign-key';
|
|
11
|
-
export * from './query';
|
package/src/query/ast.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { DXN, ObjectId } from '@dxos/keys';
|
|
|
10
10
|
import { ForeignKey } from '../foreign-key';
|
|
11
11
|
|
|
12
12
|
const TypenameSpecifier = Schema.Union(DXN.Schema, Schema.Null).annotations({
|
|
13
|
-
description: 'DXN or null
|
|
13
|
+
description: 'DXN or null; null matches any type',
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
// NOTE: This pattern with 3 definitions per schema is need to make the types opaque, and circular references in AST to not cause compiler errors.
|
|
@@ -75,7 +75,9 @@ const FilterContains_ = Schema.Struct({
|
|
|
75
75
|
type: Schema.Literal('contains'),
|
|
76
76
|
value: Schema.Any,
|
|
77
77
|
});
|
|
78
|
+
|
|
78
79
|
export interface FilterContains extends Schema.Schema.Type<typeof FilterContains_> {}
|
|
80
|
+
|
|
79
81
|
/**
|
|
80
82
|
* Predicate for an array property to contain the provided value.
|
|
81
83
|
* Nested objects are matched using strict structural matching.
|
|
@@ -89,6 +91,7 @@ const FilterTag_ = Schema.Struct({
|
|
|
89
91
|
type: Schema.Literal('tag'),
|
|
90
92
|
tag: Schema.String, // TODO(burdon): Make OR-collection?
|
|
91
93
|
});
|
|
94
|
+
|
|
92
95
|
export interface FilterTag extends Schema.Schema.Type<typeof FilterTag_> {}
|
|
93
96
|
export const FilterTag: Schema.Schema<FilterTag> = FilterTag_;
|
|
94
97
|
|
|
@@ -100,9 +103,24 @@ const FilterRange_ = Schema.Struct({
|
|
|
100
103
|
from: Schema.Any,
|
|
101
104
|
to: Schema.Any,
|
|
102
105
|
});
|
|
106
|
+
|
|
103
107
|
export interface FilterRange extends Schema.Schema.Type<typeof FilterRange_> {}
|
|
104
108
|
export const FilterRange: Schema.Schema<FilterRange> = FilterRange_;
|
|
105
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Filter by system timestamp (createdAt / updatedAt).
|
|
112
|
+
* Timestamps are unix milliseconds stored in the object meta index.
|
|
113
|
+
*/
|
|
114
|
+
const FilterTimestamp_ = Schema.Struct({
|
|
115
|
+
type: Schema.Literal('timestamp'),
|
|
116
|
+
field: Schema.Literal('createdAt', 'updatedAt'),
|
|
117
|
+
operator: Schema.Literal('gt', 'gte', 'lt', 'lte'),
|
|
118
|
+
value: Schema.Number,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
export interface FilterTimestamp extends Schema.Schema.Type<typeof FilterTimestamp_> {}
|
|
122
|
+
export const FilterTimestamp: Schema.Schema<FilterTimestamp> = FilterTimestamp_;
|
|
123
|
+
|
|
106
124
|
/**
|
|
107
125
|
* Text search.
|
|
108
126
|
*/
|
|
@@ -111,6 +129,7 @@ const FilterTextSearch_ = Schema.Struct({
|
|
|
111
129
|
text: Schema.String,
|
|
112
130
|
searchKind: Schema.optional(Schema.Literal('full-text', 'vector')),
|
|
113
131
|
});
|
|
132
|
+
|
|
114
133
|
export interface FilterTextSearch extends Schema.Schema.Type<typeof FilterTextSearch_> {}
|
|
115
134
|
export const FilterTextSearch: Schema.Schema<FilterTextSearch> = FilterTextSearch_;
|
|
116
135
|
|
|
@@ -121,6 +140,7 @@ const FilterNot_ = Schema.Struct({
|
|
|
121
140
|
type: Schema.Literal('not'),
|
|
122
141
|
filter: Schema.suspend(() => Filter),
|
|
123
142
|
});
|
|
143
|
+
|
|
124
144
|
export interface FilterNot extends Schema.Schema.Type<typeof FilterNot_> {}
|
|
125
145
|
export const FilterNot: Schema.Schema<FilterNot> = FilterNot_;
|
|
126
146
|
|
|
@@ -131,6 +151,7 @@ const FilterAnd_ = Schema.Struct({
|
|
|
131
151
|
type: Schema.Literal('and'),
|
|
132
152
|
filters: Schema.Array(Schema.suspend(() => Filter)),
|
|
133
153
|
});
|
|
154
|
+
|
|
134
155
|
export interface FilterAnd extends Schema.Schema.Type<typeof FilterAnd_> {}
|
|
135
156
|
export const FilterAnd: Schema.Schema<FilterAnd> = FilterAnd_;
|
|
136
157
|
|
|
@@ -141,6 +162,7 @@ const FilterOr_ = Schema.Struct({
|
|
|
141
162
|
type: Schema.Literal('or'),
|
|
142
163
|
filters: Schema.Array(Schema.suspend(() => Filter)),
|
|
143
164
|
});
|
|
165
|
+
|
|
144
166
|
export interface FilterOr extends Schema.Schema.Type<typeof FilterOr_> {}
|
|
145
167
|
export const FilterOr: Schema.Schema<FilterOr> = FilterOr_;
|
|
146
168
|
|
|
@@ -154,11 +176,13 @@ export const Filter = Schema.Union(
|
|
|
154
176
|
FilterContains,
|
|
155
177
|
FilterTag,
|
|
156
178
|
FilterRange,
|
|
179
|
+
FilterTimestamp,
|
|
157
180
|
FilterTextSearch,
|
|
158
181
|
FilterNot,
|
|
159
182
|
FilterAnd,
|
|
160
183
|
FilterOr,
|
|
161
|
-
).annotations({ identifier: 'dxos.
|
|
184
|
+
).annotations({ identifier: 'org.dxos.schema.filter' });
|
|
185
|
+
|
|
162
186
|
export type Filter = Schema.Schema.Type<typeof Filter>;
|
|
163
187
|
|
|
164
188
|
/**
|
|
@@ -168,6 +192,7 @@ const QuerySelectClause_ = Schema.Struct({
|
|
|
168
192
|
type: Schema.Literal('select'),
|
|
169
193
|
filter: Schema.suspend(() => Filter),
|
|
170
194
|
});
|
|
195
|
+
|
|
171
196
|
export interface QuerySelectClause extends Schema.Schema.Type<typeof QuerySelectClause_> {}
|
|
172
197
|
export const QuerySelectClause: Schema.Schema<QuerySelectClause> = QuerySelectClause_;
|
|
173
198
|
|
|
@@ -179,6 +204,7 @@ const QueryFilterClause_ = Schema.Struct({
|
|
|
179
204
|
selection: Schema.suspend(() => Query),
|
|
180
205
|
filter: Schema.suspend(() => Filter),
|
|
181
206
|
});
|
|
207
|
+
|
|
182
208
|
export interface QueryFilterClause extends Schema.Schema.Type<typeof QueryFilterClause_> {}
|
|
183
209
|
export const QueryFilterClause: Schema.Schema<QueryFilterClause> = QueryFilterClause_;
|
|
184
210
|
|
|
@@ -190,6 +216,7 @@ const QueryReferenceTraversalClause_ = Schema.Struct({
|
|
|
190
216
|
anchor: Schema.suspend(() => Query),
|
|
191
217
|
property: Schema.String, // TODO(dmaretskyi): Change to EscapedPropPath.
|
|
192
218
|
});
|
|
219
|
+
|
|
193
220
|
export interface QueryReferenceTraversalClause extends Schema.Schema.Type<typeof QueryReferenceTraversalClause_> {}
|
|
194
221
|
export const QueryReferenceTraversalClause: Schema.Schema<QueryReferenceTraversalClause> =
|
|
195
222
|
QueryReferenceTraversalClause_;
|
|
@@ -200,9 +227,14 @@ export const QueryReferenceTraversalClause: Schema.Schema<QueryReferenceTraversa
|
|
|
200
227
|
const QueryIncomingReferencesClause_ = Schema.Struct({
|
|
201
228
|
type: Schema.Literal('incoming-references'),
|
|
202
229
|
anchor: Schema.suspend(() => Query),
|
|
203
|
-
|
|
230
|
+
/**
|
|
231
|
+
* Property path where the reference is located.
|
|
232
|
+
* If null, matches references from any property.
|
|
233
|
+
*/
|
|
234
|
+
property: Schema.NullOr(Schema.String),
|
|
204
235
|
typename: TypenameSpecifier,
|
|
205
236
|
});
|
|
237
|
+
|
|
206
238
|
export interface QueryIncomingReferencesClause extends Schema.Schema.Type<typeof QueryIncomingReferencesClause_> {}
|
|
207
239
|
export const QueryIncomingReferencesClause: Schema.Schema<QueryIncomingReferencesClause> =
|
|
208
240
|
QueryIncomingReferencesClause_;
|
|
@@ -221,6 +253,7 @@ const QueryRelationClause_ = Schema.Struct({
|
|
|
221
253
|
direction: Schema.Literal('outgoing', 'incoming', 'both'),
|
|
222
254
|
filter: Schema.optional(Schema.suspend(() => Filter)),
|
|
223
255
|
});
|
|
256
|
+
|
|
224
257
|
export interface QueryRelationClause extends Schema.Schema.Type<typeof QueryRelationClause_> {}
|
|
225
258
|
export const QueryRelationClause: Schema.Schema<QueryRelationClause> = QueryRelationClause_;
|
|
226
259
|
|
|
@@ -232,9 +265,27 @@ const QueryRelationTraversalClause_ = Schema.Struct({
|
|
|
232
265
|
anchor: Schema.suspend(() => Query),
|
|
233
266
|
direction: Schema.Literal('source', 'target', 'both'),
|
|
234
267
|
});
|
|
268
|
+
|
|
235
269
|
export interface QueryRelationTraversalClause extends Schema.Schema.Type<typeof QueryRelationTraversalClause_> {}
|
|
236
270
|
export const QueryRelationTraversalClause: Schema.Schema<QueryRelationTraversalClause> = QueryRelationTraversalClause_;
|
|
237
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Traverse parent-child hierarchy.
|
|
274
|
+
*/
|
|
275
|
+
const QueryHierarchyTraversalClause_ = Schema.Struct({
|
|
276
|
+
type: Schema.Literal('hierarchy-traversal'),
|
|
277
|
+
anchor: Schema.suspend(() => Query),
|
|
278
|
+
/**
|
|
279
|
+
* to-parent: traverse from child to parent.
|
|
280
|
+
* to-children: traverse from parent to children.
|
|
281
|
+
*/
|
|
282
|
+
direction: Schema.Literal('to-parent', 'to-children'),
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
export interface QueryHierarchyTraversalClause extends Schema.Schema.Type<typeof QueryHierarchyTraversalClause_> {}
|
|
286
|
+
export const QueryHierarchyTraversalClause: Schema.Schema<QueryHierarchyTraversalClause> =
|
|
287
|
+
QueryHierarchyTraversalClause_;
|
|
288
|
+
|
|
238
289
|
/**
|
|
239
290
|
* Union of multiple queries.
|
|
240
291
|
*/
|
|
@@ -242,6 +293,7 @@ const QueryUnionClause_ = Schema.Struct({
|
|
|
242
293
|
type: Schema.Literal('union'),
|
|
243
294
|
queries: Schema.Array(Schema.suspend(() => Query)),
|
|
244
295
|
});
|
|
296
|
+
|
|
245
297
|
export interface QueryUnionClause extends Schema.Schema.Type<typeof QueryUnionClause_> {}
|
|
246
298
|
export const QueryUnionClause: Schema.Schema<QueryUnionClause> = QueryUnionClause_;
|
|
247
299
|
|
|
@@ -253,6 +305,7 @@ const QuerySetDifferenceClause_ = Schema.Struct({
|
|
|
253
305
|
source: Schema.suspend(() => Query),
|
|
254
306
|
exclude: Schema.suspend(() => Query),
|
|
255
307
|
});
|
|
308
|
+
|
|
256
309
|
export interface QuerySetDifferenceClause extends Schema.Schema.Type<typeof QuerySetDifferenceClause_> {}
|
|
257
310
|
export const QuerySetDifferenceClause: Schema.Schema<QuerySetDifferenceClause> = QuerySetDifferenceClause_;
|
|
258
311
|
|
|
@@ -269,7 +322,14 @@ const Order_ = Schema.Union(
|
|
|
269
322
|
property: Schema.String,
|
|
270
323
|
direction: OrderDirection,
|
|
271
324
|
}),
|
|
325
|
+
Schema.Struct({
|
|
326
|
+
// Order by relevance rank (for FTS/vector search results).
|
|
327
|
+
// Default direction is 'desc' (higher rank = better match first).
|
|
328
|
+
kind: Schema.Literal('rank'),
|
|
329
|
+
direction: OrderDirection,
|
|
330
|
+
}),
|
|
272
331
|
);
|
|
332
|
+
|
|
273
333
|
export type Order = Schema.Schema.Type<typeof Order_>;
|
|
274
334
|
export const Order: Schema.Schema<Order> = Order_;
|
|
275
335
|
|
|
@@ -282,6 +342,7 @@ const QueryOrderClause_ = Schema.Struct({
|
|
|
282
342
|
query: Schema.suspend(() => Query),
|
|
283
343
|
order: Schema.Array(Order),
|
|
284
344
|
});
|
|
345
|
+
|
|
285
346
|
export interface QueryOrderClause extends Schema.Schema.Type<typeof QueryOrderClause_> {}
|
|
286
347
|
export const QueryOrderClause: Schema.Schema<QueryOrderClause> = QueryOrderClause_;
|
|
287
348
|
|
|
@@ -293,9 +354,37 @@ const QueryOptionsClause_ = Schema.Struct({
|
|
|
293
354
|
query: Schema.suspend(() => Query),
|
|
294
355
|
options: Schema.suspend(() => QueryOptions),
|
|
295
356
|
});
|
|
357
|
+
|
|
296
358
|
export interface QueryOptionsClause extends Schema.Schema.Type<typeof QueryOptionsClause_> {}
|
|
297
359
|
export const QueryOptionsClause: Schema.Schema<QueryOptionsClause> = QueryOptionsClause_;
|
|
298
360
|
|
|
361
|
+
/**
|
|
362
|
+
* Limit the number of results.
|
|
363
|
+
*/
|
|
364
|
+
const QueryLimitClause_ = Schema.Struct({
|
|
365
|
+
type: Schema.Literal('limit'),
|
|
366
|
+
query: Schema.suspend(() => Query),
|
|
367
|
+
limit: Schema.Number,
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
export interface QueryLimitClause extends Schema.Schema.Type<typeof QueryLimitClause_> {}
|
|
371
|
+
export const QueryLimitClause: Schema.Schema<QueryLimitClause> = QueryLimitClause_;
|
|
372
|
+
|
|
373
|
+
export const QueryFromClause_ = Schema.Struct({
|
|
374
|
+
type: Schema.Literal('from'),
|
|
375
|
+
query: Schema.suspend(() => Query),
|
|
376
|
+
from: Schema.Union(
|
|
377
|
+
Schema.TaggedStruct('scope', {
|
|
378
|
+
scope: Schema.suspend(() => Scope),
|
|
379
|
+
}),
|
|
380
|
+
Schema.TaggedStruct('query', {
|
|
381
|
+
query: Schema.suspend(() => Query),
|
|
382
|
+
}),
|
|
383
|
+
),
|
|
384
|
+
});
|
|
385
|
+
export interface QueryFromClause extends Schema.Schema.Type<typeof QueryFromClause_> {}
|
|
386
|
+
export const QueryFromClause: Schema.Schema<QueryFromClause> = QueryFromClause_;
|
|
387
|
+
|
|
299
388
|
const Query_ = Schema.Union(
|
|
300
389
|
QuerySelectClause,
|
|
301
390
|
QueryFilterClause,
|
|
@@ -303,16 +392,31 @@ const Query_ = Schema.Union(
|
|
|
303
392
|
QueryIncomingReferencesClause,
|
|
304
393
|
QueryRelationClause,
|
|
305
394
|
QueryRelationTraversalClause,
|
|
395
|
+
QueryHierarchyTraversalClause,
|
|
306
396
|
QueryUnionClause,
|
|
307
397
|
QuerySetDifferenceClause,
|
|
308
398
|
QueryOrderClause,
|
|
309
399
|
QueryOptionsClause,
|
|
310
|
-
|
|
400
|
+
QueryLimitClause,
|
|
401
|
+
QueryFromClause,
|
|
402
|
+
).annotations({ identifier: 'org.dxos.schema.query' });
|
|
311
403
|
|
|
312
404
|
export type Query = Schema.Schema.Type<typeof Query_>;
|
|
313
405
|
export const Query: Schema.Schema<Query> = Query_;
|
|
314
406
|
|
|
315
407
|
export const QueryOptions = Schema.Struct({
|
|
408
|
+
/**
|
|
409
|
+
* Nested select statements will use this option to filter deleted objects.
|
|
410
|
+
*/
|
|
411
|
+
deleted: Schema.optional(Schema.Literal('include', 'exclude', 'only')),
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
export interface QueryOptions extends Schema.Schema.Type<typeof QueryOptions> {}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Specifies the scope of the data to query from.
|
|
418
|
+
*/
|
|
419
|
+
export const Scope = Schema.Struct({
|
|
316
420
|
/**
|
|
317
421
|
* The nested select statemets will select from the given spaces.
|
|
318
422
|
*
|
|
@@ -320,19 +424,19 @@ export const QueryOptions = Schema.Struct({
|
|
|
320
424
|
*/
|
|
321
425
|
spaceIds: Schema.optional(Schema.Array(Schema.String)),
|
|
322
426
|
|
|
427
|
+
/**
|
|
428
|
+
* If true, the nested select statements will select from all queues in the spaces specified by `spaceIds`.
|
|
429
|
+
*/
|
|
430
|
+
allQueuesFromSpaces: Schema.optional(Schema.Boolean),
|
|
431
|
+
|
|
323
432
|
/**
|
|
324
433
|
* The nested select statemets will select from the given queues.
|
|
325
434
|
*
|
|
326
435
|
* NOTE: Spaces and queues are unioned together if both are specified.
|
|
327
436
|
*/
|
|
328
437
|
queues: Schema.optional(Schema.Array(DXN.Schema)),
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Nested select statements will use this option to filter deleted objects.
|
|
332
|
-
*/
|
|
333
|
-
deleted: Schema.optional(Schema.Literal('include', 'exclude', 'only')),
|
|
334
438
|
});
|
|
335
|
-
export interface
|
|
439
|
+
export interface Scope extends Schema.Schema.Type<typeof Scope> {}
|
|
336
440
|
|
|
337
441
|
export const visit = (query: Query, visitor: (node: Query) => void) => {
|
|
338
442
|
visitor(query);
|
|
@@ -344,17 +448,57 @@ export const visit = (query: Query, visitor: (node: Query) => void) => {
|
|
|
344
448
|
Match.when({ type: 'relation' }, ({ anchor }) => visit(anchor, visitor)),
|
|
345
449
|
Match.when({ type: 'options' }, ({ query }) => visit(query, visitor)),
|
|
346
450
|
Match.when({ type: 'relation-traversal' }, ({ anchor }) => visit(anchor, visitor)),
|
|
451
|
+
Match.when({ type: 'hierarchy-traversal' }, ({ anchor }) => visit(anchor, visitor)),
|
|
347
452
|
Match.when({ type: 'union' }, ({ queries }) => queries.forEach((q) => visit(q, visitor))),
|
|
348
453
|
Match.when({ type: 'set-difference' }, ({ source, exclude }) => {
|
|
349
454
|
visit(source, visitor);
|
|
350
455
|
visit(exclude, visitor);
|
|
351
456
|
}),
|
|
352
457
|
Match.when({ type: 'order' }, ({ query }) => visit(query, visitor)),
|
|
458
|
+
Match.when({ type: 'limit' }, ({ query }) => visit(query, visitor)),
|
|
459
|
+
Match.when({ type: 'from' }, (node) => {
|
|
460
|
+
visit(node.query, visitor);
|
|
461
|
+
if (node.from._tag === 'query') {
|
|
462
|
+
visit(node.from.query, visitor);
|
|
463
|
+
}
|
|
464
|
+
}),
|
|
353
465
|
Match.when({ type: 'select' }, () => {}),
|
|
354
466
|
Match.exhaustive,
|
|
355
467
|
);
|
|
356
468
|
};
|
|
357
469
|
|
|
470
|
+
/**
|
|
471
|
+
* Recursively transforms a query tree bottom-up.
|
|
472
|
+
* The mapper receives each node with its children already transformed.
|
|
473
|
+
*/
|
|
474
|
+
export const map = (query: Query, mapper: (node: Query) => Query): Query => {
|
|
475
|
+
const mapped: Query = Match.value(query).pipe(
|
|
476
|
+
Match.when({ type: 'filter' }, (node) => ({ ...node, selection: map(node.selection, mapper) })),
|
|
477
|
+
Match.when({ type: 'reference-traversal' }, (node) => ({ ...node, anchor: map(node.anchor, mapper) })),
|
|
478
|
+
Match.when({ type: 'incoming-references' }, (node) => ({ ...node, anchor: map(node.anchor, mapper) })),
|
|
479
|
+
Match.when({ type: 'relation' }, (node) => ({ ...node, anchor: map(node.anchor, mapper) })),
|
|
480
|
+
Match.when({ type: 'relation-traversal' }, (node) => ({ ...node, anchor: map(node.anchor, mapper) })),
|
|
481
|
+
Match.when({ type: 'hierarchy-traversal' }, (node) => ({ ...node, anchor: map(node.anchor, mapper) })),
|
|
482
|
+
Match.when({ type: 'options' }, (node) => ({ ...node, query: map(node.query, mapper) })),
|
|
483
|
+
Match.when({ type: 'order' }, (node) => ({ ...node, query: map(node.query, mapper) })),
|
|
484
|
+
Match.when({ type: 'limit' }, (node) => ({ ...node, query: map(node.query, mapper) })),
|
|
485
|
+
Match.when({ type: 'from' }, (node) => ({
|
|
486
|
+
...node,
|
|
487
|
+
query: map(node.query, mapper),
|
|
488
|
+
...(node.from._tag === 'query' ? { from: { _tag: 'query' as const, query: map(node.from.query, mapper) } } : {}),
|
|
489
|
+
})),
|
|
490
|
+
Match.when({ type: 'union' }, (node) => ({ ...node, queries: node.queries.map((q) => map(q, mapper)) })),
|
|
491
|
+
Match.when({ type: 'set-difference' }, (node) => ({
|
|
492
|
+
...node,
|
|
493
|
+
source: map(node.source, mapper),
|
|
494
|
+
exclude: map(node.exclude, mapper),
|
|
495
|
+
})),
|
|
496
|
+
Match.when({ type: 'select' }, (node) => node),
|
|
497
|
+
Match.exhaustive,
|
|
498
|
+
);
|
|
499
|
+
return mapper(mapped);
|
|
500
|
+
};
|
|
501
|
+
|
|
358
502
|
export const fold = <T>(query: Query, reducer: (node: Query) => T): T[] => {
|
|
359
503
|
return Match.value(query).pipe(
|
|
360
504
|
Match.withReturnType<T[]>(),
|
|
@@ -364,11 +508,20 @@ export const fold = <T>(query: Query, reducer: (node: Query) => T): T[] => {
|
|
|
364
508
|
Match.when({ type: 'relation' }, ({ anchor }) => fold(anchor, reducer)),
|
|
365
509
|
Match.when({ type: 'options' }, ({ query }) => fold(query, reducer)),
|
|
366
510
|
Match.when({ type: 'relation-traversal' }, ({ anchor }) => fold(anchor, reducer)),
|
|
511
|
+
Match.when({ type: 'hierarchy-traversal' }, ({ anchor }) => fold(anchor, reducer)),
|
|
367
512
|
Match.when({ type: 'union' }, ({ queries }) => queries.flatMap((q) => fold(q, reducer))),
|
|
368
513
|
Match.when({ type: 'set-difference' }, ({ source, exclude }) =>
|
|
369
514
|
fold(source, reducer).concat(fold(exclude, reducer)),
|
|
370
515
|
),
|
|
371
516
|
Match.when({ type: 'order' }, ({ query }) => fold(query, reducer)),
|
|
517
|
+
Match.when({ type: 'limit' }, ({ query }) => fold(query, reducer)),
|
|
518
|
+
Match.when({ type: 'from' }, (node) => {
|
|
519
|
+
const results = fold(node.query, reducer);
|
|
520
|
+
if (node.from._tag === 'query') {
|
|
521
|
+
return results.concat(fold(node.from.query, reducer));
|
|
522
|
+
}
|
|
523
|
+
return results;
|
|
524
|
+
}),
|
|
372
525
|
Match.when({ type: 'select' }, () => []),
|
|
373
526
|
Match.exhaustive,
|
|
374
527
|
);
|
package/src/reference.ts
CHANGED
|
@@ -177,6 +177,9 @@ export const EncodedReference = Object.freeze({
|
|
|
177
177
|
return DXN.parse(EncodedReference.getReferenceString(value));
|
|
178
178
|
},
|
|
179
179
|
fromDXN: (dxn: DXN): EncodedReference => {
|
|
180
|
-
return
|
|
180
|
+
return { '/': dxn.toString() };
|
|
181
|
+
},
|
|
182
|
+
fromLegacyTypename: (typename: string): EncodedReference => {
|
|
183
|
+
return { '/': DXN.fromTypename(typename).toString() };
|
|
181
184
|
},
|
|
182
185
|
});
|