@fireproof/core-base 0.0.0-smoke-1b31059-1752074105

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.
Files changed (51) hide show
  1. package/LICENSE.md +232 -0
  2. package/apply-head-queue.d.ts +17 -0
  3. package/apply-head-queue.js +47 -0
  4. package/apply-head-queue.js.map +1 -0
  5. package/apply-head-queue.ts +72 -0
  6. package/bundle-not-impl.d.ts +1 -0
  7. package/bundle-not-impl.js +4 -0
  8. package/bundle-not-impl.js.map +1 -0
  9. package/bundle-not-impl.ts +4 -0
  10. package/crdt-clock.d.ts +25 -0
  11. package/crdt-clock.js +138 -0
  12. package/crdt-clock.js.map +1 -0
  13. package/crdt-clock.ts +192 -0
  14. package/crdt-helpers.d.ts +18 -0
  15. package/crdt-helpers.js +331 -0
  16. package/crdt-helpers.js.map +1 -0
  17. package/crdt-helpers.ts +484 -0
  18. package/crdt.d.ts +40 -0
  19. package/crdt.js +172 -0
  20. package/crdt.js.map +1 -0
  21. package/crdt.ts +268 -0
  22. package/database.d.ts +32 -0
  23. package/database.js +136 -0
  24. package/database.js.map +1 -0
  25. package/database.ts +200 -0
  26. package/index.d.ts +6 -0
  27. package/index.js +7 -0
  28. package/index.js.map +1 -0
  29. package/index.ts +9 -0
  30. package/indexer-helpers.d.ts +25 -0
  31. package/indexer-helpers.js +155 -0
  32. package/indexer-helpers.js.map +1 -0
  33. package/indexer-helpers.ts +263 -0
  34. package/indexer.d.ts +22 -0
  35. package/indexer.js +246 -0
  36. package/indexer.js.map +1 -0
  37. package/indexer.ts +360 -0
  38. package/ledger.d.ts +55 -0
  39. package/ledger.js +245 -0
  40. package/ledger.js.map +1 -0
  41. package/ledger.ts +344 -0
  42. package/package.json +54 -0
  43. package/tsconfig.json +18 -0
  44. package/version.d.ts +1 -0
  45. package/version.js +4 -0
  46. package/version.js.map +1 -0
  47. package/version.ts +3 -0
  48. package/write-queue.d.ts +4 -0
  49. package/write-queue.js +69 -0
  50. package/write-queue.js.map +1 -0
  51. package/write-queue.ts +93 -0
