@peerbit/document 8.2.0 → 9.0.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/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 -2
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +15 -6
- 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 -31
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +262 -80
- package/dist/src/search.js.map +1 -1
- package/package.json +8 -8
- package/src/domain.ts +12 -3
- package/src/program.ts +19 -13
- package/src/resumable-iterator.ts +10 -3
- package/src/search.ts +563 -206
package/dist/src/search.js
CHANGED
|
@@ -8,9 +8,8 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
10
|
import { field, serialize, variant } from "@dao-xyz/borsh";
|
|
11
|
-
import { BlockResponse } from "@peerbit/blocks";
|
|
12
11
|
import { Cache } from "@peerbit/cache";
|
|
13
|
-
import { PublicSignKey, sha256Base64Sync, } from "@peerbit/crypto";
|
|
12
|
+
import { PublicSignKey, getPublicKeyFromPeerId, sha256Base64Sync, } from "@peerbit/crypto";
|
|
14
13
|
import * as types from "@peerbit/document-interface";
|
|
15
14
|
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
16
15
|
import { HashmapIndex } from "@peerbit/indexer-simple";
|
|
@@ -18,23 +17,48 @@ import { BORSH_ENCODING, Entry } from "@peerbit/log";
|
|
|
18
17
|
import { logger as loggerFn } from "@peerbit/logger";
|
|
19
18
|
import { ClosedError, Program } from "@peerbit/program";
|
|
20
19
|
import { MissingResponsesError, RPC, queryAll, } from "@peerbit/rpc";
|
|
21
|
-
import {
|
|
20
|
+
import { SharedLog } from "@peerbit/shared-log";
|
|
22
21
|
import { SilentDelivery } from "@peerbit/stream-interface";
|
|
23
|
-
import { AbortError } from "@peerbit/time";
|
|
22
|
+
import { AbortError, waitFor } from "@peerbit/time";
|
|
24
23
|
import { concat, fromString } from "uint8arrays";
|
|
25
24
|
import { copySerialization } from "./borsh.js";
|
|
26
25
|
import { MAX_BATCH_SIZE } from "./constants.js";
|
|
27
26
|
import { isPutOperation } from "./operation.js";
|
|
28
27
|
import { ResumableIterators } from "./resumable-iterator.js";
|
|
29
28
|
const logger = loggerFn({ module: "document-index" });
|
|
30
|
-
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) => {
|
|
31
53
|
const results = [];
|
|
32
54
|
for (const response of responses) {
|
|
33
55
|
if (!response.from) {
|
|
34
56
|
logger.error("Missing from for response");
|
|
35
57
|
}
|
|
36
58
|
if (response.response instanceof types.Results) {
|
|
37
|
-
response.response.results.forEach((r) => r.
|
|
59
|
+
response.response.results.forEach((r) => r instanceof types.ResultValue
|
|
60
|
+
? r.init(documentType)
|
|
61
|
+
: r.init(indexedType));
|
|
38
62
|
if (typeof options?.remote !== "boolean" && options?.remote?.replicate) {
|
|
39
63
|
await sync(queryRequest, response.response);
|
|
40
64
|
}
|
|
@@ -124,6 +148,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
124
148
|
transformer;
|
|
125
149
|
// The indexed document wrapped in a context
|
|
126
150
|
wrappedIndexedType;
|
|
151
|
+
indexedType;
|
|
127
152
|
// The database type, for recursive indexing
|
|
128
153
|
dbType;
|
|
129
154
|
indexedTypeIsDocumentType;
|
|
@@ -132,7 +157,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
132
157
|
indexByResolver;
|
|
133
158
|
index;
|
|
134
159
|
_resumableIterators;
|
|
135
|
-
|
|
160
|
+
compatibility;
|
|
136
161
|
// Transformation, indexer
|
|
137
162
|
/* fields: IndexableFields<T, I>; */
|
|
138
163
|
_valueEncoding;
|
|
@@ -155,7 +180,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
155
180
|
this.indexedTypeIsDocumentType =
|
|
156
181
|
!properties.transform?.type ||
|
|
157
182
|
properties.transform?.type === properties.documentType;
|
|
158
|
-
this.
|
|
183
|
+
this.compatibility = properties.compatibility;
|
|
159
184
|
let IndexedClassWithContext = class IndexedClassWithContext {
|
|
160
185
|
__context;
|
|
161
186
|
constructor(value, context) {
|
|
@@ -172,13 +197,62 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
172
197
|
__metadata("design:paramtypes", [Object, IndexableContext])
|
|
173
198
|
], IndexedClassWithContext);
|
|
174
199
|
// copy all prototype values from indexedType to IndexedClassWithContext
|
|
175
|
-
|
|
200
|
+
this.indexedType = (properties.transform?.type || properties.documentType);
|
|
201
|
+
copySerialization(this.indexedType, IndexedClassWithContext);
|
|
176
202
|
this.wrappedIndexedType = IndexedClassWithContext;
|
|
177
203
|
// if this.type is a class that extends Program we want to do special functionality
|
|
178
204
|
this._isProgramValues = this.documentType instanceof Program;
|
|
179
205
|
this.dbType = properties.dbType;
|
|
180
206
|
this._resultQueue = new Map();
|
|
181
|
-
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
|
+
};
|
|
182
256
|
const transformOptions = properties.transform;
|
|
183
257
|
this.transformer = transformOptions
|
|
184
258
|
? isTransformerWithFunction(transformOptions)
|
|
@@ -226,22 +300,6 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
226
300
|
const results = await this.processQuery(query, ctx.from, false, {
|
|
227
301
|
canRead: properties.canRead,
|
|
228
302
|
});
|
|
229
|
-
if (this.emitBlocksEagerly) {
|
|
230
|
-
await Promise.all(results.results.map(async (x) => {
|
|
231
|
-
const hash = x.context.head;
|
|
232
|
-
const block = await this._log.log.blocks.get(hash);
|
|
233
|
-
if (!block) {
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
// todo dont do bytes -> entry -> bytes, but send the block directly
|
|
237
|
-
return this._log.rpc.send(new BlocksMessage(new BlockResponse(hash, block)), {
|
|
238
|
-
mode: new SilentDelivery({
|
|
239
|
-
to: [ctx.from],
|
|
240
|
-
redundancy: 1,
|
|
241
|
-
}),
|
|
242
|
-
});
|
|
243
|
-
}));
|
|
244
|
-
}
|
|
245
303
|
return new types.Results({
|
|
246
304
|
// Even if results might have length 0, respond, because then we now at least there are no matching results
|
|
247
305
|
results: results.results,
|
|
@@ -320,8 +378,12 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
320
378
|
}
|
|
321
379
|
async getDetailed(key, options) {
|
|
322
380
|
let results;
|
|
381
|
+
const resolve = options?.resolve || options?.resolve == null;
|
|
382
|
+
let requestClazz = resolve
|
|
383
|
+
? types.SearchRequest
|
|
384
|
+
: types.SearchRequestIndexed;
|
|
323
385
|
if (key instanceof Uint8Array) {
|
|
324
|
-
results = await this.
|
|
386
|
+
results = await this.queryCommence(new requestClazz({
|
|
325
387
|
query: [
|
|
326
388
|
new indexerTypes.ByteMatchQuery({ key: this.indexBy, value: key }),
|
|
327
389
|
],
|
|
@@ -331,7 +393,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
331
393
|
const indexableKey = indexerTypes.toIdeable(key);
|
|
332
394
|
if (typeof indexableKey === "number" ||
|
|
333
395
|
typeof indexableKey === "bigint") {
|
|
334
|
-
results = await this.
|
|
396
|
+
results = await this.queryCommence(new requestClazz({
|
|
335
397
|
query: [
|
|
336
398
|
new indexerTypes.IntegerCompare({
|
|
337
399
|
key: this.indexBy,
|
|
@@ -342,7 +404,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
342
404
|
}), options);
|
|
343
405
|
}
|
|
344
406
|
else if (typeof indexableKey === "string") {
|
|
345
|
-
results = await this.
|
|
407
|
+
results = await this.queryCommence(new requestClazz({
|
|
346
408
|
query: [
|
|
347
409
|
new indexerTypes.StringMatch({
|
|
348
410
|
key: this.indexBy,
|
|
@@ -352,7 +414,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
352
414
|
}), options);
|
|
353
415
|
}
|
|
354
416
|
else if (indexableKey instanceof Uint8Array) {
|
|
355
|
-
results = await this.
|
|
417
|
+
results = await this.queryCommence(new requestClazz({
|
|
356
418
|
query: [
|
|
357
419
|
new indexerTypes.ByteMatchQuery({
|
|
358
420
|
key: this.indexBy,
|
|
@@ -362,24 +424,48 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
362
424
|
}), options);
|
|
363
425
|
}
|
|
364
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
|
+
}
|
|
365
450
|
return results;
|
|
366
451
|
}
|
|
367
452
|
getSize() {
|
|
368
453
|
return this.index.getSize();
|
|
369
454
|
}
|
|
370
455
|
async resolveDocument(value) {
|
|
371
|
-
const
|
|
372
|
-
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);
|
|
373
459
|
if (cached != null) {
|
|
374
460
|
return { value: cached };
|
|
375
461
|
}
|
|
376
462
|
if (this.indexedTypeIsDocumentType) {
|
|
377
463
|
// cast value to T, i.e. convert the class but keep all properties except the __context
|
|
378
|
-
const obj = Object.assign(Object.create(this.documentType.prototype), value.
|
|
464
|
+
const obj = Object.assign(Object.create(this.documentType.prototype), value.indexed);
|
|
379
465
|
delete obj.__context;
|
|
380
466
|
return { value: obj };
|
|
381
467
|
}
|
|
382
|
-
const head = await this._log.log.get(value.
|
|
468
|
+
const head = await this._log.log.get(value.head);
|
|
383
469
|
if (!head) {
|
|
384
470
|
return undefined; // we could end up here if we recently pruned the document and other peers never persisted the entry
|
|
385
471
|
// TODO update changes in index before removing entries from log entry storage
|
|
@@ -403,10 +489,14 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
403
489
|
throw new Error("Different from in queued results");
|
|
404
490
|
}
|
|
405
491
|
let indexedResult = undefined;
|
|
406
|
-
|
|
492
|
+
let fromQuery;
|
|
493
|
+
if (query instanceof types.SearchRequest ||
|
|
494
|
+
query instanceof types.SearchRequestIndexed) {
|
|
495
|
+
fromQuery = query;
|
|
407
496
|
indexedResult = await this._resumableIterators.iterateAndFetch(query);
|
|
408
497
|
}
|
|
409
498
|
else if (query instanceof types.CollectNextRequest) {
|
|
499
|
+
fromQuery = this._resumableIterators.queues.get(query.idString)?.request;
|
|
410
500
|
indexedResult =
|
|
411
501
|
prevQueued?.keptInIndex === 0
|
|
412
502
|
? []
|
|
@@ -415,7 +505,6 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
415
505
|
else {
|
|
416
506
|
throw new Error("Unsupported");
|
|
417
507
|
}
|
|
418
|
-
const filteredResults = [];
|
|
419
508
|
let resultSize = 0;
|
|
420
509
|
let toIterate = prevQueued
|
|
421
510
|
? [...prevQueued.queue, ...indexedResult]
|
|
@@ -437,6 +526,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
437
526
|
};
|
|
438
527
|
this._resultQueue.set(query.idString, prevQueued);
|
|
439
528
|
}
|
|
529
|
+
const filteredResults = [];
|
|
440
530
|
for (const result of toIterate) {
|
|
441
531
|
if (!isLocal) {
|
|
442
532
|
resultSize += result.value.__context.size;
|
|
@@ -445,17 +535,40 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
445
535
|
continue;
|
|
446
536
|
}
|
|
447
537
|
}
|
|
448
|
-
const
|
|
449
|
-
if (
|
|
450
|
-
|
|
538
|
+
const indexedUnwrapped = Object.assign(Object.create(this.indexedType.prototype), result.value);
|
|
539
|
+
if (options?.canRead &&
|
|
540
|
+
!(await options.canRead(indexedUnwrapped, from))) {
|
|
451
541
|
continue;
|
|
452
542
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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
|
+
}
|
|
459
572
|
}
|
|
460
573
|
const results = new types.Results({
|
|
461
574
|
results: filteredResults,
|
|
@@ -495,7 +608,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
495
608
|
* @param options
|
|
496
609
|
* @returns
|
|
497
610
|
*/
|
|
498
|
-
async
|
|
611
|
+
async queryCommence(queryRequest, options) {
|
|
499
612
|
const local = typeof options?.local === "boolean" ? options?.local : true;
|
|
500
613
|
let remote = undefined;
|
|
501
614
|
if (typeof options?.remote === "boolean") {
|
|
@@ -536,7 +649,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
536
649
|
if (replicatorGroups) {
|
|
537
650
|
const groupHashes = replicatorGroups.map((x) => [x]);
|
|
538
651
|
const responseHandler = async (results) => {
|
|
539
|
-
|
|
652
|
+
const resultInitialized = await introduceEntries(queryRequest, results, this.documentType, this.indexedType, this._sync, options);
|
|
653
|
+
for (const r of resultInitialized) {
|
|
540
654
|
resolved.push(r.response);
|
|
541
655
|
}
|
|
542
656
|
};
|
|
@@ -583,7 +697,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
583
697
|
}
|
|
584
698
|
}
|
|
585
699
|
}
|
|
586
|
-
return allResults;
|
|
700
|
+
return allResults; // TODO types
|
|
587
701
|
}
|
|
588
702
|
/**
|
|
589
703
|
* Query and retrieve results
|
|
@@ -593,19 +707,21 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
593
707
|
*/
|
|
594
708
|
async search(queryRequest, options) {
|
|
595
709
|
// Set fetch to search size, or max value (default to max u32 (4294967295))
|
|
596
|
-
|
|
710
|
+
const coercedRequest = coerceQuery(queryRequest, options);
|
|
711
|
+
coercedRequest.fetch = coercedRequest.fetch ?? 0xffffffff;
|
|
597
712
|
// So that the iterator is pre-fetching the right amount of entries
|
|
598
|
-
const iterator = this.iterate(
|
|
713
|
+
const iterator = this.iterate(coercedRequest, options);
|
|
599
714
|
// So that this call will not do any remote requests
|
|
600
715
|
const allResults = [];
|
|
601
|
-
while (iterator.done() !== true &&
|
|
716
|
+
while (iterator.done() !== true &&
|
|
717
|
+
coercedRequest.fetch > allResults.length) {
|
|
602
718
|
// We might need to pull .next multiple time due to data message size limitations
|
|
603
|
-
for (const result of await iterator.next(
|
|
719
|
+
for (const result of await iterator.next(coercedRequest.fetch - allResults.length)) {
|
|
604
720
|
allResults.push(result);
|
|
605
721
|
}
|
|
606
722
|
}
|
|
607
723
|
await iterator.close();
|
|
608
|
-
//
|
|
724
|
+
// Deduplicate and return values directly
|
|
609
725
|
return dedup(allResults, this.indexByResolver);
|
|
610
726
|
}
|
|
611
727
|
/**
|
|
@@ -615,6 +731,30 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
615
731
|
* @returns
|
|
616
732
|
*/
|
|
617
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
|
+
}
|
|
618
758
|
let fetchPromise = undefined;
|
|
619
759
|
const peerBufferMap = new Map();
|
|
620
760
|
const visited = new Set();
|
|
@@ -627,8 +767,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
627
767
|
};
|
|
628
768
|
const fetchFirst = async (n) => {
|
|
629
769
|
done = true; // Assume we are donne
|
|
630
|
-
|
|
631
|
-
await this.
|
|
770
|
+
queryRequestCoerced.fetch = n;
|
|
771
|
+
await this.queryCommence(queryRequestCoerced, {
|
|
632
772
|
...options,
|
|
633
773
|
onResponse: async (response, from) => {
|
|
634
774
|
if (!from) {
|
|
@@ -649,18 +789,33 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
649
789
|
}
|
|
650
790
|
const buffer = [];
|
|
651
791
|
for (const result of results.results) {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
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
|
+
});
|
|
655
818
|
}
|
|
656
|
-
visited.add(indexKey);
|
|
657
|
-
buffer.push({
|
|
658
|
-
value: result.value,
|
|
659
|
-
context: result.context,
|
|
660
|
-
from,
|
|
661
|
-
indexed: result.indexed ||
|
|
662
|
-
(await this.transformer(result.value, result.context)),
|
|
663
|
-
});
|
|
664
819
|
}
|
|
665
820
|
peerBufferMap.set(from.hashcode(), {
|
|
666
821
|
buffer,
|
|
@@ -673,7 +828,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
673
828
|
},
|
|
674
829
|
});
|
|
675
830
|
if (done) {
|
|
676
|
-
this.clearResultsQueue(
|
|
831
|
+
this.clearResultsQueue(queryRequestCoerced);
|
|
677
832
|
}
|
|
678
833
|
return done;
|
|
679
834
|
};
|
|
@@ -703,7 +858,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
703
858
|
// TODO buffer more than deleted?
|
|
704
859
|
// TODO batch to multiple 'to's
|
|
705
860
|
const collectRequest = new types.CollectNextRequest({
|
|
706
|
-
id:
|
|
861
|
+
id: queryRequestCoerced.id,
|
|
707
862
|
amount: n - buffer.buffer.length,
|
|
708
863
|
});
|
|
709
864
|
// Fetch locally?
|
|
@@ -753,11 +908,12 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
753
908
|
priority: 1,
|
|
754
909
|
mode: new SilentDelivery({ to: [peer], redundancy: 1 }),
|
|
755
910
|
})
|
|
756
|
-
.then((response) => introduceEntries(
|
|
757
|
-
.then((responses) => {
|
|
758
|
-
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) => {
|
|
759
914
|
resultsLeft += Number(response.response.kept);
|
|
760
|
-
|
|
915
|
+
const from = responses[i].from;
|
|
916
|
+
if (!from) {
|
|
761
917
|
logger.error("Missing from for sorted query");
|
|
762
918
|
return;
|
|
763
919
|
}
|
|
@@ -773,19 +929,20 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
773
929
|
}
|
|
774
930
|
peerBuffer.kept = Number(response.response.kept);
|
|
775
931
|
for (const result of response.response.results) {
|
|
776
|
-
|
|
932
|
+
const idPrimitive = indexerTypes.toId(this.indexByResolver(result.value)).primitive;
|
|
933
|
+
if (visited.has(idPrimitive)) {
|
|
777
934
|
continue;
|
|
778
935
|
}
|
|
779
|
-
visited.add(
|
|
936
|
+
visited.add(idPrimitive);
|
|
780
937
|
peerBuffer.buffer.push({
|
|
781
938
|
value: result.value,
|
|
782
939
|
context: result.context,
|
|
783
|
-
from:
|
|
784
|
-
indexed: this.transformer(result.value, result.context),
|
|
940
|
+
from: from,
|
|
941
|
+
indexed: await this.transformer(result.value, result.context),
|
|
785
942
|
});
|
|
786
943
|
}
|
|
787
944
|
}
|
|
788
|
-
});
|
|
945
|
+
}));
|
|
789
946
|
})
|
|
790
947
|
.catch((e) => {
|
|
791
948
|
logger.error("Failed to collect sorted results from: " +
|
|
@@ -815,7 +972,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
815
972
|
const fetchedAll = await fetchAtLeast(n);
|
|
816
973
|
// get n next top entries, shift and pull more results
|
|
817
974
|
const peerBuffersArr = peerBuffers();
|
|
818
|
-
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));
|
|
819
976
|
const pendingMoreResults = n < results.length;
|
|
820
977
|
const batch = results.splice(0, n);
|
|
821
978
|
for (const result of batch) {
|
|
@@ -830,12 +987,24 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
830
987
|
}
|
|
831
988
|
}
|
|
832
989
|
done = fetchedAll && !pendingMoreResults;
|
|
833
|
-
|
|
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);
|
|
834
1003
|
};
|
|
835
1004
|
const close = async () => {
|
|
836
1005
|
controller.abort(new AbortError("Iterator closed"));
|
|
837
1006
|
const closeRequest = new types.CloseIteratorRequest({
|
|
838
|
-
id:
|
|
1007
|
+
id: queryRequestCoerced.id,
|
|
839
1008
|
});
|
|
840
1009
|
const promises = [];
|
|
841
1010
|
for (const [peer, buffer] of peerBufferMap) {
|
|
@@ -872,6 +1041,19 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
872
1041
|
},
|
|
873
1042
|
};
|
|
874
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
|
+
}
|
|
875
1057
|
};
|
|
876
1058
|
__decorate([
|
|
877
1059
|
field({ type: RPC }),
|