@peerbit/document 8.1.2 → 8.2.0-a4ac71a
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/iterate-replicate-2.js +7 -1
- package/dist/benchmark/iterate-replicate-2.js.map +1 -1
- package/dist/src/domain.d.ts +9 -3
- package/dist/src/domain.d.ts.map +1 -1
- package/dist/src/domain.js.map +1 -1
- package/dist/src/program.d.ts +2 -1
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +15 -4
- package/dist/src/program.js.map +1 -1
- package/dist/src/resumable-iterator.d.ts +6 -3
- package/dist/src/resumable-iterator.d.ts.map +1 -1
- package/dist/src/resumable-iterator.js +6 -2
- package/dist/src/resumable-iterator.js.map +1 -1
- package/dist/src/search.d.ts +33 -29
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +261 -60
- package/dist/src/search.js.map +1 -1
- package/package.json +74 -74
- package/src/domain.ts +12 -3
- package/src/program.ts +19 -8
- package/src/resumable-iterator.ts +10 -3
- package/src/search.ts +564 -174
package/dist/src/search.js
CHANGED
|
@@ -9,7 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
};
|
|
10
10
|
import { field, serialize, variant } from "@dao-xyz/borsh";
|
|
11
11
|
import { Cache } from "@peerbit/cache";
|
|
12
|
-
import { PublicSignKey, sha256Base64Sync, } from "@peerbit/crypto";
|
|
12
|
+
import { PublicSignKey, getPublicKeyFromPeerId, sha256Base64Sync, } from "@peerbit/crypto";
|
|
13
13
|
import * as types from "@peerbit/document-interface";
|
|
14
14
|
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
15
15
|
import { HashmapIndex } from "@peerbit/indexer-simple";
|
|
@@ -19,21 +19,46 @@ import { ClosedError, Program } from "@peerbit/program";
|
|
|
19
19
|
import { MissingResponsesError, RPC, queryAll, } from "@peerbit/rpc";
|
|
20
20
|
import { SharedLog } from "@peerbit/shared-log";
|
|
21
21
|
import { SilentDelivery } from "@peerbit/stream-interface";
|
|
22
|
-
import { AbortError } from "@peerbit/time";
|
|
22
|
+
import { AbortError, waitFor } from "@peerbit/time";
|
|
23
23
|
import { concat, fromString } from "uint8arrays";
|
|
24
24
|
import { copySerialization } from "./borsh.js";
|
|
25
25
|
import { MAX_BATCH_SIZE } from "./constants.js";
|
|
26
26
|
import { isPutOperation } from "./operation.js";
|
|
27
27
|
import { ResumableIterators } from "./resumable-iterator.js";
|
|
28
28
|
const logger = loggerFn({ module: "document-index" });
|
|
29
|
-
const
|
|
29
|
+
const coerceQuery = (query, options) => {
|
|
30
|
+
let replicate = typeof options?.remote !== "boolean" ? options?.remote?.replicate : false;
|
|
31
|
+
if (query instanceof types.SearchRequestIndexed &&
|
|
32
|
+
query.replicate === false &&
|
|
33
|
+
replicate) {
|
|
34
|
+
query.replicate = true;
|
|
35
|
+
return query;
|
|
36
|
+
}
|
|
37
|
+
if (query instanceof types.SearchRequest) {
|
|
38
|
+
return query;
|
|
39
|
+
}
|
|
40
|
+
const queryObject = query;
|
|
41
|
+
return options?.resolve || options?.resolve == null
|
|
42
|
+
? new types.SearchRequest({
|
|
43
|
+
query: indexerTypes.toQuery(queryObject.query),
|
|
44
|
+
sort: indexerTypes.toSort(query.sort),
|
|
45
|
+
})
|
|
46
|
+
: new types.SearchRequestIndexed({
|
|
47
|
+
query: indexerTypes.toQuery(queryObject.query),
|
|
48
|
+
sort: indexerTypes.toSort(query.sort),
|
|
49
|
+
replicate,
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
const introduceEntries = async (queryRequest, responses, documentType, indexedType, sync, options) => {
|
|
30
53
|
const results = [];
|
|
31
54
|
for (const response of responses) {
|
|
32
55
|
if (!response.from) {
|
|
33
56
|
logger.error("Missing from for response");
|
|
34
57
|
}
|
|
35
58
|
if (response.response instanceof types.Results) {
|
|
36
|
-
response.response.results.forEach((r) => r.
|
|
59
|
+
response.response.results.forEach((r) => r instanceof types.ResultValue
|
|
60
|
+
? r.init(documentType)
|
|
61
|
+
: r.init(indexedType));
|
|
37
62
|
if (typeof options?.remote !== "boolean" && options?.remote?.replicate) {
|
|
38
63
|
await sync(queryRequest, response.response);
|
|
39
64
|
}
|
|
@@ -123,6 +148,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
123
148
|
transformer;
|
|
124
149
|
// The indexed document wrapped in a context
|
|
125
150
|
wrappedIndexedType;
|
|
151
|
+
indexedType;
|
|
126
152
|
// The database type, for recursive indexing
|
|
127
153
|
dbType;
|
|
128
154
|
indexedTypeIsDocumentType;
|
|
@@ -131,6 +157,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
131
157
|
indexByResolver;
|
|
132
158
|
index;
|
|
133
159
|
_resumableIterators;
|
|
160
|
+
compatibility;
|
|
134
161
|
// Transformation, indexer
|
|
135
162
|
/* fields: IndexableFields<T, I>; */
|
|
136
163
|
_valueEncoding;
|
|
@@ -153,6 +180,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
153
180
|
this.indexedTypeIsDocumentType =
|
|
154
181
|
!properties.transform?.type ||
|
|
155
182
|
properties.transform?.type === properties.documentType;
|
|
183
|
+
this.compatibility = properties.compatibility;
|
|
156
184
|
let IndexedClassWithContext = class IndexedClassWithContext {
|
|
157
185
|
__context;
|
|
158
186
|
constructor(value, context) {
|
|
@@ -169,13 +197,62 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
169
197
|
__metadata("design:paramtypes", [Object, IndexableContext])
|
|
170
198
|
], IndexedClassWithContext);
|
|
171
199
|
// copy all prototype values from indexedType to IndexedClassWithContext
|
|
172
|
-
|
|
200
|
+
this.indexedType = (properties.transform?.type || properties.documentType);
|
|
201
|
+
copySerialization(this.indexedType, IndexedClassWithContext);
|
|
173
202
|
this.wrappedIndexedType = IndexedClassWithContext;
|
|
174
203
|
// if this.type is a class that extends Program we want to do special functionality
|
|
175
204
|
this._isProgramValues = this.documentType instanceof Program;
|
|
176
205
|
this.dbType = properties.dbType;
|
|
177
206
|
this._resultQueue = new Map();
|
|
178
|
-
this._sync =
|
|
207
|
+
this._sync = async (request, results) => {
|
|
208
|
+
/*
|
|
209
|
+
let allPromises: Promise<void> | undefined = undefined
|
|
210
|
+
if (waitForValue) {
|
|
211
|
+
let promises: Map<string, DeferredPromise<T>> = new Map();
|
|
212
|
+
|
|
213
|
+
for (const result of results) {
|
|
214
|
+
for (let i = 0; i < result.results.length; i++) {
|
|
215
|
+
let promise = defer<T>();
|
|
216
|
+
let r = result.results[i];
|
|
217
|
+
promises.set(r.context.head, promise);
|
|
218
|
+
const head = result.results[0].context.head;
|
|
219
|
+
let listeners = this.hashToValueListener.get(head);
|
|
220
|
+
if (!listeners) {
|
|
221
|
+
listeners = [];
|
|
222
|
+
this.hashToValueListener.set(head, listeners);
|
|
223
|
+
}
|
|
224
|
+
listeners.push(async (value) => {
|
|
225
|
+
promise.resolve(value);
|
|
226
|
+
result.results[i] = new types.ResultValue<T>({
|
|
227
|
+
context: r.context,
|
|
228
|
+
value,
|
|
229
|
+
source: serialize(value),
|
|
230
|
+
indexed: r.indexed,
|
|
231
|
+
}) as any;
|
|
232
|
+
});
|
|
233
|
+
promise.promise.finally(() => {
|
|
234
|
+
this.hashToValueListener.delete(head);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
let timeout = setTimeout(() => {
|
|
240
|
+
for (const promise of promises!) {
|
|
241
|
+
promise[1].reject("Timed out resolving search result from value");
|
|
242
|
+
}
|
|
243
|
+
}, 1e4);
|
|
244
|
+
|
|
245
|
+
allPromises = Promise.all([...promises.values()].map((x) => x.promise)).then(
|
|
246
|
+
() => {
|
|
247
|
+
clearTimeout(timeout);
|
|
248
|
+
},
|
|
249
|
+
);
|
|
250
|
+
} */
|
|
251
|
+
await properties.replicate(request, results);
|
|
252
|
+
/* if (allPromises) {
|
|
253
|
+
await allPromises;
|
|
254
|
+
} */
|
|
255
|
+
};
|
|
179
256
|
const transformOptions = properties.transform;
|
|
180
257
|
this.transformer = transformOptions
|
|
181
258
|
? isTransformerWithFunction(transformOptions)
|
|
@@ -301,8 +378,12 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
301
378
|
}
|
|
302
379
|
async getDetailed(key, options) {
|
|
303
380
|
let results;
|
|
381
|
+
const resolve = options?.resolve || options?.resolve == null;
|
|
382
|
+
let requestClazz = resolve
|
|
383
|
+
? types.SearchRequest
|
|
384
|
+
: types.SearchRequestIndexed;
|
|
304
385
|
if (key instanceof Uint8Array) {
|
|
305
|
-
results = await this.
|
|
386
|
+
results = await this.queryCommence(new requestClazz({
|
|
306
387
|
query: [
|
|
307
388
|
new indexerTypes.ByteMatchQuery({ key: this.indexBy, value: key }),
|
|
308
389
|
],
|
|
@@ -312,7 +393,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
312
393
|
const indexableKey = indexerTypes.toIdeable(key);
|
|
313
394
|
if (typeof indexableKey === "number" ||
|
|
314
395
|
typeof indexableKey === "bigint") {
|
|
315
|
-
results = await this.
|
|
396
|
+
results = await this.queryCommence(new requestClazz({
|
|
316
397
|
query: [
|
|
317
398
|
new indexerTypes.IntegerCompare({
|
|
318
399
|
key: this.indexBy,
|
|
@@ -323,7 +404,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
323
404
|
}), options);
|
|
324
405
|
}
|
|
325
406
|
else if (typeof indexableKey === "string") {
|
|
326
|
-
results = await this.
|
|
407
|
+
results = await this.queryCommence(new requestClazz({
|
|
327
408
|
query: [
|
|
328
409
|
new indexerTypes.StringMatch({
|
|
329
410
|
key: this.indexBy,
|
|
@@ -333,7 +414,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
333
414
|
}), options);
|
|
334
415
|
}
|
|
335
416
|
else if (indexableKey instanceof Uint8Array) {
|
|
336
|
-
results = await this.
|
|
417
|
+
results = await this.queryCommence(new requestClazz({
|
|
337
418
|
query: [
|
|
338
419
|
new indexerTypes.ByteMatchQuery({
|
|
339
420
|
key: this.indexBy,
|
|
@@ -343,24 +424,48 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
343
424
|
}), options);
|
|
344
425
|
}
|
|
345
426
|
}
|
|
427
|
+
if (resolve &&
|
|
428
|
+
requestClazz === types.SearchRequestIndexed &&
|
|
429
|
+
!this.indexedTypeIsDocumentType &&
|
|
430
|
+
results) {
|
|
431
|
+
for (const set of results) {
|
|
432
|
+
let coercedResult = [];
|
|
433
|
+
for (const value of set.results) {
|
|
434
|
+
const resolved = value instanceof types.ResultIndexedValue
|
|
435
|
+
? (await this.resolveDocument({
|
|
436
|
+
indexed: value.value,
|
|
437
|
+
head: value.context.head,
|
|
438
|
+
}))?.value
|
|
439
|
+
: value.value;
|
|
440
|
+
if (resolved) {
|
|
441
|
+
coercedResult.push(new types.ResultValue({
|
|
442
|
+
context: value.context,
|
|
443
|
+
value: resolved,
|
|
444
|
+
}));
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
set.results = coercedResult;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
346
450
|
return results;
|
|
347
451
|
}
|
|
348
452
|
getSize() {
|
|
349
453
|
return this.index.getSize();
|
|
350
454
|
}
|
|
351
455
|
async resolveDocument(value) {
|
|
352
|
-
const
|
|
353
|
-
this.
|
|
456
|
+
const id = value.id ??
|
|
457
|
+
indexerTypes.toId(this.indexByResolver(value.indexed)).primitive;
|
|
458
|
+
const cached = this._resolverCache.get(id) || this._resolverProgramCache?.get(id);
|
|
354
459
|
if (cached != null) {
|
|
355
460
|
return { value: cached };
|
|
356
461
|
}
|
|
357
462
|
if (this.indexedTypeIsDocumentType) {
|
|
358
463
|
// cast value to T, i.e. convert the class but keep all properties except the __context
|
|
359
|
-
const obj = Object.assign(Object.create(this.documentType.prototype), value.
|
|
464
|
+
const obj = Object.assign(Object.create(this.documentType.prototype), value.indexed);
|
|
360
465
|
delete obj.__context;
|
|
361
466
|
return { value: obj };
|
|
362
467
|
}
|
|
363
|
-
const head = await this._log.log.get(value.
|
|
468
|
+
const head = await this._log.log.get(value.head);
|
|
364
469
|
if (!head) {
|
|
365
470
|
return undefined; // we could end up here if we recently pruned the document and other peers never persisted the entry
|
|
366
471
|
// TODO update changes in index before removing entries from log entry storage
|
|
@@ -384,10 +489,14 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
384
489
|
throw new Error("Different from in queued results");
|
|
385
490
|
}
|
|
386
491
|
let indexedResult = undefined;
|
|
387
|
-
|
|
492
|
+
let fromQuery;
|
|
493
|
+
if (query instanceof types.SearchRequest ||
|
|
494
|
+
query instanceof types.SearchRequestIndexed) {
|
|
495
|
+
fromQuery = query;
|
|
388
496
|
indexedResult = await this._resumableIterators.iterateAndFetch(query);
|
|
389
497
|
}
|
|
390
498
|
else if (query instanceof types.CollectNextRequest) {
|
|
499
|
+
fromQuery = this._resumableIterators.queues.get(query.idString)?.request;
|
|
391
500
|
indexedResult =
|
|
392
501
|
prevQueued?.keptInIndex === 0
|
|
393
502
|
? []
|
|
@@ -396,7 +505,6 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
396
505
|
else {
|
|
397
506
|
throw new Error("Unsupported");
|
|
398
507
|
}
|
|
399
|
-
const filteredResults = [];
|
|
400
508
|
let resultSize = 0;
|
|
401
509
|
let toIterate = prevQueued
|
|
402
510
|
? [...prevQueued.queue, ...indexedResult]
|
|
@@ -418,6 +526,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
418
526
|
};
|
|
419
527
|
this._resultQueue.set(query.idString, prevQueued);
|
|
420
528
|
}
|
|
529
|
+
const filteredResults = [];
|
|
421
530
|
for (const result of toIterate) {
|
|
422
531
|
if (!isLocal) {
|
|
423
532
|
resultSize += result.value.__context.size;
|
|
@@ -426,17 +535,40 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
426
535
|
continue;
|
|
427
536
|
}
|
|
428
537
|
}
|
|
429
|
-
const
|
|
430
|
-
if (
|
|
431
|
-
|
|
538
|
+
const indexedUnwrapped = Object.assign(Object.create(this.indexedType.prototype), result.value);
|
|
539
|
+
if (options?.canRead &&
|
|
540
|
+
!(await options.canRead(indexedUnwrapped, from))) {
|
|
432
541
|
continue;
|
|
433
542
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
543
|
+
if (fromQuery instanceof types.SearchRequest) {
|
|
544
|
+
const value = await this.resolveDocument({
|
|
545
|
+
indexed: result.value,
|
|
546
|
+
head: result.value.__context.head,
|
|
547
|
+
});
|
|
548
|
+
if (!value) {
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
filteredResults.push(new types.ResultValue({
|
|
552
|
+
context: result.value.__context.toContext(),
|
|
553
|
+
value: value.value,
|
|
554
|
+
source: serialize(value.value),
|
|
555
|
+
indexed: indexedUnwrapped,
|
|
556
|
+
}));
|
|
557
|
+
}
|
|
558
|
+
else if (fromQuery instanceof types.SearchRequestIndexed) {
|
|
559
|
+
const context = result.value.__context.toContext();
|
|
560
|
+
const head = await this._log.log.get(context.head);
|
|
561
|
+
// assume remote peer will start to replicate (TODO is this ideal?)
|
|
562
|
+
if (fromQuery.replicate) {
|
|
563
|
+
this._log.addPeersToGidPeerHistory(context.gid, [from.hashcode()]);
|
|
564
|
+
}
|
|
565
|
+
filteredResults.push(new types.ResultIndexedValue({
|
|
566
|
+
context,
|
|
567
|
+
source: serialize(indexedUnwrapped),
|
|
568
|
+
indexed: indexedUnwrapped,
|
|
569
|
+
entries: head ? [head] : [],
|
|
570
|
+
}));
|
|
571
|
+
}
|
|
440
572
|
}
|
|
441
573
|
const results = new types.Results({
|
|
442
574
|
results: filteredResults,
|
|
@@ -476,7 +608,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
476
608
|
* @param options
|
|
477
609
|
* @returns
|
|
478
610
|
*/
|
|
479
|
-
async
|
|
611
|
+
async queryCommence(queryRequest, options) {
|
|
480
612
|
const local = typeof options?.local === "boolean" ? options?.local : true;
|
|
481
613
|
let remote = undefined;
|
|
482
614
|
if (typeof options?.remote === "boolean") {
|
|
@@ -517,7 +649,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
517
649
|
if (replicatorGroups) {
|
|
518
650
|
const groupHashes = replicatorGroups.map((x) => [x]);
|
|
519
651
|
const responseHandler = async (results) => {
|
|
520
|
-
|
|
652
|
+
const resultInitialized = await introduceEntries(queryRequest, results, this.documentType, this.indexedType, this._sync, options);
|
|
653
|
+
for (const r of resultInitialized) {
|
|
521
654
|
resolved.push(r.response);
|
|
522
655
|
}
|
|
523
656
|
};
|
|
@@ -564,7 +697,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
564
697
|
}
|
|
565
698
|
}
|
|
566
699
|
}
|
|
567
|
-
return allResults;
|
|
700
|
+
return allResults; // TODO types
|
|
568
701
|
}
|
|
569
702
|
/**
|
|
570
703
|
* Query and retrieve results
|
|
@@ -574,19 +707,21 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
574
707
|
*/
|
|
575
708
|
async search(queryRequest, options) {
|
|
576
709
|
// Set fetch to search size, or max value (default to max u32 (4294967295))
|
|
577
|
-
|
|
710
|
+
const coercedRequest = coerceQuery(queryRequest, options);
|
|
711
|
+
coercedRequest.fetch = coercedRequest.fetch ?? 0xffffffff;
|
|
578
712
|
// So that the iterator is pre-fetching the right amount of entries
|
|
579
|
-
const iterator = this.iterate(
|
|
713
|
+
const iterator = this.iterate(coercedRequest, options);
|
|
580
714
|
// So that this call will not do any remote requests
|
|
581
715
|
const allResults = [];
|
|
582
|
-
while (iterator.done() !== true &&
|
|
716
|
+
while (iterator.done() !== true &&
|
|
717
|
+
coercedRequest.fetch > allResults.length) {
|
|
583
718
|
// We might need to pull .next multiple time due to data message size limitations
|
|
584
|
-
for (const result of await iterator.next(
|
|
719
|
+
for (const result of await iterator.next(coercedRequest.fetch - allResults.length)) {
|
|
585
720
|
allResults.push(result);
|
|
586
721
|
}
|
|
587
722
|
}
|
|
588
723
|
await iterator.close();
|
|
589
|
-
//
|
|
724
|
+
// Deduplicate and return values directly
|
|
590
725
|
return dedup(allResults, this.indexByResolver);
|
|
591
726
|
}
|
|
592
727
|
/**
|
|
@@ -596,6 +731,30 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
596
731
|
* @returns
|
|
597
732
|
*/
|
|
598
733
|
iterate(queryRequest, options) {
|
|
734
|
+
let queryRequestCoerced = coerceQuery(queryRequest, options);
|
|
735
|
+
let resolve = false;
|
|
736
|
+
if (options?.remote &&
|
|
737
|
+
typeof options.remote !== "boolean" &&
|
|
738
|
+
options.remote.replicate &&
|
|
739
|
+
options?.resolve !== false) {
|
|
740
|
+
if ((queryRequest instanceof types.SearchRequestIndexed === false &&
|
|
741
|
+
this.compatibility == null) ||
|
|
742
|
+
(this.compatibility != null && this.compatibility > 8)) {
|
|
743
|
+
queryRequestCoerced = new types.SearchRequestIndexed({
|
|
744
|
+
query: queryRequestCoerced.query,
|
|
745
|
+
fetch: queryRequestCoerced.fetch,
|
|
746
|
+
sort: queryRequestCoerced.sort,
|
|
747
|
+
});
|
|
748
|
+
resolve = true;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
let replicate = options?.remote &&
|
|
752
|
+
typeof options.remote !== "boolean" &&
|
|
753
|
+
options.remote.replicate;
|
|
754
|
+
if (replicate &&
|
|
755
|
+
queryRequestCoerced instanceof types.SearchRequestIndexed) {
|
|
756
|
+
queryRequestCoerced.replicate = true;
|
|
757
|
+
}
|
|
599
758
|
let fetchPromise = undefined;
|
|
600
759
|
const peerBufferMap = new Map();
|
|
601
760
|
const visited = new Set();
|
|
@@ -608,8 +767,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
608
767
|
};
|
|
609
768
|
const fetchFirst = async (n) => {
|
|
610
769
|
done = true; // Assume we are donne
|
|
611
|
-
|
|
612
|
-
await this.
|
|
770
|
+
queryRequestCoerced.fetch = n;
|
|
771
|
+
await this.queryCommence(queryRequestCoerced, {
|
|
613
772
|
...options,
|
|
614
773
|
onResponse: async (response, from) => {
|
|
615
774
|
if (!from) {
|
|
@@ -630,18 +789,33 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
630
789
|
}
|
|
631
790
|
const buffer = [];
|
|
632
791
|
for (const result of results.results) {
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
792
|
+
if (result instanceof types.ResultValue) {
|
|
793
|
+
const indexKey = indexerTypes.toId(this.indexByResolver(result.value)).primitive;
|
|
794
|
+
if (visited.has(indexKey)) {
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
visited.add(indexKey);
|
|
798
|
+
buffer.push({
|
|
799
|
+
value: result.value,
|
|
800
|
+
context: result.context,
|
|
801
|
+
from,
|
|
802
|
+
indexed: result.indexed ||
|
|
803
|
+
(await this.transformer(result.value, result.context)),
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
else {
|
|
807
|
+
const indexKey = indexerTypes.toId(this.indexByResolver(result.value)).primitive;
|
|
808
|
+
if (visited.has(indexKey)) {
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
visited.add(indexKey);
|
|
812
|
+
buffer.push({
|
|
813
|
+
value: result.value,
|
|
814
|
+
context: result.context,
|
|
815
|
+
from,
|
|
816
|
+
indexed: result.indexed || result.value,
|
|
817
|
+
});
|
|
636
818
|
}
|
|
637
|
-
visited.add(indexKey);
|
|
638
|
-
buffer.push({
|
|
639
|
-
value: result.value,
|
|
640
|
-
context: result.context,
|
|
641
|
-
from,
|
|
642
|
-
indexed: result.indexed ||
|
|
643
|
-
(await this.transformer(result.value, result.context)),
|
|
644
|
-
});
|
|
645
819
|
}
|
|
646
820
|
peerBufferMap.set(from.hashcode(), {
|
|
647
821
|
buffer,
|
|
@@ -654,7 +828,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
654
828
|
},
|
|
655
829
|
});
|
|
656
830
|
if (done) {
|
|
657
|
-
this.clearResultsQueue(
|
|
831
|
+
this.clearResultsQueue(queryRequestCoerced);
|
|
658
832
|
}
|
|
659
833
|
return done;
|
|
660
834
|
};
|
|
@@ -684,7 +858,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
684
858
|
// TODO buffer more than deleted?
|
|
685
859
|
// TODO batch to multiple 'to's
|
|
686
860
|
const collectRequest = new types.CollectNextRequest({
|
|
687
|
-
id:
|
|
861
|
+
id: queryRequestCoerced.id,
|
|
688
862
|
amount: n - buffer.buffer.length,
|
|
689
863
|
});
|
|
690
864
|
// Fetch locally?
|
|
@@ -734,11 +908,12 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
734
908
|
priority: 1,
|
|
735
909
|
mode: new SilentDelivery({ to: [peer], redundancy: 1 }),
|
|
736
910
|
})
|
|
737
|
-
.then((response) => introduceEntries(
|
|
738
|
-
.then((responses) => {
|
|
739
|
-
responses.map((response) => {
|
|
911
|
+
.then((response) => introduceEntries(queryRequestCoerced, response, this.documentType, this.indexedType, this._sync, options)
|
|
912
|
+
.then(async (responses) => {
|
|
913
|
+
return Promise.all(responses.map(async (response, i) => {
|
|
740
914
|
resultsLeft += Number(response.response.kept);
|
|
741
|
-
|
|
915
|
+
const from = responses[i].from;
|
|
916
|
+
if (!from) {
|
|
742
917
|
logger.error("Missing from for sorted query");
|
|
743
918
|
return;
|
|
744
919
|
}
|
|
@@ -754,19 +929,20 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
754
929
|
}
|
|
755
930
|
peerBuffer.kept = Number(response.response.kept);
|
|
756
931
|
for (const result of response.response.results) {
|
|
757
|
-
|
|
932
|
+
const idPrimitive = indexerTypes.toId(this.indexByResolver(result.value)).primitive;
|
|
933
|
+
if (visited.has(idPrimitive)) {
|
|
758
934
|
continue;
|
|
759
935
|
}
|
|
760
|
-
visited.add(
|
|
936
|
+
visited.add(idPrimitive);
|
|
761
937
|
peerBuffer.buffer.push({
|
|
762
938
|
value: result.value,
|
|
763
939
|
context: result.context,
|
|
764
|
-
from:
|
|
765
|
-
indexed: this.transformer(result.value, result.context),
|
|
940
|
+
from: from,
|
|
941
|
+
indexed: await this.transformer(result.value, result.context),
|
|
766
942
|
});
|
|
767
943
|
}
|
|
768
944
|
}
|
|
769
|
-
});
|
|
945
|
+
}));
|
|
770
946
|
})
|
|
771
947
|
.catch((e) => {
|
|
772
948
|
logger.error("Failed to collect sorted results from: " +
|
|
@@ -796,7 +972,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
796
972
|
const fetchedAll = await fetchAtLeast(n);
|
|
797
973
|
// get n next top entries, shift and pull more results
|
|
798
974
|
const peerBuffersArr = peerBuffers();
|
|
799
|
-
const results = peerBuffersArr.sort((a, b) => indexerTypes.extractSortCompare(a.indexed, b.indexed,
|
|
975
|
+
const results = peerBuffersArr.sort((a, b) => indexerTypes.extractSortCompare(a.indexed, b.indexed, queryRequestCoerced.sort));
|
|
800
976
|
const pendingMoreResults = n < results.length;
|
|
801
977
|
const batch = results.splice(0, n);
|
|
802
978
|
for (const result of batch) {
|
|
@@ -811,12 +987,24 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
811
987
|
}
|
|
812
988
|
}
|
|
813
989
|
done = fetchedAll && !pendingMoreResults;
|
|
814
|
-
|
|
990
|
+
let coercedBatch;
|
|
991
|
+
if (resolve) {
|
|
992
|
+
coercedBatch = (await Promise.all(batch.map(async (x) => x.value instanceof this.documentType
|
|
993
|
+
? x.value
|
|
994
|
+
: (await this.resolveDocument({
|
|
995
|
+
head: x.context.head,
|
|
996
|
+
indexed: x.indexed,
|
|
997
|
+
}))?.value))).filter((x) => !!x);
|
|
998
|
+
}
|
|
999
|
+
else {
|
|
1000
|
+
coercedBatch = batch.map((x) => x.value);
|
|
1001
|
+
}
|
|
1002
|
+
return dedup(coercedBatch, this.indexByResolver);
|
|
815
1003
|
};
|
|
816
1004
|
const close = async () => {
|
|
817
1005
|
controller.abort(new AbortError("Iterator closed"));
|
|
818
1006
|
const closeRequest = new types.CloseIteratorRequest({
|
|
819
|
-
id:
|
|
1007
|
+
id: queryRequestCoerced.id,
|
|
820
1008
|
});
|
|
821
1009
|
const promises = [];
|
|
822
1010
|
for (const [peer, buffer] of peerBufferMap) {
|
|
@@ -853,6 +1041,19 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
853
1041
|
},
|
|
854
1042
|
};
|
|
855
1043
|
}
|
|
1044
|
+
async waitFor(other, options) {
|
|
1045
|
+
await super.waitFor(other, options);
|
|
1046
|
+
const ids = Array.isArray(other) ? other : [other];
|
|
1047
|
+
const expectedHashes = new Set(ids.map((x) => typeof x === "string"
|
|
1048
|
+
? x
|
|
1049
|
+
: x instanceof PublicSignKey
|
|
1050
|
+
? x.hashcode()
|
|
1051
|
+
: getPublicKeyFromPeerId(x).hashcode()));
|
|
1052
|
+
for (const key of expectedHashes) {
|
|
1053
|
+
await waitFor(async () => (await this._log.replicationIndex.count({ query: { hash: key } })) >
|
|
1054
|
+
0, options);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
856
1057
|
};
|
|
857
1058
|
__decorate([
|
|
858
1059
|
field({ type: RPC }),
|