package/indexer.js ADDED
@@ -0,0 +1,246 @@
1
+ import { throwFalsy, } from "@fireproof/core-types-base";
2
+ import { bulkIndex, indexEntriesForChanges, byIdOpts, byKeyOpts, applyQuery, encodeRange, encodeKey, loadIndex, } from "./indexer-helpers.js";
3
+ import { ensureLogger } from "@fireproof/core-runtime";
4
+ function refLedger(u) {
5
+ return !!u.ledger;
6
+ }
7
+ export function index(refDb, name, mapFn, meta) {
8
+ const crdt = refLedger(refDb) ? refDb.ledger.crdt : refDb.crdt;
9
+ if (mapFn && meta)
10
+ throw refDb.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
11
+ if (mapFn && mapFn.constructor.name !== "Function")
12
+ throw refDb.logger.Error().Msg("mapFn must be a function").AsError();
13
+ if (crdt.indexers.has(name)) {
14
+ const idx = crdt.indexers.get(name);
15
+ idx.applyMapFn(name, mapFn, meta);
16
+ }
17
+ else {
18
+ const idx = new Index(refDb.sthis, crdt, name, mapFn, meta);
19
+ crdt.indexers.set(name, idx);
20
+ }
21
+ return crdt.indexers.get(name);
22
+ }
23
+ export class Index {
24
+ blockstore;
25
+ crdt;
26
+ name;
27
+ mapFn;
28
+ mapFnString = "";
29
+ byKey = {};
30
+ byId = {};
31
+ indexHead;
32
+ initError;
33
+ ready() {
34
+ return Promise.all([this.blockstore.ready(), this.crdt.ready()]).then(() => {
35
+ });
36
+ }
37
+ logger;
38
+ constructor(sthis, crdt, name, mapFn, meta) {
39
+ this.logger = ensureLogger(sthis, "Index");
40
+ if (!crdt.indexBlockstore) {
41
+ throw sthis.logger.Error().Msg("indexBlockstore not set").AsError();
42
+ }
43
+ this.blockstore = crdt.indexBlockstore;
44
+ this.crdt = crdt;
45
+ this.applyMapFn(name, mapFn, meta);
46
+ this.name = name;
47
+ if (!(this.mapFnString || this.initError))
48
+ throw this.logger.Error().Msg("missing mapFnString").AsError();
49
+ }
50
+ applyMapFn(name, mapFn, meta) {
51
+ if (mapFn && meta)
52
+ throw this.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
53
+ if (this.name && this.name !== name)
54
+ throw this.logger.Error().Msg("cannot change name").AsError();
55
+ try {
56
+ let mapFnChanged = false;
57
+ if (meta) {
58
+ if (this.indexHead && this.indexHead.map((c) => c.toString()).join() !== meta.head.map((c) => c.toString()).join()) {
59
+ throw this.logger.Error().Msg("cannot apply different head meta").AsError();
60
+ }
61
+ if (this.mapFnString) {
62
+ if (this.mapFnString !== meta.map) {
63
+ this.mapFnString = meta.map;
64
+ mapFnChanged = true;
65
+ }
66
+ this.byId.cid = meta.byId;
67
+ this.byKey.cid = meta.byKey;
68
+ this.indexHead = meta.head;
69
+ }
70
+ else {
71
+ this.mapFnString = meta.map;
72
+ this.byId.cid = meta.byId;
73
+ this.byKey.cid = meta.byKey;
74
+ this.indexHead = meta.head;
75
+ }
76
+ }
77
+ else {
78
+ if (this.mapFn) {
79
+ if (mapFn) {
80
+ if (this.mapFn.toString() !== mapFn.toString()) {
81
+ this.mapFn = mapFn;
82
+ this.mapFnString = mapFn.toString();
83
+ mapFnChanged = true;
84
+ }
85
+ }
86
+ }
87
+ else {
88
+ if (!mapFn) {
89
+ mapFn = ((doc) => doc[name] ?? undefined);
90
+ }
91
+ if (this.mapFnString) {
92
+ if (this.mapFnString !== mapFn.toString()) {
93
+ mapFnChanged = true;
94
+ }
95
+ }
96
+ else {
97
+ this.mapFnString = mapFn.toString();
98
+ }
99
+ this.mapFn = mapFn;
100
+ }
101
+ }
102
+ if (mapFnChanged) {
103
+ this._resetIndex();
104
+ }
105
+ }
106
+ catch (e) {
107
+ this.initError = e;
108
+ }
109
+ }
110
+ async query(opts = {}) {
111
+ this.logger.Debug().Msg("enter query");
112
+ await this.ready();
113
+ this.logger.Debug().Msg("post ready query");
114
+ await this._updateIndex();
115
+ this.logger.Debug().Msg("post _updateIndex query");
116
+ await this._hydrateIndex();
117
+ this.logger.Debug().Msg("post _hydrateIndex query");
118
+ if (!this.byKey.root) {
119
+ return await applyQuery(this.crdt, { result: [] }, opts);
120
+ }
121
+ if (opts.includeDocs === undefined)
122
+ opts.includeDocs = true;
123
+ if (opts.range) {
124
+ const eRange = encodeRange(opts.range);
125
+ return await applyQuery(this.crdt, await throwFalsy(this.byKey.root).range(eRange[0], eRange[1]), opts);
126
+ }
127
+ if (typeof opts.key === "boolean" || opts.key) {
128
+ const encodedKey = encodeKey(opts.key);
129
+ return await applyQuery(this.crdt, await throwFalsy(this.byKey.root).get(encodedKey), opts);
130
+ }
131
+ if (Array.isArray(opts.keys)) {
132
+ const optsWithoutLimit = { ...opts };
133
+ delete optsWithoutLimit.limit;
134
+ const results = await Promise.all(opts.keys.map(async (key) => {
135
+ const encodedKey = encodeKey(key);
136
+ return (await applyQuery(this.crdt, await throwFalsy(this.byKey.root).get(encodedKey), optsWithoutLimit)).rows;
137
+ }));
138
+ let flattenedRows = results.flat();
139
+ if (opts) {
140
+ flattenedRows = flattenedRows.slice(0, opts.limit);
141
+ }
142
+ return {
143
+ rows: flattenedRows,
144
+ docs: flattenedRows.map((r) => r.doc).filter((r) => !!r),
145
+ };
146
+ }
147
+ if (opts.prefix) {
148
+ if (!Array.isArray(opts.prefix))
149
+ opts.prefix = [opts.prefix];
150
+ const start = [...opts.prefix, NaN];
151
+ const end = [...opts.prefix, Infinity];
152
+ const encodedR = encodeRange([start, end]);
153
+ return await applyQuery(this.crdt, await this.byKey.root.range(...encodedR), opts);
154
+ }
155
+ const all = await this.byKey.root.getAllEntries();
156
+ return await applyQuery(this.crdt, {
157
+ result: all.result.map(({ key: [k, id], value }) => ({
158
+ key: k,
159
+ id,
160
+ value,
161
+ })),
162
+ }, opts);
163
+ }
164
+ _resetIndex() {
165
+ this.byId = {};
166
+ this.byKey = {};
167
+ this.indexHead = undefined;
168
+ }
169
+ async _hydrateIndex() {
170
+ if (this.byId.root && this.byKey.root)
171
+ return;
172
+ if (!this.byId.cid || !this.byKey.cid)
173
+ return;
174
+ this.byId.root = await loadIndex(this.blockstore, this.byId.cid, byIdOpts);
175
+ this.byKey.root = await loadIndex(this.blockstore, this.byKey.cid, byKeyOpts);
176
+ }
177
+ async _updateIndex() {
178
+ await this.ready();
179
+ this.logger.Debug().Msg("enter _updateIndex");
180
+ if (this.initError)
181
+ throw this.initError;
182
+ if (!this.mapFn)
183
+ throw this.logger.Error().Msg("No map function defined").AsError();
184
+ let result, head;
185
+ if (!this.indexHead || this.indexHead.length === 0) {
186
+ ({ result, head } = await this.crdt.allDocs());
187
+ this.logger.Debug().Msg("enter crdt.allDocs");
188
+ }
189
+ else {
190
+ ({ result, head } = await this.crdt.changes(this.indexHead));
191
+ this.logger.Debug().Msg("enter crdt.changes");
192
+ }
193
+ if (result.length === 0) {
194
+ this.indexHead = head;
195
+ }
196
+ let staleKeyIndexEntries = [];
197
+ let removeIdIndexEntries = [];
198
+ if (this.byId.root) {
199
+ const removeIds = result.map(({ id: key }) => key);
200
+ const { result: oldChangeEntries } = await this.byId.root.getMany(removeIds);
201
+ staleKeyIndexEntries = oldChangeEntries.map((key) => ({ key, del: true }));
202
+ removeIdIndexEntries = oldChangeEntries.map((key) => ({ key: key[1], del: true }));
203
+ }
204
+ const indexEntries = indexEntriesForChanges(result, this.mapFn);
205
+ const byIdIndexEntries = indexEntries.map(({ key }) => ({
206
+ key: key[1],
207
+ value: key,
208
+ }));
209
+ const indexerMeta = { indexes: new Map() };
210
+ for (const [name, indexer] of this.crdt.indexers) {
211
+ if (indexer.indexHead) {
212
+ indexerMeta.indexes?.set(name, {
213
+ byId: indexer.byId.cid,
214
+ byKey: indexer.byKey.cid,
215
+ head: indexer.indexHead,
216
+ map: indexer.mapFnString,
217
+ name: indexer.name,
218
+ });
219
+ }
220
+ }
221
+ if (result.length === 0) {
222
+ return indexerMeta;
223
+ }
224
+ this.logger.Debug().Msg("pre this.blockstore.transaction");
225
+ const { meta } = await this.blockstore.transaction(async (tblocks) => {
226
+ this.byId = await bulkIndex(this.logger, tblocks, this.byId, removeIdIndexEntries.concat(byIdIndexEntries), byIdOpts);
227
+ this.byKey = await bulkIndex(this.logger, tblocks, this.byKey, staleKeyIndexEntries.concat(indexEntries), byKeyOpts);
228
+ this.indexHead = head;
229
+ if (this.byId.cid && this.byKey.cid) {
230
+ const idxMeta = {
231
+ byId: this.byId.cid,
232
+ byKey: this.byKey.cid,
233
+ head,
234
+ map: this.mapFnString,
235
+ name: this.name,
236
+ };
237
+ indexerMeta.indexes?.set(this.name, idxMeta);
238
+ }
239
+ this.logger.Debug().Any("indexerMeta", new Array(indexerMeta.indexes?.entries())).Msg("exit this.blockstore.transaction fn");
240
+ return indexerMeta;
241
+ });
242
+ this.logger.Debug().Msg("post this.blockstore.transaction");
243
+ return meta;
244
+ }
245
+ }
246
+ //# sourceMappingURL=indexer.js.map
package/indexer.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexer.js","sourceRoot":"","sources":["indexer.ts"],"names":[],"mappings":"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"}
package/indexer.ts ADDED
@@ -0,0 +1,360 @@
1
+ /// <reference types="@fireproof/core-types-base/prolly-trees.d.ts" />
2
+
3
+ import {
4
+ type ClockHead,
5
+ type DocUpdate,
6
+ type MapFn,
7
+ type IndexUpdate,
8
+ type QueryOpts,
9
+ type IdxMeta,
10
+ type DocFragment,
11
+ type IdxMetaMap,
12
+ type IndexKeyType,
13
+ type IndexRows,
14
+ type DocTypes,
15
+ type IndexUpdateString,
16
+ throwFalsy,
17
+ type IndexTransactionMeta,
18
+ type SuperThis,
19
+ type BaseBlockstore,
20
+ type CRDT,
21
+ type HasCRDT,
22
+ type HasLogger,
23
+ type HasSuperThis,
24
+ type RefLedger,
25
+ type DocWithId,
26
+ IndexIf,
27
+ IndexTree,
28
+ } from "@fireproof/core-types-base";
29
+ // import { BaseBlockstore } from "./blockstore/index.js";
30
+
31
+ import {
32
+ bulkIndex,
33
+ indexEntriesForChanges,
34
+ byIdOpts,
35
+ byKeyOpts,
36
+ applyQuery,
37
+ encodeRange,
38
+ encodeKey,
39
+ loadIndex,
40
+ IndexDocString,
41
+ CompareKey,
42
+ } from "./indexer-helpers.js";
43
+ import { ensureLogger } from "@fireproof/core-runtime";
44
+ import { Logger } from "@adviser/cement";
45
+
46
+ // import { ProllyNode } from "prolly-trees/base";
47
+
48
+ function refLedger(u: HasCRDT | RefLedger): u is RefLedger {
49
+ return !!(u as RefLedger).ledger;
50
+ }
51
+
52
+ export function index<T extends DocTypes = DocTypes, K extends IndexKeyType = string, R extends DocFragment = T>(
53
+ refDb: HasLogger & HasSuperThis & (HasCRDT | RefLedger),
54
+ name: string,
55
+ mapFn?: MapFn<T>,
56
+ meta?: IdxMeta,
57
+ ): Index<T, K, R> {
58
+ const crdt = refLedger(refDb) ? refDb.ledger.crdt : refDb.crdt;
59
+
60
+ if (mapFn && meta) throw refDb.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
61
+ if (mapFn && mapFn.constructor.name !== "Function") throw refDb.logger.Error().Msg("mapFn must be a function").AsError();
62
+ if (crdt.indexers.has(name)) {
63
+ const idx = crdt.indexers.get(name) as unknown as Index<T, K>;
64
+ idx.applyMapFn(name, mapFn, meta);
65
+ } else {
66
+ const idx = new Index<T, K>(refDb.sthis, crdt, name, mapFn, meta);
67
+ crdt.indexers.set(name, idx as unknown as Index<DocTypes, K, DocTypes>);
68
+ }
69
+ return crdt.indexers.get(name) as unknown as Index<T, K, R>;
70
+ }
71
+
72
+ // interface ByIdIndexIten<K extends IndexKeyType> {
73
+ // readonly key: K;
74
+ // readonly value: [K, K];
75
+ // }
76
+
77
+ export class Index<T extends DocTypes, K extends IndexKeyType = string, R extends DocFragment = T> implements IndexIf<T, K, R> {
78
+ readonly blockstore: BaseBlockstore;
79
+ readonly crdt: CRDT;
80
+ readonly name: string;
81
+ mapFn?: MapFn<T>;
82
+ mapFnString = "";
83
+ byKey: IndexTree<K, R> = {};
84
+ byId: IndexTree<K, R> = {};
85
+ indexHead?: ClockHead;
86
+
87
+ initError?: Error;
88
+
89
+ ready(): Promise<void> {
90
+ return Promise.all([this.blockstore.ready(), this.crdt.ready()]).then(() => {
91
+ /* noop */
92
+ });
93
+ }
94
+
95
+ // close(): Promise<void> {
96
+ // return Promise.all([this.blockstore.close(), this.crdt.close()]).then(() => {
97
+ // /* noop */
98
+ // });
99
+ // }
100
+ // destroy(): Promise<void> {
101
+ // return Promise.all([this.blockstore.destroy(), this.crdt.destroy()]).then(() => {
102
+ // /* noop */
103
+ // });
104
+ // }
105
+
106
+ readonly logger: Logger;
107
+
108
+ constructor(sthis: SuperThis, crdt: CRDT, name: string, mapFn?: MapFn<T>, meta?: IdxMeta) {
109
+ this.logger = ensureLogger(sthis, "Index");
110
+ if (!crdt.indexBlockstore) {
111
+ throw sthis.logger.Error().Msg("indexBlockstore not set").AsError();
112
+ }
113
+ this.blockstore = crdt.indexBlockstore;
114
+ this.crdt = crdt as CRDT;
115
+ this.applyMapFn(name, mapFn, meta);
116
+ this.name = name;
117
+ if (!(this.mapFnString || this.initError)) throw this.logger.Error().Msg("missing mapFnString").AsError();
118
+ // this.ready = this.blockstore.ready.then(() => {
119
+ // return;
120
+ // });
121
+ // .then((header: IdxCarHeader) => {
122
+ // // @ts-ignore
123
+ // if (header.head) throw new Error('cannot have head in idx header')
124
+ // if (header.indexes === undefined) throw new Error('missing indexes in idx header')
125
+ // // for (const [name, idx] of Object.entries(header.indexes)) {
126
+ // // index({ _crdt: crdt }, name, undefined, idx as IdxMeta)
127
+ // // }
128
+ // })
129
+ }
130
+
131
+ applyMapFn(name: string, mapFn?: MapFn<T>, meta?: IdxMeta) {
132
+ if (mapFn && meta) throw this.logger.Error().Msg("cannot provide both mapFn and meta").AsError();
133
+ if (this.name && this.name !== name) throw this.logger.Error().Msg("cannot change name").AsError();
134
+ // this.name = name;
135
+ try {
136
+ let mapFnChanged = false;
137
+
138
+ if (meta) {
139
+ // hydrating from header
140
+ if (this.indexHead && this.indexHead.map((c) => c.toString()).join() !== meta.head.map((c) => c.toString()).join()) {
141
+ throw this.logger.Error().Msg("cannot apply different head meta").AsError();
142
+ }
143
+
144
+ if (this.mapFnString) {
145
+ // we already initialized from application code
146
+ if (this.mapFnString !== meta.map) {
147
+ this.mapFnString = meta.map;
148
+ mapFnChanged = true;
149
+ }
150
+ // Always apply the metadata
151
+ this.byId.cid = meta.byId;
152
+ this.byKey.cid = meta.byKey;
153
+ this.indexHead = meta.head;
154
+ } else {
155
+ // we are first
156
+ this.mapFnString = meta.map;
157
+ this.byId.cid = meta.byId;
158
+ this.byKey.cid = meta.byKey;
159
+ this.indexHead = meta.head;
160
+ }
161
+ } else {
162
+ if (this.mapFn) {
163
+ // we already initialized from application code
164
+ if (mapFn) {
165
+ if (this.mapFn.toString() !== mapFn.toString()) {
166
+ this.mapFn = mapFn;
167
+ this.mapFnString = mapFn.toString();
168
+ mapFnChanged = true;
169
+ }
170
+ }
171
+ } else {
172
+ // application code is creating an index
173
+ if (!mapFn) {
174
+ mapFn = ((doc) => (doc as unknown as Record<string, unknown>)[name] ?? undefined) as MapFn<T>;
175
+ }
176
+ if (this.mapFnString) {
177
+ // we already loaded from a header
178
+ if (this.mapFnString !== mapFn.toString()) {
179
+ mapFnChanged = true;
180
+ }
181
+ } else {
182
+ // we are first
183
+ this.mapFnString = mapFn.toString();
184
+ }
185
+ this.mapFn = mapFn;
186
+ }
187
+ }
188
+
189
+ // If the map function changed, reset the index for correctness
190
+ if (mapFnChanged) {
191
+ this._resetIndex();
192
+ }
193
+ } catch (e) {
194
+ this.initError = e as Error;
195
+ }
196
+ }
197
+
198
+ async query(opts: QueryOpts<K> = {}): Promise<IndexRows<T, K, R>> {
199
+ this.logger.Debug().Msg("enter query");
200
+ await this.ready();
201
+ // this._resetIndex();
202
+ this.logger.Debug().Msg("post ready query");
203
+ await this._updateIndex();
204
+ this.logger.Debug().Msg("post _updateIndex query");
205
+ await this._hydrateIndex();
206
+ this.logger.Debug().Msg("post _hydrateIndex query");
207
+ if (!this.byKey.root) {
208
+ return await applyQuery<T, K, R>(this.crdt, { result: [] }, opts);
209
+ }
210
+ if (opts.includeDocs === undefined) opts.includeDocs = true;
211
+ if (opts.range) {
212
+ const eRange = encodeRange(opts.range);
213
+ return await applyQuery<T, K, R>(this.crdt, await throwFalsy(this.byKey.root).range(eRange[0], eRange[1]), opts);
214
+ }
215
+ if (typeof opts.key === "boolean" || opts.key) {
216
+ const encodedKey = encodeKey(opts.key);
217
+ return await applyQuery<T, K, R>(this.crdt, await throwFalsy(this.byKey.root).get(encodedKey), opts);
218
+ }
219
+ if (Array.isArray(opts.keys)) {
220
+ // Create a new options object without the limit to avoid limiting individual key results
221
+ const optsWithoutLimit = { ...opts };
222
+ delete optsWithoutLimit.limit;
223
+
224
+ // Process each key separately but don't apply limit yet
225
+ const results = await Promise.all(
226
+ opts.keys.map(async (key: DocFragment) => {
227
+ const encodedKey = encodeKey(key);
228
+ return (await applyQuery<T, K, R>(this.crdt, await throwFalsy(this.byKey.root).get(encodedKey), optsWithoutLimit)).rows;
229
+ }),
230
+ );
231
+
232
+ // Flatten all results into a single array
233
+ let flattenedRows = results.flat();
234
+
235
+ // Apply the original limit to the combined results if it was specified
236
+ if (opts) {
237
+ flattenedRows = flattenedRows.slice(0, opts.limit);
238
+ }
239
+
240
+ return {
241
+ rows: flattenedRows,
242
+ docs: flattenedRows.map((r) => r.doc).filter((r): r is DocWithId<T> => !!r),
243
+ };
244
+ }
245
+ if (opts.prefix) {
246
+ if (!Array.isArray(opts.prefix)) opts.prefix = [opts.prefix];
247
+ // prefix should be always an array
248
+ const start = [...opts.prefix, NaN];
249
+ const end = [...opts.prefix, Infinity];
250
+ const encodedR = encodeRange([start, end]);
251
+ return await applyQuery<T, K, R>(this.crdt, await this.byKey.root.range(...encodedR), opts);
252
+ }
253
+ const all = await this.byKey.root.getAllEntries(); // funky return type
254
+ return await applyQuery<T, K, R>(
255
+ this.crdt,
256
+ {
257
+ // getAllEntries returns a different type than range
258
+ result: all.result.map(({ key: [k, id], value }) => ({
259
+ key: k as [K, string],
260
+ id,
261
+ value,
262
+ })),
263
+ },
264
+ opts,
265
+ );
266
+ }
267
+
268
+ _resetIndex() {
269
+ this.byId = {};
270
+ this.byKey = {};
271
+ this.indexHead = undefined;
272
+ }
273
+
274
+ async _hydrateIndex() {
275
+ if (this.byId.root && this.byKey.root) return;
276
+ if (!this.byId.cid || !this.byKey.cid) return;
277
+ this.byId.root = await loadIndex<K, R, string | number>(this.blockstore, this.byId.cid, byIdOpts);
278
+ this.byKey.root = await loadIndex<K, R, CompareKey>(this.blockstore, this.byKey.cid, byKeyOpts);
279
+ }
280
+
281
+ async _updateIndex(): Promise<IndexTransactionMeta> {
282
+ await this.ready();
283
+ this.logger.Debug().Msg("enter _updateIndex");
284
+ if (this.initError) throw this.initError;
285
+ if (!this.mapFn) throw this.logger.Error().Msg("No map function defined").AsError();
286
+ let result: DocUpdate<T>[], head: ClockHead;
287
+ if (!this.indexHead || this.indexHead.length === 0) {
288
+ ({ result, head } = await this.crdt.allDocs<T>());
289
+ this.logger.Debug().Msg("enter crdt.allDocs");
290
+ } else {
291
+ ({ result, head } = await this.crdt.changes<T>(this.indexHead));
292
+ this.logger.Debug().Msg("enter crdt.changes");
293
+ }
294
+ if (result.length === 0) {
295
+ this.indexHead = head;
296
+ // return { byId: this.byId, byKey: this.byKey } as IndexTransactionMeta;
297
+ }
298
+ let staleKeyIndexEntries: IndexUpdate<K>[] = [];
299
+ let removeIdIndexEntries: IndexUpdateString[] = [];
300
+ if (this.byId.root) {
301
+ const removeIds = result.map(({ id: key }) => key);
302
+ const { result: oldChangeEntries } = await this.byId.root.getMany(removeIds);
303
+ staleKeyIndexEntries = oldChangeEntries.map((key) => ({ key, del: true }));
304
+ removeIdIndexEntries = oldChangeEntries.map((key) => ({ key: key[1], del: true }));
305
+ }
306
+ const indexEntries = indexEntriesForChanges<T, K>(result, this.mapFn); // use a getter to translate from string
307
+ const byIdIndexEntries: IndexDocString[] = indexEntries.map(({ key }) => ({
308
+ key: key[1],
309
+ value: key,
310
+ }));
311
+ const indexerMeta: IdxMetaMap = { indexes: new Map() };
312
+
313
+ for (const [name, indexer] of this.crdt.indexers) {
314
+ if (indexer.indexHead) {
315
+ indexerMeta.indexes?.set(name, {
316
+ byId: indexer.byId.cid,
317
+ byKey: indexer.byKey.cid,
318
+ head: indexer.indexHead,
319
+ map: indexer.mapFnString,
320
+ name: indexer.name,
321
+ } as IdxMeta);
322
+ }
323
+ }
324
+ if (result.length === 0) {
325
+ return indexerMeta as unknown as IndexTransactionMeta;
326
+ }
327
+ this.logger.Debug().Msg("pre this.blockstore.transaction");
328
+ const { meta } = await this.blockstore.transaction<IndexTransactionMeta>(async (tblocks): Promise<IndexTransactionMeta> => {
329
+ this.byId = await bulkIndex<K, R, string | number>(
330
+ this.logger,
331
+ tblocks,
332
+ this.byId,
333
+ removeIdIndexEntries.concat(byIdIndexEntries),
334
+ byIdOpts,
335
+ );
336
+ this.byKey = await bulkIndex<K, R, CompareKey>(
337
+ this.logger,
338
+ tblocks,
339
+ this.byKey,
340
+ staleKeyIndexEntries.concat(indexEntries),
341
+ byKeyOpts,
342
+ );
343
+ this.indexHead = head;
344
+ if (this.byId.cid && this.byKey.cid) {
345
+ const idxMeta = {
346
+ byId: this.byId.cid,
347
+ byKey: this.byKey.cid,
348
+ head,
349
+ map: this.mapFnString,
350
+ name: this.name,
351
+ } as IdxMeta;
352
+ indexerMeta.indexes?.set(this.name, idxMeta);
353
+ }
354
+ this.logger.Debug().Any("indexerMeta", new Array(indexerMeta.indexes?.entries())).Msg("exit this.blockstore.transaction fn");
355
+ return indexerMeta as unknown as IndexTransactionMeta;
356
+ });
357
+ this.logger.Debug().Msg("post this.blockstore.transaction");
358
+ return meta;
359
+ }
360
+ }
package/ledger.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ import { Logger, ResolveOnce, AppContext } from "@adviser/cement";
2
+ import { DocUpdate, ConfigOpts, ListenerFn, DocTypes, SuperThis, Database, Ledger, WriteQueue, CRDT, LedgerOpts, Attachable, Attached, LedgerOptsOptionalTracer } from "@fireproof/core-types-base";
3
+ import { StoreURIRuntime, StoreUrlsOpts } from "@fireproof/core-types-blockstore";
4
+ export declare function keyConfigOpts(sthis: SuperThis, name: string, opts?: ConfigOpts): string;
5
+ export declare function isLedger(db: unknown): db is Ledger;
6
+ export declare function LedgerFactory(name: string, opts?: ConfigOpts): Ledger;
7
+ export declare class LedgerShell implements Ledger {
8
+ readonly ref: LedgerImpl;
9
+ readonly writeQueue: WriteQueue<DocUpdate<DocTypes>>;
10
+ readonly name: string;
11
+ constructor(ref: LedgerImpl);
12
+ attach(a: Attachable): Promise<Attached>;
13
+ get opts(): LedgerOpts;
14
+ get ctx(): AppContext;
15
+ refId(): Promise<string>;
16
+ get logger(): Logger;
17
+ get sthis(): SuperThis;
18
+ get crdt(): CRDT;
19
+ onClosed(fn: () => void): () => void;
20
+ close(): Promise<void>;
21
+ destroy(): Promise<void>;
22
+ ready(): Promise<void>;
23
+ subscribe<T extends DocTypes>(listener: ListenerFn<T>, updates?: boolean): () => void;
24
+ }
25
+ declare class LedgerImpl implements Ledger {
26
+ readonly opts: LedgerOpts;
27
+ _listening: boolean;
28
+ readonly _listeners: Set<ListenerFn<{}>>;
29
+ readonly _noupdate_listeners: Set<ListenerFn<{}>>;
30
+ readonly crdt: CRDT;
31
+ readonly writeQueue: WriteQueue<DocUpdate<DocTypes>>;
32
+ readonly shells: Set<LedgerShell>;
33
+ readonly ctx: AppContext;
34
+ get name(): string;
35
+ addShell(shell: LedgerShell): void;
36
+ readonly _refid: ResolveOnce<string, void>;
37
+ refId(): Promise<string>;
38
+ readonly _onClosedFns: Map<string, () => void>;
39
+ onClosed(fn: () => void): () => void;
40
+ close(): Promise<void>;
41
+ shellClose(db: LedgerShell): Promise<void>;
42
+ destroy(): Promise<void>;
43
+ readonly _ready: ResolveOnce<void>;
44
+ ready(): Promise<void>;
45
+ readonly logger: Logger;
46
+ readonly sthis: SuperThis;
47
+ constructor(sthis: SuperThis, opts: LedgerOptsOptionalTracer);
48
+ attach(a: Attachable): Promise<Attached>;
49
+ subscribe<T extends DocTypes>(listener: ListenerFn<T>, updates?: boolean): () => void;
50
+ private _notify;
51
+ private _no_update_notify;
52
+ }
53
+ export declare function toStoreURIRuntime(sthis: SuperThis, name: string, sopts?: StoreUrlsOpts): StoreURIRuntime;
54
+ export declare function fireproof(name: string, opts?: ConfigOpts): Database;
55
+ export {};