@dxos/echo-pipeline 0.8.3 → 0.8.4-main.05e74ebcff
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 +102 -5
- package/README.md +1 -1
- package/dist/lib/neutral/chunk-46DCRDA7.mjs +271 -0
- package/dist/lib/neutral/chunk-46DCRDA7.mjs.map +7 -0
- package/dist/lib/{browser/chunk-35I6ERLG.mjs → neutral/chunk-LR7UFVQX.mjs} +313 -709
- package/dist/lib/neutral/chunk-LR7UFVQX.mjs.map +7 -0
- package/dist/lib/{browser → neutral}/filter/index.mjs +3 -2
- package/dist/lib/neutral/index.mjs +7332 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/{browser → neutral}/testing/index.mjs +90 -311
- package/dist/lib/neutral/testing/index.mjs.map +7 -0
- package/dist/types/src/automerge/automerge-host-subduction.test.d.ts +2 -0
- package/dist/types/src/automerge/automerge-host-subduction.test.d.ts.map +1 -0
- package/dist/types/src/automerge/automerge-host.d.ts +119 -54
- package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-repo-subduction.test.d.ts +2 -0
- package/dist/types/src/automerge/automerge-repo-subduction.test.d.ts.map +1 -0
- package/dist/types/src/automerge/automerge-repo.test.d.ts +1 -1
- package/dist/types/src/automerge/automerge-repo.test.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-subduction.test.d.ts +2 -0
- package/dist/types/src/automerge/automerge-subduction.test.d.ts.map +1 -0
- package/dist/types/src/automerge/collection-synchronizer.d.ts +25 -4
- package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -1
- package/dist/types/src/automerge/echo-data-monitor.d.ts.map +1 -1
- package/dist/types/src/automerge/echo-network-adapter.d.ts +23 -10
- package/dist/types/src/automerge/echo-network-adapter.d.ts.map +1 -1
- package/dist/types/src/automerge/echo-replicator.d.ts +46 -15
- package/dist/types/src/automerge/echo-replicator.d.ts.map +1 -1
- package/dist/types/src/automerge/errors.d.ts +35 -0
- package/dist/types/src/automerge/errors.d.ts.map +1 -0
- package/dist/types/src/automerge/handle-state.d.ts +52 -0
- package/dist/types/src/automerge/handle-state.d.ts.map +1 -0
- package/dist/types/src/automerge/heads-store.d.ts +9 -2
- package/dist/types/src/automerge/heads-store.d.ts.map +1 -1
- package/dist/types/src/automerge/index.d.ts +3 -1
- package/dist/types/src/automerge/index.d.ts.map +1 -1
- package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +11 -5
- package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -1
- package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts +9 -8
- package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts.map +1 -1
- package/dist/types/src/automerge/mesh-echo-replicator.d.ts +6 -5
- package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
- package/dist/types/src/automerge/network-protocol.d.ts.map +1 -1
- package/dist/types/src/automerge/space-collection.d.ts.map +1 -1
- package/dist/types/src/common/codec.d.ts +1 -1
- package/dist/types/src/common/codec.d.ts.map +1 -1
- package/dist/types/src/common/feeds.d.ts.map +1 -1
- package/dist/types/src/common/space-id.d.ts.map +1 -1
- package/dist/types/src/db-host/automerge-data-source.d.ts +35 -0
- package/dist/types/src/db-host/automerge-data-source.d.ts.map +1 -0
- package/dist/types/src/db-host/automerge-data-source.test.d.ts +2 -0
- package/dist/types/src/db-host/automerge-data-source.test.d.ts.map +1 -0
- package/dist/types/src/db-host/automerge-metrics.d.ts.map +1 -1
- package/dist/types/src/db-host/data-service.d.ts +13 -7
- package/dist/types/src/db-host/data-service.d.ts.map +1 -1
- package/dist/types/src/db-host/database-root.d.ts +9 -3
- package/dist/types/src/db-host/database-root.d.ts.map +1 -1
- package/dist/types/src/db-host/documents-synchronizer.d.ts +30 -8
- package/dist/types/src/db-host/documents-synchronizer.d.ts.map +1 -1
- package/dist/types/src/db-host/echo-host.d.ts +74 -28
- package/dist/types/src/db-host/echo-host.d.ts.map +1 -1
- package/dist/types/src/db-host/index.d.ts +2 -0
- package/dist/types/src/db-host/index.d.ts.map +1 -1
- package/dist/types/src/db-host/invalidation-hint.d.ts +19 -0
- package/dist/types/src/db-host/invalidation-hint.d.ts.map +1 -0
- package/dist/types/src/db-host/local-queue-service.d.ts +19 -0
- package/dist/types/src/db-host/local-queue-service.d.ts.map +1 -0
- package/dist/types/src/db-host/query-invalidation.test.d.ts +2 -0
- package/dist/types/src/db-host/query-invalidation.test.d.ts.map +1 -0
- package/dist/types/src/db-host/query-service.d.ts +19 -11
- package/dist/types/src/db-host/query-service.d.ts.map +1 -1
- package/dist/types/src/db-host/queue-data-source.d.ts +38 -0
- package/dist/types/src/db-host/queue-data-source.d.ts.map +1 -0
- package/dist/types/src/db-host/queue-service.test.d.ts +2 -0
- package/dist/types/src/db-host/queue-service.test.d.ts.map +1 -0
- package/dist/types/src/db-host/space-state-manager.d.ts +4 -3
- package/dist/types/src/db-host/space-state-manager.d.ts.map +1 -1
- package/dist/types/src/db-host/stub.d.ts +11 -0
- package/dist/types/src/db-host/stub.d.ts.map +1 -0
- package/dist/types/src/edge/echo-edge-replicator.d.ts +10 -7
- package/dist/types/src/edge/echo-edge-replicator.d.ts.map +1 -1
- package/dist/types/src/edge/echo-edge-subduction-replicator.d.ts +39 -0
- package/dist/types/src/edge/echo-edge-subduction-replicator.d.ts.map +1 -0
- package/dist/types/src/edge/echo-edge-subduction-replicator.test.d.ts +2 -0
- package/dist/types/src/edge/echo-edge-subduction-replicator.test.d.ts.map +1 -0
- package/dist/types/src/edge/index.d.ts +1 -0
- package/dist/types/src/edge/index.d.ts.map +1 -1
- package/dist/types/src/edge/inflight-request-limiter.d.ts.map +1 -1
- package/dist/types/src/filter/filter-match.d.ts +4 -1
- package/dist/types/src/filter/filter-match.d.ts.map +1 -1
- package/dist/types/src/metadata/metadata-store.d.ts +1 -1
- package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
- package/dist/types/src/pipeline/message-selector.d.ts.map +1 -1
- package/dist/types/src/pipeline/pipeline.d.ts +3 -3
- package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
- package/dist/types/src/pipeline/timeframe-clock.d.ts.map +1 -1
- package/dist/types/src/query/errors.d.ts +22 -10
- package/dist/types/src/query/errors.d.ts.map +1 -1
- package/dist/types/src/query/plan.d.ts +66 -8
- package/dist/types/src/query/plan.d.ts.map +1 -1
- package/dist/types/src/query/query-executor.d.ts +66 -11
- package/dist/types/src/query/query-executor.d.ts.map +1 -1
- package/dist/types/src/query/query-planner.d.ts +12 -1
- package/dist/types/src/query/query-planner.d.ts.map +1 -1
- package/dist/types/src/space/admission-discovery-extension.d.ts.map +1 -1
- package/dist/types/src/space/auth.d.ts +3 -3
- package/dist/types/src/space/auth.d.ts.map +1 -1
- package/dist/types/src/space/control-pipeline.d.ts +5 -4
- package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
- package/dist/types/src/space/space-manager.d.ts +8 -8
- package/dist/types/src/space/space-manager.d.ts.map +1 -1
- package/dist/types/src/space/space-protocol.d.ts +10 -9
- package/dist/types/src/space/space-protocol.d.ts.map +1 -1
- package/dist/types/src/space/space.d.ts +6 -6
- package/dist/types/src/space/space.d.ts.map +1 -1
- package/dist/types/src/testing/change-metadata.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +0 -2
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-agent-builder.d.ts +2 -2
- package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
- package/dist/types/src/testing/test-feed-builder.d.ts.map +1 -1
- package/dist/types/src/testing/test-network-adapter.d.ts +1 -1
- package/dist/types/src/testing/test-network-adapter.d.ts.map +1 -1
- package/dist/types/src/testing/test-replicator.d.ts +14 -13
- package/dist/types/src/testing/test-replicator.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +1 -1
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +59 -55
- package/src/automerge/automerge-host-subduction.test.ts +263 -0
- package/src/automerge/automerge-host.test.ts +162 -39
- package/src/automerge/automerge-host.ts +679 -201
- package/src/automerge/automerge-repo-subduction.test.ts +1054 -0
- package/src/automerge/automerge-repo.test.ts +349 -91
- package/src/automerge/automerge-subduction.test.ts +330 -0
- package/src/automerge/collection-synchronizer.test.ts +98 -17
- package/src/automerge/collection-synchronizer.ts +141 -37
- package/src/automerge/echo-data-monitor.ts +1 -1
- package/src/automerge/echo-network-adapter.test.ts +5 -4
- package/src/automerge/echo-network-adapter.ts +76 -31
- package/src/automerge/echo-replicator.ts +50 -15
- package/src/automerge/errors.ts +10 -0
- package/src/automerge/handle-state.ts +62 -0
- package/src/automerge/heads-store.ts +42 -3
- package/src/automerge/index.ts +3 -1
- package/src/automerge/leveldb-storage-adapter.ts +77 -11
- package/src/automerge/mesh-echo-replicator-connection.ts +12 -8
- package/src/automerge/mesh-echo-replicator.ts +15 -11
- package/src/automerge/storage-adapter.test.ts +1 -1
- package/src/common/space-id.ts +1 -1
- package/src/db-host/automerge-data-source.test.ts +299 -0
- package/src/db-host/automerge-data-source.ts +187 -0
- package/src/db-host/data-service.ts +35 -26
- package/src/db-host/database-root.ts +20 -8
- package/src/db-host/documents-synchronizer.test.ts +145 -14
- package/src/db-host/documents-synchronizer.ts +163 -51
- package/src/db-host/echo-host.ts +384 -99
- package/src/db-host/index.ts +2 -0
- package/src/db-host/invalidation-hint.ts +50 -0
- package/src/db-host/local-queue-service.ts +127 -0
- package/src/db-host/query-invalidation.test.ts +270 -0
- package/src/db-host/query-service.ts +111 -106
- package/src/db-host/queue-data-source.ts +160 -0
- package/src/db-host/queue-service.test.ts +145 -0
- package/src/db-host/space-state-manager.ts +12 -10
- package/src/db-host/stub.ts +33 -0
- package/src/edge/echo-edge-replicator.test.ts +12 -10
- package/src/edge/echo-edge-replicator.ts +144 -58
- package/src/edge/echo-edge-subduction-replicator.test.ts +158 -0
- package/src/edge/echo-edge-subduction-replicator.ts +377 -0
- package/src/edge/index.ts +1 -0
- package/src/filter/filter-match.test.ts +68 -32
- package/src/filter/filter-match.ts +230 -21
- package/src/metadata/metadata-store.ts +11 -8
- package/src/pipeline/pipeline-stress.test.ts +1 -1
- package/src/pipeline/pipeline.test.ts +2 -2
- package/src/pipeline/pipeline.ts +9 -7
- package/src/query/errors.ts +3 -1
- package/src/query/plan.ts +84 -9
- package/src/query/query-executor.ts +1197 -165
- package/src/query/query-planner.test.ts +993 -81
- package/src/query/query-planner.ts +503 -27
- package/src/space/admission-discovery-extension.ts +3 -3
- package/src/space/auth.ts +6 -6
- package/src/space/control-pipeline.test.ts +5 -4
- package/src/space/control-pipeline.ts +16 -13
- package/src/space/space-manager.browser.test.ts +1 -1
- package/src/space/space-manager.ts +16 -20
- package/src/space/space-protocol.browser.test.ts +15 -14
- package/src/space/space-protocol.test.ts +15 -14
- package/src/space/space-protocol.ts +22 -18
- package/src/space/space.test.ts +3 -3
- package/src/space/space.ts +11 -11
- package/src/testing/index.ts +0 -2
- package/src/testing/test-agent-builder.ts +3 -3
- package/src/testing/test-network-adapter.ts +24 -3
- package/src/testing/test-replicator.ts +19 -20
- package/src/util.ts +7 -3
- package/dist/lib/browser/chunk-35I6ERLG.mjs.map +0 -7
- package/dist/lib/browser/chunk-CGS2ULMK.mjs +0 -11
- package/dist/lib/browser/chunk-CGS2ULMK.mjs.map +0 -7
- package/dist/lib/browser/chunk-TQJTKNMS.mjs +0 -126
- package/dist/lib/browser/chunk-TQJTKNMS.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -4743
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node/chunk-HOPOFWAL.cjs +0 -147
- package/dist/lib/node/chunk-HOPOFWAL.cjs.map +0 -7
- package/dist/lib/node/chunk-JXX6LF5U.cjs +0 -2084
- package/dist/lib/node/chunk-JXX6LF5U.cjs.map +0 -7
- package/dist/lib/node/chunk-Q7SFCCGT.cjs +0 -33
- package/dist/lib/node/chunk-Q7SFCCGT.cjs.map +0 -7
- package/dist/lib/node/filter/index.cjs +0 -32
- package/dist/lib/node/filter/index.cjs.map +0 -7
- package/dist/lib/node/index.cjs +0 -4699
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/lib/node/testing/index.cjs +0 -753
- package/dist/lib/node/testing/index.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-5BHLPT24.mjs +0 -2067
- package/dist/lib/node-esm/chunk-5BHLPT24.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-RVK35BS7.mjs +0 -126
- package/dist/lib/node-esm/chunk-RVK35BS7.mjs.map +0 -7
- package/dist/lib/node-esm/filter/index.mjs +0 -11
- package/dist/lib/node-esm/filter/index.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -4743
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/testing/index.mjs +0 -742
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/types/src/db-host/documents-iterator.d.ts +0 -7
- package/dist/types/src/db-host/documents-iterator.d.ts.map +0 -1
- package/dist/types/src/testing/test-data.d.ts +0 -18
- package/dist/types/src/testing/test-data.d.ts.map +0 -1
- package/dist/types/src/testing/test-schema.d.ts +0 -37
- package/dist/types/src/testing/test-schema.d.ts.map +0 -1
- package/src/db-host/documents-iterator.ts +0 -74
- package/src/testing/test-data.ts +0 -127
- package/src/testing/test-schema.ts +0 -53
- /package/dist/lib/{browser → neutral}/filter/index.mjs.map +0 -0
|
@@ -4,81 +4,117 @@
|
|
|
4
4
|
|
|
5
5
|
import { describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
|
-
import { Filter } from '@dxos/echo';
|
|
7
|
+
import { Filter, Ref } from '@dxos/echo';
|
|
8
8
|
import { ObjectStructure } from '@dxos/echo-protocol';
|
|
9
|
-
import {
|
|
9
|
+
import { TestSchema } from '@dxos/echo/testing';
|
|
10
10
|
import { DXN, ObjectId, SpaceId } from '@dxos/keys';
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { type MatchedObject, filterMatchObject } from './filter-match';
|
|
13
13
|
|
|
14
14
|
describe('filterMatch', () => {
|
|
15
|
+
test('everything', () => {
|
|
16
|
+
expect(filterMatchObject(Filter.everything().ast, OBJECT_1)).to.be.true;
|
|
17
|
+
expect(filterMatchObject(Filter.everything().ast, OBJECT_2)).to.be.true;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('nothing', () => {
|
|
21
|
+
expect(filterMatchObject(Filter.nothing().ast, OBJECT_1)).to.be.false;
|
|
22
|
+
expect(filterMatchObject(Filter.nothing().ast, OBJECT_2)).to.be.false;
|
|
23
|
+
});
|
|
24
|
+
|
|
15
25
|
test('properties', () => {
|
|
16
|
-
expect(filterMatchObject(Filter.type(Expando, { title: 'test' }).ast, OBJECT_1)).to.be.true;
|
|
17
|
-
expect(filterMatchObject(Filter.type(Expando, { value: 100 }).ast, OBJECT_1)).to.be.true;
|
|
18
|
-
expect(filterMatchObject(Filter.type(Expando, { complete: false }).ast, OBJECT_1)).to.be.false;
|
|
19
|
-
expect(filterMatchObject(Filter.type(Expando, { missing: undefined }).ast, OBJECT_1)).to.be.true;
|
|
26
|
+
expect(filterMatchObject(Filter.type(TestSchema.Expando, { title: 'test' }).ast, OBJECT_1)).to.be.true;
|
|
27
|
+
expect(filterMatchObject(Filter.type(TestSchema.Expando, { value: 100 }).ast, OBJECT_1)).to.be.true;
|
|
28
|
+
expect(filterMatchObject(Filter.type(TestSchema.Expando, { complete: false }).ast, OBJECT_1)).to.be.false;
|
|
29
|
+
expect(filterMatchObject(Filter.type(TestSchema.Expando, { missing: undefined }).ast, OBJECT_1)).to.be.true;
|
|
30
|
+
expect(filterMatchObject(Filter.type(TestSchema.Expando, { properties: { subject: 'test' } }).ast, OBJECT_1)).to.be
|
|
31
|
+
.true;
|
|
32
|
+
expect(filterMatchObject(Filter.type(TestSchema.Expando, { array: Filter.contains('two') }).ast, OBJECT_1)).to.be
|
|
33
|
+
.true;
|
|
20
34
|
});
|
|
21
35
|
|
|
22
36
|
test('and', () => {
|
|
23
|
-
const filter1 = Filter.type(Expando, { title: 'test' });
|
|
24
|
-
const filter2 = Filter.type(Expando, { value: 100 });
|
|
25
|
-
const filter3 = Filter.type(Expando, { complete: true });
|
|
37
|
+
const filter1 = Filter.type(TestSchema.Expando, { title: 'test' });
|
|
38
|
+
const filter2 = Filter.type(TestSchema.Expando, { value: 100 });
|
|
39
|
+
const filter3 = Filter.type(TestSchema.Expando, { complete: true });
|
|
26
40
|
|
|
27
41
|
expect(filterMatchObject(Filter.and(filter1, filter2, filter3).ast, OBJECT_1)).to.be.true;
|
|
28
42
|
});
|
|
29
43
|
|
|
30
44
|
test('or', () => {
|
|
31
|
-
const filter1 = Filter.type(Expando, { value: 200 });
|
|
32
|
-
const filter2 = Filter.type(Expando, { title: 'test' });
|
|
33
|
-
const filter3 = Filter.type(Expando, { complete: false });
|
|
45
|
+
const filter1 = Filter.type(TestSchema.Expando, { value: 200 });
|
|
46
|
+
const filter2 = Filter.type(TestSchema.Expando, { title: 'test' });
|
|
47
|
+
const filter3 = Filter.type(TestSchema.Expando, { complete: false });
|
|
34
48
|
|
|
35
49
|
expect(filterMatchObject(Filter.or(filter1, filter2, filter3).ast, OBJECT_1)).to.be.true;
|
|
36
50
|
});
|
|
37
51
|
|
|
38
52
|
test('not', () => {
|
|
39
|
-
const filter1 = Filter.type(Expando, { title: 'test' });
|
|
53
|
+
const filter1 = Filter.type(TestSchema.Expando, { title: 'test' });
|
|
40
54
|
const filter2 = Filter.not(filter1);
|
|
41
55
|
|
|
42
56
|
expect(filterMatchObject(filter1.ast, OBJECT_1)).to.be.true;
|
|
43
57
|
expect(filterMatchObject(filter2.ast, OBJECT_1)).to.be.false;
|
|
44
58
|
});
|
|
45
59
|
|
|
60
|
+
test('contains', () => {
|
|
61
|
+
expect(
|
|
62
|
+
filterMatchObject(
|
|
63
|
+
Filter.type(TestSchema.Expando, { properties: { label: Filter.contains('test') } }).ast,
|
|
64
|
+
OBJECT_1,
|
|
65
|
+
),
|
|
66
|
+
).to.be.true;
|
|
67
|
+
expect(
|
|
68
|
+
filterMatchObject(
|
|
69
|
+
Filter.type(TestSchema.Expando, { fields: Filter.contains({ label: 'label', value: 'test' }) }).ast,
|
|
70
|
+
OBJECT_1,
|
|
71
|
+
),
|
|
72
|
+
).to.be.true;
|
|
73
|
+
});
|
|
74
|
+
|
|
46
75
|
test('complex', () => {
|
|
47
|
-
const filter1 = Filter.type(Expando, { title: 'bad' });
|
|
48
|
-
const filter2 = Filter.type(Expando, { value: 0 });
|
|
76
|
+
const filter1 = Filter.type(TestSchema.Expando, { title: 'bad' });
|
|
77
|
+
const filter2 = Filter.type(TestSchema.Expando, { value: 0 });
|
|
49
78
|
expect(filterMatchObject(Filter.not(Filter.or(filter1, filter2)).ast, OBJECT_1)).to.be.true;
|
|
50
79
|
});
|
|
51
80
|
|
|
52
81
|
test('ids', () => {
|
|
53
|
-
const filter = Filter.
|
|
82
|
+
const filter = Filter.id(OBJECT_1.id);
|
|
54
83
|
expect(filterMatchObject(filter.ast, OBJECT_1)).to.be.true;
|
|
55
84
|
expect(filterMatchObject(filter.ast, OBJECT_2)).to.be.false;
|
|
56
85
|
});
|
|
57
86
|
|
|
58
|
-
test('everything', () => {
|
|
59
|
-
expect(filterMatchObject(Filter.everything().ast, OBJECT_1)).to.be.true;
|
|
60
|
-
expect(filterMatchObject(Filter.everything().ast, OBJECT_2)).to.be.true;
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test('nothing', () => {
|
|
64
|
-
expect(filterMatchObject(Filter.nothing().ast, OBJECT_1)).to.be.false;
|
|
65
|
-
expect(filterMatchObject(Filter.nothing().ast, OBJECT_2)).to.be.false;
|
|
66
|
-
});
|
|
67
|
-
|
|
68
87
|
test('refs', () => {
|
|
69
|
-
const filter = Filter.type(Expando, { parent: Ref.fromDXN(DXN.fromLocalObjectId(OBJECT_1.id)) });
|
|
88
|
+
const filter = Filter.type(TestSchema.Expando, { parent: Ref.fromDXN(DXN.fromLocalObjectId(OBJECT_1.id)) });
|
|
70
89
|
expect(filterMatchObject(filter.ast, OBJECT_1)).to.be.false;
|
|
71
90
|
expect(filterMatchObject(filter.ast, OBJECT_2)).to.be.false;
|
|
72
91
|
expect(filterMatchObject(filter.ast, OBJECT_3)).to.be.true;
|
|
73
92
|
});
|
|
93
|
+
|
|
94
|
+
test('standalone timestamp filter throws invariant (must be handled at index level)', () => {
|
|
95
|
+
expect(() => filterMatchObject(Filter.updated({ after: Date.now() - 1000 }).ast, OBJECT_1)).to.throw();
|
|
96
|
+
expect(() => filterMatchObject(Filter.created({ before: Date.now() + 1000 }).ast, OBJECT_1)).to.throw();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('and(type, timestamp) throws on timestamp part', () => {
|
|
100
|
+
const filter = Filter.and(Filter.type(TestSchema.Expando), Filter.updated({ after: Date.now() - 1000 }));
|
|
101
|
+
expect(() => filterMatchObject(filter.ast, OBJECT_1)).to.throw();
|
|
102
|
+
});
|
|
74
103
|
});
|
|
75
104
|
|
|
76
105
|
const OBJECT_1: MatchedObject = {
|
|
77
106
|
id: ObjectId.make('01JVS9YYT5VMVJW0GGTM1YHCCH'),
|
|
78
107
|
spaceId: SpaceId.make('B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO'),
|
|
79
108
|
doc: ObjectStructure.makeObject({
|
|
80
|
-
type: DXN.fromTypenameAndVersion(
|
|
81
|
-
data: {
|
|
109
|
+
type: DXN.fromTypenameAndVersion(TestSchema.Expando.typename, '0.1.0').toString(),
|
|
110
|
+
data: {
|
|
111
|
+
title: 'test',
|
|
112
|
+
value: 100,
|
|
113
|
+
complete: true,
|
|
114
|
+
array: ['one', 'two', 'three'],
|
|
115
|
+
properties: { label: ['test'], subject: 'test' },
|
|
116
|
+
fields: [{ label: 'label', value: 'test' }],
|
|
117
|
+
},
|
|
82
118
|
}),
|
|
83
119
|
};
|
|
84
120
|
|
|
@@ -86,7 +122,7 @@ const OBJECT_2: MatchedObject = {
|
|
|
86
122
|
id: ObjectId.make('01JT5TD6K9FFJ3VNM5FGMS5C0Q'),
|
|
87
123
|
spaceId: SpaceId.make('B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO'),
|
|
88
124
|
doc: ObjectStructure.makeObject({
|
|
89
|
-
type: DXN.fromTypenameAndVersion(
|
|
125
|
+
type: DXN.fromTypenameAndVersion(TestSchema.Expando.typename, '0.1.0').toString(),
|
|
90
126
|
data: { title: 'test', value: 100, complete: true },
|
|
91
127
|
deleted: true,
|
|
92
128
|
}),
|
|
@@ -96,7 +132,7 @@ const OBJECT_3: MatchedObject = {
|
|
|
96
132
|
id: ObjectId.make('01JT5TD6K9FFJ3VNM5FGMS5C0Q'),
|
|
97
133
|
spaceId: SpaceId.make('B2NJDFNVZIW77OQSXUBNAD7BUMBD3G5PO'),
|
|
98
134
|
doc: ObjectStructure.makeObject({
|
|
99
|
-
type: DXN.fromTypenameAndVersion(
|
|
135
|
+
type: DXN.fromTypenameAndVersion(TestSchema.Expando.typename, '0.1.0').toString(),
|
|
100
136
|
data: { title: 'test', value: 100, complete: true, parent: { '/': DXN.fromLocalObjectId(OBJECT_1.id).toString() } },
|
|
101
137
|
}),
|
|
102
138
|
};
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
|
|
5
|
+
import * as semver from 'semver';
|
|
6
|
+
|
|
7
|
+
import { EncodedReference, ObjectStructure, type QueryAST, isEncodedReference } from '@dxos/echo-protocol';
|
|
8
|
+
import { ATTR_META, type ObjectJSON } from '@dxos/echo/internal';
|
|
7
9
|
import { DXN, type ObjectId, type SpaceId } from '@dxos/keys';
|
|
8
10
|
|
|
9
11
|
export type MatchedObject = {
|
|
@@ -14,35 +16,32 @@ export type MatchedObject = {
|
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Matches an object against a filter AST.
|
|
19
|
+
* @param obj object structure as stored in automerge.
|
|
17
20
|
*/
|
|
18
21
|
export const filterMatchObject = (filter: QueryAST.Filter, obj: MatchedObject): boolean => {
|
|
19
22
|
switch (filter.type) {
|
|
20
23
|
case 'object': {
|
|
21
|
-
// Check typename if specified
|
|
24
|
+
// Check typename if specified.
|
|
22
25
|
if (filter.typename !== null) {
|
|
23
26
|
// TODO(dmaretskyi): `system` is missing in some cases.
|
|
24
|
-
if (!obj.doc
|
|
25
|
-
// Objects with no type are
|
|
26
|
-
|
|
27
|
-
if (expectedDXN?.type !== EXPANDO_TYPENAME) {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
27
|
+
if (!obj.doc?.system?.type?.['/']) {
|
|
28
|
+
// Objects with no type are deprecated.
|
|
29
|
+
return false;
|
|
30
30
|
} else {
|
|
31
31
|
const actualDXN = DXN.parse(obj.doc.system.type['/']);
|
|
32
32
|
const expectedDXN = DXN.parse(filter.typename);
|
|
33
|
-
|
|
34
33
|
if (!compareTypename(expectedDXN, actualDXN)) {
|
|
35
34
|
return false;
|
|
36
35
|
}
|
|
37
36
|
}
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
// Check IDs if specified
|
|
39
|
+
// Check IDs if specified.
|
|
41
40
|
if (filter.id && filter.id.length > 0 && !filter.id.includes(obj.id)) {
|
|
42
41
|
return false;
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
// Check properties
|
|
44
|
+
// Check properties.
|
|
46
45
|
if (filter.props) {
|
|
47
46
|
for (const [key, valueFilter] of Object.entries(filter.props)) {
|
|
48
47
|
const value = obj.doc.data[key];
|
|
@@ -52,7 +51,7 @@ export const filterMatchObject = (filter: QueryAST.Filter, obj: MatchedObject):
|
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
// Check foreign keys if specified
|
|
54
|
+
// Check foreign keys if specified.
|
|
56
55
|
if (filter.foreignKeys && filter.foreignKeys.length > 0) {
|
|
57
56
|
const hasMatchingKey = filter.foreignKeys.some((filterKey) =>
|
|
58
57
|
obj.doc.meta.keys.some((objKey) => objKey.source === filterKey.source && objKey.id === filterKey.id),
|
|
@@ -62,14 +61,35 @@ export const filterMatchObject = (filter: QueryAST.Filter, obj: MatchedObject):
|
|
|
62
61
|
}
|
|
63
62
|
}
|
|
64
63
|
|
|
64
|
+
// Check registry meta key / version if specified.
|
|
65
|
+
if (
|
|
66
|
+
filter.metaKey !== undefined &&
|
|
67
|
+
!matchMetaKey(filter.metaKey, filter.metaVersion, obj.doc.meta.key, obj.doc.meta.version)
|
|
68
|
+
) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
65
72
|
return true;
|
|
66
73
|
}
|
|
67
74
|
|
|
75
|
+
case 'tag': {
|
|
76
|
+
const tags = ObjectStructure.getTags(obj.doc);
|
|
77
|
+
return tags.some((tag) => tag === filter.tag);
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
case 'text-search': {
|
|
69
|
-
// TODO: Implement text search
|
|
81
|
+
// TODO(???): Implement text search.
|
|
70
82
|
return false;
|
|
71
83
|
}
|
|
72
84
|
|
|
85
|
+
case 'timestamp': {
|
|
86
|
+
throw new Error('Timestamp filters must be handled at the index level, not in-memory matching.');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
case 'child-of': {
|
|
90
|
+
throw new Error('child-of filters must be handled at the executor level, not in-memory matching.');
|
|
91
|
+
}
|
|
92
|
+
|
|
73
93
|
case 'not': {
|
|
74
94
|
return !filterMatchObject(filter.filter, obj);
|
|
75
95
|
}
|
|
@@ -87,6 +107,163 @@ export const filterMatchObject = (filter: QueryAST.Filter, obj: MatchedObject):
|
|
|
87
107
|
}
|
|
88
108
|
};
|
|
89
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Matches a meta `key` / `version` constraint against an object's meta `key` and `version`.
|
|
112
|
+
* - `key` must match exactly.
|
|
113
|
+
* - If `versionRange` is set, the object's `version` must satisfy it (semver).
|
|
114
|
+
* Objects without a `version` or with an invalid `version` do not match a version-constrained filter.
|
|
115
|
+
*/
|
|
116
|
+
const matchMetaKey = (
|
|
117
|
+
key: string,
|
|
118
|
+
versionRange: string | undefined,
|
|
119
|
+
objKey: string | undefined,
|
|
120
|
+
objVersion: string | undefined,
|
|
121
|
+
): boolean => {
|
|
122
|
+
if (objKey !== key) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
if (versionRange === undefined) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
if (objVersion === undefined || semver.valid(objVersion) === null) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
if (semver.validRange(versionRange) === null) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
return semver.satisfies(objVersion, versionRange, { includePrerelease: true });
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// TODO(burdon): Reconcile with filterMatchObject.
|
|
138
|
+
export const filterMatchObjectJSON = (filter: QueryAST.Filter, obj: ObjectJSON): boolean => {
|
|
139
|
+
switch (filter.type) {
|
|
140
|
+
case 'object': {
|
|
141
|
+
// Check typename if specified
|
|
142
|
+
if (filter.typename !== null) {
|
|
143
|
+
// TODO(dmaretskyi): `system` is missing in some cases.
|
|
144
|
+
if (!obj['@type']) {
|
|
145
|
+
// Objects with no type are deprecated.
|
|
146
|
+
return false;
|
|
147
|
+
} else {
|
|
148
|
+
const actualDXN = DXN.parse(obj['@type']);
|
|
149
|
+
const expectedDXN = DXN.parse(filter.typename);
|
|
150
|
+
if (!compareTypename(expectedDXN, actualDXN)) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Check IDs if specified
|
|
157
|
+
if (filter.id && filter.id.length > 0 && !filter.id.includes(obj.id)) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Check properties
|
|
162
|
+
if (filter.props) {
|
|
163
|
+
for (const [key, valueFilter] of Object.entries(filter.props)) {
|
|
164
|
+
if (key.startsWith('@')) {
|
|
165
|
+
// ignore meta properties
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
const value = (obj as any)[key];
|
|
169
|
+
if (!filterMatchValue(valueFilter, value)) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Check foreign keys if specified
|
|
176
|
+
if (filter.foreignKeys && filter.foreignKeys.length > 0) {
|
|
177
|
+
const hasMatchingKey = filter.foreignKeys.some((filterKey) =>
|
|
178
|
+
obj['@meta']?.keys?.some((objKey) => objKey.source === filterKey.source && objKey.id === filterKey.id),
|
|
179
|
+
);
|
|
180
|
+
if (!hasMatchingKey) {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Check registry meta key / version if specified.
|
|
186
|
+
if (
|
|
187
|
+
filter.metaKey !== undefined &&
|
|
188
|
+
!matchMetaKey(filter.metaKey, filter.metaVersion, obj[ATTR_META]?.key, obj[ATTR_META]?.version)
|
|
189
|
+
) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
case 'tag': {
|
|
197
|
+
const tags = obj[ATTR_META]?.tags ?? [];
|
|
198
|
+
return tags.some((tag) => tag === filter.tag);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// TODO: Implement text search.
|
|
202
|
+
case 'text-search': {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
case 'timestamp': {
|
|
207
|
+
throw new Error('Timestamp filters must be handled at the index level, not in-memory matching.');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
case 'child-of': {
|
|
211
|
+
throw new Error('child-of filters must be handled at the executor level, not in-memory matching.');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
case 'not': {
|
|
215
|
+
return !filterMatchObjectJSON(filter.filter, obj);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
case 'and': {
|
|
219
|
+
return filter.filters.every((f) => filterMatchObjectJSON(f, obj));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
case 'or': {
|
|
223
|
+
return filter.filters.some((f) => filterMatchObjectJSON(f, obj));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
default:
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Performs structural matching between a filter object and a target object.
|
|
233
|
+
* This handles nested object comparison for array matching scenarios.
|
|
234
|
+
*/
|
|
235
|
+
// TODO(wittjosiah): Add ast support for non-strict matching.
|
|
236
|
+
const structuralMatch = (filterObj: any, targetObj: any, strict = true): boolean => {
|
|
237
|
+
if (typeof filterObj !== 'object' || filterObj === null) {
|
|
238
|
+
return filterObj === targetObj;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (typeof targetObj !== 'object' || targetObj === null) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Prohibit extra keys in targetObj.
|
|
246
|
+
const filterKeys = Object.keys(filterObj);
|
|
247
|
+
const targetKeys = Object.keys(targetObj);
|
|
248
|
+
if (strict && filterKeys.length !== targetKeys.length) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return filterKeys.every((key) => {
|
|
253
|
+
if (!(key in targetObj)) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
const filterValue = filterObj[key];
|
|
257
|
+
const targetValue = targetObj[key];
|
|
258
|
+
|
|
259
|
+
if (typeof filterValue === 'object' && filterValue !== null) {
|
|
260
|
+
return structuralMatch(filterValue, targetValue);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return filterValue === targetValue;
|
|
264
|
+
});
|
|
265
|
+
};
|
|
266
|
+
|
|
90
267
|
export const filterMatchValue = (filter: QueryAST.Filter, value: unknown): boolean => {
|
|
91
268
|
switch (filter.type) {
|
|
92
269
|
case 'compare': {
|
|
@@ -97,7 +274,7 @@ export const filterMatchValue = (filter: QueryAST.Filter, value: unknown): boole
|
|
|
97
274
|
if (!isEncodedReference(value)) {
|
|
98
275
|
return false;
|
|
99
276
|
}
|
|
100
|
-
return DXN.equals(
|
|
277
|
+
return DXN.equals(EncodedReference.toDXN(value), EncodedReference.toDXN(compareValue));
|
|
101
278
|
}
|
|
102
279
|
return value === compareValue;
|
|
103
280
|
case 'neq':
|
|
@@ -110,12 +287,44 @@ export const filterMatchValue = (filter: QueryAST.Filter, value: unknown): boole
|
|
|
110
287
|
return (value as any) < compareValue;
|
|
111
288
|
case 'lte':
|
|
112
289
|
return (value as any) <= compareValue;
|
|
290
|
+
default:
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
case 'object': {
|
|
295
|
+
// Handle nested object filters for property matching
|
|
296
|
+
if (typeof value !== 'object' || value === null) {
|
|
297
|
+
return false;
|
|
113
298
|
}
|
|
114
|
-
|
|
299
|
+
|
|
300
|
+
// Check properties
|
|
301
|
+
if (filter.props) {
|
|
302
|
+
for (const [key, valueFilter] of Object.entries(filter.props)) {
|
|
303
|
+
const nestedValue = (value as any)[key];
|
|
304
|
+
if (!filterMatchValue(valueFilter, nestedValue)) {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return true;
|
|
115
311
|
}
|
|
116
312
|
case 'in': {
|
|
117
313
|
return filter.values.includes(value);
|
|
118
314
|
}
|
|
315
|
+
case 'contains': {
|
|
316
|
+
if (!Array.isArray(value)) {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return value.some((element) => {
|
|
321
|
+
if (typeof filter.value === 'object' && filter.value !== null && !Array.isArray(filter.value)) {
|
|
322
|
+
return structuralMatch(filter.value, element);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return element === filter.value;
|
|
326
|
+
});
|
|
327
|
+
}
|
|
119
328
|
case 'range': {
|
|
120
329
|
return (value as any) >= filter.from && (value as any) <= filter.to;
|
|
121
330
|
}
|
|
@@ -143,11 +352,11 @@ export const filterMatchValue = (filter: QueryAST.Filter, value: unknown): boole
|
|
|
143
352
|
*
|
|
144
353
|
* Examples: (expected) (actual)
|
|
145
354
|
*
|
|
146
|
-
* dxn:type:example.
|
|
147
|
-
* dxn:type:example.
|
|
148
|
-
* dxn:type:example.
|
|
149
|
-
* dxn:type:example.
|
|
150
|
-
* dxn:type:example.
|
|
355
|
+
* dxn:type:com.example.type.task !== dxn:type:com.example.type.contact
|
|
356
|
+
* dxn:type:com.example.type.task === dxn:type:com.example.type.task
|
|
357
|
+
* dxn:type:com.example.type.task:0.1.0 !== dxn:type:com.example.type.task:0.2.0
|
|
358
|
+
* dxn:type:com.example.type.task === dxn:type:com.example.type.task:0.1.0
|
|
359
|
+
* dxn:type:com.example.type.task:0.1.0 === dxn:type:com.example.type.task
|
|
151
360
|
*
|
|
152
361
|
*/
|
|
153
362
|
const compareTypename = (expectedDXN: DXN, actualDXN: DXN): boolean => {
|
|
@@ -16,11 +16,11 @@ import { Invitation, SpaceState } from '@dxos/protocols/proto/dxos/client/servic
|
|
|
16
16
|
import {
|
|
17
17
|
type ControlPipelineSnapshot,
|
|
18
18
|
type EchoMetadata,
|
|
19
|
-
type
|
|
19
|
+
type EdgeReplicationSetting,
|
|
20
20
|
type IdentityRecord,
|
|
21
|
-
type SpaceCache,
|
|
22
21
|
type LargeSpaceMetadata,
|
|
23
|
-
type
|
|
22
|
+
type SpaceCache,
|
|
23
|
+
type SpaceMetadata,
|
|
24
24
|
} from '@dxos/protocols/proto/dxos/echo/metadata';
|
|
25
25
|
import { type Directory, type File } from '@dxos/random-access-storage';
|
|
26
26
|
import { type Timeframe } from '@dxos/timeframe';
|
|
@@ -91,14 +91,17 @@ export class MetadataStore {
|
|
|
91
91
|
log('loaded', { size: dataSize, checksum, name: file.filename });
|
|
92
92
|
|
|
93
93
|
if (fileLength < dataSize + 8) {
|
|
94
|
-
throw new DataCorruptionError(
|
|
94
|
+
throw new DataCorruptionError({
|
|
95
|
+
message: 'Metadata size is smaller than expected.',
|
|
96
|
+
context: { fileLength, dataSize },
|
|
97
|
+
});
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
const data = await file.read(8, dataSize);
|
|
98
101
|
|
|
99
102
|
const calculatedChecksum = CRC32.buf(data);
|
|
100
103
|
if (calculatedChecksum !== checksum) {
|
|
101
|
-
throw new DataCorruptionError('Metadata checksum is invalid.');
|
|
104
|
+
throw new DataCorruptionError({ message: 'Metadata checksum is invalid.' });
|
|
102
105
|
}
|
|
103
106
|
|
|
104
107
|
return codec.decode(data);
|
|
@@ -363,9 +366,9 @@ const fromBytesInt32 = (buf: Buffer) => buf.readInt32LE(0);
|
|
|
363
366
|
export const hasInvitationExpired = (invitation: Invitation): boolean => {
|
|
364
367
|
return Boolean(
|
|
365
368
|
invitation.created &&
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
+
invitation.lifetime &&
|
|
370
|
+
invitation.lifetime !== 0 &&
|
|
371
|
+
invitation.created.getTime() + invitation.lifetime * 1000 < Date.now(),
|
|
369
372
|
);
|
|
370
373
|
};
|
|
371
374
|
|
|
@@ -15,8 +15,8 @@ import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
|
15
15
|
import { Timeframe } from '@dxos/timeframe';
|
|
16
16
|
import { range } from '@dxos/util';
|
|
17
17
|
|
|
18
|
-
import { Pipeline } from './pipeline';
|
|
19
18
|
import { TestFeedBuilder } from '../testing';
|
|
19
|
+
import { Pipeline } from './pipeline';
|
|
20
20
|
|
|
21
21
|
const NUM_AGENTS = 2;
|
|
22
22
|
const NUM_MESSAGES = 10;
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { describe, expect,
|
|
5
|
+
import { describe, expect, onTestFinished, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { Event, sleep } from '@dxos/async';
|
|
8
8
|
import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
9
9
|
import { Timeframe } from '@dxos/timeframe';
|
|
10
10
|
import { range } from '@dxos/util';
|
|
11
11
|
|
|
12
|
-
import { Pipeline } from './pipeline';
|
|
13
12
|
import { TestFeedBuilder } from '../testing';
|
|
13
|
+
import { Pipeline } from './pipeline';
|
|
14
14
|
|
|
15
15
|
const TEST_MESSAGE: FeedMessage = {
|
|
16
16
|
timeframe: new Timeframe(),
|
package/src/pipeline/pipeline.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Event, sleepWithContext, synchronized
|
|
5
|
+
import { Event, Trigger, sleepWithContext, synchronized } from '@dxos/async';
|
|
6
6
|
import { Context, rejectOnDispose } from '@dxos/context';
|
|
7
7
|
import { failUndefined } from '@dxos/debug';
|
|
8
8
|
import { FeedSetIterator, type FeedWrapper, type FeedWriter } from '@dxos/feed-store';
|
|
@@ -14,11 +14,11 @@ import type { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
|
14
14
|
import { Timeframe } from '@dxos/timeframe';
|
|
15
15
|
import { ComplexMap } from '@dxos/util';
|
|
16
16
|
|
|
17
|
-
import { createMessageSelector } from './message-selector';
|
|
18
|
-
import { mapFeedIndexesToTimeframe, startAfter, TimeframeClock } from './timeframe-clock';
|
|
19
17
|
import { createMappedFeedWriter } from '../common';
|
|
18
|
+
import { createMessageSelector } from './message-selector';
|
|
19
|
+
import { TimeframeClock, mapFeedIndexesToTimeframe, startAfter } from './timeframe-clock';
|
|
20
20
|
|
|
21
|
-
export type
|
|
21
|
+
export type WaitUntilReachedTargetProps = {
|
|
22
22
|
/**
|
|
23
23
|
* For cancellation.
|
|
24
24
|
*/
|
|
@@ -40,8 +40,10 @@ export class PipelineState {
|
|
|
40
40
|
*/
|
|
41
41
|
_ctx = new Context();
|
|
42
42
|
|
|
43
|
-
// TODO(dmaretskyi): Remove?.
|
|
44
|
-
public
|
|
43
|
+
// TODO(dmaretskyi): Remove?. Avoid accessing `_timeframeClock` before constructor initialization.
|
|
44
|
+
public get timeframeUpdate() {
|
|
45
|
+
return this._timeframeClock.update;
|
|
46
|
+
}
|
|
45
47
|
|
|
46
48
|
public readonly stalled = new Event();
|
|
47
49
|
|
|
@@ -129,7 +131,7 @@ export class PipelineState {
|
|
|
129
131
|
ctx = new Context(),
|
|
130
132
|
timeout,
|
|
131
133
|
breakOnStall = true,
|
|
132
|
-
}:
|
|
134
|
+
}: WaitUntilReachedTargetProps = {}): Promise<void> {
|
|
133
135
|
log('waitUntilReachedTargetTimeframe', {
|
|
134
136
|
timeout,
|
|
135
137
|
current: this.timeframe,
|
package/src/query/errors.ts
CHANGED