@peerbit/document 15.0.11 → 15.0.13
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/src/program.d.ts +1 -0
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +30 -4
- package/dist/src/program.js.map +1 -1
- package/dist/src/search.d.ts +5 -2
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +20 -6
- package/dist/src/search.js.map +1 -1
- package/package.json +15 -13
- package/src/program.ts +45 -4
- package/src/search.ts +44 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peerbit/document",
|
|
3
|
-
"version": "15.0.
|
|
3
|
+
"version": "15.0.13",
|
|
4
4
|
"description": "Document store implementation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -61,20 +61,20 @@
|
|
|
61
61
|
"p-defer": "^4.0.0",
|
|
62
62
|
"uint8arrays": "^5.1.0",
|
|
63
63
|
"@peerbit/cache": "3.1.1",
|
|
64
|
+
"@peerbit/document-interface": "3.2.66",
|
|
64
65
|
"@peerbit/crypto": "3.1.6",
|
|
65
|
-
"@peerbit/
|
|
66
|
-
"@peerbit/indexer-
|
|
67
|
-
"@peerbit/indexer-
|
|
68
|
-
"@peerbit/indexer-
|
|
69
|
-
"@peerbit/
|
|
70
|
-
"@peerbit/log": "6.2.21",
|
|
71
|
-
"@peerbit/program": "6.0.53",
|
|
66
|
+
"@peerbit/indexer-cache": "0.2.15",
|
|
67
|
+
"@peerbit/indexer-interface": "3.0.12",
|
|
68
|
+
"@peerbit/indexer-simple": "1.2.16",
|
|
69
|
+
"@peerbit/indexer-sqlite3": "3.0.18",
|
|
70
|
+
"@peerbit/log": "6.2.23",
|
|
72
71
|
"@peerbit/logger": "2.0.2",
|
|
72
|
+
"@peerbit/program": "6.0.54",
|
|
73
73
|
"@peerbit/pubsub": "5.4.2",
|
|
74
|
-
"@peerbit/
|
|
74
|
+
"@peerbit/shared-log": "16.0.13",
|
|
75
|
+
"@peerbit/rpc": "6.1.22",
|
|
75
76
|
"@peerbit/stream-interface": "6.0.16",
|
|
76
|
-
"@peerbit/time": "3.0.1"
|
|
77
|
-
"@peerbit/shared-log": "16.0.11"
|
|
77
|
+
"@peerbit/time": "3.0.1"
|
|
78
78
|
},
|
|
79
79
|
"optionalDependencies": {
|
|
80
80
|
"@peerbit/document-rust": "0.1.1"
|
|
@@ -87,8 +87,8 @@
|
|
|
87
87
|
"uuid": "^11.1.1",
|
|
88
88
|
"@peerbit/log-rust": "1.1.4",
|
|
89
89
|
"@peerbit/native-backbone": "0.2.10",
|
|
90
|
-
"@peerbit/test-utils": "3.1.
|
|
91
|
-
"peerbit": "5.3.
|
|
90
|
+
"@peerbit/test-utils": "3.1.33",
|
|
91
|
+
"peerbit": "5.3.33"
|
|
92
92
|
},
|
|
93
93
|
"repository": {
|
|
94
94
|
"type": "git",
|
|
@@ -102,6 +102,8 @@
|
|
|
102
102
|
"scripts": {
|
|
103
103
|
"clean": "aegir clean",
|
|
104
104
|
"build": "aegir build --no-bundle",
|
|
105
|
+
"bench:ordered-remote-projection": "node --loader ts-node/esm ./benchmark/ordered-remote-projection.ts",
|
|
106
|
+
"bench:shared-fs-cold-join": "node --loader ts-node/esm ./benchmark/shared-fs-cold-join.ts",
|
|
105
107
|
"test": "aegir test --target node",
|
|
106
108
|
"test:document-rust-core": "npm run build && PEERBIT_SHARED_LOG_RUST_CORE=1 aegir test -t node --grep '^(?!.*(uses the validated local append path|uses the independent native prepared batch path|uses native shared-log planning for replicated target-none puts|uses commit-only local puts when coordinate persistence is deferred)).*(native conformance guard |operations basic |operations get |operations index |operations search |iterate sort |count approximate |query distribution |returnIndexed |caching |custom index |prefetch )' -- --forbid-pending",
|
|
107
109
|
"lint": "aegir lint",
|
package/src/program.ts
CHANGED
|
@@ -74,6 +74,7 @@ import {
|
|
|
74
74
|
type CanRead,
|
|
75
75
|
type CanSearch,
|
|
76
76
|
DocumentIndex,
|
|
77
|
+
type DocumentIndexWriteSession,
|
|
77
78
|
type GetOptions,
|
|
78
79
|
INDEX_CONTEXT_SHAPE,
|
|
79
80
|
type IndexedContextOnly,
|
|
@@ -2025,6 +2026,7 @@ export class Documents<
|
|
|
2025
2026
|
*/
|
|
2026
2027
|
private getLocalIndexedContextForChange(
|
|
2027
2028
|
key: indexerTypes.IdKey,
|
|
2029
|
+
orderedSession?: DocumentIndexWriteSession<I>,
|
|
2028
2030
|
): Promise<indexerTypes.IndexedResult<IndexedContextOnly<I>> | undefined> {
|
|
2029
2031
|
// Not every backing index resolves asynchronously (the native one answers
|
|
2030
2032
|
// synchronously, and may throw synchronously), so guard both shapes without
|
|
@@ -2033,9 +2035,9 @@ export class Documents<
|
|
|
2033
2035
|
| indexerTypes.IndexedResult<IndexedContextOnly<I>>
|
|
2034
2036
|
| undefined;
|
|
2035
2037
|
try {
|
|
2036
|
-
const result =
|
|
2037
|
-
key,
|
|
2038
|
-
|
|
2038
|
+
const result = (orderedSession
|
|
2039
|
+
? orderedSession.get(key, { shape: INDEX_CONTEXT_SHAPE })
|
|
2040
|
+
: this.getLocalIndexedContext(key)) as MaybePromise<LocalIndexedContext>;
|
|
2039
2041
|
return (
|
|
2040
2042
|
isPromiseLike(result)
|
|
2041
2043
|
? result.catch((error) => this.recoverClosedIndexContextRead(error))
|
|
@@ -5342,6 +5344,24 @@ export class Documents<
|
|
|
5342
5344
|
reference?: PutChangeReference<T, I>,
|
|
5343
5345
|
): Promise<void> {
|
|
5344
5346
|
logger.trace("handleChanges called", change);
|
|
5347
|
+
if (
|
|
5348
|
+
reference == null &&
|
|
5349
|
+
change.added.length >= 2 &&
|
|
5350
|
+
!this.isNativeMode() &&
|
|
5351
|
+
this._index.canUseOrderedWriteSession()
|
|
5352
|
+
) {
|
|
5353
|
+
return this._index.withOrderedWriteSession((orderedSession) =>
|
|
5354
|
+
this.handleChangesInOrder(change, reference, orderedSession),
|
|
5355
|
+
);
|
|
5356
|
+
}
|
|
5357
|
+
return this.handleChangesInOrder(change, reference);
|
|
5358
|
+
}
|
|
5359
|
+
|
|
5360
|
+
private async handleChangesInOrder(
|
|
5361
|
+
change: Change<Operation>,
|
|
5362
|
+
reference?: PutChangeReference<T, I>,
|
|
5363
|
+
orderedSession?: DocumentIndexWriteSession<I>,
|
|
5364
|
+
): Promise<void> {
|
|
5345
5365
|
const isAppendOperation =
|
|
5346
5366
|
change?.added.length === 1 ? !!change.added[0] : false;
|
|
5347
5367
|
const removedSet = new Map<string, ShallowOrFullEntry<Operation>>();
|
|
@@ -5382,6 +5402,7 @@ export class Documents<
|
|
|
5382
5402
|
let modified: Set<string | number | bigint> = new Set();
|
|
5383
5403
|
for (const item of sortedEntries) {
|
|
5384
5404
|
if (!item) {
|
|
5405
|
+
await orderedSession?.flush();
|
|
5385
5406
|
continue;
|
|
5386
5407
|
}
|
|
5387
5408
|
|
|
@@ -5394,6 +5415,7 @@ export class Documents<
|
|
|
5394
5415
|
? reference.operation
|
|
5395
5416
|
: await this.getAppendOperation(item);
|
|
5396
5417
|
if (!payload) {
|
|
5418
|
+
await orderedSession?.flush();
|
|
5397
5419
|
continue;
|
|
5398
5420
|
}
|
|
5399
5421
|
|
|
@@ -5448,6 +5470,9 @@ export class Documents<
|
|
|
5448
5470
|
|
|
5449
5471
|
// document is already updated with more recent entry
|
|
5450
5472
|
if (modified.has(key.primitive)) {
|
|
5473
|
+
// Duplicate ids deliberately retain the scalar boundary until
|
|
5474
|
+
// their callback and event semantics are proven independently.
|
|
5475
|
+
await orderedSession?.flush();
|
|
5451
5476
|
continue;
|
|
5452
5477
|
}
|
|
5453
5478
|
|
|
@@ -5459,7 +5484,10 @@ export class Documents<
|
|
|
5459
5484
|
? reference.existing
|
|
5460
5485
|
: this.isNativeMode()
|
|
5461
5486
|
? this.getNativeModeIndexedContext(key) || null
|
|
5462
|
-
: (await this.getLocalIndexedContextForChange(
|
|
5487
|
+
: (await this.getLocalIndexedContextForChange(
|
|
5488
|
+
key,
|
|
5489
|
+
orderedSession,
|
|
5490
|
+
)) || null;
|
|
5463
5491
|
if (!this.strictHistory && existing) {
|
|
5464
5492
|
// if immutable use oldest, else use newest
|
|
5465
5493
|
let shouldIgnoreChange = this.immutable
|
|
@@ -5468,10 +5496,19 @@ export class Documents<
|
|
|
5468
5496
|
: existing.value.__context.modified >
|
|
5469
5497
|
item.meta.clock.timestamp.wallTime;
|
|
5470
5498
|
if (shouldIgnoreChange) {
|
|
5499
|
+
await orderedSession?.flush();
|
|
5471
5500
|
continue;
|
|
5472
5501
|
}
|
|
5473
5502
|
}
|
|
5474
5503
|
|
|
5504
|
+
const useOrderedWrite =
|
|
5505
|
+
orderedSession != null &&
|
|
5506
|
+
existing == null &&
|
|
5507
|
+
!(value instanceof Program);
|
|
5508
|
+
if (!useOrderedWrite) {
|
|
5509
|
+
await orderedSession?.flush();
|
|
5510
|
+
}
|
|
5511
|
+
|
|
5475
5512
|
// Program specific
|
|
5476
5513
|
if (value instanceof Program) {
|
|
5477
5514
|
// if replicator, then open
|
|
@@ -5497,6 +5534,7 @@ export class Documents<
|
|
|
5497
5534
|
key,
|
|
5498
5535
|
item,
|
|
5499
5536
|
existing,
|
|
5537
|
+
useOrderedWrite ? orderedSession : undefined,
|
|
5500
5538
|
);
|
|
5501
5539
|
documentsChanged?.added.push(
|
|
5502
5540
|
coerceWithIndexed(coerceWithContext(value, context), indexable),
|
|
@@ -5508,6 +5546,7 @@ export class Documents<
|
|
|
5508
5546
|
isPutOperation(payload) ||
|
|
5509
5547
|
removedSet.has(item.hash)
|
|
5510
5548
|
) {
|
|
5549
|
+
await orderedSession?.flush();
|
|
5511
5550
|
if (
|
|
5512
5551
|
!documentsChanged &&
|
|
5513
5552
|
(await this.collectRemovedPutChangeFromNativeId(payload, modified))
|
|
@@ -5525,12 +5564,14 @@ export class Documents<
|
|
|
5525
5564
|
}
|
|
5526
5565
|
} catch (error) {
|
|
5527
5566
|
if (error instanceof AccessError) {
|
|
5567
|
+
await orderedSession?.flush();
|
|
5528
5568
|
continue;
|
|
5529
5569
|
}
|
|
5530
5570
|
throw error;
|
|
5531
5571
|
}
|
|
5532
5572
|
}
|
|
5533
5573
|
|
|
5574
|
+
await orderedSession?.flush();
|
|
5534
5575
|
if (canRemoveByIndexedHead && change.removed.length > 0) {
|
|
5535
5576
|
const handled = await this.collectRemovedDocumentChangesFromIndexedHeads(
|
|
5536
5577
|
change.removed,
|
package/src/search.ts
CHANGED
|
@@ -739,6 +739,9 @@ export type WithContext<I> = {
|
|
|
739
739
|
__context: types.Context;
|
|
740
740
|
} & I;
|
|
741
741
|
|
|
742
|
+
export type DocumentIndexWriteSession<I extends Record<string, any>> =
|
|
743
|
+
indexerTypes.OrderedIndexWriteSession<WithContext<I>>;
|
|
744
|
+
|
|
742
745
|
export const INDEX_CONTEXT_SHAPE = {
|
|
743
746
|
__context: {
|
|
744
747
|
created: true,
|
|
@@ -1135,6 +1138,23 @@ export class DocumentIndex<
|
|
|
1135
1138
|
return this._valueEncoding;
|
|
1136
1139
|
}
|
|
1137
1140
|
|
|
1141
|
+
public canUseOrderedWriteSession(): boolean {
|
|
1142
|
+
return (
|
|
1143
|
+
!this.isProgramValued &&
|
|
1144
|
+
typeof this.index.withOrderedWriteSession === "function"
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
public async withOrderedWriteSession<R>(
|
|
1149
|
+
operation: (session: DocumentIndexWriteSession<I>) => MaybePromise<R>,
|
|
1150
|
+
): Promise<R> {
|
|
1151
|
+
const withSession = this.index.withOrderedWriteSession;
|
|
1152
|
+
if (!withSession) {
|
|
1153
|
+
throw new Error("Backing index does not support ordered write sessions");
|
|
1154
|
+
}
|
|
1155
|
+
return withSession.call(this.index, operation) as MaybePromise<R>;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1138
1158
|
private ensurePrefetchAccumulator() {
|
|
1139
1159
|
if (!this._prefetch) {
|
|
1140
1160
|
this._prefetch = {
|
|
@@ -3090,10 +3110,11 @@ export class DocumentIndex<
|
|
|
3090
3110
|
| indexerTypes.IndexedResult<IndexedContextOnly<I>>
|
|
3091
3111
|
| null
|
|
3092
3112
|
| undefined,
|
|
3113
|
+
orderedSession?: DocumentIndexWriteSession<I>,
|
|
3093
3114
|
): Promise<{ context: types.Context; indexable: I }> {
|
|
3094
3115
|
const existingDefined =
|
|
3095
3116
|
existing === undefined
|
|
3096
|
-
? await this.index.get(id, {
|
|
3117
|
+
? await (orderedSession ?? this.index).get(id, {
|
|
3097
3118
|
shape: INDEX_CONTEXT_SHAPE,
|
|
3098
3119
|
})
|
|
3099
3120
|
: existing;
|
|
@@ -3106,10 +3127,16 @@ export class DocumentIndex<
|
|
|
3106
3127
|
gid: entry.meta.gid,
|
|
3107
3128
|
size: entry.payload.byteLength,
|
|
3108
3129
|
});
|
|
3109
|
-
return this.putWithContext(
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3130
|
+
return this.putWithContext(
|
|
3131
|
+
value,
|
|
3132
|
+
id,
|
|
3133
|
+
context,
|
|
3134
|
+
{
|
|
3135
|
+
replace: existingDefined != null,
|
|
3136
|
+
transformFacts: { entryPublicKeys: entry.publicKeys },
|
|
3137
|
+
},
|
|
3138
|
+
orderedSession,
|
|
3139
|
+
);
|
|
3113
3140
|
}
|
|
3114
3141
|
|
|
3115
3142
|
public async putWithContext(
|
|
@@ -3117,6 +3144,7 @@ export class DocumentIndex<
|
|
|
3117
3144
|
id: indexerTypes.IdKey,
|
|
3118
3145
|
context: types.Context,
|
|
3119
3146
|
options?: ContextualPutOptions,
|
|
3147
|
+
orderedSession?: DocumentIndexWriteSession<I>,
|
|
3120
3148
|
): Promise<{ context: types.Context; indexable: I }> {
|
|
3121
3149
|
const idString = id.primitive;
|
|
3122
3150
|
this.cacheResolvedValue(idString, value);
|
|
@@ -3129,10 +3157,17 @@ export class DocumentIndex<
|
|
|
3129
3157
|
coerceWithContext(value, context);
|
|
3130
3158
|
|
|
3131
3159
|
try {
|
|
3132
|
-
const contextualPut =
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3160
|
+
const contextualPut =
|
|
3161
|
+
!orderedSession && this.transformerIsIdentity
|
|
3162
|
+
? (this.index as ContextualIndexPut<I>).putWithContext
|
|
3163
|
+
: undefined;
|
|
3164
|
+
if (orderedSession) {
|
|
3165
|
+
await orderedSession.put(
|
|
3166
|
+
new this.wrappedIndexedType(valueToIndex, context),
|
|
3167
|
+
id,
|
|
3168
|
+
stripEncodedValue(options),
|
|
3169
|
+
);
|
|
3170
|
+
} else if (contextualPut) {
|
|
3136
3171
|
const encodedValueParts = this.encodeContextualIndexedValueParts(
|
|
3137
3172
|
options?.encodedValue,
|
|
3138
3173
|
context,
|