@peerbit/document 6.0.7-aa577a5 → 6.0.7-cccc078
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/index.js +13 -14
- package/dist/benchmark/index.js.map +1 -1
- package/dist/benchmark/memory/index.d.ts +2 -0
- package/dist/benchmark/memory/index.d.ts.map +1 -0
- package/dist/benchmark/memory/index.js +122 -0
- package/dist/benchmark/memory/index.js.map +1 -0
- package/dist/benchmark/memory/insert.d.ts +2 -0
- package/dist/benchmark/memory/insert.d.ts.map +1 -0
- package/dist/benchmark/memory/insert.js +133 -0
- package/dist/benchmark/memory/insert.js.map +1 -0
- package/dist/benchmark/memory/utils.d.ts +13 -0
- package/dist/benchmark/memory/utils.d.ts.map +1 -0
- package/dist/benchmark/memory/utils.js +2 -0
- package/dist/benchmark/memory/utils.js.map +1 -0
- package/dist/benchmark/replication.js +27 -29
- package/dist/benchmark/replication.js.map +1 -1
- package/dist/src/borsh.d.ts +2 -0
- package/dist/src/borsh.d.ts.map +1 -0
- package/dist/src/borsh.js +16 -0
- package/dist/src/borsh.js.map +1 -0
- package/dist/src/index.d.ts +0 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/program.d.ts +16 -19
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +57 -68
- package/dist/src/program.js.map +1 -1
- package/dist/src/search.d.ts +46 -32
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +236 -133
- package/dist/src/search.js.map +1 -1
- package/package.json +16 -11
- package/src/borsh.ts +19 -0
- package/src/index.ts +0 -1
- package/src/program.ts +118 -118
- package/src/search.ts +438 -218
package/dist/src/search.js
CHANGED
|
@@ -8,18 +8,20 @@ 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 {
|
|
12
|
-
import {
|
|
11
|
+
import { Cache } from "@peerbit/cache";
|
|
12
|
+
import { PublicSignKey, sha256Base64Sync, } from "@peerbit/crypto";
|
|
13
13
|
import * as types from "@peerbit/document-interface";
|
|
14
|
-
import
|
|
14
|
+
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
15
|
+
import { HashmapIndex } from "@peerbit/indexer-simple";
|
|
16
|
+
import { BORSH_ENCODING, Entry } from "@peerbit/log";
|
|
15
17
|
import { logger as loggerFn } from "@peerbit/logger";
|
|
16
|
-
import {
|
|
18
|
+
import { Program } from "@peerbit/program";
|
|
19
|
+
import { MissingResponsesError, RPC, queryAll, } from "@peerbit/rpc";
|
|
17
20
|
import { SharedLog } from "@peerbit/shared-log";
|
|
18
|
-
import { concat, fromString } from "uint8arrays";
|
|
19
21
|
import { SilentDelivery } from "@peerbit/stream-interface";
|
|
20
22
|
import { AbortError } from "@peerbit/time";
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
+
import { concat, fromString } from "uint8arrays";
|
|
24
|
+
import { copySerialization } from "./borsh.js";
|
|
23
25
|
import { MAX_BATCH_SIZE } from "./constants.js";
|
|
24
26
|
const logger = loggerFn({ module: "document-index" });
|
|
25
27
|
let Operation = class Operation /* <T> */ {
|
|
@@ -37,10 +39,7 @@ let PutOperation = class PutOperation extends Operation /* <T> */ {
|
|
|
37
39
|
/* _value?: T; */
|
|
38
40
|
constructor(props) {
|
|
39
41
|
super();
|
|
40
|
-
|
|
41
|
-
this.data = props.data;
|
|
42
|
-
/* this._value = props.value; */
|
|
43
|
-
}
|
|
42
|
+
this.data = props.data;
|
|
44
43
|
}
|
|
45
44
|
};
|
|
46
45
|
__decorate([
|
|
@@ -76,8 +75,8 @@ let DeleteOperation = class DeleteOperation extends Operation {
|
|
|
76
75
|
}
|
|
77
76
|
};
|
|
78
77
|
__decorate([
|
|
79
|
-
field({ type:
|
|
80
|
-
__metadata("design:type",
|
|
78
|
+
field({ type: indexerTypes.IdKey }),
|
|
79
|
+
__metadata("design:type", indexerTypes.IdKey)
|
|
81
80
|
], DeleteOperation.prototype, "key", void 0);
|
|
82
81
|
DeleteOperation = __decorate([
|
|
83
82
|
variant(2),
|
|
@@ -112,33 +111,44 @@ const dedup = (allResult, dedupBy) => {
|
|
|
112
111
|
const unique = new Set();
|
|
113
112
|
const dedup = [];
|
|
114
113
|
for (const result of allResult) {
|
|
115
|
-
const key =
|
|
116
|
-
|
|
114
|
+
const key = indexerTypes.toId(dedupBy(result));
|
|
115
|
+
const primitive = key.primitive;
|
|
116
|
+
if (unique.has(primitive)) {
|
|
117
117
|
continue;
|
|
118
118
|
}
|
|
119
|
-
unique.add(
|
|
119
|
+
unique.add(primitive);
|
|
120
120
|
dedup.push(result);
|
|
121
121
|
}
|
|
122
122
|
return dedup;
|
|
123
123
|
};
|
|
124
124
|
const DEFAULT_INDEX_BY = "id";
|
|
125
|
+
const isTransformerWithFunction = (options) => {
|
|
126
|
+
return options.transform != null;
|
|
127
|
+
};
|
|
125
128
|
let DocumentIndex = class DocumentIndex extends Program {
|
|
126
129
|
_query;
|
|
127
|
-
|
|
128
|
-
|
|
130
|
+
// Original document representation
|
|
131
|
+
documentType;
|
|
132
|
+
// transform options
|
|
133
|
+
transformer;
|
|
134
|
+
// The indexed document wrapped in a context
|
|
135
|
+
wrappedIndexedType;
|
|
136
|
+
// The database type, for recursive indexing
|
|
129
137
|
dbType;
|
|
138
|
+
indexedTypeIsDocumentType;
|
|
130
139
|
// Index key
|
|
131
140
|
indexBy;
|
|
132
|
-
indexByArr;
|
|
133
141
|
indexByResolver;
|
|
142
|
+
index;
|
|
134
143
|
// Transformation, indexer
|
|
135
|
-
fields
|
|
144
|
+
/* fields: IndexableFields<T, I>; */
|
|
136
145
|
_valueEncoding;
|
|
137
146
|
_sync;
|
|
138
147
|
_log;
|
|
139
148
|
_resolverProgramCache;
|
|
140
149
|
_resolverCache;
|
|
141
150
|
_isProgramValues;
|
|
151
|
+
_resultQueue;
|
|
142
152
|
constructor(properties) {
|
|
143
153
|
super();
|
|
144
154
|
this._query = properties?.query || new RPC();
|
|
@@ -148,35 +158,55 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
148
158
|
}
|
|
149
159
|
async open(properties) {
|
|
150
160
|
this._log = properties.log;
|
|
151
|
-
this.
|
|
161
|
+
this.documentType = properties.documentType;
|
|
162
|
+
this.indexedTypeIsDocumentType =
|
|
163
|
+
!properties.transform?.type ||
|
|
164
|
+
properties.transform?.type === properties.documentType;
|
|
165
|
+
class IndexedClassWithContex {
|
|
166
|
+
__context;
|
|
167
|
+
constructor(value, context) {
|
|
168
|
+
Object.assign(this, value);
|
|
169
|
+
this.__context = context;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
__decorate([
|
|
173
|
+
field({ type: types.Context }),
|
|
174
|
+
__metadata("design:type", types.Context)
|
|
175
|
+
], IndexedClassWithContex.prototype, "__context", void 0);
|
|
176
|
+
// copy all prototype values from indexedType to IndexedClassWithContex
|
|
177
|
+
copySerialization((properties.transform?.type || properties.documentType), IndexedClassWithContex);
|
|
178
|
+
this.wrappedIndexedType = IndexedClassWithContex;
|
|
152
179
|
// if this.type is a class that extends Program we want to do special functionality
|
|
153
|
-
this._isProgramValues = this.
|
|
180
|
+
this._isProgramValues = this.documentType instanceof Program;
|
|
154
181
|
this.dbType = properties.dbType;
|
|
182
|
+
this._resultQueue = new Map();
|
|
155
183
|
this._sync = properties.sync;
|
|
156
|
-
|
|
157
|
-
this.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
this.
|
|
184
|
+
const transformOptions = properties.transform;
|
|
185
|
+
this.transformer = transformOptions
|
|
186
|
+
? isTransformerWithFunction(transformOptions)
|
|
187
|
+
? (obj, context) => transformOptions.transform(obj, context)
|
|
188
|
+
: transformOptions.type
|
|
189
|
+
? (obj, context) => new transformOptions.type(obj, context)
|
|
190
|
+
: (obj) => obj
|
|
191
|
+
: (obj) => obj; // TODO types
|
|
192
|
+
const maybeArr = properties.indexBy || DEFAULT_INDEX_BY;
|
|
193
|
+
this.indexBy = Array.isArray(maybeArr) ? maybeArr : [maybeArr];
|
|
194
|
+
this.indexByResolver = (obj) => indexerTypes.extractFieldValue(obj, this.indexBy);
|
|
195
|
+
this._valueEncoding = BORSH_ENCODING(this.documentType);
|
|
166
196
|
if (this._isProgramValues) {
|
|
167
197
|
this._resolverProgramCache = new Map();
|
|
168
198
|
}
|
|
169
|
-
this._resolverCache = new Cache({ max:
|
|
170
|
-
this.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
199
|
+
this._resolverCache = new Cache({ max: 10 }); // TODO choose limit better (adaptive)
|
|
200
|
+
this.index =
|
|
201
|
+
(await (await this.node.indexer.scope(sha256Base64Sync(concat([this._log.log.id, fromString("/document-index")])))).init({
|
|
202
|
+
indexBy: this.indexBy,
|
|
203
|
+
schema: this.wrappedIndexedType,
|
|
204
|
+
nested: {
|
|
205
|
+
match: (obj) => obj instanceof this.dbType,
|
|
206
|
+
query: async (obj, query) => obj.index.search(query),
|
|
207
|
+
},
|
|
208
|
+
/* maxBatchSize: MAX_BATCH_SIZE */
|
|
209
|
+
})) || new HashmapIndex();
|
|
180
210
|
await this._query.open({
|
|
181
211
|
topic: sha256Base64Sync(concat([this._log.log.id, fromString("/document")])),
|
|
182
212
|
responseHandler: async (query, ctx) => {
|
|
@@ -185,45 +215,53 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
185
215
|
return;
|
|
186
216
|
}
|
|
187
217
|
if (properties.canSearch &&
|
|
188
|
-
(query instanceof
|
|
189
|
-
query instanceof
|
|
218
|
+
(query instanceof indexerTypes.SearchRequest ||
|
|
219
|
+
query instanceof indexerTypes.CollectNextRequest) &&
|
|
190
220
|
!(await properties.canSearch(query, ctx.from))) {
|
|
191
221
|
return new types.NoAccess();
|
|
192
222
|
}
|
|
193
|
-
if (query instanceof
|
|
223
|
+
if (query instanceof indexerTypes.CloseIteratorRequest) {
|
|
194
224
|
this.processCloseIteratorRequest(query, ctx.from);
|
|
195
225
|
}
|
|
196
226
|
else {
|
|
197
|
-
const results = await this.processQuery(query, ctx.from, {
|
|
198
|
-
canRead: properties.canRead
|
|
227
|
+
const results = await this.processQuery(query, ctx.from, false, {
|
|
228
|
+
canRead: properties.canRead,
|
|
199
229
|
});
|
|
200
230
|
return new types.Results({
|
|
201
231
|
// Even if results might have length 0, respond, because then we now at least there are no matching results
|
|
202
232
|
results: results.results,
|
|
203
|
-
kept: results.kept
|
|
233
|
+
kept: results.kept,
|
|
204
234
|
});
|
|
205
235
|
}
|
|
206
236
|
},
|
|
207
237
|
responseType: types.AbstractSearchResult,
|
|
208
|
-
queryType:
|
|
238
|
+
queryType: indexerTypes.AbstractSearchRequest,
|
|
209
239
|
});
|
|
210
240
|
}
|
|
241
|
+
getPending(cursorId) {
|
|
242
|
+
const queue = this._resultQueue.get(cursorId);
|
|
243
|
+
if (queue) {
|
|
244
|
+
return queue.queue.length + queue.keptInIndex;
|
|
245
|
+
}
|
|
246
|
+
return this.index.getPending(cursorId);
|
|
247
|
+
}
|
|
211
248
|
async close(from) {
|
|
212
249
|
const closed = await super.close(from);
|
|
213
250
|
if (closed) {
|
|
214
|
-
await this.
|
|
251
|
+
await this.index.stop?.();
|
|
215
252
|
}
|
|
216
253
|
return closed;
|
|
217
254
|
}
|
|
218
255
|
async drop(from) {
|
|
219
|
-
const
|
|
220
|
-
if (
|
|
221
|
-
await this.
|
|
256
|
+
const dropped = await super.drop(from);
|
|
257
|
+
if (dropped) {
|
|
258
|
+
await this.index.drop?.();
|
|
259
|
+
await this.index.stop?.();
|
|
222
260
|
}
|
|
223
|
-
return
|
|
261
|
+
return dropped;
|
|
224
262
|
}
|
|
225
263
|
async get(key, options) {
|
|
226
|
-
return (await this.getDetailed(key instanceof
|
|
264
|
+
return (await this.getDetailed(key instanceof indexerTypes.IdKey ? key : indexerTypes.toId(key), options))?.[0]?.results[0]?.value;
|
|
227
265
|
}
|
|
228
266
|
async put(value, entry, id) {
|
|
229
267
|
const idString = id.primitive;
|
|
@@ -233,73 +271,78 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
233
271
|
else {
|
|
234
272
|
this._resolverCache.add(idString, value);
|
|
235
273
|
}
|
|
274
|
+
const existing = await this.index.get(id);
|
|
236
275
|
const context = new types.Context({
|
|
237
|
-
created:
|
|
276
|
+
created: existing?.value.__context.created ||
|
|
238
277
|
entry.meta.clock.timestamp.wallTime,
|
|
239
278
|
modified: entry.meta.clock.timestamp.wallTime,
|
|
240
279
|
head: entry.hash,
|
|
241
|
-
gid: entry.gid
|
|
242
|
-
|
|
243
|
-
const valueToIndex = await this.fields(value, context);
|
|
244
|
-
this.engine.put({
|
|
245
|
-
id,
|
|
246
|
-
indexed: valueToIndex,
|
|
247
|
-
context,
|
|
248
|
-
size: entry.payload.data.byteLength
|
|
249
|
-
/* reference:
|
|
250
|
-
valueToIndex === value || value instanceof Program
|
|
251
|
-
? { value }
|
|
252
|
-
: undefined */
|
|
280
|
+
gid: entry.gid,
|
|
281
|
+
size: entry.payloadByteLength,
|
|
253
282
|
});
|
|
283
|
+
const valueToIndex = await this.transformer(value, context);
|
|
284
|
+
const wrappedValueToIndex = new this.wrappedIndexedType(valueToIndex, context);
|
|
285
|
+
await this.index.put(wrappedValueToIndex);
|
|
254
286
|
}
|
|
255
287
|
del(key) {
|
|
256
|
-
const keyObject = types.toId(key);
|
|
257
288
|
if (this._isProgramValues) {
|
|
258
|
-
this._resolverProgramCache.delete(key);
|
|
289
|
+
this._resolverProgramCache.delete(key.primitive);
|
|
259
290
|
}
|
|
260
291
|
else {
|
|
261
|
-
this._resolverCache.del(key);
|
|
292
|
+
this._resolverCache.del(key.primitive);
|
|
262
293
|
}
|
|
263
|
-
return this.
|
|
294
|
+
return this.index.del(new indexerTypes.DeleteRequest({
|
|
295
|
+
query: [indexerTypes.getMatcher(this.indexBy, key.key)],
|
|
296
|
+
}));
|
|
264
297
|
}
|
|
265
298
|
async getDetailed(key, options) {
|
|
266
299
|
let results;
|
|
267
300
|
if (key instanceof Uint8Array) {
|
|
268
|
-
results = await this.queryDetailed(new
|
|
301
|
+
results = await this.queryDetailed(new indexerTypes.SearchRequest({
|
|
269
302
|
query: [
|
|
270
|
-
new
|
|
271
|
-
]
|
|
303
|
+
new indexerTypes.ByteMatchQuery({ key: this.indexBy, value: key }),
|
|
304
|
+
],
|
|
272
305
|
}), options);
|
|
273
306
|
}
|
|
274
307
|
else {
|
|
275
|
-
const indexableKey =
|
|
308
|
+
const indexableKey = indexerTypes.toIdeable(key);
|
|
276
309
|
if (typeof indexableKey === "number" ||
|
|
277
310
|
typeof indexableKey === "bigint") {
|
|
278
|
-
results = await this.queryDetailed(new
|
|
311
|
+
results = await this.queryDetailed(new indexerTypes.SearchRequest({
|
|
279
312
|
query: [
|
|
280
|
-
new
|
|
281
|
-
key: this.
|
|
282
|
-
compare:
|
|
283
|
-
value: indexableKey
|
|
284
|
-
})
|
|
285
|
-
]
|
|
313
|
+
new indexerTypes.IntegerCompare({
|
|
314
|
+
key: this.indexBy,
|
|
315
|
+
compare: indexerTypes.Compare.Equal,
|
|
316
|
+
value: indexableKey,
|
|
317
|
+
}),
|
|
318
|
+
],
|
|
286
319
|
}), options);
|
|
287
320
|
}
|
|
288
|
-
else {
|
|
289
|
-
results = await this.queryDetailed(new
|
|
321
|
+
else if (typeof indexableKey === "string") {
|
|
322
|
+
results = await this.queryDetailed(new indexerTypes.SearchRequest({
|
|
290
323
|
query: [
|
|
291
|
-
new
|
|
292
|
-
key: this.
|
|
293
|
-
value: indexableKey
|
|
294
|
-
})
|
|
295
|
-
]
|
|
324
|
+
new indexerTypes.StringMatch({
|
|
325
|
+
key: this.indexBy,
|
|
326
|
+
value: indexableKey,
|
|
327
|
+
}),
|
|
328
|
+
],
|
|
329
|
+
}), options);
|
|
330
|
+
}
|
|
331
|
+
else if (indexableKey instanceof Uint8Array) {
|
|
332
|
+
results = await this.queryDetailed(new indexerTypes.SearchRequest({
|
|
333
|
+
query: [
|
|
334
|
+
new indexerTypes.ByteMatchQuery({
|
|
335
|
+
key: this.indexBy,
|
|
336
|
+
value: indexableKey,
|
|
337
|
+
}),
|
|
338
|
+
],
|
|
296
339
|
}), options);
|
|
297
340
|
}
|
|
298
341
|
}
|
|
299
342
|
return results;
|
|
300
343
|
}
|
|
301
344
|
getSize() {
|
|
302
|
-
return this.
|
|
345
|
+
return this.index.getSize();
|
|
303
346
|
}
|
|
304
347
|
async resolveDocument(value) {
|
|
305
348
|
const cached = this._resolverCache.get(value.id.primitive) ||
|
|
@@ -307,10 +350,13 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
307
350
|
if (cached != null) {
|
|
308
351
|
return { value: cached };
|
|
309
352
|
}
|
|
310
|
-
if (
|
|
311
|
-
|
|
353
|
+
if (this.indexedTypeIsDocumentType) {
|
|
354
|
+
// cast value to T, i.e. convert the class but keep all properties except the __context
|
|
355
|
+
const obj = Object.assign(Object.create(this.documentType.prototype), value.value);
|
|
356
|
+
delete obj.__context;
|
|
357
|
+
return { value: obj };
|
|
312
358
|
}
|
|
313
|
-
const head = await
|
|
359
|
+
const head = await this._log.log.get(value.value.__context.head);
|
|
314
360
|
if (!head) {
|
|
315
361
|
return undefined; // we could end up here if we recently pruned the document and other peers never persisted the entry
|
|
316
362
|
// TODO update changes in index before removing entries from log entry storage
|
|
@@ -318,47 +364,98 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
318
364
|
const payloadValue = await head.getPayloadValue();
|
|
319
365
|
if (payloadValue instanceof PutOperation) {
|
|
320
366
|
return {
|
|
321
|
-
value: this.valueEncoding.decoder(payloadValue.data)
|
|
367
|
+
value: this.valueEncoding.decoder(payloadValue.data),
|
|
322
368
|
/* size: payloadValue.data.byteLength */
|
|
323
369
|
};
|
|
324
370
|
}
|
|
325
371
|
throw new Error("Unexpected value type when getting document: " +
|
|
326
372
|
payloadValue?.constructor?.name || typeof payloadValue);
|
|
327
373
|
}
|
|
328
|
-
async processQuery(query, from, options) {
|
|
374
|
+
async processQuery(query, from, isLocal, options) {
|
|
329
375
|
// We do special case for querying the id as we can do it faster than iterating
|
|
376
|
+
let prevQueued = isLocal
|
|
377
|
+
? undefined
|
|
378
|
+
: this._resultQueue.get(query.idString);
|
|
379
|
+
if (prevQueued && !from.equals(prevQueued.from)) {
|
|
380
|
+
throw new Error("Different from in queued results");
|
|
381
|
+
}
|
|
330
382
|
let indexedResult = undefined;
|
|
331
|
-
if (query instanceof
|
|
332
|
-
indexedResult = await this.
|
|
383
|
+
if (query instanceof indexerTypes.SearchRequest) {
|
|
384
|
+
indexedResult = await this.index.query(query);
|
|
333
385
|
}
|
|
334
|
-
else if (query instanceof
|
|
335
|
-
indexedResult =
|
|
386
|
+
else if (query instanceof indexerTypes.CollectNextRequest) {
|
|
387
|
+
indexedResult =
|
|
388
|
+
prevQueued?.keptInIndex === 0
|
|
389
|
+
? { kept: 0, results: [] }
|
|
390
|
+
: await this.index.next(query);
|
|
336
391
|
}
|
|
337
392
|
else {
|
|
338
393
|
throw new Error("Unsupported");
|
|
339
394
|
}
|
|
340
395
|
const filteredResults = [];
|
|
341
|
-
|
|
396
|
+
let resultSize = 0;
|
|
397
|
+
let toIterate = prevQueued
|
|
398
|
+
? [...prevQueued.queue, ...indexedResult.results]
|
|
399
|
+
: indexedResult.results;
|
|
400
|
+
if (prevQueued) {
|
|
401
|
+
this._resultQueue.delete(query.idString);
|
|
402
|
+
prevQueued = undefined;
|
|
403
|
+
}
|
|
404
|
+
if (!isLocal) {
|
|
405
|
+
prevQueued = {
|
|
406
|
+
from,
|
|
407
|
+
queue: [],
|
|
408
|
+
timeout: setTimeout(() => {
|
|
409
|
+
this._resultQueue.delete(query.idString);
|
|
410
|
+
}, 6e4),
|
|
411
|
+
keptInIndex: indexedResult.kept,
|
|
412
|
+
};
|
|
413
|
+
this._resultQueue.set(query.idString, prevQueued);
|
|
414
|
+
}
|
|
415
|
+
for (const result of toIterate) {
|
|
416
|
+
if (!isLocal) {
|
|
417
|
+
resultSize += result.value.__context.size;
|
|
418
|
+
if (resultSize > MAX_BATCH_SIZE) {
|
|
419
|
+
prevQueued.queue.push(result);
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
342
423
|
const value = await this.resolveDocument(result);
|
|
343
424
|
if (!value ||
|
|
344
425
|
(options?.canRead && !(await options.canRead(value.value, from)))) {
|
|
345
426
|
continue;
|
|
346
427
|
}
|
|
347
428
|
filteredResults.push(new types.ResultWithSource({
|
|
348
|
-
context: result.
|
|
429
|
+
context: result.value.__context,
|
|
349
430
|
value: value.value,
|
|
350
431
|
source: serialize(value.value),
|
|
351
|
-
indexed: result.
|
|
432
|
+
indexed: result.value,
|
|
352
433
|
}));
|
|
353
434
|
}
|
|
354
435
|
const results = new types.Results({
|
|
355
436
|
results: filteredResults,
|
|
356
|
-
kept: BigInt(indexedResult.kept)
|
|
437
|
+
kept: BigInt(indexedResult.kept + (prevQueued?.queue.length || 0)),
|
|
357
438
|
});
|
|
439
|
+
if (!isLocal && results.kept === 0n) {
|
|
440
|
+
this.clearResultsQueue(query);
|
|
441
|
+
}
|
|
358
442
|
return results;
|
|
359
443
|
}
|
|
444
|
+
clearResultsQueue(query) {
|
|
445
|
+
const queue = this._resultQueue.get(query.idString);
|
|
446
|
+
if (queue) {
|
|
447
|
+
clearTimeout(queue.timeout);
|
|
448
|
+
this._resultQueue.delete(query.idString);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
360
451
|
async processCloseIteratorRequest(query, publicKey) {
|
|
361
|
-
|
|
452
|
+
const queueData = this._resultQueue.get(query.idString);
|
|
453
|
+
if (queueData && !queueData.from.equals(publicKey)) {
|
|
454
|
+
logger.info("Ignoring close iterator request from different peer");
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
this.clearResultsQueue(query);
|
|
458
|
+
return this.index.close(query);
|
|
362
459
|
}
|
|
363
460
|
/**
|
|
364
461
|
* Query and retrieve results with most details
|
|
@@ -367,7 +464,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
367
464
|
* @returns
|
|
368
465
|
*/
|
|
369
466
|
async queryDetailed(queryRequest, options) {
|
|
370
|
-
const local = typeof options?.local
|
|
467
|
+
const local = typeof options?.local === "boolean" ? options?.local : true;
|
|
371
468
|
let remote = undefined;
|
|
372
469
|
if (typeof options?.remote === "boolean") {
|
|
373
470
|
if (options?.remote) {
|
|
@@ -392,7 +489,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
392
489
|
}
|
|
393
490
|
const allResults = [];
|
|
394
491
|
if (local) {
|
|
395
|
-
const results = await this.processQuery(queryRequest, this.node.identity.publicKey);
|
|
492
|
+
const results = await this.processQuery(queryRequest, this.node.identity.publicKey, true);
|
|
396
493
|
if (results.results.length > 0) {
|
|
397
494
|
options?.onResponse &&
|
|
398
495
|
(await options.onResponse(results, this.node.identity.publicKey));
|
|
@@ -406,12 +503,12 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
406
503
|
const fn = async () => {
|
|
407
504
|
const rs = [];
|
|
408
505
|
const responseHandler = async (results) => {
|
|
409
|
-
for (const r of await introduceEntries(results, this.
|
|
506
|
+
for (const r of await introduceEntries(results, this.documentType, this._sync, options)) {
|
|
410
507
|
rs.push(r.response);
|
|
411
508
|
}
|
|
412
509
|
};
|
|
413
510
|
try {
|
|
414
|
-
if (queryRequest instanceof
|
|
511
|
+
if (queryRequest instanceof indexerTypes.CloseIteratorRequest) {
|
|
415
512
|
// don't wait for responses
|
|
416
513
|
await this._query.request(queryRequest, { mode: remote.mode });
|
|
417
514
|
}
|
|
@@ -467,7 +564,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
467
564
|
*/
|
|
468
565
|
async search(queryRequest, options) {
|
|
469
566
|
// Set fetch to search size, or max value (default to max u32 (4294967295))
|
|
470
|
-
queryRequest.fetch =
|
|
567
|
+
queryRequest.fetch = queryRequest.fetch ?? 0xffffffff;
|
|
471
568
|
// So that the iterator is pre-fetching the right amount of entries
|
|
472
569
|
const iterator = this.iterate(queryRequest, options);
|
|
473
570
|
// So that this call will not do any remote requests
|
|
@@ -524,7 +621,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
524
621
|
}
|
|
525
622
|
const buffer = [];
|
|
526
623
|
for (const result of results.results) {
|
|
527
|
-
const indexKey =
|
|
624
|
+
const indexKey = indexerTypes.toId(this.indexByResolver(result.value)).primitive;
|
|
528
625
|
if (visited.has(indexKey)) {
|
|
529
626
|
continue;
|
|
530
627
|
}
|
|
@@ -532,21 +629,24 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
532
629
|
buffer.push({
|
|
533
630
|
value: result.value,
|
|
534
631
|
context: result.context,
|
|
535
|
-
from
|
|
632
|
+
from,
|
|
536
633
|
indexed: result.indexed ||
|
|
537
|
-
(await this.
|
|
634
|
+
(await this.transformer(result.value, result.context)),
|
|
538
635
|
});
|
|
539
636
|
}
|
|
540
637
|
peerBufferMap.set(from.hashcode(), {
|
|
541
638
|
buffer,
|
|
542
|
-
kept: Number(response.kept)
|
|
639
|
+
kept: Number(response.kept),
|
|
543
640
|
});
|
|
544
641
|
}
|
|
545
642
|
else {
|
|
546
643
|
throw new Error("Unsupported result type: " + response?.constructor?.name);
|
|
547
644
|
}
|
|
548
|
-
}
|
|
645
|
+
},
|
|
549
646
|
});
|
|
647
|
+
if (done) {
|
|
648
|
+
this.clearResultsQueue(queryRequest);
|
|
649
|
+
}
|
|
550
650
|
return done;
|
|
551
651
|
};
|
|
552
652
|
const fetchAtLeast = async (n) => {
|
|
@@ -571,13 +671,13 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
571
671
|
}
|
|
572
672
|
// TODO buffer more than deleted?
|
|
573
673
|
// TODO batch to multiple 'to's
|
|
574
|
-
const collectRequest = new
|
|
674
|
+
const collectRequest = new indexerTypes.CollectNextRequest({
|
|
575
675
|
id: queryRequest.id,
|
|
576
|
-
amount: n - buffer.buffer.length
|
|
676
|
+
amount: n - buffer.buffer.length,
|
|
577
677
|
});
|
|
578
678
|
// Fetch locally?
|
|
579
679
|
if (peer === this.node.identity.publicKey.hashcode()) {
|
|
580
|
-
promises.push(this.processQuery(collectRequest, this.node.identity.publicKey)
|
|
680
|
+
promises.push(this.processQuery(collectRequest, this.node.identity.publicKey, true)
|
|
581
681
|
.then(async (results) => {
|
|
582
682
|
resultsLeft += Number(results.kept);
|
|
583
683
|
if (results.results.length === 0) {
|
|
@@ -592,16 +692,18 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
592
692
|
}
|
|
593
693
|
peerBuffer.kept = Number(results.kept);
|
|
594
694
|
for (const result of results.results) {
|
|
595
|
-
if (visited.has(
|
|
695
|
+
if (visited.has(indexerTypes.toId(this.indexByResolver(result.value))
|
|
696
|
+
.primitive)) {
|
|
596
697
|
continue;
|
|
597
698
|
}
|
|
598
|
-
visited.add(
|
|
699
|
+
visited.add(indexerTypes.toId(this.indexByResolver(result.value))
|
|
700
|
+
.primitive);
|
|
599
701
|
peerBuffer.buffer.push({
|
|
600
702
|
value: result.value,
|
|
601
703
|
context: result.context,
|
|
602
704
|
from: this.node.identity.publicKey,
|
|
603
705
|
indexed: result.indexed ||
|
|
604
|
-
(await this.
|
|
706
|
+
(await this.transformer(result.value, result.context)),
|
|
605
707
|
});
|
|
606
708
|
}
|
|
607
709
|
}
|
|
@@ -618,9 +720,9 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
618
720
|
...options,
|
|
619
721
|
signal: controller.signal,
|
|
620
722
|
priority: 1,
|
|
621
|
-
mode: new SilentDelivery({ to: [peer], redundancy: 1 })
|
|
723
|
+
mode: new SilentDelivery({ to: [peer], redundancy: 1 }),
|
|
622
724
|
})
|
|
623
|
-
.then((response) => introduceEntries(response, this.
|
|
725
|
+
.then((response) => introduceEntries(response, this.documentType, this._sync, options)
|
|
624
726
|
.then((responses) => {
|
|
625
727
|
responses.map((response) => {
|
|
626
728
|
resultsLeft += Number(response.response.kept);
|
|
@@ -640,15 +742,15 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
640
742
|
}
|
|
641
743
|
peerBuffer.kept = Number(response.response.kept);
|
|
642
744
|
for (const result of response.response.results) {
|
|
643
|
-
if (visited.has(
|
|
745
|
+
if (visited.has(indexerTypes.toId(this.indexByResolver(result.value)).primitive)) {
|
|
644
746
|
continue;
|
|
645
747
|
}
|
|
646
|
-
visited.add(
|
|
748
|
+
visited.add(indexerTypes.toId(this.indexByResolver(result.value)).primitive);
|
|
647
749
|
peerBuffer.buffer.push({
|
|
648
750
|
value: result.value,
|
|
649
751
|
context: result.context,
|
|
650
752
|
from: response.from,
|
|
651
|
-
indexed: this.
|
|
753
|
+
indexed: this.transformer(result.value, result.context),
|
|
652
754
|
});
|
|
653
755
|
}
|
|
654
756
|
}
|
|
@@ -681,7 +783,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
681
783
|
// TODO everything below is not very optimized
|
|
682
784
|
const fetchedAll = await fetchAtLeast(n);
|
|
683
785
|
// get n next top entries, shift and pull more results
|
|
684
|
-
const
|
|
786
|
+
const peerBuffersArr = peerBuffers();
|
|
787
|
+
const results = peerBuffersArr.sort((a, b) => indexerTypes.extractSortCompare(a.indexed, b.indexed, queryRequest.sort));
|
|
685
788
|
const pendingMoreResults = n < results.length;
|
|
686
789
|
const batch = results.splice(0, n);
|
|
687
790
|
for (const result of batch) {
|
|
@@ -690,7 +793,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
690
793
|
logger.error("Unexpected empty result buffer");
|
|
691
794
|
continue;
|
|
692
795
|
}
|
|
693
|
-
const idx = arr.buffer.findIndex((x) => x.value
|
|
796
|
+
const idx = arr.buffer.findIndex((x) => x.value === result.value);
|
|
694
797
|
if (idx >= 0) {
|
|
695
798
|
arr.buffer.splice(idx, 1);
|
|
696
799
|
}
|
|
@@ -700,8 +803,8 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
700
803
|
};
|
|
701
804
|
const close = async () => {
|
|
702
805
|
controller.abort(new AbortError("Iterator closed"));
|
|
703
|
-
const closeRequest = new
|
|
704
|
-
id: queryRequest.id
|
|
806
|
+
const closeRequest = new indexerTypes.CloseIteratorRequest({
|
|
807
|
+
id: queryRequest.id,
|
|
705
808
|
});
|
|
706
809
|
const promises = [];
|
|
707
810
|
for (const [peer, buffer] of peerBufferMap) {
|
|
@@ -717,7 +820,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
717
820
|
// Close remote
|
|
718
821
|
promises.push(this._query.send(closeRequest, {
|
|
719
822
|
...options,
|
|
720
|
-
mode: new SilentDelivery({ to: [peer], redundancy: 1 })
|
|
823
|
+
mode: new SilentDelivery({ to: [peer], redundancy: 1 }),
|
|
721
824
|
}));
|
|
722
825
|
}
|
|
723
826
|
}
|
|
@@ -726,7 +829,7 @@ let DocumentIndex = class DocumentIndex extends Program {
|
|
|
726
829
|
return {
|
|
727
830
|
close,
|
|
728
831
|
next,
|
|
729
|
-
done: () => done
|
|
832
|
+
done: () => done,
|
|
730
833
|
};
|
|
731
834
|
}
|
|
732
835
|
};
|