@peerbit/document 6.0.7 → 7.0.0-3a75d6e
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/README.md +2 -2
- package/dist/benchmark/index.d.ts +2 -0
- package/dist/benchmark/index.d.ts.map +1 -0
- package/dist/benchmark/index.js +125 -0
- package/dist/benchmark/index.js.map +1 -0
- 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.d.ts +2 -0
- package/dist/benchmark/replication.d.ts.map +1 -0
- package/dist/benchmark/replication.js +172 -0
- package/dist/benchmark/replication.js.map +1 -0
- 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/constants.d.ts +2 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +2 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/program.d.ts +87 -0
- package/dist/src/program.d.ts.map +1 -0
- package/{lib/esm/document-store.js → dist/src/program.js} +159 -138
- package/dist/src/program.js.map +1 -0
- package/dist/src/search.d.ts +132 -0
- package/dist/src/search.d.ts.map +1 -0
- package/dist/src/search.js +845 -0
- package/dist/src/search.js.map +1 -0
- package/package.json +74 -43
- package/src/borsh.ts +19 -0
- package/src/constants.ts +1 -0
- package/src/index.ts +3 -3
- package/src/program.ts +580 -0
- package/src/search.ts +1217 -0
- package/LICENSE +0 -202
- package/lib/esm/document-index.d.ts +0 -147
- package/lib/esm/document-index.js +0 -942
- package/lib/esm/document-index.js.map +0 -1
- package/lib/esm/document-store.d.ts +0 -72
- package/lib/esm/document-store.js.map +0 -1
- package/lib/esm/index.d.ts +0 -3
- package/lib/esm/index.js +0 -4
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/query.d.ts +0 -191
- package/lib/esm/query.js +0 -615
- package/lib/esm/query.js.map +0 -1
- package/lib/esm/utils.d.ts +0 -3
- package/lib/esm/utils.js +0 -12
- package/lib/esm/utils.js.map +0 -1
- package/src/document-index.ts +0 -1268
- package/src/document-store.ts +0 -547
- package/src/query.ts +0 -525
- package/src/utils.ts +0 -17
package/src/document-store.ts
DELETED
|
@@ -1,547 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AbstractType,
|
|
3
|
-
BorshError,
|
|
4
|
-
deserialize,
|
|
5
|
-
field,
|
|
6
|
-
serialize,
|
|
7
|
-
variant
|
|
8
|
-
} from "@dao-xyz/borsh";
|
|
9
|
-
import { Change, Entry, EntryType, TrimOptions } from "@peerbit/log";
|
|
10
|
-
import { Program, ProgramEvents } from "@peerbit/program";
|
|
11
|
-
import { AccessError, DecryptedThing } from "@peerbit/crypto";
|
|
12
|
-
import { logger as loggerFn } from "@peerbit/logger";
|
|
13
|
-
import { AppendOptions } from "@peerbit/log";
|
|
14
|
-
import { CustomEvent } from "@libp2p/interface";
|
|
15
|
-
import {
|
|
16
|
-
RoleOptions,
|
|
17
|
-
Observer,
|
|
18
|
-
Replicator,
|
|
19
|
-
SharedLog,
|
|
20
|
-
SharedLogOptions,
|
|
21
|
-
SharedAppendOptions
|
|
22
|
-
} from "@peerbit/shared-log";
|
|
23
|
-
|
|
24
|
-
export type { RoleOptions }; // For convenience (so that consumers does not have to do the import above from shared-log packages)
|
|
25
|
-
|
|
26
|
-
import {
|
|
27
|
-
IndexableFields,
|
|
28
|
-
BORSH_ENCODING_OPERATION,
|
|
29
|
-
DeleteOperation,
|
|
30
|
-
DocumentIndex,
|
|
31
|
-
Operation,
|
|
32
|
-
PutOperation,
|
|
33
|
-
CanSearch,
|
|
34
|
-
CanRead,
|
|
35
|
-
InMemoryIndex,
|
|
36
|
-
MAX_DOCUMENT_SIZE
|
|
37
|
-
} from "./document-index.js";
|
|
38
|
-
import { asString, checkKeyable, Keyable } from "./utils.js";
|
|
39
|
-
import { Context, Results } from "./query.js";
|
|
40
|
-
export { MAX_DOCUMENT_SIZE };
|
|
41
|
-
|
|
42
|
-
const logger = loggerFn({ module: "document" });
|
|
43
|
-
|
|
44
|
-
export class OperationError extends Error {
|
|
45
|
-
constructor(message?: string) {
|
|
46
|
-
super(message);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
export interface DocumentsChange<T> {
|
|
50
|
-
added: T[];
|
|
51
|
-
removed: T[];
|
|
52
|
-
}
|
|
53
|
-
export interface DocumentEvents<T> {
|
|
54
|
-
change: CustomEvent<DocumentsChange<T>>;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export type TransactionContext<T> = {
|
|
58
|
-
entry: Entry<Operation<T>>;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
type MaybePromise = Promise<boolean> | boolean;
|
|
62
|
-
|
|
63
|
-
export type CanPerform<T> = (
|
|
64
|
-
operation: PutOperation<T> | DeleteOperation,
|
|
65
|
-
context: TransactionContext<T>
|
|
66
|
-
) => MaybePromise;
|
|
67
|
-
|
|
68
|
-
export type SetupOptions<T> = {
|
|
69
|
-
type: AbstractType<T>;
|
|
70
|
-
canOpen?: (program: T) => MaybePromise;
|
|
71
|
-
canPerform?: CanPerform<T>;
|
|
72
|
-
index?: {
|
|
73
|
-
key?: string | string[];
|
|
74
|
-
fields?: IndexableFields<T>;
|
|
75
|
-
canSearch?: CanSearch;
|
|
76
|
-
canRead?: CanRead<T>;
|
|
77
|
-
};
|
|
78
|
-
log?: {
|
|
79
|
-
trim?: TrimOptions;
|
|
80
|
-
};
|
|
81
|
-
} & SharedLogOptions<Operation<T>>;
|
|
82
|
-
|
|
83
|
-
@variant("documents")
|
|
84
|
-
export class Documents<T extends Record<string, any>>
|
|
85
|
-
extends Program<SetupOptions<T>, DocumentEvents<T> & ProgramEvents>
|
|
86
|
-
implements InMemoryIndex<T>
|
|
87
|
-
{
|
|
88
|
-
@field({ type: SharedLog })
|
|
89
|
-
log: SharedLog<Operation<T>>;
|
|
90
|
-
|
|
91
|
-
@field({ type: "bool" })
|
|
92
|
-
immutable: boolean; // "Can I overwrite a document?"
|
|
93
|
-
|
|
94
|
-
@field({ type: DocumentIndex })
|
|
95
|
-
private _index: DocumentIndex<T>;
|
|
96
|
-
|
|
97
|
-
private _clazz: AbstractType<T>;
|
|
98
|
-
|
|
99
|
-
private _optionCanPerform?: CanPerform<T>;
|
|
100
|
-
private _manuallySynced: Set<string>;
|
|
101
|
-
|
|
102
|
-
canOpen?: (
|
|
103
|
-
program: T,
|
|
104
|
-
entry: Entry<Operation<T>>
|
|
105
|
-
) => Promise<boolean> | boolean;
|
|
106
|
-
|
|
107
|
-
constructor(properties?: {
|
|
108
|
-
id?: Uint8Array;
|
|
109
|
-
immutable?: boolean;
|
|
110
|
-
index?: DocumentIndex<T>;
|
|
111
|
-
}) {
|
|
112
|
-
super();
|
|
113
|
-
|
|
114
|
-
this.log = new SharedLog(properties);
|
|
115
|
-
this.immutable = properties?.immutable ?? false;
|
|
116
|
-
this._index = properties?.index || new DocumentIndex();
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
get index(): DocumentIndex<T> {
|
|
120
|
-
return this._index;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async open(options: SetupOptions<T>) {
|
|
124
|
-
this._clazz = options.type;
|
|
125
|
-
this.canOpen = options.canOpen;
|
|
126
|
-
|
|
127
|
-
/* eslint-disable */
|
|
128
|
-
if (Program.isPrototypeOf(this._clazz)) {
|
|
129
|
-
if (!this.canOpen) {
|
|
130
|
-
throw new Error(
|
|
131
|
-
"Document store needs to be opened with canOpen option when the document type is a Program"
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
this._optionCanPerform = options.canPerform;
|
|
137
|
-
|
|
138
|
-
this._manuallySynced = new Set();
|
|
139
|
-
|
|
140
|
-
await this._index.open({
|
|
141
|
-
type: this._clazz,
|
|
142
|
-
log: this.log,
|
|
143
|
-
canRead: options?.index?.canRead,
|
|
144
|
-
canSearch: options.index?.canSearch,
|
|
145
|
-
fields: options.index?.fields || ((obj) => obj),
|
|
146
|
-
indexBy: options.index?.key,
|
|
147
|
-
sync: async (result: Results<T>) => {
|
|
148
|
-
// here we arrive for all the results we want to persist.
|
|
149
|
-
// we we need to do here is
|
|
150
|
-
// 1. add the entry to a list of entries that we should persist through prunes
|
|
151
|
-
let heads: string[] = [];
|
|
152
|
-
for (const entry of result.results) {
|
|
153
|
-
this._manuallySynced.add(entry.context.gid);
|
|
154
|
-
heads.push(entry.context.head);
|
|
155
|
-
}
|
|
156
|
-
return this.log.log.join(heads);
|
|
157
|
-
},
|
|
158
|
-
dbType: this.constructor
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
await this.log.open({
|
|
162
|
-
encoding: BORSH_ENCODING_OPERATION,
|
|
163
|
-
canReplicate: options?.canReplicate,
|
|
164
|
-
canAppend: this.canAppend.bind(this),
|
|
165
|
-
onChange: this.handleChanges.bind(this),
|
|
166
|
-
trim: options?.log?.trim,
|
|
167
|
-
role: options?.role,
|
|
168
|
-
replicas: options?.replicas,
|
|
169
|
-
sync: (entry) => {
|
|
170
|
-
// here we arrive when ever a insertion/pruning behaviour processes an entry
|
|
171
|
-
// returning true means that it should persist
|
|
172
|
-
return this._manuallySynced.has(entry.gid);
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
async recover() {
|
|
178
|
-
return this.log.recover();
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
private async _resolveEntry(history: Entry<Operation<T>> | string) {
|
|
182
|
-
return typeof history === "string"
|
|
183
|
-
? (await this.log.log.get(history)) ||
|
|
184
|
-
(await Entry.fromMultihash<Operation<T>>(
|
|
185
|
-
this.log.log.blocks,
|
|
186
|
-
history
|
|
187
|
-
))
|
|
188
|
-
: history;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async updateRole(role: RoleOptions) {
|
|
192
|
-
await this.log.updateRole(role);
|
|
193
|
-
}
|
|
194
|
-
get role(): Replicator | Observer {
|
|
195
|
-
return this.log.role;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async canAppend(entry: Entry<Operation<T>>): Promise<boolean> {
|
|
199
|
-
const l0 = await this._canAppend(entry);
|
|
200
|
-
if (!l0) {
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
try {
|
|
205
|
-
const payload = await entry.getPayloadValue();
|
|
206
|
-
if (payload instanceof PutOperation) {
|
|
207
|
-
(payload as PutOperation<T>).getValue(this.index.valueEncoding); // Decode they value so callbacks can jsut do .value
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (this._optionCanPerform) {
|
|
211
|
-
if (
|
|
212
|
-
!(await this._optionCanPerform(
|
|
213
|
-
payload as PutOperation<T> | DeleteOperation,
|
|
214
|
-
{
|
|
215
|
-
entry
|
|
216
|
-
}
|
|
217
|
-
))
|
|
218
|
-
) {
|
|
219
|
-
return false;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
} catch (error) {
|
|
223
|
-
if (error instanceof BorshError) {
|
|
224
|
-
logger.warn("Received payload that could not be decoded, skipping");
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
throw error;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return true;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
async _canAppend(entry: Entry<Operation<T>>): Promise<boolean> {
|
|
234
|
-
const resolve = async (history: Entry<Operation<T>> | string) => {
|
|
235
|
-
return typeof history === "string"
|
|
236
|
-
? this.log.log.get(history) ||
|
|
237
|
-
(await Entry.fromMultihash(this.log.log.blocks, history))
|
|
238
|
-
: history;
|
|
239
|
-
};
|
|
240
|
-
const pointsToHistory = async (history: Entry<Operation<T>> | string) => {
|
|
241
|
-
// make sure nexts only points to this document at some point in history
|
|
242
|
-
let current = await resolve(history);
|
|
243
|
-
|
|
244
|
-
const next = entry.next[0];
|
|
245
|
-
while (
|
|
246
|
-
current?.hash &&
|
|
247
|
-
next !== current?.hash &&
|
|
248
|
-
current.next.length > 0
|
|
249
|
-
) {
|
|
250
|
-
current = await this.log.log.get(current.next[0])!;
|
|
251
|
-
}
|
|
252
|
-
if (current?.hash === next) {
|
|
253
|
-
return true; // Ok, we are pointing this new edit to some exising point in time of the old document
|
|
254
|
-
}
|
|
255
|
-
return false;
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
try {
|
|
259
|
-
entry.init({
|
|
260
|
-
encoding: this.log.log.encoding,
|
|
261
|
-
keychain: this.node.services.keychain
|
|
262
|
-
});
|
|
263
|
-
const operation =
|
|
264
|
-
entry._payload instanceof DecryptedThing
|
|
265
|
-
? entry.payload.getValue(entry.encoding)
|
|
266
|
-
: await entry.getPayloadValue();
|
|
267
|
-
if (operation instanceof PutOperation) {
|
|
268
|
-
// check nexts
|
|
269
|
-
const putOperation = operation as PutOperation<T>;
|
|
270
|
-
|
|
271
|
-
const key = this._index.indexByResolver(
|
|
272
|
-
putOperation.getValue(this.index.valueEncoding)
|
|
273
|
-
) as Keyable;
|
|
274
|
-
|
|
275
|
-
checkKeyable(key);
|
|
276
|
-
|
|
277
|
-
const existingDocument = this.index.index.get(asString(key));
|
|
278
|
-
if (existingDocument) {
|
|
279
|
-
if (this.immutable) {
|
|
280
|
-
//Key already exist and this instance Documents can note overrite/edit'
|
|
281
|
-
return false;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (entry.next.length !== 1) {
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
|
-
let doc = await this.log.log.get(existingDocument.context.head);
|
|
288
|
-
if (!doc) {
|
|
289
|
-
logger.error("Failed to find Document from head");
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
return pointsToHistory(doc);
|
|
293
|
-
} else {
|
|
294
|
-
if (entry.next.length !== 0) {
|
|
295
|
-
return false;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
} else if (operation instanceof DeleteOperation) {
|
|
299
|
-
if (entry.next.length !== 1) {
|
|
300
|
-
return false;
|
|
301
|
-
}
|
|
302
|
-
const existingDocument = this._index.index.get(operation.key);
|
|
303
|
-
if (!existingDocument) {
|
|
304
|
-
// already deleted
|
|
305
|
-
return true; // assume ok
|
|
306
|
-
}
|
|
307
|
-
let doc = await this.log.log.get(existingDocument.context.head);
|
|
308
|
-
if (!doc) {
|
|
309
|
-
logger.error("Failed to find Document from head");
|
|
310
|
-
return false;
|
|
311
|
-
}
|
|
312
|
-
return pointsToHistory(doc); // references the existing document
|
|
313
|
-
}
|
|
314
|
-
} catch (error) {
|
|
315
|
-
if (error instanceof AccessError) {
|
|
316
|
-
return false; // we cant index because we can not decrypt
|
|
317
|
-
} else if (error instanceof BorshError) {
|
|
318
|
-
logger.warn("Received payload that could not be decoded, skipping");
|
|
319
|
-
return false;
|
|
320
|
-
}
|
|
321
|
-
throw error;
|
|
322
|
-
}
|
|
323
|
-
return true;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
public async put(
|
|
327
|
-
doc: T,
|
|
328
|
-
options?: SharedAppendOptions<Operation<T>> & { unique?: boolean }
|
|
329
|
-
) {
|
|
330
|
-
const key = this._index.indexByResolver(doc as any as Keyable);
|
|
331
|
-
checkKeyable(key);
|
|
332
|
-
const ser = serialize(doc);
|
|
333
|
-
if (ser.length > MAX_DOCUMENT_SIZE) {
|
|
334
|
-
throw new Error(
|
|
335
|
-
`Document is too large (${
|
|
336
|
-
ser.length * 1e-6
|
|
337
|
-
}) mb). Needs to be less than ${MAX_DOCUMENT_SIZE * 1e-6} mb`
|
|
338
|
-
);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
const existingDocument = options?.unique
|
|
342
|
-
? undefined
|
|
343
|
-
: (
|
|
344
|
-
await this._index.getDetailed(key, {
|
|
345
|
-
local: true,
|
|
346
|
-
remote: { sync: true } // only query remote if we know they exist
|
|
347
|
-
})
|
|
348
|
-
)?.[0]?.results[0];
|
|
349
|
-
|
|
350
|
-
return this.log.append(
|
|
351
|
-
new PutOperation({
|
|
352
|
-
key: asString(key),
|
|
353
|
-
data: ser,
|
|
354
|
-
value: doc
|
|
355
|
-
}),
|
|
356
|
-
{
|
|
357
|
-
...options,
|
|
358
|
-
meta: {
|
|
359
|
-
next: existingDocument
|
|
360
|
-
? [await this._resolveEntry(existingDocument.context.head)]
|
|
361
|
-
: [],
|
|
362
|
-
...options?.meta
|
|
363
|
-
} //
|
|
364
|
-
}
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
async del(key: Keyable, options?: SharedAppendOptions<Operation<T>>) {
|
|
369
|
-
const existing = (
|
|
370
|
-
await this._index.getDetailed(key, {
|
|
371
|
-
local: true,
|
|
372
|
-
remote: { sync: true }
|
|
373
|
-
})
|
|
374
|
-
)?.[0]?.results[0];
|
|
375
|
-
if (!existing) {
|
|
376
|
-
throw new Error(`No entry with key '${key}' in the database`);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
return this.log.append(
|
|
380
|
-
new DeleteOperation({
|
|
381
|
-
key: asString(key)
|
|
382
|
-
}),
|
|
383
|
-
{
|
|
384
|
-
...options,
|
|
385
|
-
meta: {
|
|
386
|
-
next: [await this._resolveEntry(existing.context.head)],
|
|
387
|
-
type: EntryType.CUT,
|
|
388
|
-
...options?.meta
|
|
389
|
-
}
|
|
390
|
-
} //
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
async handleChanges(change: Change<Operation<T>>): Promise<void> {
|
|
395
|
-
const removed = [...(change.removed || [])];
|
|
396
|
-
const removedSet = new Map<string, Entry<Operation<T>>>();
|
|
397
|
-
for (const r of removed) {
|
|
398
|
-
removedSet.set(r.hash, r);
|
|
399
|
-
}
|
|
400
|
-
const entries = [...change.added, ...(removed || [])]
|
|
401
|
-
.sort(this.log.log.sortFn)
|
|
402
|
-
.reverse(); // sort so we get newest to oldest
|
|
403
|
-
|
|
404
|
-
// There might be a case where change.added and change.removed contains the same document id. Usaully because you use the "trim" option
|
|
405
|
-
// in combination with inserting the same document. To mitigate this, we loop through the changes and modify the behaviour for this
|
|
406
|
-
|
|
407
|
-
let visited = new Map<string, Entry<Operation<T>>[]>();
|
|
408
|
-
for (const item of entries) {
|
|
409
|
-
const payload =
|
|
410
|
-
item._payload instanceof DecryptedThing
|
|
411
|
-
? item.payload.getValue(item.encoding)
|
|
412
|
-
: await item.getPayloadValue();
|
|
413
|
-
let itemKey: string;
|
|
414
|
-
if (
|
|
415
|
-
payload instanceof PutOperation ||
|
|
416
|
-
payload instanceof DeleteOperation
|
|
417
|
-
) {
|
|
418
|
-
itemKey = payload.key;
|
|
419
|
-
} else {
|
|
420
|
-
throw new Error("Unsupported operation type");
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
let arr = visited.get(itemKey);
|
|
424
|
-
if (!arr) {
|
|
425
|
-
arr = [];
|
|
426
|
-
visited.set(itemKey, arr);
|
|
427
|
-
}
|
|
428
|
-
arr.push(item);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
let documentsChanged: DocumentsChange<T> = {
|
|
432
|
-
added: [],
|
|
433
|
-
removed: []
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
for (const [_key, entries] of visited) {
|
|
437
|
-
try {
|
|
438
|
-
const item = entries[0];
|
|
439
|
-
const payload =
|
|
440
|
-
item._payload instanceof DecryptedThing
|
|
441
|
-
? item.payload.getValue(item.encoding)
|
|
442
|
-
: await item.getPayloadValue();
|
|
443
|
-
if (payload instanceof PutOperation && !removedSet.has(item.hash)) {
|
|
444
|
-
const key = payload.key;
|
|
445
|
-
|
|
446
|
-
let value = this.deserializeOrPass(payload);
|
|
447
|
-
|
|
448
|
-
// Program specific
|
|
449
|
-
if (value instanceof Program) {
|
|
450
|
-
// if replicator, then open
|
|
451
|
-
if (
|
|
452
|
-
(await this.canOpen!(value, item)) &&
|
|
453
|
-
this.log.role instanceof Replicator &&
|
|
454
|
-
(await this.log.replicator(item)) // TODO types, throw runtime error if replicator is not provided
|
|
455
|
-
) {
|
|
456
|
-
value = (await this.node.open(value, {
|
|
457
|
-
parent: this as Program<any, any>,
|
|
458
|
-
existing: "reuse"
|
|
459
|
-
})) as any as T; // TODO types
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
documentsChanged.added.push(value);
|
|
463
|
-
|
|
464
|
-
const context = new Context({
|
|
465
|
-
created:
|
|
466
|
-
this._index.index.get(key)?.context.created ||
|
|
467
|
-
item.meta.clock.timestamp.wallTime,
|
|
468
|
-
modified: item.meta.clock.timestamp.wallTime,
|
|
469
|
-
head: item.hash,
|
|
470
|
-
gid: item.gid
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
const valueToIndex = this._index.toIndex(value, context);
|
|
474
|
-
this._index.index.set(key, {
|
|
475
|
-
key: payload.key,
|
|
476
|
-
value: isPromise(valueToIndex) ? await valueToIndex : valueToIndex,
|
|
477
|
-
context,
|
|
478
|
-
reference:
|
|
479
|
-
valueToIndex === value || value instanceof Program
|
|
480
|
-
? { value, last: payload }
|
|
481
|
-
: undefined
|
|
482
|
-
});
|
|
483
|
-
} else if (
|
|
484
|
-
(payload instanceof DeleteOperation && !removedSet.has(item.hash)) ||
|
|
485
|
-
payload instanceof PutOperation ||
|
|
486
|
-
removedSet.has(item.hash)
|
|
487
|
-
) {
|
|
488
|
-
this._manuallySynced.delete(item.gid);
|
|
489
|
-
|
|
490
|
-
const key = (payload as DeleteOperation | PutOperation<T>).key;
|
|
491
|
-
if (!this.index.index.has(key)) {
|
|
492
|
-
continue;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
let value: T;
|
|
496
|
-
if (payload instanceof PutOperation) {
|
|
497
|
-
value = this.deserializeOrPass(payload);
|
|
498
|
-
} else if (payload instanceof DeleteOperation) {
|
|
499
|
-
value = await this.getDocumentFromEntry(entries[1]!);
|
|
500
|
-
} else {
|
|
501
|
-
throw new Error("Unexpected");
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
documentsChanged.removed.push(value);
|
|
505
|
-
|
|
506
|
-
if (value instanceof Program) {
|
|
507
|
-
await value.drop(this);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
// update index
|
|
511
|
-
this._index.index.delete(key);
|
|
512
|
-
} else {
|
|
513
|
-
// Unknown operation
|
|
514
|
-
}
|
|
515
|
-
} catch (error) {
|
|
516
|
-
if (error instanceof AccessError) {
|
|
517
|
-
continue;
|
|
518
|
-
}
|
|
519
|
-
throw error;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
this.events.dispatchEvent(
|
|
524
|
-
new CustomEvent("change", { detail: documentsChanged })
|
|
525
|
-
);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
private async getDocumentFromEntry(entry: Entry<Operation<T>>) {
|
|
529
|
-
const payloadValue = await entry.getPayloadValue();
|
|
530
|
-
if (payloadValue instanceof PutOperation) {
|
|
531
|
-
return payloadValue.getValue(this.index.valueEncoding);
|
|
532
|
-
}
|
|
533
|
-
throw new Error("Unexpected");
|
|
534
|
-
}
|
|
535
|
-
deserializeOrPass(value: PutOperation<T>): T {
|
|
536
|
-
if (value._value) {
|
|
537
|
-
return value._value;
|
|
538
|
-
} else {
|
|
539
|
-
value._value = deserialize(value.data, this.index.type);
|
|
540
|
-
return value._value!;
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
function isPromise(value) {
|
|
546
|
-
return Boolean(value && typeof value.then === "function");
|
|
547
|
-
}
|