@peerbit/document 13.0.44 → 13.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/benchmark/document-put.js +1224 -63
- package/dist/benchmark/document-put.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/native-rust.d.ts +50 -0
- package/dist/src/native-rust.d.ts.map +1 -0
- package/dist/src/native-rust.js +38 -0
- package/dist/src/native-rust.js.map +1 -0
- package/dist/src/policy.d.ts +51 -0
- package/dist/src/policy.d.ts.map +1 -0
- package/dist/src/policy.js +347 -0
- package/dist/src/policy.js.map +1 -0
- package/dist/src/program.d.ts +139 -22
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +3073 -342
- package/dist/src/program.js.map +1 -1
- package/dist/src/search.d.ts +78 -6
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +1105 -53
- package/dist/src/search.js.map +1 -1
- package/dist/src/transform.d.ts +42 -0
- package/dist/src/transform.d.ts.map +1 -0
- package/dist/src/transform.js +136 -0
- package/dist/src/transform.js.map +1 -0
- package/package.json +21 -16
- package/src/index.ts +2 -0
- package/src/native-rust.ts +152 -0
- package/src/policy.ts +592 -0
- package/src/program.ts +5019 -467
- package/src/search.ts +1777 -188
- package/src/transform.ts +277 -0
package/dist/src/search.js
CHANGED
|
@@ -32,10 +32,11 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
32
32
|
}
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
|
-
import { field, getSchema, serialize, variant, } from "@dao-xyz/borsh";
|
|
35
|
+
import { FixedArrayKind, field, getSchema, serialize, variant, } from "@dao-xyz/borsh";
|
|
36
36
|
import { Cache } from "@peerbit/cache";
|
|
37
37
|
import { PublicSignKey, sha256Base64Sync, } from "@peerbit/crypto";
|
|
38
38
|
import * as types from "@peerbit/document-interface";
|
|
39
|
+
import { tryProjectDocumentIndexSimple, } from "./native-rust.js";
|
|
39
40
|
import { CachedIndex } from "@peerbit/indexer-cache";
|
|
40
41
|
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
41
42
|
import { HashmapIndex } from "@peerbit/indexer-simple";
|
|
@@ -55,6 +56,7 @@ import { isPutOperation } from "./operation.js";
|
|
|
55
56
|
import { Prefetch } from "./prefetch.js";
|
|
56
57
|
import { initializeResultType, isResultIndexedValue, isResultValue, isResults, } from "./result-shape.js";
|
|
57
58
|
import { ResumableIterators } from "./resumable-iterator.js";
|
|
59
|
+
import { canPrepareDocumentTransformBeforeAppend, canPrepareDocumentTransformWithAppendFacts, documentTransformPreservesFieldPath, getDocumentTransformDescriptor, } from "./transform.js";
|
|
58
60
|
const WARNING_WHEN_ITERATING_FOR_MORE_THAN = 1e5;
|
|
59
61
|
const logger = loggerFn("peerbit:program:document:search");
|
|
60
62
|
const warn = logger.newScope("warn");
|
|
@@ -64,6 +66,166 @@ const indexRpcLogger = documentIndexLogger.newScope("rpc");
|
|
|
64
66
|
const indexCacheLogger = documentIndexLogger.newScope("cache");
|
|
65
67
|
const indexPrefetchLogger = documentIndexLogger.newScope("prefetch");
|
|
66
68
|
const indexIteratorLogger = documentIndexLogger.newScope("iterate");
|
|
69
|
+
const isPromiseLike = (value) => !!value && typeof value.then === "function";
|
|
70
|
+
const schemaVariant = (schema) => {
|
|
71
|
+
const variant = schema?.variant;
|
|
72
|
+
if (variant == null) {
|
|
73
|
+
return {};
|
|
74
|
+
}
|
|
75
|
+
if (typeof variant === "number") {
|
|
76
|
+
return { type: "u8", value: String(variant) };
|
|
77
|
+
}
|
|
78
|
+
if (typeof variant === "string") {
|
|
79
|
+
return { type: "string", value: variant };
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
};
|
|
83
|
+
const schemaTypeName = (type) => {
|
|
84
|
+
if (typeof type === "string") {
|
|
85
|
+
switch (type) {
|
|
86
|
+
case "string":
|
|
87
|
+
case "u8":
|
|
88
|
+
case "u32":
|
|
89
|
+
case "u64":
|
|
90
|
+
case "bool":
|
|
91
|
+
return type;
|
|
92
|
+
default:
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (type === Uint8Array) {
|
|
97
|
+
return "bytes";
|
|
98
|
+
}
|
|
99
|
+
if (type === PublicSignKey) {
|
|
100
|
+
return "publicsignkey";
|
|
101
|
+
}
|
|
102
|
+
if (type instanceof FixedArrayKind && type.elementType === "u8") {
|
|
103
|
+
return `fixedbytes:${type.length}`;
|
|
104
|
+
}
|
|
105
|
+
const kind = type;
|
|
106
|
+
if (kind.constructor?.name === "OptionKind") {
|
|
107
|
+
const element = schemaTypeName(kind.elementType);
|
|
108
|
+
return element ? `option:${element}` : undefined;
|
|
109
|
+
}
|
|
110
|
+
if (kind.constructor?.name === "VecKind") {
|
|
111
|
+
const element = schemaTypeName(kind.elementType);
|
|
112
|
+
return kind.sizeEncoding === "u32" && element
|
|
113
|
+
? `vec:${element}`
|
|
114
|
+
: undefined;
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
};
|
|
118
|
+
const schemaFieldPlan = (schema) => {
|
|
119
|
+
if (!schema?.fields) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const names = [];
|
|
123
|
+
const types = [];
|
|
124
|
+
for (const field of schema.fields) {
|
|
125
|
+
const type = schemaTypeName(field.type);
|
|
126
|
+
if (!type) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
names.push(field.key);
|
|
130
|
+
types.push(type);
|
|
131
|
+
}
|
|
132
|
+
return { names, types };
|
|
133
|
+
};
|
|
134
|
+
const asSingleFieldPath = (path) => typeof path === "string" ? path : path.length === 1 ? path[0] : undefined;
|
|
135
|
+
const createSimpleProjectionPlan = (documentSchema, indexedSchema, descriptor) => {
|
|
136
|
+
if (!descriptor || descriptor.kind === "identity") {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const documentVariant = schemaVariant(documentSchema);
|
|
140
|
+
const outputVariant = schemaVariant(indexedSchema);
|
|
141
|
+
const documentFields = schemaFieldPlan(documentSchema);
|
|
142
|
+
const outputFields = schemaFieldPlan(indexedSchema);
|
|
143
|
+
if (!documentVariant || !outputVariant || !documentFields || !outputFields) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const sources = new Map();
|
|
147
|
+
if (descriptor.kind === "pick") {
|
|
148
|
+
for (const field of descriptor.fields) {
|
|
149
|
+
const name = asSingleFieldPath(field);
|
|
150
|
+
if (!name) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
sources.set(name, { kind: "field", value: name });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
for (const field of descriptor.fields) {
|
|
158
|
+
const target = asSingleFieldPath(field.target);
|
|
159
|
+
if (!target) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
switch (field.source.kind) {
|
|
163
|
+
case "field": {
|
|
164
|
+
const source = asSingleFieldPath(field.source.path);
|
|
165
|
+
if (!source) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
sources.set(target, { kind: "field", value: source });
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case "context":
|
|
172
|
+
sources.set(target, {
|
|
173
|
+
kind: "context",
|
|
174
|
+
value: field.source.field,
|
|
175
|
+
});
|
|
176
|
+
break;
|
|
177
|
+
case "entryFirstSignerPublicKey":
|
|
178
|
+
sources.set(target, {
|
|
179
|
+
kind: "entryFirstSignerPublicKey",
|
|
180
|
+
value: "",
|
|
181
|
+
});
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const sourceKinds = [];
|
|
187
|
+
const sourceValues = [];
|
|
188
|
+
for (const field of outputFields.names) {
|
|
189
|
+
const source = sources.get(field);
|
|
190
|
+
if (!source) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
sourceKinds.push(source.kind);
|
|
194
|
+
sourceValues.push(source.value);
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
documentVariantType: documentVariant.type,
|
|
198
|
+
documentVariantValue: documentVariant.value,
|
|
199
|
+
documentFieldNames: documentFields.names,
|
|
200
|
+
documentFieldTypes: documentFields.types,
|
|
201
|
+
outputVariantType: outputVariant.type,
|
|
202
|
+
outputVariantValue: outputVariant.value,
|
|
203
|
+
outputFieldTypes: outputFields.types,
|
|
204
|
+
sourceKinds,
|
|
205
|
+
sourceValues,
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
const createSimpleFieldExtractionPlan = (documentSchema, path) => {
|
|
209
|
+
const fieldName = asSingleFieldPath(path);
|
|
210
|
+
if (!fieldName) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const documentVariant = schemaVariant(documentSchema);
|
|
214
|
+
const documentFields = schemaFieldPlan(documentSchema);
|
|
215
|
+
if (!documentVariant || !documentFields) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (!documentFields.names.includes(fieldName)) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
documentVariantType: documentVariant.type,
|
|
223
|
+
documentVariantValue: documentVariant.value,
|
|
224
|
+
documentFieldNames: documentFields.names,
|
|
225
|
+
documentFieldTypes: documentFields.types,
|
|
226
|
+
fieldName,
|
|
227
|
+
};
|
|
228
|
+
};
|
|
67
229
|
const getRemoteQueryPriority = (remote) => typeof remote === "object" && remote.priority != null
|
|
68
230
|
? remote.priority
|
|
69
231
|
: FOREGROUND_READ_MESSAGE_PRIORITY;
|
|
@@ -228,6 +390,42 @@ export const INDEX_CONTEXT_SHAPE = {
|
|
|
228
390
|
const isTransformerWithFunction = (options) => {
|
|
229
391
|
return options.transform != null;
|
|
230
392
|
};
|
|
393
|
+
const stripEncodedValue = (options) => options?.encodedValue || options?.encodedValueParts || options?.transformFacts
|
|
394
|
+
? { replace: options.replace }
|
|
395
|
+
: options;
|
|
396
|
+
const writeU32Le = (target, offset, value) => {
|
|
397
|
+
target[offset] = value & 0xff;
|
|
398
|
+
target[offset + 1] = (value >>> 8) & 0xff;
|
|
399
|
+
target[offset + 2] = (value >>> 16) & 0xff;
|
|
400
|
+
target[offset + 3] = (value >>> 24) & 0xff;
|
|
401
|
+
return offset + 4;
|
|
402
|
+
};
|
|
403
|
+
const writeU64Le = (target, offset, value) => {
|
|
404
|
+
let remaining = value;
|
|
405
|
+
for (let i = 0; i < 8; i++) {
|
|
406
|
+
target[offset + i] = Number(remaining & 0xffn);
|
|
407
|
+
remaining >>= 8n;
|
|
408
|
+
}
|
|
409
|
+
return offset + 8;
|
|
410
|
+
};
|
|
411
|
+
export const encodeContextSuffix = (context) => {
|
|
412
|
+
const head = fromString(context.head);
|
|
413
|
+
const gid = fromString(context.gid);
|
|
414
|
+
const encoded = new Uint8Array(1 + 8 + 8 + 4 + head.byteLength + 4 + gid.byteLength + 4);
|
|
415
|
+
let offset = 0;
|
|
416
|
+
// Context is @variant(0); keep this byte-for-byte aligned with Borsh.
|
|
417
|
+
encoded[offset++] = 0;
|
|
418
|
+
offset = writeU64Le(encoded, offset, context.created);
|
|
419
|
+
offset = writeU64Le(encoded, offset, context.modified);
|
|
420
|
+
offset = writeU32Le(encoded, offset, head.byteLength);
|
|
421
|
+
encoded.set(head, offset);
|
|
422
|
+
offset += head.byteLength;
|
|
423
|
+
offset = writeU32Le(encoded, offset, gid.byteLength);
|
|
424
|
+
encoded.set(gid, offset);
|
|
425
|
+
offset += gid.byteLength;
|
|
426
|
+
writeU32Le(encoded, offset, context.size);
|
|
427
|
+
return encoded;
|
|
428
|
+
};
|
|
231
429
|
export const coerceWithContext = (value, context) => {
|
|
232
430
|
let valueWithContext = value;
|
|
233
431
|
valueWithContext.__context = context;
|
|
@@ -238,6 +436,32 @@ export const coerceWithIndexed = (value, indexed) => {
|
|
|
238
436
|
valueWithContext.__indexed = indexed;
|
|
239
437
|
return valueWithContext;
|
|
240
438
|
};
|
|
439
|
+
export const coerceWithLazyIndexed = (value, getIndexable) => {
|
|
440
|
+
let cached;
|
|
441
|
+
let hasCached = false;
|
|
442
|
+
Object.defineProperty(value, "__indexed", {
|
|
443
|
+
configurable: true,
|
|
444
|
+
enumerable: true,
|
|
445
|
+
get() {
|
|
446
|
+
if (!hasCached) {
|
|
447
|
+
cached = getIndexable();
|
|
448
|
+
hasCached = true;
|
|
449
|
+
Object.defineProperty(value, "__indexed", {
|
|
450
|
+
configurable: true,
|
|
451
|
+
enumerable: true,
|
|
452
|
+
writable: true,
|
|
453
|
+
value: cached,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
return cached;
|
|
457
|
+
},
|
|
458
|
+
set(indexed) {
|
|
459
|
+
cached = indexed;
|
|
460
|
+
hasCached = true;
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
return value;
|
|
464
|
+
};
|
|
241
465
|
let DocumentIndex = (() => {
|
|
242
466
|
let _classDecorators = [variant("documents_index")];
|
|
243
467
|
let _classDescriptor;
|
|
@@ -263,6 +487,10 @@ let DocumentIndex = (() => {
|
|
|
263
487
|
documentType = __runInitializers(this, __query_extraInitializers);
|
|
264
488
|
// transform options
|
|
265
489
|
transformer;
|
|
490
|
+
transformerIsIdentity = false;
|
|
491
|
+
nativeTransformDescriptor;
|
|
492
|
+
nativeTransformProjectionPlan;
|
|
493
|
+
nativeBackboneDocumentProjection;
|
|
266
494
|
// The indexed document wrapped in a context
|
|
267
495
|
wrappedIndexedType;
|
|
268
496
|
indexedType;
|
|
@@ -292,9 +520,19 @@ let DocumentIndex = (() => {
|
|
|
292
520
|
_joinListener;
|
|
293
521
|
_resultQueue;
|
|
294
522
|
iteratorKeepAliveTimers;
|
|
523
|
+
deleteResolvedCacheForKey(key) {
|
|
524
|
+
if (this.isProgramValued) {
|
|
525
|
+
this._resolverProgramCache.delete(key.primitive);
|
|
526
|
+
indexCacheLogger("cache:del:program", { id: key.primitive });
|
|
527
|
+
}
|
|
528
|
+
else if (this._resolverCache?.del(key.primitive)) {
|
|
529
|
+
indexCacheLogger("cache:del:value", { id: key.primitive });
|
|
530
|
+
}
|
|
531
|
+
}
|
|
295
532
|
constructor(properties) {
|
|
296
533
|
super();
|
|
297
534
|
this._query = properties?.query || new RPC();
|
|
535
|
+
this._resultQueue = new Map();
|
|
298
536
|
this.iteratorKeepAliveTimers = new Map();
|
|
299
537
|
}
|
|
300
538
|
get valueEncoding() {
|
|
@@ -407,7 +645,11 @@ let DocumentIndex = (() => {
|
|
|
407
645
|
}
|
|
408
646
|
return results;
|
|
409
647
|
}
|
|
410
|
-
|
|
648
|
+
// Bound in open(). Deserialized instances skip constructor/field initializers
|
|
649
|
+
// (borsh creates objects via Object.create), so this must not rely on a field
|
|
650
|
+
// initializer to exist.
|
|
651
|
+
handleDocumentChange;
|
|
652
|
+
async onDocumentChange(event) {
|
|
411
653
|
const added = event.detail.added;
|
|
412
654
|
if (!added.length) {
|
|
413
655
|
return;
|
|
@@ -474,7 +716,7 @@ let DocumentIndex = (() => {
|
|
|
474
716
|
queue.pushInFlight = false;
|
|
475
717
|
}
|
|
476
718
|
}
|
|
477
|
-
}
|
|
719
|
+
}
|
|
478
720
|
get nestedProperties() {
|
|
479
721
|
return {
|
|
480
722
|
match: (obj) => obj instanceof this.dbType,
|
|
@@ -567,9 +809,19 @@ let DocumentIndex = (() => {
|
|
|
567
809
|
return replicateFn(rq, rs);
|
|
568
810
|
};
|
|
569
811
|
const transformOptions = properties.transform;
|
|
812
|
+
const hasTransformFunction = transformOptions != null && isTransformerWithFunction(transformOptions);
|
|
813
|
+
this.nativeTransformDescriptor = hasTransformFunction
|
|
814
|
+
? getDocumentTransformDescriptor(transformOptions.transform)
|
|
815
|
+
: undefined;
|
|
816
|
+
this.nativeTransformProjectionPlan = createSimpleProjectionPlan(getSchema(this.documentType), indexedSchema, this.nativeTransformDescriptor);
|
|
817
|
+
this.transformerIsIdentity =
|
|
818
|
+
transformOptions == null ||
|
|
819
|
+
(!hasTransformFunction && transformOptions.type == null) ||
|
|
820
|
+
(this.nativeTransformDescriptor?.kind === "identity" &&
|
|
821
|
+
this.indexedTypeIsDocumentType);
|
|
570
822
|
this.transformer = transformOptions
|
|
571
|
-
?
|
|
572
|
-
? (obj, context) => transformOptions.transform(obj, context)
|
|
823
|
+
? hasTransformFunction
|
|
824
|
+
? (obj, context, facts) => transformOptions.transform(obj, context, facts)
|
|
573
825
|
: transformOptions.type
|
|
574
826
|
? (obj, context) => new transformOptions.type(obj, context)
|
|
575
827
|
: (obj) => obj
|
|
@@ -659,9 +911,213 @@ let DocumentIndex = (() => {
|
|
|
659
911
|
responseType: types.AbstractSearchResult,
|
|
660
912
|
queryType: types.AbstractSearchRequest,
|
|
661
913
|
});
|
|
662
|
-
|
|
663
|
-
|
|
914
|
+
this.handleDocumentChange ??= (event) => this.onDocumentChange(event);
|
|
915
|
+
this.documentEvents.addEventListener("change", this.handleDocumentChange);
|
|
916
|
+
}
|
|
917
|
+
attachNativeBackboneDocumentIndex(backbone, options) {
|
|
918
|
+
this.nativeBackboneDocumentProjection = undefined;
|
|
919
|
+
if (!backbone ||
|
|
920
|
+
this.isProgramValued ||
|
|
921
|
+
!this.canUseNativeBackboneDocumentIndex()) {
|
|
922
|
+
return false;
|
|
664
923
|
}
|
|
924
|
+
const attach = this.index
|
|
925
|
+
.attachNativeBackboneDocumentIndex;
|
|
926
|
+
const attached = typeof attach === "function" &&
|
|
927
|
+
attach.call(this.index, backbone, options) === true;
|
|
928
|
+
if (attached) {
|
|
929
|
+
const projection = backbone;
|
|
930
|
+
if (typeof projection.projectDocumentIndexSimple === "function") {
|
|
931
|
+
this.nativeBackboneDocumentProjection = projection;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return attached;
|
|
935
|
+
}
|
|
936
|
+
canUseNativeBackboneDocumentIndex() {
|
|
937
|
+
return ((this.transformerIsIdentity && this.indexedTypeIsDocumentType) ||
|
|
938
|
+
this.nativeTransformDescriptor != null);
|
|
939
|
+
}
|
|
940
|
+
getNativeDocumentFieldExtractionPlan(path) {
|
|
941
|
+
return createSimpleFieldExtractionPlan(getSchema(this.documentType), path);
|
|
942
|
+
}
|
|
943
|
+
canPrepareNativeBackboneDocumentIndexCommit() {
|
|
944
|
+
return ((this.transformerIsIdentity && this.indexedTypeIsDocumentType) ||
|
|
945
|
+
canPrepareDocumentTransformBeforeAppend(this.nativeTransformDescriptor));
|
|
946
|
+
}
|
|
947
|
+
canPrepareNativeBackboneDocumentIndexCommitWithAppendFacts() {
|
|
948
|
+
return (this.canPrepareNativeBackboneDocumentIndexCommit() ||
|
|
949
|
+
!!this.nativeTransformProjectionPlan ||
|
|
950
|
+
canPrepareDocumentTransformWithAppendFacts(this.nativeTransformDescriptor));
|
|
951
|
+
}
|
|
952
|
+
canUseNativeBackboneContextualBatch() {
|
|
953
|
+
return (!this.isProgramValued &&
|
|
954
|
+
typeof this.index.putWithContextBatch ===
|
|
955
|
+
"function" &&
|
|
956
|
+
((this.transformerIsIdentity && this.indexedTypeIsDocumentType) ||
|
|
957
|
+
this.canPrepareNativeBackboneDocumentIndexCommitWithAppendFacts()));
|
|
958
|
+
}
|
|
959
|
+
prepareNativeBackboneDocumentIndexCommit(value, encodedDocument, transformFacts) {
|
|
960
|
+
if (this.transformerIsIdentity && this.indexedTypeIsDocumentType) {
|
|
961
|
+
return {
|
|
962
|
+
valuePrefixBytes: encodedDocument,
|
|
963
|
+
usePlainPutPayload: true,
|
|
964
|
+
indexable: value,
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
if (this.nativeTransformProjectionPlan) {
|
|
968
|
+
let projectionContext;
|
|
969
|
+
let cached;
|
|
970
|
+
let hasCached = false;
|
|
971
|
+
return {
|
|
972
|
+
projection: {
|
|
973
|
+
encodedDocument,
|
|
974
|
+
plan: this.nativeTransformProjectionPlan,
|
|
975
|
+
signer: transformFacts?.entryPublicKeys?.[0]?.bytes,
|
|
976
|
+
},
|
|
977
|
+
getIndexable: () => {
|
|
978
|
+
if (!hasCached) {
|
|
979
|
+
const transformed = this.transformer(value, projectionContext, transformFacts);
|
|
980
|
+
if (isPromiseLike(transformed)) {
|
|
981
|
+
throw new Error("Native descriptor transform unexpectedly returned a promise");
|
|
982
|
+
}
|
|
983
|
+
cached = transformed;
|
|
984
|
+
hasCached = true;
|
|
985
|
+
}
|
|
986
|
+
return cached;
|
|
987
|
+
},
|
|
988
|
+
setContext: (context) => {
|
|
989
|
+
projectionContext = context;
|
|
990
|
+
hasCached = false;
|
|
991
|
+
cached = undefined;
|
|
992
|
+
},
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
if (!canPrepareDocumentTransformBeforeAppend(this.nativeTransformDescriptor)) {
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
const transformed = this.transformer(value, undefined, transformFacts);
|
|
999
|
+
const finish = (indexable) => ({
|
|
1000
|
+
valuePrefixBytes: serialize(this.asIndexedTypeValue(indexable)),
|
|
1001
|
+
indexable,
|
|
1002
|
+
});
|
|
1003
|
+
return isPromiseLike(transformed)
|
|
1004
|
+
? transformed.then(finish)
|
|
1005
|
+
: finish(transformed);
|
|
1006
|
+
}
|
|
1007
|
+
prepareNativeBackboneDocumentIndexCommitWithAppendFacts(value, encodedDocument, context, transformFacts) {
|
|
1008
|
+
if (this.transformerIsIdentity && this.indexedTypeIsDocumentType) {
|
|
1009
|
+
return {
|
|
1010
|
+
valuePrefixBytes: encodedDocument,
|
|
1011
|
+
usePlainPutPayload: true,
|
|
1012
|
+
indexable: value,
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
if (this.nativeTransformProjectionPlan) {
|
|
1016
|
+
let projectionContext = {
|
|
1017
|
+
created: context.created,
|
|
1018
|
+
modified: context.modified,
|
|
1019
|
+
head: context.head,
|
|
1020
|
+
gid: context.gid,
|
|
1021
|
+
size: context.size,
|
|
1022
|
+
signer: transformFacts?.entryPublicKeys?.[0]?.bytes,
|
|
1023
|
+
};
|
|
1024
|
+
let cached;
|
|
1025
|
+
let hasCached = false;
|
|
1026
|
+
return {
|
|
1027
|
+
projection: {
|
|
1028
|
+
encodedDocument,
|
|
1029
|
+
plan: this.nativeTransformProjectionPlan,
|
|
1030
|
+
signer: projectionContext.signer,
|
|
1031
|
+
},
|
|
1032
|
+
getIndexable: () => {
|
|
1033
|
+
if (!hasCached) {
|
|
1034
|
+
const transformed = this.transformer(value, projectionContext, transformFacts);
|
|
1035
|
+
if (isPromiseLike(transformed)) {
|
|
1036
|
+
throw new Error("Native descriptor transform unexpectedly returned a promise");
|
|
1037
|
+
}
|
|
1038
|
+
cached = transformed;
|
|
1039
|
+
hasCached = true;
|
|
1040
|
+
}
|
|
1041
|
+
return cached;
|
|
1042
|
+
},
|
|
1043
|
+
setContext: (nextContext) => {
|
|
1044
|
+
projectionContext = {
|
|
1045
|
+
created: nextContext.created,
|
|
1046
|
+
modified: nextContext.modified,
|
|
1047
|
+
head: nextContext.head,
|
|
1048
|
+
gid: nextContext.gid,
|
|
1049
|
+
size: nextContext.size,
|
|
1050
|
+
signer: transformFacts?.entryPublicKeys?.[0]?.bytes,
|
|
1051
|
+
};
|
|
1052
|
+
hasCached = false;
|
|
1053
|
+
cached = undefined;
|
|
1054
|
+
},
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
if (!canPrepareDocumentTransformWithAppendFacts(this.nativeTransformDescriptor) &&
|
|
1058
|
+
!canPrepareDocumentTransformBeforeAppend(this.nativeTransformDescriptor)) {
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
const transformed = this.transformer(value, context, transformFacts);
|
|
1062
|
+
if (isPromiseLike(transformed)) {
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
const indexable = transformed;
|
|
1066
|
+
return {
|
|
1067
|
+
valuePrefixBytes: serialize(this.asIndexedTypeValue(indexable)),
|
|
1068
|
+
indexable,
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
prepareNativeBackboneDocumentIndexStoredCommitWithAppendFacts(encodedDocument, context, transformFacts) {
|
|
1072
|
+
if (this.transformerIsIdentity && this.indexedTypeIsDocumentType) {
|
|
1073
|
+
return {
|
|
1074
|
+
valuePrefixBytes: encodedDocument,
|
|
1075
|
+
usePlainPutPayload: true,
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
if (this.nativeTransformProjectionPlan) {
|
|
1079
|
+
return {
|
|
1080
|
+
projection: {
|
|
1081
|
+
encodedDocument,
|
|
1082
|
+
plan: this.nativeTransformProjectionPlan,
|
|
1083
|
+
signer: transformFacts?.entryPublicKeys?.[0]?.bytes,
|
|
1084
|
+
},
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
if (!canPrepareDocumentTransformWithAppendFacts(this.nativeTransformDescriptor) &&
|
|
1088
|
+
!canPrepareDocumentTransformBeforeAppend(this.nativeTransformDescriptor)) {
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
nativeBackboneDocumentIndexValuePrefixBytes(nativeDocumentIndex, context) {
|
|
1094
|
+
return (nativeDocumentIndex.valuePrefixBytes ??
|
|
1095
|
+
(nativeDocumentIndex.projection
|
|
1096
|
+
? (this.nativeBackboneDocumentProjection?.projectDocumentIndexSimple?.(nativeDocumentIndex.projection.encodedDocument, nativeDocumentIndex.projection.plan, {
|
|
1097
|
+
created: context.created,
|
|
1098
|
+
modified: context.modified,
|
|
1099
|
+
head: context.head,
|
|
1100
|
+
gid: context.gid,
|
|
1101
|
+
size: context.size,
|
|
1102
|
+
signer: nativeDocumentIndex.projection.signer,
|
|
1103
|
+
}) ??
|
|
1104
|
+
tryProjectDocumentIndexSimple(nativeDocumentIndex.projection.encodedDocument, nativeDocumentIndex.projection.plan, {
|
|
1105
|
+
created: context.created,
|
|
1106
|
+
modified: context.modified,
|
|
1107
|
+
head: context.head,
|
|
1108
|
+
gid: context.gid,
|
|
1109
|
+
size: context.size,
|
|
1110
|
+
signer: nativeDocumentIndex.projection.signer,
|
|
1111
|
+
}))
|
|
1112
|
+
: undefined));
|
|
1113
|
+
}
|
|
1114
|
+
asIndexedTypeValue(value) {
|
|
1115
|
+
if (value &&
|
|
1116
|
+
Object.getPrototypeOf(value) ===
|
|
1117
|
+
this.indexedType.prototype) {
|
|
1118
|
+
return value;
|
|
1119
|
+
}
|
|
1120
|
+
return Object.assign(Object.create(this.indexedType.prototype), value);
|
|
665
1121
|
}
|
|
666
1122
|
get prefetch() {
|
|
667
1123
|
return this._prefetch;
|
|
@@ -818,11 +1274,11 @@ let DocumentIndex = (() => {
|
|
|
818
1274
|
if (this._joinListener) {
|
|
819
1275
|
this._query.events.removeEventListener("join", this._joinListener);
|
|
820
1276
|
}
|
|
821
|
-
if (this.handleDocumentChange) {
|
|
1277
|
+
if (this.handleDocumentChange && this.documentEvents) {
|
|
822
1278
|
this.documentEvents.removeEventListener("change", this.handleDocumentChange);
|
|
823
1279
|
}
|
|
824
1280
|
this.clearAllResultQueues();
|
|
825
|
-
await this._resumableIterators
|
|
1281
|
+
await this._resumableIterators?.clearAll();
|
|
826
1282
|
if (this.iteratorKeepAliveTimers) {
|
|
827
1283
|
for (const timer of this.iteratorKeepAliveTimers.values()) {
|
|
828
1284
|
clearTimeout(timer);
|
|
@@ -846,9 +1302,9 @@ let DocumentIndex = (() => {
|
|
|
846
1302
|
async drop(from) {
|
|
847
1303
|
const dropped = await super.drop(from);
|
|
848
1304
|
if (dropped) {
|
|
849
|
-
this.documentEvents
|
|
1305
|
+
this.documentEvents?.removeEventListener("change", this.handleDocumentChange);
|
|
850
1306
|
this.clearAllResultQueues();
|
|
851
|
-
await this._resumableIterators
|
|
1307
|
+
await this._resumableIterators?.clearAll();
|
|
852
1308
|
if (this.iteratorKeepAliveTimers) {
|
|
853
1309
|
for (const timer of this.iteratorKeepAliveTimers.values()) {
|
|
854
1310
|
clearTimeout(timer);
|
|
@@ -977,6 +1433,426 @@ let DocumentIndex = (() => {
|
|
|
977
1433
|
await iterator.close();
|
|
978
1434
|
return one[0];
|
|
979
1435
|
}
|
|
1436
|
+
async getIdentityIndexedByHead(head) {
|
|
1437
|
+
if (!this.canGetIdentityIndexedByHead()) {
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
return this.index.getByContextHead?.(head);
|
|
1441
|
+
}
|
|
1442
|
+
async getIdentityIndexedKeyByHead(head) {
|
|
1443
|
+
const key = this.getIndexedKeyByHead(head);
|
|
1444
|
+
if (key) {
|
|
1445
|
+
return key;
|
|
1446
|
+
}
|
|
1447
|
+
const indexed = await this.getIdentityIndexedByHead(head);
|
|
1448
|
+
return indexed?.id;
|
|
1449
|
+
}
|
|
1450
|
+
getIndexedKeyByHead(head) {
|
|
1451
|
+
const getIdByHead = this.index.getIdByContextHead;
|
|
1452
|
+
return typeof getIdByHead === "function"
|
|
1453
|
+
? getIdByHead.call(this.index, head)
|
|
1454
|
+
: undefined;
|
|
1455
|
+
}
|
|
1456
|
+
getIndexedKeysByHeads(heads) {
|
|
1457
|
+
const getIdByHead = this.index.getIdByContextHead;
|
|
1458
|
+
if (typeof getIdByHead !== "function") {
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
return heads.map((head) => getIdByHead.call(this.index, head));
|
|
1462
|
+
}
|
|
1463
|
+
tryGetIdentityIndexedKeyByHead(head) {
|
|
1464
|
+
const getIdByHead = this.index.getIdByContextHead;
|
|
1465
|
+
if (typeof getIdByHead !== "function") {
|
|
1466
|
+
return { supported: false };
|
|
1467
|
+
}
|
|
1468
|
+
return {
|
|
1469
|
+
supported: true,
|
|
1470
|
+
key: getIdByHead.call(this.index, head),
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
async getIdentityIndexedByHeads(heads) {
|
|
1474
|
+
if (!this.canGetIdentityIndexedByHead()) {
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
const batch = this.index.getByContextHeadBatch;
|
|
1478
|
+
if (batch) {
|
|
1479
|
+
return batch.call(this.index, heads);
|
|
1480
|
+
}
|
|
1481
|
+
return Promise.all(heads.map((head) => this.getIdentityIndexedByHead(head)));
|
|
1482
|
+
}
|
|
1483
|
+
canGetIdentityIndexedByHead() {
|
|
1484
|
+
return (this.transformerIsIdentity &&
|
|
1485
|
+
this.indexedTypeIsDocumentType &&
|
|
1486
|
+
!this.isProgramValued &&
|
|
1487
|
+
typeof this.index.getByContextHead === "function");
|
|
1488
|
+
}
|
|
1489
|
+
canGetIndexedKeyByHead() {
|
|
1490
|
+
return (!this.isProgramValued &&
|
|
1491
|
+
typeof this.index.getIdByContextHead ===
|
|
1492
|
+
"function");
|
|
1493
|
+
}
|
|
1494
|
+
canReadOriginalFieldPathsFromIndexedValue(paths) {
|
|
1495
|
+
return (!this.isProgramValued &&
|
|
1496
|
+
paths.every((path) => this.transformerIsIdentity && this.indexedTypeIsDocumentType
|
|
1497
|
+
? true
|
|
1498
|
+
: documentTransformPreservesFieldPath(this.nativeTransformDescriptor, path)));
|
|
1499
|
+
}
|
|
1500
|
+
canReadNativeIndexedFieldValues(paths) {
|
|
1501
|
+
return (this.canReadOriginalFieldPathsFromIndexedValue(paths) &&
|
|
1502
|
+
typeof this.index.getNativeIndexedFieldValue === "function");
|
|
1503
|
+
}
|
|
1504
|
+
getNativeIndexedFieldValue(id, path) {
|
|
1505
|
+
const read = this.index.getNativeIndexedFieldValue;
|
|
1506
|
+
if (typeof read !== "function") {
|
|
1507
|
+
return undefined;
|
|
1508
|
+
}
|
|
1509
|
+
return read.call(this.index, id, typeof path === "string" ? [path] : path);
|
|
1510
|
+
}
|
|
1511
|
+
_putIdentityWithContext(value, id, context, options) {
|
|
1512
|
+
const contextualPut = this.transformerIsIdentity
|
|
1513
|
+
? this.index.putWithContext
|
|
1514
|
+
: undefined;
|
|
1515
|
+
if (!contextualPut || this.isProgramValued) {
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
const indexable = value;
|
|
1519
|
+
const indexedValue = coerceWithIndexed(coerceWithContext(value, context), indexable);
|
|
1520
|
+
this.cacheResolvedValue(id.primitive, value);
|
|
1521
|
+
const handleError = (error) => {
|
|
1522
|
+
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
1523
|
+
return indexedValue;
|
|
1524
|
+
}
|
|
1525
|
+
throw error;
|
|
1526
|
+
};
|
|
1527
|
+
try {
|
|
1528
|
+
const putResult = contextualPut.call(this.index, indexable, id, context, this.withContextualEncodedValue(options, context));
|
|
1529
|
+
return isPromiseLike(putResult)
|
|
1530
|
+
? putResult.then(() => indexedValue, handleError)
|
|
1531
|
+
: indexedValue;
|
|
1532
|
+
}
|
|
1533
|
+
catch (error) {
|
|
1534
|
+
return handleError(error);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
_putStoredIdentityWithContext(value, id, context, encodedValueParts, options) {
|
|
1538
|
+
const contextualStoredPut = this.transformerIsIdentity
|
|
1539
|
+
? this.index.putStoredContextualEncodedValue
|
|
1540
|
+
: undefined;
|
|
1541
|
+
if (!contextualStoredPut ||
|
|
1542
|
+
this.isProgramValued ||
|
|
1543
|
+
!this.indexedTypeIsDocumentType) {
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
const indexable = value;
|
|
1547
|
+
const indexedValue = coerceWithIndexed(coerceWithContext(value, context), indexable);
|
|
1548
|
+
this.cacheResolvedValue(id.primitive, value);
|
|
1549
|
+
const handleError = (error) => {
|
|
1550
|
+
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
1551
|
+
return indexedValue;
|
|
1552
|
+
}
|
|
1553
|
+
throw error;
|
|
1554
|
+
};
|
|
1555
|
+
try {
|
|
1556
|
+
const putResult = contextualStoredPut.call(this.index, id, encodedValueParts, options);
|
|
1557
|
+
if (putResult === false) {
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1560
|
+
return isPromiseLike(putResult)
|
|
1561
|
+
? putResult.then(() => indexedValue, handleError)
|
|
1562
|
+
: indexedValue;
|
|
1563
|
+
}
|
|
1564
|
+
catch (error) {
|
|
1565
|
+
return handleError(error);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
_putPreparedNativeBackboneDocumentIndexWithContext(value, id, context, nativeDocumentIndex, options) {
|
|
1569
|
+
const contextualStoredPut = this.index
|
|
1570
|
+
.putStoredContextualEncodedValue;
|
|
1571
|
+
if (!contextualStoredPut || this.isProgramValued) {
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
nativeDocumentIndex.setContext?.(context);
|
|
1575
|
+
const valueWithContext = coerceWithContext(value, context);
|
|
1576
|
+
const indexedValue = nativeDocumentIndex.indexable
|
|
1577
|
+
? coerceWithIndexed(valueWithContext, nativeDocumentIndex.indexable)
|
|
1578
|
+
: nativeDocumentIndex.getIndexable
|
|
1579
|
+
? coerceWithLazyIndexed(valueWithContext, nativeDocumentIndex.getIndexable)
|
|
1580
|
+
: undefined;
|
|
1581
|
+
if (!indexedValue) {
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
this.cacheResolvedValue(id.primitive, value);
|
|
1585
|
+
const valuePrefixBytes = this.nativeBackboneDocumentIndexValuePrefixBytes(nativeDocumentIndex, context);
|
|
1586
|
+
if (!valuePrefixBytes) {
|
|
1587
|
+
return;
|
|
1588
|
+
}
|
|
1589
|
+
const encodedValueParts = {
|
|
1590
|
+
prefix: valuePrefixBytes,
|
|
1591
|
+
suffix: encodeContextSuffix(context),
|
|
1592
|
+
};
|
|
1593
|
+
const handleError = (error) => {
|
|
1594
|
+
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
1595
|
+
return indexedValue;
|
|
1596
|
+
}
|
|
1597
|
+
throw error;
|
|
1598
|
+
};
|
|
1599
|
+
try {
|
|
1600
|
+
const putResult = contextualStoredPut.call(this.index, id, encodedValueParts, options);
|
|
1601
|
+
if (putResult === false) {
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1604
|
+
return isPromiseLike(putResult)
|
|
1605
|
+
? putResult.then(() => indexedValue, handleError)
|
|
1606
|
+
: indexedValue;
|
|
1607
|
+
}
|
|
1608
|
+
catch (error) {
|
|
1609
|
+
return handleError(error);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
_putPreparedNativeBackboneDocumentIndexStoredWithContext(id, context, nativeDocumentIndex, options) {
|
|
1613
|
+
const contextualStoredPut = this.index
|
|
1614
|
+
.putStoredContextualEncodedValue;
|
|
1615
|
+
if (!contextualStoredPut || this.isProgramValued) {
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
nativeDocumentIndex.setContext?.(context);
|
|
1619
|
+
const valuePrefixBytes = this.nativeBackboneDocumentIndexValuePrefixBytes(nativeDocumentIndex, context);
|
|
1620
|
+
if (!valuePrefixBytes) {
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
const encodedValueParts = {
|
|
1624
|
+
prefix: valuePrefixBytes,
|
|
1625
|
+
suffix: encodeContextSuffix(context),
|
|
1626
|
+
};
|
|
1627
|
+
const handleError = (error) => {
|
|
1628
|
+
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
1629
|
+
return true;
|
|
1630
|
+
}
|
|
1631
|
+
throw error;
|
|
1632
|
+
};
|
|
1633
|
+
try {
|
|
1634
|
+
const putResult = contextualStoredPut.call(this.index, id, encodedValueParts, options);
|
|
1635
|
+
if (putResult === false) {
|
|
1636
|
+
return false;
|
|
1637
|
+
}
|
|
1638
|
+
return isPromiseLike(putResult)
|
|
1639
|
+
? putResult.then(() => true, handleError)
|
|
1640
|
+
: true;
|
|
1641
|
+
}
|
|
1642
|
+
catch (error) {
|
|
1643
|
+
return handleError(error);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
_persistPreparedNativeBackboneDocumentIndexStoredWithContext(id, context, nativeDocumentIndex, encodedValueParts, options) {
|
|
1647
|
+
const persistStoredPut = this.index
|
|
1648
|
+
.persistStoredContextualEncodedValue;
|
|
1649
|
+
if (!persistStoredPut || this.isProgramValued) {
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
let storedParts;
|
|
1653
|
+
if (this.transformerIsIdentity &&
|
|
1654
|
+
this.indexedTypeIsDocumentType &&
|
|
1655
|
+
encodedValueParts) {
|
|
1656
|
+
storedParts = encodedValueParts;
|
|
1657
|
+
}
|
|
1658
|
+
else if (nativeDocumentIndex) {
|
|
1659
|
+
nativeDocumentIndex.setContext?.(context);
|
|
1660
|
+
const valuePrefixBytes = nativeDocumentIndex.valuePrefixBytes ??
|
|
1661
|
+
this.nativeBackboneDocumentIndexValuePrefixBytes(nativeDocumentIndex, context);
|
|
1662
|
+
if (!valuePrefixBytes) {
|
|
1663
|
+
return;
|
|
1664
|
+
}
|
|
1665
|
+
storedParts = {
|
|
1666
|
+
prefix: valuePrefixBytes,
|
|
1667
|
+
suffix: encodeContextSuffix(context),
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
else {
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
try {
|
|
1674
|
+
const persistResult = persistStoredPut.call(this.index, id, storedParts, options);
|
|
1675
|
+
if (persistResult === false) {
|
|
1676
|
+
return false;
|
|
1677
|
+
}
|
|
1678
|
+
return isPromiseLike(persistResult)
|
|
1679
|
+
? persistResult.then(() => true, (error) => {
|
|
1680
|
+
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
1681
|
+
return true;
|
|
1682
|
+
}
|
|
1683
|
+
throw error;
|
|
1684
|
+
})
|
|
1685
|
+
: true;
|
|
1686
|
+
}
|
|
1687
|
+
catch (error) {
|
|
1688
|
+
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
1689
|
+
return true;
|
|
1690
|
+
}
|
|
1691
|
+
throw error;
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
async _putManyPreparedNativeBackboneDocumentIndexWithContext(values) {
|
|
1695
|
+
if (values.length === 0) {
|
|
1696
|
+
return [];
|
|
1697
|
+
}
|
|
1698
|
+
const contextualBatchPut = this.index
|
|
1699
|
+
.putWithContextBatch;
|
|
1700
|
+
if (!contextualBatchPut || this.isProgramValued) {
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
const indexedValues = [];
|
|
1704
|
+
const batchValues = [];
|
|
1705
|
+
for (const item of values) {
|
|
1706
|
+
if (!item.nativeDocumentIndex) {
|
|
1707
|
+
return;
|
|
1708
|
+
}
|
|
1709
|
+
item.nativeDocumentIndex.setContext?.(item.context);
|
|
1710
|
+
const valueWithContext = coerceWithContext(item.value, item.context);
|
|
1711
|
+
const indexedValue = item.nativeDocumentIndex.indexable
|
|
1712
|
+
? coerceWithIndexed(valueWithContext, item.nativeDocumentIndex.indexable)
|
|
1713
|
+
: item.nativeDocumentIndex.getIndexable
|
|
1714
|
+
? coerceWithLazyIndexed(valueWithContext, item.nativeDocumentIndex.getIndexable)
|
|
1715
|
+
: undefined;
|
|
1716
|
+
if (!indexedValue) {
|
|
1717
|
+
return;
|
|
1718
|
+
}
|
|
1719
|
+
const valuePrefixBytes = this.nativeBackboneDocumentIndexValuePrefixBytes(item.nativeDocumentIndex, item.context);
|
|
1720
|
+
if (!valuePrefixBytes) {
|
|
1721
|
+
return;
|
|
1722
|
+
}
|
|
1723
|
+
this.cacheResolvedValue(item.id.primitive, item.value);
|
|
1724
|
+
indexedValues.push(indexedValue);
|
|
1725
|
+
batchValues.push({
|
|
1726
|
+
// Encoded native batches store from encodedValueParts; descriptor
|
|
1727
|
+
// projections keep the JS indexable lazy for event consumers.
|
|
1728
|
+
value: item.nativeDocumentIndex.indexable ?? undefined,
|
|
1729
|
+
id: item.id,
|
|
1730
|
+
context: item.context,
|
|
1731
|
+
options: {
|
|
1732
|
+
replace: item.options?.replace,
|
|
1733
|
+
encodedValueParts: {
|
|
1734
|
+
prefix: valuePrefixBytes,
|
|
1735
|
+
suffix: encodeContextSuffix(item.context),
|
|
1736
|
+
},
|
|
1737
|
+
},
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1740
|
+
const handleError = (error) => {
|
|
1741
|
+
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
1742
|
+
return indexedValues;
|
|
1743
|
+
}
|
|
1744
|
+
throw error;
|
|
1745
|
+
};
|
|
1746
|
+
try {
|
|
1747
|
+
const putResult = contextualBatchPut.call(this.index, batchValues);
|
|
1748
|
+
return isPromiseLike(putResult)
|
|
1749
|
+
? putResult.then(() => indexedValues, handleError)
|
|
1750
|
+
: indexedValues;
|
|
1751
|
+
}
|
|
1752
|
+
catch (error) {
|
|
1753
|
+
return handleError(error);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
async _putManyPreparedNativeBackboneDocumentIndexStored(values) {
|
|
1757
|
+
if (values.length === 0) {
|
|
1758
|
+
return true;
|
|
1759
|
+
}
|
|
1760
|
+
if (this.isProgramValued) {
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1763
|
+
const storedBatchPut = this.index
|
|
1764
|
+
.putStoredContextualEncodedValueBatch;
|
|
1765
|
+
if (!storedBatchPut) {
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
const batchValues = [];
|
|
1769
|
+
for (const item of values) {
|
|
1770
|
+
let encodedValueParts;
|
|
1771
|
+
if (this.transformerIsIdentity &&
|
|
1772
|
+
this.indexedTypeIsDocumentType &&
|
|
1773
|
+
item.encodedValueParts) {
|
|
1774
|
+
encodedValueParts = item.encodedValueParts;
|
|
1775
|
+
}
|
|
1776
|
+
else if (item.nativeDocumentIndex) {
|
|
1777
|
+
item.nativeDocumentIndex.setContext?.(item.context);
|
|
1778
|
+
const valuePrefixBytes = item.nativeDocumentIndex.valuePrefixBytes ??
|
|
1779
|
+
this.nativeBackboneDocumentIndexValuePrefixBytes(item.nativeDocumentIndex, item.context);
|
|
1780
|
+
if (!valuePrefixBytes) {
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
encodedValueParts = {
|
|
1784
|
+
prefix: valuePrefixBytes,
|
|
1785
|
+
suffix: encodeContextSuffix(item.context),
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
else {
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
this.cacheResolvedValue(item.id.primitive, item.value);
|
|
1792
|
+
batchValues.push({
|
|
1793
|
+
id: item.id,
|
|
1794
|
+
encodedValueParts,
|
|
1795
|
+
options: item.options,
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
const handleError = (error) => {
|
|
1799
|
+
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
1800
|
+
return true;
|
|
1801
|
+
}
|
|
1802
|
+
throw error;
|
|
1803
|
+
};
|
|
1804
|
+
try {
|
|
1805
|
+
return await storedBatchPut.call(this.index, batchValues);
|
|
1806
|
+
}
|
|
1807
|
+
catch (error) {
|
|
1808
|
+
return handleError(error);
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
async _putManyIdentityWithContext(values) {
|
|
1812
|
+
if (values.length === 0) {
|
|
1813
|
+
return [];
|
|
1814
|
+
}
|
|
1815
|
+
const contextualPut = this.transformerIsIdentity
|
|
1816
|
+
? this.index.putWithContext
|
|
1817
|
+
: undefined;
|
|
1818
|
+
const contextualBatchPut = this.transformerIsIdentity
|
|
1819
|
+
? this.index.putWithContextBatch
|
|
1820
|
+
: undefined;
|
|
1821
|
+
if ((!contextualBatchPut && !contextualPut) || this.isProgramValued) {
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
const indexedValues = values.map((item) => {
|
|
1825
|
+
const indexable = item.value;
|
|
1826
|
+
this.cacheResolvedValue(item.id.primitive, item.value);
|
|
1827
|
+
return {
|
|
1828
|
+
indexable,
|
|
1829
|
+
value: coerceWithIndexed(coerceWithContext(item.value, item.context), indexable),
|
|
1830
|
+
};
|
|
1831
|
+
});
|
|
1832
|
+
try {
|
|
1833
|
+
if (contextualBatchPut) {
|
|
1834
|
+
await contextualBatchPut.call(this.index, values.map((item, index) => ({
|
|
1835
|
+
value: indexedValues[index].indexable,
|
|
1836
|
+
id: item.id,
|
|
1837
|
+
context: item.context,
|
|
1838
|
+
options: this.withContextualEncodedValue(item.options, item.context),
|
|
1839
|
+
})));
|
|
1840
|
+
}
|
|
1841
|
+
else {
|
|
1842
|
+
for (let i = 0; i < values.length; i++) {
|
|
1843
|
+
const item = values[i];
|
|
1844
|
+
await contextualPut.call(this.index, indexedValues[i].indexable, item.id, item.context, this.withContextualEncodedValue(item.options, item.context));
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
catch (error) {
|
|
1849
|
+
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
1850
|
+
return indexedValues.map((item) => item.value);
|
|
1851
|
+
}
|
|
1852
|
+
throw error;
|
|
1853
|
+
}
|
|
1854
|
+
return indexedValues.map((item) => item.value);
|
|
1855
|
+
}
|
|
980
1856
|
async put(value, id, entry, existing) {
|
|
981
1857
|
const existingDefined = existing === undefined
|
|
982
1858
|
? await this.index.get(id, {
|
|
@@ -993,31 +1869,33 @@ let DocumentIndex = (() => {
|
|
|
993
1869
|
});
|
|
994
1870
|
return this.putWithContext(value, id, context, {
|
|
995
1871
|
replace: existingDefined != null,
|
|
1872
|
+
transformFacts: { entryPublicKeys: entry.publicKeys },
|
|
996
1873
|
});
|
|
997
1874
|
}
|
|
998
1875
|
async putWithContext(value, id, context, options) {
|
|
999
1876
|
const idString = id.primitive;
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
(value as Program).parents.includes(this._log) */) {
|
|
1005
|
-
// TODO make last condition more efficient if there are many docs
|
|
1006
|
-
this._resolverProgramCache.set(idString, value);
|
|
1007
|
-
indexCacheLogger("cache:set:program", { id: idString });
|
|
1008
|
-
}
|
|
1009
|
-
else {
|
|
1010
|
-
if (this._resolverCache) {
|
|
1011
|
-
this._resolverCache.add(idString, value);
|
|
1012
|
-
indexCacheLogger("cache:set:value", { id: idString });
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
const valueToIndex = await this.transformer(value, context);
|
|
1016
|
-
const wrappedValueToIndex = new this.wrappedIndexedType(valueToIndex, context);
|
|
1877
|
+
this.cacheResolvedValue(idString, value);
|
|
1878
|
+
const valueToIndex = this.transformerIsIdentity
|
|
1879
|
+
? value
|
|
1880
|
+
: await this.transformer(value, context, options?.transformFacts);
|
|
1017
1881
|
coerceWithIndexed(value, valueToIndex);
|
|
1018
1882
|
coerceWithContext(value, context);
|
|
1019
1883
|
try {
|
|
1020
|
-
|
|
1884
|
+
const contextualPut = this.transformerIsIdentity
|
|
1885
|
+
? this.index.putWithContext
|
|
1886
|
+
: undefined;
|
|
1887
|
+
if (contextualPut) {
|
|
1888
|
+
const encodedValueParts = this.encodeContextualIndexedValueParts(options?.encodedValue, context);
|
|
1889
|
+
await contextualPut.call(this.index, valueToIndex, id, context, encodedValueParts
|
|
1890
|
+
? { ...options, encodedValue: undefined, encodedValueParts }
|
|
1891
|
+
: options?.encodedValue
|
|
1892
|
+
? { ...options, encodedValue: undefined }
|
|
1893
|
+
: options);
|
|
1894
|
+
}
|
|
1895
|
+
else {
|
|
1896
|
+
const wrappedValueToIndex = new this.wrappedIndexedType(valueToIndex, context);
|
|
1897
|
+
await this.index.put(wrappedValueToIndex, id, stripEncodedValue(options));
|
|
1898
|
+
}
|
|
1021
1899
|
}
|
|
1022
1900
|
catch (error) {
|
|
1023
1901
|
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
@@ -1027,20 +1905,157 @@ let DocumentIndex = (() => {
|
|
|
1027
1905
|
}
|
|
1028
1906
|
return { context, indexable: valueToIndex };
|
|
1029
1907
|
}
|
|
1030
|
-
|
|
1031
|
-
if (
|
|
1032
|
-
|
|
1033
|
-
|
|
1908
|
+
async putManyWithContext(values) {
|
|
1909
|
+
if (values.length === 0) {
|
|
1910
|
+
return [];
|
|
1911
|
+
}
|
|
1912
|
+
let transformed;
|
|
1913
|
+
if (this.transformerIsIdentity) {
|
|
1914
|
+
transformed = new Array(values.length);
|
|
1915
|
+
for (let i = 0; i < values.length; i++) {
|
|
1916
|
+
const item = values[i];
|
|
1917
|
+
this.cacheResolvedValue(item.id.primitive, item.value);
|
|
1918
|
+
const indexable = item.value;
|
|
1919
|
+
coerceWithIndexed(item.value, indexable);
|
|
1920
|
+
coerceWithContext(item.value, item.context);
|
|
1921
|
+
transformed[i] = { ...item, indexable };
|
|
1922
|
+
}
|
|
1034
1923
|
}
|
|
1035
1924
|
else {
|
|
1036
|
-
|
|
1037
|
-
|
|
1925
|
+
transformed = await Promise.all(values.map(async (item) => {
|
|
1926
|
+
this.cacheResolvedValue(item.id.primitive, item.value);
|
|
1927
|
+
const indexable = await this.transformer(item.value, item.context);
|
|
1928
|
+
coerceWithIndexed(item.value, indexable);
|
|
1929
|
+
coerceWithContext(item.value, item.context);
|
|
1930
|
+
return { ...item, indexable };
|
|
1931
|
+
}));
|
|
1932
|
+
}
|
|
1933
|
+
try {
|
|
1934
|
+
const contextualBatchPut = this.transformerIsIdentity
|
|
1935
|
+
? this.index.putWithContextBatch
|
|
1936
|
+
: undefined;
|
|
1937
|
+
if (contextualBatchPut) {
|
|
1938
|
+
await contextualBatchPut.call(this.index, transformed.map((item) => ({
|
|
1939
|
+
value: item.indexable,
|
|
1940
|
+
id: item.id,
|
|
1941
|
+
context: item.context,
|
|
1942
|
+
options: this.withContextualEncodedValue(item.options, item.context),
|
|
1943
|
+
})));
|
|
1944
|
+
}
|
|
1945
|
+
else if (transformed.every((item) => item.options?.replace !== true) &&
|
|
1946
|
+
this.index.putBatch) {
|
|
1947
|
+
await this.index.putBatch(transformed.map((item) => new this.wrappedIndexedType(item.indexable, item.context)));
|
|
1948
|
+
}
|
|
1949
|
+
else {
|
|
1950
|
+
const contextualPut = this.transformerIsIdentity
|
|
1951
|
+
? this.index.putWithContext
|
|
1952
|
+
: undefined;
|
|
1953
|
+
for (const item of transformed) {
|
|
1954
|
+
if (contextualPut) {
|
|
1955
|
+
await contextualPut.call(this.index, item.indexable, item.id, item.context, this.withContextualEncodedValue(item.options, item.context));
|
|
1956
|
+
}
|
|
1957
|
+
else {
|
|
1958
|
+
await this.index.put(new this.wrappedIndexedType(item.indexable, item.context), item.id, stripEncodedValue(item.options));
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
catch (error) {
|
|
1964
|
+
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
1965
|
+
return transformed.map((item) => ({
|
|
1966
|
+
context: item.context,
|
|
1967
|
+
indexable: item.indexable,
|
|
1968
|
+
}));
|
|
1038
1969
|
}
|
|
1970
|
+
throw error;
|
|
1971
|
+
}
|
|
1972
|
+
return transformed.map((item) => ({
|
|
1973
|
+
context: item.context,
|
|
1974
|
+
indexable: item.indexable,
|
|
1975
|
+
}));
|
|
1976
|
+
}
|
|
1977
|
+
_cacheResolvedIdentityValue(id, value) {
|
|
1978
|
+
this.cacheResolvedValue(id, value);
|
|
1979
|
+
}
|
|
1980
|
+
cacheResolvedValue(id, value) {
|
|
1981
|
+
if (this.isProgramValued) {
|
|
1982
|
+
this._resolverProgramCache.set(id, value);
|
|
1983
|
+
indexCacheLogger("cache:set:program", { id });
|
|
1984
|
+
}
|
|
1985
|
+
else if (this._resolverCache) {
|
|
1986
|
+
this._resolverCache.add(id, value);
|
|
1987
|
+
indexCacheLogger("cache:set:value", { id });
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
withContextualEncodedValue(options, context) {
|
|
1991
|
+
if (!options?.encodedValue) {
|
|
1992
|
+
return options;
|
|
1993
|
+
}
|
|
1994
|
+
const encodedValueParts = this.encodeContextualIndexedValueParts(options.encodedValue, context);
|
|
1995
|
+
return encodedValueParts
|
|
1996
|
+
? { ...options, encodedValue: undefined, encodedValueParts }
|
|
1997
|
+
: options;
|
|
1998
|
+
}
|
|
1999
|
+
encodeContextualIndexedValueParts(encodedValue, context) {
|
|
2000
|
+
if (!encodedValue ||
|
|
2001
|
+
!this.transformerIsIdentity ||
|
|
2002
|
+
!this.indexedTypeIsDocumentType) {
|
|
2003
|
+
return;
|
|
1039
2004
|
}
|
|
2005
|
+
return {
|
|
2006
|
+
prefix: encodedValue,
|
|
2007
|
+
suffix: encodeContextSuffix(context),
|
|
2008
|
+
};
|
|
2009
|
+
}
|
|
2010
|
+
del(key) {
|
|
2011
|
+
this.deleteResolvedCacheForKey(key);
|
|
1040
2012
|
return this.index.del({
|
|
1041
2013
|
query: [indexerTypes.getMatcher(this.indexBy, key.key)],
|
|
1042
2014
|
});
|
|
1043
2015
|
}
|
|
2016
|
+
async delMany(keys) {
|
|
2017
|
+
if (keys.length === 0) {
|
|
2018
|
+
return;
|
|
2019
|
+
}
|
|
2020
|
+
for (const key of keys) {
|
|
2021
|
+
this.deleteResolvedCacheForKey(key);
|
|
2022
|
+
}
|
|
2023
|
+
const delIdsNoReturn = this.index.delIdsNoReturn;
|
|
2024
|
+
if (delIdsNoReturn) {
|
|
2025
|
+
await delIdsNoReturn.call(this.index, keys);
|
|
2026
|
+
return;
|
|
2027
|
+
}
|
|
2028
|
+
const delIds = this.index.delIds;
|
|
2029
|
+
if (delIds) {
|
|
2030
|
+
await delIds.call(this.index, keys);
|
|
2031
|
+
return;
|
|
2032
|
+
}
|
|
2033
|
+
await Promise.all(keys.map((key) => this.del(key)));
|
|
2034
|
+
}
|
|
2035
|
+
clearResolvedCacheForKeys(keys) {
|
|
2036
|
+
for (const key of keys) {
|
|
2037
|
+
this.deleteResolvedCacheForKey(key);
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
delManyMaybe(keys) {
|
|
2041
|
+
if (keys.length === 0) {
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
for (const key of keys) {
|
|
2045
|
+
this.deleteResolvedCacheForKey(key);
|
|
2046
|
+
}
|
|
2047
|
+
const delIdsNoReturn = this.index.delIdsNoReturn;
|
|
2048
|
+
if (delIdsNoReturn) {
|
|
2049
|
+
const result = delIdsNoReturn.call(this.index, keys);
|
|
2050
|
+
return isPromiseLike(result) ? result.then(() => undefined) : undefined;
|
|
2051
|
+
}
|
|
2052
|
+
const delIds = this.index.delIds;
|
|
2053
|
+
if (delIds) {
|
|
2054
|
+
const result = delIds.call(this.index, keys);
|
|
2055
|
+
return isPromiseLike(result) ? result.then(() => undefined) : undefined;
|
|
2056
|
+
}
|
|
2057
|
+
return Promise.all(keys.map((key) => this.del(key))).then(() => undefined);
|
|
2058
|
+
}
|
|
1044
2059
|
async getDetailed(key, options) {
|
|
1045
2060
|
let coercedOptions = options;
|
|
1046
2061
|
if (options?.remote && typeof options.remote !== "boolean") {
|
|
@@ -1393,14 +2408,17 @@ let DocumentIndex = (() => {
|
|
|
1393
2408
|
}
|
|
1394
2409
|
}
|
|
1395
2410
|
get countIteratorsInProgress() {
|
|
1396
|
-
return this._resumableIterators
|
|
2411
|
+
return this._resumableIterators?.queues.size ?? 0;
|
|
1397
2412
|
}
|
|
1398
2413
|
clearAllResultQueues() {
|
|
2414
|
+
if (!this._resultQueue) {
|
|
2415
|
+
return;
|
|
2416
|
+
}
|
|
1399
2417
|
for (const [key, queue] of this._resultQueue) {
|
|
1400
2418
|
clearTimeout(queue.timeout);
|
|
1401
2419
|
this._resultQueue.delete(key);
|
|
1402
2420
|
this.cancelIteratorKeepAlive(key);
|
|
1403
|
-
this._resumableIterators
|
|
2421
|
+
this._resumableIterators?.close({ idString: key });
|
|
1404
2422
|
}
|
|
1405
2423
|
}
|
|
1406
2424
|
async waitForCoverReady(params) {
|
|
@@ -1614,33 +2632,58 @@ let DocumentIndex = (() => {
|
|
|
1614
2632
|
reachableOnly: !!remote.wait, // when we want to merge joining we can ignore pending to be online peers and instead consider them once they become online
|
|
1615
2633
|
signal: options?.signal,
|
|
1616
2634
|
});
|
|
1617
|
-
// Cold start: cover can be temporarily self-only
|
|
1618
|
-
// converges. For explicit remote searches,
|
|
1619
|
-
// instead of waiting for replicator
|
|
2635
|
+
// Cold start: cover can be temporarily self-only or empty while
|
|
2636
|
+
// replication metadata converges. For explicit bounded remote searches,
|
|
2637
|
+
// query bounded connected peers instead of waiting for replicator
|
|
2638
|
+
// metadata to catch up.
|
|
1620
2639
|
if (!options?.remote?.from && isDefaultDomainArgs && remoteWasExplicit) {
|
|
1621
2640
|
const selfHash = this.node.identity.publicKey.hashcode();
|
|
1622
2641
|
const remoteCount = replicatorGroups.filter((h) => h !== selfHash).length;
|
|
1623
2642
|
if (remoteCount === 0) {
|
|
1624
2643
|
const waitEnabled = Boolean(remote.wait);
|
|
1625
2644
|
const coverIsSelfOnly = replicatorGroups.length === 1 && replicatorGroups[0] === selfHash;
|
|
1626
|
-
|
|
1627
|
-
// the
|
|
1628
|
-
|
|
2645
|
+
const coverIsColdEmpty = replicatorGroups.length === 0 && remote.timeout != null;
|
|
2646
|
+
// If the cover is explicitly empty (no shards), don't override it
|
|
2647
|
+
// unless the caller requested waiting for joins (e.g. get(waitFor))
|
|
2648
|
+
// or bounded the remote query with a timeout.
|
|
2649
|
+
if (waitEnabled || coverIsSelfOnly || coverIsColdEmpty) {
|
|
2650
|
+
const extra = [];
|
|
2651
|
+
const addExtra = (hash) => {
|
|
2652
|
+
if (!hash || hash === selfHash || extra.includes(hash)) {
|
|
2653
|
+
return;
|
|
2654
|
+
}
|
|
2655
|
+
extra.push(hash);
|
|
2656
|
+
};
|
|
1629
2657
|
const peerMap = this.node.services.pubsub?.peers;
|
|
2658
|
+
// Only consider replicators that are currently reachable.
|
|
2659
|
+
// The replicator index can contain stale (offline) peers, e.g.
|
|
2660
|
+
// persisted replicators after a restart; querying those would
|
|
2661
|
+
// block the first batch for the full wait timeout instead of
|
|
2662
|
+
// letting joining peers be merged as they arrive.
|
|
2663
|
+
if (peerMap?.has) {
|
|
2664
|
+
try {
|
|
2665
|
+
for (const hash of await this._log.getReplicators()) {
|
|
2666
|
+
if (peerMap.has(hash)) {
|
|
2667
|
+
addExtra(hash);
|
|
2668
|
+
}
|
|
2669
|
+
if (extra.length >= 8)
|
|
2670
|
+
break;
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
catch {
|
|
2674
|
+
// Fall through to connected peers when the local replicator
|
|
2675
|
+
// index is not ready yet.
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
1630
2678
|
if (peerMap?.keys) {
|
|
1631
|
-
const extra = [];
|
|
1632
2679
|
for (const hash of peerMap.keys()) {
|
|
1633
|
-
|
|
1634
|
-
continue;
|
|
1635
|
-
extra.push(hash);
|
|
2680
|
+
addExtra(hash);
|
|
1636
2681
|
if (extra.length >= 8)
|
|
1637
2682
|
break;
|
|
1638
2683
|
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
];
|
|
1643
|
-
}
|
|
2684
|
+
}
|
|
2685
|
+
if (extra.length > 0) {
|
|
2686
|
+
replicatorGroups = [...new Set([...replicatorGroups, ...extra])];
|
|
1644
2687
|
}
|
|
1645
2688
|
}
|
|
1646
2689
|
}
|
|
@@ -2521,6 +3564,7 @@ let DocumentIndex = (() => {
|
|
|
2521
3564
|
if (n === 0) {
|
|
2522
3565
|
return [];
|
|
2523
3566
|
}
|
|
3567
|
+
await pendingUpdateProcessing;
|
|
2524
3568
|
const bufferedBeforeFetch = peerBuffers().length;
|
|
2525
3569
|
const localHash = this.node.identity.publicKey.hashcode();
|
|
2526
3570
|
const hasBufferedRemoteResults = [...peerBufferMap.entries()].some(([peerHash, peerBuffer]) => peerHash !== localHash && peerBuffer.buffer.length > 0);
|
|
@@ -2710,6 +3754,7 @@ let DocumentIndex = (() => {
|
|
|
2710
3754
|
const updateCallbacks = updateCallbacksRaw;
|
|
2711
3755
|
let pendingBatchReason;
|
|
2712
3756
|
let hasDeliveredResults = false;
|
|
3757
|
+
let pendingUpdateProcessing = Promise.resolve();
|
|
2713
3758
|
const emitOnBatch = async (batch, defaultReason) => {
|
|
2714
3759
|
if (!updateCallbacks?.onBatch || batch.length === 0) {
|
|
2715
3760
|
return;
|
|
@@ -2929,7 +3974,7 @@ let DocumentIndex = (() => {
|
|
|
2929
3974
|
}
|
|
2930
3975
|
return value;
|
|
2931
3976
|
};
|
|
2932
|
-
const
|
|
3977
|
+
const processChange = async (evt) => {
|
|
2933
3978
|
// Optional filter to mutate/suppress change events
|
|
2934
3979
|
indexIteratorLogger.trace("processing live update change event", evt.detail);
|
|
2935
3980
|
let filtered = evt.detail;
|
|
@@ -3047,6 +4092,13 @@ let DocumentIndex = (() => {
|
|
|
3047
4092
|
}
|
|
3048
4093
|
signalUpdate();
|
|
3049
4094
|
};
|
|
4095
|
+
const onChange = (evt) => {
|
|
4096
|
+
const task = pendingUpdateProcessing.then(() => processChange(evt));
|
|
4097
|
+
pendingUpdateProcessing = task.catch((error) => {
|
|
4098
|
+
warn("Failed to process iterator update", error);
|
|
4099
|
+
});
|
|
4100
|
+
return task;
|
|
4101
|
+
};
|
|
3050
4102
|
this.documentEvents.addEventListener("change", onChange);
|
|
3051
4103
|
updatesCleanup = () => {
|
|
3052
4104
|
this.documentEvents.removeEventListener("change", onChange);
|