@peerbit/document 15.0.13 → 15.0.15
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/callback-detachment.d.ts +19 -0
- package/dist/src/callback-detachment.d.ts.map +1 -0
- package/dist/src/callback-detachment.js +605 -0
- package/dist/src/callback-detachment.js.map +1 -0
- package/dist/src/domain.d.ts.map +1 -1
- package/dist/src/domain.js +5 -3
- package/dist/src/domain.js.map +1 -1
- package/dist/src/program.d.ts +5 -0
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +149 -40
- package/dist/src/program.js.map +1 -1
- package/dist/src/search.d.ts +2 -0
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +36 -6
- package/dist/src/search.js.map +1 -1
- package/dist/src/transform.d.ts +2 -0
- package/dist/src/transform.d.ts.map +1 -1
- package/dist/src/transform.js +4 -0
- package/dist/src/transform.js.map +1 -1
- package/package.json +9 -9
- package/src/callback-detachment.ts +848 -0
- package/src/domain.ts +10 -3
- package/src/program.ts +233 -49
- package/src/search.ts +49 -5
- package/src/transform.ts +7 -0
package/src/domain.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type ReplicationDomain,
|
|
10
10
|
type SharedLog,
|
|
11
11
|
} from "@peerbit/shared-log";
|
|
12
|
+
import { detachEntryForCallback } from "./callback-detachment.js";
|
|
12
13
|
import { type Operation, isPutOperation } from "./operation.js";
|
|
13
14
|
import type { DocumentIndex } from "./search.js";
|
|
14
15
|
|
|
@@ -93,8 +94,12 @@ export const createDocumentDomain =
|
|
|
93
94
|
): ((db: DB) => CustomDocumentDomain<InferR<DB>>) =>
|
|
94
95
|
(db: DB) => {
|
|
95
96
|
let maxValue = args.resolution === "u32" ? MAX_U32 : MAX_U64;
|
|
97
|
+
const detachEntry = (
|
|
98
|
+
entry: ShallowEntry | Entry<Operation> | EntryReplicated<any>,
|
|
99
|
+
) => detachEntryForCallback(entry);
|
|
96
100
|
let fromEntry = (args as FromEntry<InferR<DB>>).fromEntry
|
|
97
|
-
? (
|
|
101
|
+
? (entry: ShallowEntry | Entry<Operation> | EntryReplicated<any>) =>
|
|
102
|
+
(args as FromEntry<InferR<DB>>).fromEntry!(detachEntry(entry))
|
|
98
103
|
: async (
|
|
99
104
|
entry: ShallowEntry | Entry<Operation> | EntryReplicated<any>,
|
|
100
105
|
) => {
|
|
@@ -106,11 +111,13 @@ export const createDocumentDomain =
|
|
|
106
111
|
if (!item) {
|
|
107
112
|
logger.error("Item not found");
|
|
108
113
|
} else if (isPutOperation(item)) {
|
|
109
|
-
document = db.index.valueEncoding.decoder(
|
|
114
|
+
document = db.index.valueEncoding.decoder(
|
|
115
|
+
new Uint8Array(item.data),
|
|
116
|
+
);
|
|
110
117
|
}
|
|
111
118
|
return (args as FromValue<any, any>).fromValue!(
|
|
112
119
|
document,
|
|
113
|
-
entry,
|
|
120
|
+
detachEntry(entry),
|
|
114
121
|
) as NumberFromType<InferR<DB>>;
|
|
115
122
|
};
|
|
116
123
|
return {
|
package/src/program.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AbstractType,
|
|
3
3
|
BorshError,
|
|
4
|
+
deserialize,
|
|
4
5
|
field,
|
|
5
6
|
serialize,
|
|
6
7
|
variant,
|
|
@@ -44,6 +45,11 @@ import {
|
|
|
44
45
|
SharedLog,
|
|
45
46
|
type SharedLogOptions,
|
|
46
47
|
} from "@peerbit/shared-log";
|
|
48
|
+
import {
|
|
49
|
+
detachCanPerformCallbackProperties,
|
|
50
|
+
detachEntryForCallback,
|
|
51
|
+
detachEntryPayloadForCallback,
|
|
52
|
+
} from "./callback-detachment.js";
|
|
47
53
|
import { MAX_BATCH_SIZE } from "./constants.js";
|
|
48
54
|
import type { CustomDocumentDomain } from "./domain.js";
|
|
49
55
|
import type { DocumentEvents, DocumentsChange } from "./events.js";
|
|
@@ -1088,12 +1094,23 @@ export class Documents<
|
|
|
1088
1094
|
private _documentChangeListenerTrackingInitialized = false;
|
|
1089
1095
|
private _documentBackend!: DocumentBackend<T>;
|
|
1090
1096
|
private _canAppendDecodedDocuments = new WeakMap<PutOperation, T>();
|
|
1097
|
+
private acceptPutOperation(
|
|
1098
|
+
operation: PutOperation,
|
|
1099
|
+
document: T | undefined,
|
|
1100
|
+
hasDocument: boolean,
|
|
1101
|
+
): PutOperation {
|
|
1102
|
+
if (hasDocument) {
|
|
1103
|
+
this._canAppendDecodedDocuments.set(operation, document!);
|
|
1104
|
+
}
|
|
1105
|
+
return operation;
|
|
1106
|
+
}
|
|
1091
1107
|
private _nativeDocumentIdExtractionPlan?: SimpleDocumentFieldExtractionPlan;
|
|
1092
1108
|
private _nativeDocumentFieldExtractionPlans?: Map<
|
|
1093
1109
|
string,
|
|
1094
1110
|
SimpleDocumentFieldExtractionPlan | undefined
|
|
1095
1111
|
>;
|
|
1096
1112
|
private _hasLogTrim = false;
|
|
1113
|
+
private _hasCustomIdResolver = false;
|
|
1097
1114
|
private idResolver!: (any: any) => indexerTypes.Ideable;
|
|
1098
1115
|
private domain?: CustomDocumentDomain<InferR<D>>;
|
|
1099
1116
|
private strictHistory: boolean;
|
|
@@ -1131,6 +1148,99 @@ export class Documents<
|
|
|
1131
1148
|
);
|
|
1132
1149
|
}
|
|
1133
1150
|
|
|
1151
|
+
private detachDomainEntryCallback(
|
|
1152
|
+
domain: CustomDocumentDomain<InferR<D>>,
|
|
1153
|
+
): CustomDocumentDomain<InferR<D>> {
|
|
1154
|
+
const boundMethods = new Map<
|
|
1155
|
+
PropertyKey,
|
|
1156
|
+
{ source: Function; bound: Function }
|
|
1157
|
+
>();
|
|
1158
|
+
const detachedFromEntry = (
|
|
1159
|
+
entry: Parameters<CustomDocumentDomain<InferR<D>>["fromEntry"]>[0],
|
|
1160
|
+
) => {
|
|
1161
|
+
const fromEntry = Reflect.get(
|
|
1162
|
+
domain,
|
|
1163
|
+
"fromEntry",
|
|
1164
|
+
domain,
|
|
1165
|
+
) as CustomDocumentDomain<InferR<D>>["fromEntry"];
|
|
1166
|
+
return Reflect.apply(fromEntry, domain, [detachEntryForCallback(entry)]);
|
|
1167
|
+
};
|
|
1168
|
+
const facade = Object.create(
|
|
1169
|
+
Object.getPrototypeOf(domain),
|
|
1170
|
+
) as CustomDocumentDomain<InferR<D>>;
|
|
1171
|
+
let callbackDomain: CustomDocumentDomain<InferR<D>>;
|
|
1172
|
+
callbackDomain = new Proxy(facade, {
|
|
1173
|
+
get(_target, property) {
|
|
1174
|
+
if (property === "fromEntry") {
|
|
1175
|
+
return detachedFromEntry;
|
|
1176
|
+
}
|
|
1177
|
+
if (property === "valueOf") {
|
|
1178
|
+
return () => callbackDomain;
|
|
1179
|
+
}
|
|
1180
|
+
const value = Reflect.get(domain, property, domain);
|
|
1181
|
+
if (property === "constructor" || typeof value !== "function") {
|
|
1182
|
+
return value;
|
|
1183
|
+
}
|
|
1184
|
+
const existing = boundMethods.get(property);
|
|
1185
|
+
if (existing && existing.source === value) {
|
|
1186
|
+
return existing.bound;
|
|
1187
|
+
}
|
|
1188
|
+
const bound = value.bind(domain);
|
|
1189
|
+
boundMethods.set(property, { source: value, bound });
|
|
1190
|
+
return bound;
|
|
1191
|
+
},
|
|
1192
|
+
set(_target, property, value) {
|
|
1193
|
+
return Reflect.set(domain, property, value, domain);
|
|
1194
|
+
},
|
|
1195
|
+
has(_target, property) {
|
|
1196
|
+
return Reflect.has(domain, property);
|
|
1197
|
+
},
|
|
1198
|
+
ownKeys() {
|
|
1199
|
+
return Reflect.ownKeys(domain);
|
|
1200
|
+
},
|
|
1201
|
+
getOwnPropertyDescriptor(_target, property) {
|
|
1202
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(domain, property);
|
|
1203
|
+
if (!descriptor) {
|
|
1204
|
+
return undefined;
|
|
1205
|
+
}
|
|
1206
|
+
if (property === "fromEntry") {
|
|
1207
|
+
return "value" in descriptor
|
|
1208
|
+
? {
|
|
1209
|
+
...descriptor,
|
|
1210
|
+
value: detachedFromEntry,
|
|
1211
|
+
configurable: true,
|
|
1212
|
+
}
|
|
1213
|
+
: {
|
|
1214
|
+
...descriptor,
|
|
1215
|
+
get: () => detachedFromEntry,
|
|
1216
|
+
configurable: true,
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
return { ...descriptor, configurable: true };
|
|
1220
|
+
},
|
|
1221
|
+
});
|
|
1222
|
+
return callbackDomain;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
private detachTrimEntryCallback(
|
|
1226
|
+
option: TrimOptions | undefined,
|
|
1227
|
+
): TrimOptions | undefined {
|
|
1228
|
+
const filter = option?.filter;
|
|
1229
|
+
if (!option || !filter?.canTrim) {
|
|
1230
|
+
return option;
|
|
1231
|
+
}
|
|
1232
|
+
const canTrim = filter.canTrim;
|
|
1233
|
+
return {
|
|
1234
|
+
...option,
|
|
1235
|
+
filter: {
|
|
1236
|
+
...filter,
|
|
1237
|
+
canTrim: function (this: unknown, entry: ShallowEntry) {
|
|
1238
|
+
return Reflect.apply(canTrim, this, [detachEntryForCallback(entry)]);
|
|
1239
|
+
},
|
|
1240
|
+
},
|
|
1241
|
+
} as TrimOptions;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1134
1244
|
private createNativeDocumentBackendContext(): NativeDocumentBackendContext<
|
|
1135
1245
|
T,
|
|
1136
1246
|
I
|
|
@@ -2356,6 +2466,7 @@ export class Documents<
|
|
|
2356
2466
|
: (obj: any) =>
|
|
2357
2467
|
indexerTypes.extractFieldValue(obj, idProperty as string[]));
|
|
2358
2468
|
|
|
2469
|
+
this._hasCustomIdResolver = options.id != null;
|
|
2359
2470
|
this.idResolver = idResolver;
|
|
2360
2471
|
this.strictHistory = options.strictHistory ?? false;
|
|
2361
2472
|
this._hasLogTrim = options.log?.trim != null;
|
|
@@ -2404,7 +2515,9 @@ export class Documents<
|
|
|
2404
2515
|
// 7 -> log v9) is retired; the rejection at the top of open() fires for
|
|
2405
2516
|
// any defined value before this point.
|
|
2406
2517
|
|
|
2407
|
-
this.domain = options.domain
|
|
2518
|
+
this.domain = options.domain
|
|
2519
|
+
? this.detachDomainEntryCallback(options.domain(this))
|
|
2520
|
+
: undefined;
|
|
2408
2521
|
|
|
2409
2522
|
let keepFunction:
|
|
2410
2523
|
| ((
|
|
@@ -2449,7 +2562,12 @@ export class Documents<
|
|
|
2449
2562
|
return false;
|
|
2450
2563
|
};
|
|
2451
2564
|
} else {
|
|
2452
|
-
|
|
2565
|
+
const keep = options?.keep;
|
|
2566
|
+
keepFunction = keep
|
|
2567
|
+
? function (this: unknown, entry) {
|
|
2568
|
+
return Reflect.apply(keep, this, [detachEntryForCallback(entry)]);
|
|
2569
|
+
}
|
|
2570
|
+
: undefined;
|
|
2453
2571
|
}
|
|
2454
2572
|
|
|
2455
2573
|
await this.log.open({
|
|
@@ -2457,7 +2575,7 @@ export class Documents<
|
|
|
2457
2575
|
canReplicate: options?.canReplicate,
|
|
2458
2576
|
canAppend: this.canAppend.bind(this),
|
|
2459
2577
|
onChange: this.handleChanges.bind(this),
|
|
2460
|
-
trim: options?.log?.trim,
|
|
2578
|
+
trim: this.detachTrimEntryCallback(options?.log?.trim),
|
|
2461
2579
|
appendDurability: options?.appendDurability,
|
|
2462
2580
|
nativeBackbone: options?.nativeBackbone,
|
|
2463
2581
|
nativeGraph: options?.nativeGraph,
|
|
@@ -2473,7 +2591,10 @@ export class Documents<
|
|
|
2473
2591
|
distributionDebounceTime: options?.distributionDebounceTime,
|
|
2474
2592
|
strictFullReplicaFallback: false,
|
|
2475
2593
|
domain: options?.domain
|
|
2476
|
-
? () =>
|
|
2594
|
+
? () =>
|
|
2595
|
+
this.detachDomainEntryCallback(
|
|
2596
|
+
options.domain!(this),
|
|
2597
|
+
) as unknown as D
|
|
2477
2598
|
: undefined,
|
|
2478
2599
|
eagerBlocks: options?.eagerBlocks,
|
|
2479
2600
|
fanout: options?.fanout,
|
|
@@ -2565,7 +2686,7 @@ export class Documents<
|
|
|
2565
2686
|
}
|
|
2566
2687
|
|
|
2567
2688
|
try {
|
|
2568
|
-
|
|
2689
|
+
const operation: PutOperation | DeleteOperation = l0;
|
|
2569
2690
|
if (this._optionCanPerform) {
|
|
2570
2691
|
if (this._optionCanPerformNativePolicy && this.isNativeMode()) {
|
|
2571
2692
|
return this.nativeCanPerformAllowsAppend(
|
|
@@ -2575,22 +2696,22 @@ export class Documents<
|
|
|
2575
2696
|
reference?.document,
|
|
2576
2697
|
);
|
|
2577
2698
|
}
|
|
2578
|
-
let document: T | undefined
|
|
2579
|
-
if (
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
} else if (isDeleteOperation(l0)) {
|
|
2588
|
-
// Nothing to do here by default.
|
|
2589
|
-
// Checking if the document exists is not necessary since it
|
|
2590
|
-
// might already be deleted.
|
|
2591
|
-
} else {
|
|
2592
|
-
throw new Error("Unsupported operation");
|
|
2699
|
+
let document: T | undefined;
|
|
2700
|
+
if (isPutOperation(l0)) {
|
|
2701
|
+
const cachedDocument = this._canAppendDecodedDocuments.get(l0);
|
|
2702
|
+
this._canAppendDecodedDocuments.delete(l0);
|
|
2703
|
+
document =
|
|
2704
|
+
cachedDocument ??
|
|
2705
|
+
this._index.valueEncoding.decoder(new Uint8Array(l0.data));
|
|
2706
|
+
if (!document) {
|
|
2707
|
+
return false;
|
|
2593
2708
|
}
|
|
2709
|
+
} else if (isDeleteOperation(l0)) {
|
|
2710
|
+
// Nothing to do here by default.
|
|
2711
|
+
// Checking if the document exists is not necessary since it
|
|
2712
|
+
// might already be deleted.
|
|
2713
|
+
} else {
|
|
2714
|
+
throw new Error("Unsupported operation");
|
|
2594
2715
|
}
|
|
2595
2716
|
const previousEntries =
|
|
2596
2717
|
this._optionCanPerformNativePolicy &&
|
|
@@ -2598,7 +2719,9 @@ export class Documents<
|
|
|
2598
2719
|
canPerformPolicyNeedsPreviousEntries(
|
|
2599
2720
|
this._optionCanPerformNativePolicy,
|
|
2600
2721
|
)
|
|
2601
|
-
? await this.resolveCanPerformPreviousEntries(entry)
|
|
2722
|
+
? (await this.resolveCanPerformPreviousEntries(entry)).map(
|
|
2723
|
+
detachEntryPayloadForCallback,
|
|
2724
|
+
)
|
|
2602
2725
|
: undefined;
|
|
2603
2726
|
const deleteValue =
|
|
2604
2727
|
this._optionCanPerformNativePolicy &&
|
|
@@ -2610,20 +2733,22 @@ export class Documents<
|
|
|
2610
2733
|
: undefined;
|
|
2611
2734
|
if (
|
|
2612
2735
|
!(await this._optionCanPerform(
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2736
|
+
detachCanPerformCallbackProperties(
|
|
2737
|
+
isPutOperation(operation)
|
|
2738
|
+
? {
|
|
2739
|
+
type: "put",
|
|
2740
|
+
value: document!,
|
|
2741
|
+
operation,
|
|
2742
|
+
entry: entry as unknown as Entry<PutOperation>,
|
|
2743
|
+
previousEntries,
|
|
2744
|
+
}
|
|
2745
|
+
: {
|
|
2746
|
+
type: "delete",
|
|
2747
|
+
value: deleteValue,
|
|
2748
|
+
operation,
|
|
2749
|
+
entry: entry as unknown as Entry<DeleteOperation>,
|
|
2750
|
+
},
|
|
2751
|
+
),
|
|
2627
2752
|
))
|
|
2628
2753
|
) {
|
|
2629
2754
|
return false;
|
|
@@ -2712,6 +2837,12 @@ export class Documents<
|
|
|
2712
2837
|
return entries;
|
|
2713
2838
|
}
|
|
2714
2839
|
|
|
2840
|
+
private detachDocumentValueForCallback(document: T): T {
|
|
2841
|
+
return this._index.valueEncoding.decoder(
|
|
2842
|
+
this._index.valueEncoding.encoder(document),
|
|
2843
|
+
);
|
|
2844
|
+
}
|
|
2845
|
+
|
|
2715
2846
|
private async resolveCanPerformDeleteValue(
|
|
2716
2847
|
operation: DeleteOperation,
|
|
2717
2848
|
options?: { allowEntryFallback?: boolean },
|
|
@@ -2728,12 +2859,15 @@ export class Documents<
|
|
|
2728
2859
|
const indexedDocument =
|
|
2729
2860
|
await this.getLocalIdentityDocumentByHead(existingHead);
|
|
2730
2861
|
if (indexedDocument) {
|
|
2731
|
-
return indexedDocument;
|
|
2862
|
+
return this.detachDocumentValueForCallback(indexedDocument);
|
|
2732
2863
|
}
|
|
2733
2864
|
const indexedPolicyDocument =
|
|
2734
2865
|
await this.getLocalIndexedDocumentForNativeDeletePolicy(key);
|
|
2735
2866
|
if (indexedPolicyDocument) {
|
|
2736
|
-
return
|
|
2867
|
+
return deserialize(
|
|
2868
|
+
serialize(indexedPolicyDocument),
|
|
2869
|
+
this._index.indexedType,
|
|
2870
|
+
) as unknown as T;
|
|
2737
2871
|
}
|
|
2738
2872
|
if (options?.allowEntryFallback === false) {
|
|
2739
2873
|
return;
|
|
@@ -2745,7 +2879,9 @@ export class Documents<
|
|
|
2745
2879
|
if (!isPutOperation(existingOperation)) {
|
|
2746
2880
|
return;
|
|
2747
2881
|
}
|
|
2748
|
-
return this._index.valueEncoding.decoder(
|
|
2882
|
+
return this._index.valueEncoding.decoder(
|
|
2883
|
+
new Uint8Array(existingOperation.data),
|
|
2884
|
+
);
|
|
2749
2885
|
}
|
|
2750
2886
|
|
|
2751
2887
|
protected async _canAppend(
|
|
@@ -2796,17 +2932,32 @@ export class Documents<
|
|
|
2796
2932
|
if (isPutOperation(operation)) {
|
|
2797
2933
|
// check nexts
|
|
2798
2934
|
const putOperation = operation as PutOperation;
|
|
2935
|
+
let decodedDocumentForCanPerform: T | undefined;
|
|
2936
|
+
let hasDecodedDocumentForCanPerform = false;
|
|
2799
2937
|
let keyValue: indexerTypes.Ideable | undefined;
|
|
2800
2938
|
if (reference?.document) {
|
|
2801
|
-
keyValue = this.idResolver(
|
|
2939
|
+
keyValue = this.idResolver(
|
|
2940
|
+
this._hasCustomIdResolver
|
|
2941
|
+
? this.index.valueEncoding.decoder(
|
|
2942
|
+
new Uint8Array(putOperation.data),
|
|
2943
|
+
)
|
|
2944
|
+
: reference.document,
|
|
2945
|
+
);
|
|
2802
2946
|
} else {
|
|
2803
2947
|
keyValue = await this.getNativeDocumentIdFromPutOperation(putOperation);
|
|
2804
2948
|
if (keyValue == null) {
|
|
2805
2949
|
if (this.isNativeMode()) {
|
|
2806
2950
|
return false;
|
|
2807
2951
|
}
|
|
2808
|
-
const value = this.index.valueEncoding.decoder(
|
|
2809
|
-
|
|
2952
|
+
const value = this.index.valueEncoding.decoder(
|
|
2953
|
+
this._hasCustomIdResolver || this._optionCanPerform
|
|
2954
|
+
? new Uint8Array(putOperation.data)
|
|
2955
|
+
: putOperation.data,
|
|
2956
|
+
);
|
|
2957
|
+
if (this._optionCanPerform && !this._hasCustomIdResolver) {
|
|
2958
|
+
decodedDocumentForCanPerform = value;
|
|
2959
|
+
hasDecodedDocumentForCanPerform = true;
|
|
2960
|
+
}
|
|
2810
2961
|
keyValue = this.idResolver(value);
|
|
2811
2962
|
}
|
|
2812
2963
|
}
|
|
@@ -2843,7 +2994,11 @@ export class Documents<
|
|
|
2843
2994
|
return false; // can not append to immutable document
|
|
2844
2995
|
}
|
|
2845
2996
|
|
|
2846
|
-
return
|
|
2997
|
+
return this.acceptPutOperation(
|
|
2998
|
+
putOperation,
|
|
2999
|
+
decodedDocumentForCanPerform,
|
|
3000
|
+
hasDecodedDocumentForCanPerform,
|
|
3001
|
+
);
|
|
2847
3002
|
} else {
|
|
2848
3003
|
if (this.strictHistory) {
|
|
2849
3004
|
// make sure that the next pointer exist and points to the existing documents
|
|
@@ -2851,7 +3006,11 @@ export class Documents<
|
|
|
2851
3006
|
return false;
|
|
2852
3007
|
}
|
|
2853
3008
|
if (entry.meta.next[0] === existingContext.head) {
|
|
2854
|
-
return
|
|
3009
|
+
return this.acceptPutOperation(
|
|
3010
|
+
putOperation,
|
|
3011
|
+
decodedDocumentForCanPerform,
|
|
3012
|
+
hasDecodedDocumentForCanPerform,
|
|
3013
|
+
);
|
|
2855
3014
|
}
|
|
2856
3015
|
|
|
2857
3016
|
const prevEntry = await this.log.log.entryIndex.get(
|
|
@@ -2866,14 +3025,29 @@ export class Documents<
|
|
|
2866
3025
|
}
|
|
2867
3026
|
const referenceHistoryCorrectly =
|
|
2868
3027
|
await pointsToHistory(prevEntry);
|
|
2869
|
-
return referenceHistoryCorrectly
|
|
3028
|
+
return referenceHistoryCorrectly
|
|
3029
|
+
? this.acceptPutOperation(
|
|
3030
|
+
putOperation,
|
|
3031
|
+
decodedDocumentForCanPerform,
|
|
3032
|
+
hasDecodedDocumentForCanPerform,
|
|
3033
|
+
)
|
|
3034
|
+
: false;
|
|
2870
3035
|
} else {
|
|
2871
|
-
return
|
|
3036
|
+
return this.acceptPutOperation(
|
|
3037
|
+
putOperation,
|
|
3038
|
+
decodedDocumentForCanPerform,
|
|
3039
|
+
hasDecodedDocumentForCanPerform,
|
|
3040
|
+
);
|
|
2872
3041
|
}
|
|
2873
3042
|
}
|
|
2874
3043
|
} else {
|
|
2875
3044
|
// Keep existing behavior: next pointers may express document dependencies.
|
|
2876
3045
|
}
|
|
3046
|
+
return this.acceptPutOperation(
|
|
3047
|
+
putOperation,
|
|
3048
|
+
decodedDocumentForCanPerform,
|
|
3049
|
+
hasDecodedDocumentForCanPerform,
|
|
3050
|
+
);
|
|
2877
3051
|
} else if (isDeleteOperation(operation)) {
|
|
2878
3052
|
if (entry.meta.next.length !== 1) {
|
|
2879
3053
|
return false;
|
|
@@ -2924,7 +3098,6 @@ export class Documents<
|
|
|
2924
3098
|
throw new Error("Unsupported operation");
|
|
2925
3099
|
}
|
|
2926
3100
|
|
|
2927
|
-
return operation;
|
|
2928
3101
|
} catch (error) {
|
|
2929
3102
|
if (error instanceof AccessError) {
|
|
2930
3103
|
return false; // we cant index because we can not decrypt
|
|
@@ -5459,14 +5632,25 @@ export class Documents<
|
|
|
5459
5632
|
}
|
|
5460
5633
|
}
|
|
5461
5634
|
let value =
|
|
5462
|
-
|
|
5463
|
-
|
|
5635
|
+
isReferencedAppendEntry && reference?.document
|
|
5636
|
+
? reference.document
|
|
5637
|
+
: this.index.valueEncoding.decoder(
|
|
5638
|
+
new Uint8Array(payload.data),
|
|
5639
|
+
);
|
|
5464
5640
|
|
|
5465
5641
|
// get index key from value
|
|
5466
5642
|
const key =
|
|
5467
5643
|
isReferencedAppendEntry && reference?.key
|
|
5468
5644
|
? reference.key
|
|
5469
|
-
: indexerTypes.toId(
|
|
5645
|
+
: indexerTypes.toId(
|
|
5646
|
+
this.idResolver(
|
|
5647
|
+
this._hasCustomIdResolver
|
|
5648
|
+
? this.index.valueEncoding.decoder(
|
|
5649
|
+
new Uint8Array(payload.data),
|
|
5650
|
+
)
|
|
5651
|
+
: value,
|
|
5652
|
+
),
|
|
5653
|
+
);
|
|
5470
5654
|
|
|
5471
5655
|
// document is already updated with more recent entry
|
|
5472
5656
|
if (modified.has(key.primitive)) {
|
package/src/search.ts
CHANGED
|
@@ -44,6 +44,7 @@ import { AbortError, TimeoutError, waitFor } from "@peerbit/time";
|
|
|
44
44
|
import pDefer, { type DeferredPromise } from "p-defer";
|
|
45
45
|
import { concat, equals, fromString } from "uint8arrays";
|
|
46
46
|
import { copySerialization } from "./borsh.js";
|
|
47
|
+
import { detachPublicKeysForCallback } from "./callback-detachment.js";
|
|
47
48
|
import { MAX_BATCH_SIZE } from "./constants.js";
|
|
48
49
|
import type { DocumentEvents, DocumentsChange } from "./events.js";
|
|
49
50
|
import type { QueryPredictor } from "./most-common-query-predictor.js";
|
|
@@ -74,6 +75,7 @@ import {
|
|
|
74
75
|
canPrepareDocumentTransformWithAppendFacts,
|
|
75
76
|
documentTransformPreservesFieldPath,
|
|
76
77
|
getDocumentTransformDescriptor,
|
|
78
|
+
isBuiltInDocumentTransformer,
|
|
77
79
|
} from "./transform.js";
|
|
78
80
|
|
|
79
81
|
const WARNING_WHEN_ITERATING_FOR_MORE_THAN = 1e5;
|
|
@@ -1050,6 +1052,7 @@ export class DocumentIndex<
|
|
|
1050
1052
|
// transform options
|
|
1051
1053
|
transformer: Transformer<T, I>;
|
|
1052
1054
|
private transformerIsIdentity = false;
|
|
1055
|
+
private detachTransformerFacts = false;
|
|
1053
1056
|
private nativeTransformDescriptor?: DocumentTransformDescriptor;
|
|
1054
1057
|
private nativeTransformProjectionPlan?: SimpleDocumentProjectionPlan;
|
|
1055
1058
|
private nativeBackboneDocumentProjection?: NativeBackboneDocumentProjection;
|
|
@@ -1631,6 +1634,9 @@ export class DocumentIndex<
|
|
|
1631
1634
|
this.nativeTransformDescriptor = hasTransformFunction
|
|
1632
1635
|
? getDocumentTransformDescriptor(transformOptions.transform)
|
|
1633
1636
|
: undefined;
|
|
1637
|
+
this.detachTransformerFacts =
|
|
1638
|
+
hasTransformFunction &&
|
|
1639
|
+
!isBuiltInDocumentTransformer(transformOptions.transform);
|
|
1634
1640
|
this.nativeTransformProjectionPlan = createSimpleProjectionPlan(
|
|
1635
1641
|
getSchema(this.documentType),
|
|
1636
1642
|
indexedSchema,
|
|
@@ -1827,6 +1833,36 @@ export class DocumentIndex<
|
|
|
1827
1833
|
);
|
|
1828
1834
|
}
|
|
1829
1835
|
|
|
1836
|
+
private transformWithDetachedFacts(
|
|
1837
|
+
value: T,
|
|
1838
|
+
context: types.Context,
|
|
1839
|
+
facts?: DocumentTransformFacts,
|
|
1840
|
+
): MaybePromise<I> {
|
|
1841
|
+
let callbackFacts = facts;
|
|
1842
|
+
if (facts?.entryPublicKeys && this.detachTransformerFacts) {
|
|
1843
|
+
const sourceKeys = facts.entryPublicKeys;
|
|
1844
|
+
let callbackKeys: readonly PublicSignKey[] | undefined;
|
|
1845
|
+
let resolved = false;
|
|
1846
|
+
callbackFacts = { ...facts };
|
|
1847
|
+
Object.defineProperty(callbackFacts, "entryPublicKeys", {
|
|
1848
|
+
configurable: true,
|
|
1849
|
+
enumerable: true,
|
|
1850
|
+
get: () => {
|
|
1851
|
+
if (!resolved) {
|
|
1852
|
+
callbackKeys = detachPublicKeysForCallback(sourceKeys);
|
|
1853
|
+
resolved = true;
|
|
1854
|
+
}
|
|
1855
|
+
return callbackKeys;
|
|
1856
|
+
},
|
|
1857
|
+
set: (value: readonly PublicSignKey[] | undefined) => {
|
|
1858
|
+
callbackKeys = value;
|
|
1859
|
+
resolved = true;
|
|
1860
|
+
},
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
return this.transformer(value, context, callbackFacts);
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1830
1866
|
private prepareNativeBackboneDocumentIndexCommit(
|
|
1831
1867
|
value: T,
|
|
1832
1868
|
encodedDocument: Uint8Array,
|
|
@@ -1851,7 +1887,7 @@ export class DocumentIndex<
|
|
|
1851
1887
|
},
|
|
1852
1888
|
getIndexable: () => {
|
|
1853
1889
|
if (!hasCached) {
|
|
1854
|
-
const transformed = this.
|
|
1890
|
+
const transformed = this.transformWithDetachedFacts(
|
|
1855
1891
|
value,
|
|
1856
1892
|
projectionContext as types.Context,
|
|
1857
1893
|
transformFacts,
|
|
@@ -1878,7 +1914,7 @@ export class DocumentIndex<
|
|
|
1878
1914
|
) {
|
|
1879
1915
|
return;
|
|
1880
1916
|
}
|
|
1881
|
-
const transformed = this.
|
|
1917
|
+
const transformed = this.transformWithDetachedFacts(
|
|
1882
1918
|
value,
|
|
1883
1919
|
undefined as unknown as types.Context,
|
|
1884
1920
|
transformFacts,
|
|
@@ -1924,7 +1960,7 @@ export class DocumentIndex<
|
|
|
1924
1960
|
},
|
|
1925
1961
|
getIndexable: () => {
|
|
1926
1962
|
if (!hasCached) {
|
|
1927
|
-
const transformed = this.
|
|
1963
|
+
const transformed = this.transformWithDetachedFacts(
|
|
1928
1964
|
value,
|
|
1929
1965
|
projectionContext as types.Context,
|
|
1930
1966
|
transformFacts,
|
|
@@ -1961,7 +1997,11 @@ export class DocumentIndex<
|
|
|
1961
1997
|
) {
|
|
1962
1998
|
return;
|
|
1963
1999
|
}
|
|
1964
|
-
const transformed = this.
|
|
2000
|
+
const transformed = this.transformWithDetachedFacts(
|
|
2001
|
+
value,
|
|
2002
|
+
context,
|
|
2003
|
+
transformFacts,
|
|
2004
|
+
);
|
|
1965
2005
|
if (isPromiseLike(transformed)) {
|
|
1966
2006
|
return;
|
|
1967
2007
|
}
|
|
@@ -3150,7 +3190,11 @@ export class DocumentIndex<
|
|
|
3150
3190
|
this.cacheResolvedValue(idString, value);
|
|
3151
3191
|
const valueToIndex = this.transformerIsIdentity
|
|
3152
3192
|
? (value as any as I)
|
|
3153
|
-
: await this.
|
|
3193
|
+
: await this.transformWithDetachedFacts(
|
|
3194
|
+
value,
|
|
3195
|
+
context,
|
|
3196
|
+
options?.transformFacts,
|
|
3197
|
+
);
|
|
3154
3198
|
|
|
3155
3199
|
coerceWithIndexed(value, valueToIndex);
|
|
3156
3200
|
|
package/src/transform.ts
CHANGED
|
@@ -43,6 +43,7 @@ export type DocumentTransformDescriptor =
|
|
|
43
43
|
const NATIVE_DOCUMENT_TRANSFORM = Symbol.for(
|
|
44
44
|
"@peerbit/document/native-document-transform",
|
|
45
45
|
);
|
|
46
|
+
const builtInDocumentTransformers = new WeakSet<Function>();
|
|
46
47
|
|
|
47
48
|
type DescribedDocumentTransformer<T, I> = DocumentTransformer<T, I> & {
|
|
48
49
|
readonly [NATIVE_DOCUMENT_TRANSFORM]?: DocumentTransformDescriptor;
|
|
@@ -142,9 +143,15 @@ const attachDocumentTransformDescriptor = <T, I>(
|
|
|
142
143
|
writable: false,
|
|
143
144
|
configurable: false,
|
|
144
145
|
});
|
|
146
|
+
builtInDocumentTransformers.add(fn);
|
|
145
147
|
return fn;
|
|
146
148
|
};
|
|
147
149
|
|
|
150
|
+
/** Distinguish library-created transforms from forgeable public descriptors. */
|
|
151
|
+
export const isBuiltInDocumentTransformer = <T, I>(
|
|
152
|
+
transformer: DocumentTransformer<T, I> | undefined,
|
|
153
|
+
): boolean => !!transformer && builtInDocumentTransformers.has(transformer);
|
|
154
|
+
|
|
148
155
|
export const getDocumentTransformDescriptor = <T, I>(
|
|
149
156
|
transformer: DocumentTransformer<T, I> | undefined,
|
|
150
157
|
): DocumentTransformDescriptor | undefined =>
|