@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.
- package/LICENSE.md +232 -0
- package/apply-head-queue.d.ts +17 -0
- package/apply-head-queue.js +47 -0
- package/apply-head-queue.js.map +1 -0
- package/apply-head-queue.ts +72 -0
- package/bundle-not-impl.d.ts +1 -0
- package/bundle-not-impl.js +4 -0
- package/bundle-not-impl.js.map +1 -0
- package/bundle-not-impl.ts +4 -0
- package/crdt-clock.d.ts +25 -0
- package/crdt-clock.js +138 -0
- package/crdt-clock.js.map +1 -0
- package/crdt-clock.ts +192 -0
- package/crdt-helpers.d.ts +18 -0
- package/crdt-helpers.js +331 -0
- package/crdt-helpers.js.map +1 -0
- package/crdt-helpers.ts +484 -0
- package/crdt.d.ts +40 -0
- package/crdt.js +172 -0
- package/crdt.js.map +1 -0
- package/crdt.ts +268 -0
- package/database.d.ts +32 -0
- package/database.js +136 -0
- package/database.js.map +1 -0
- package/database.ts +200 -0
- package/index.d.ts +6 -0
- package/index.js +7 -0
- package/index.js.map +1 -0
- package/index.ts +9 -0
- package/indexer-helpers.d.ts +25 -0
- package/indexer-helpers.js +155 -0
- package/indexer-helpers.js.map +1 -0
- package/indexer-helpers.ts +263 -0
- package/indexer.d.ts +22 -0
- package/indexer.js +246 -0
- package/indexer.js.map +1 -0
- package/indexer.ts +360 -0
- package/ledger.d.ts +55 -0
- package/ledger.js +245 -0
- package/ledger.js.map +1 -0
- package/ledger.ts +344 -0
- package/package.json +54 -0
- package/tsconfig.json +18 -0
- package/version.d.ts +1 -0
- package/version.js +4 -0
- package/version.js.map +1 -0
- package/version.ts +3 -0
- package/write-queue.d.ts +4 -0
- package/write-queue.js +69 -0
- package/write-queue.js.map +1 -0
- package/write-queue.ts +93 -0
package/index.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { DocUpdate, MapFn, DocFragment, IndexUpdate, QueryOpts, IndexRows, IndexKeyType, IndexKey, DocTypes, DocObject, IndexUpdateString, CarTransaction, CRDT, IndexTree } from "@fireproof/core-types-base";
|
|
2
|
+
import { BlockFetcher, AnyLink } from "@fireproof/core-types-blockstore";
|
|
3
|
+
import { Logger } from "@adviser/cement";
|
|
4
|
+
import { StaticProllyOptions, BaseNode as ProllyNode, IndexRow } from "prolly-trees/base";
|
|
5
|
+
type CompareRef = string | number;
|
|
6
|
+
export type CompareKey = [string | number, CompareRef];
|
|
7
|
+
export declare const byKeyOpts: StaticProllyOptions<CompareKey>;
|
|
8
|
+
export declare const byIdOpts: StaticProllyOptions<string | number>;
|
|
9
|
+
export interface IndexDoc<K extends IndexKeyType> {
|
|
10
|
+
readonly key: IndexKey<K>;
|
|
11
|
+
readonly value: DocFragment;
|
|
12
|
+
}
|
|
13
|
+
export interface IndexDocString {
|
|
14
|
+
readonly key: string;
|
|
15
|
+
readonly value: DocFragment;
|
|
16
|
+
}
|
|
17
|
+
export declare function indexEntriesForChanges<T extends DocTypes, K extends IndexKeyType>(changes: DocUpdate<T>[], mapFn: MapFn<T>): IndexDoc<K>[];
|
|
18
|
+
export declare function bulkIndex<K extends IndexKeyType, T extends DocFragment, CT>(logger: Logger, tblocks: CarTransaction, inIndex: IndexTree<K, T>, indexEntries: (IndexUpdate<K> | IndexUpdateString)[], opts: StaticProllyOptions<CT>): Promise<IndexTree<K, T>>;
|
|
19
|
+
export declare function loadIndex<K extends IndexKeyType, T extends DocFragment, CT>(tblocks: BlockFetcher, cid: AnyLink, opts: StaticProllyOptions<CT>): Promise<ProllyNode<K, T>>;
|
|
20
|
+
export declare function applyQuery<T extends DocObject, K extends IndexKeyType, R extends DocFragment>(crdt: CRDT, resp: {
|
|
21
|
+
result: IndexRow<K, R>[];
|
|
22
|
+
}, query: QueryOpts<K>): Promise<IndexRows<T, K, R>>;
|
|
23
|
+
export declare function encodeRange(range: [IndexKeyType, IndexKeyType]): [string, string];
|
|
24
|
+
export declare function encodeKey(key: DocFragment): string;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { sha256 as hasher } from "multiformats/hashes/sha2";
|
|
2
|
+
import * as codec from "@ipld/dag-cbor";
|
|
3
|
+
import charwise from "charwise";
|
|
4
|
+
import * as DbIndex from "prolly-trees/db-index";
|
|
5
|
+
import { bf, simpleCompare } from "prolly-trees/utils";
|
|
6
|
+
import { nocache as cache } from "prolly-trees/cache";
|
|
7
|
+
import { anyBlock2FPBlock } from "@fireproof/core-blockstore";
|
|
8
|
+
import { asyncBlockCreate } from "@fireproof/core-runtime";
|
|
9
|
+
function refCompare(aRef, bRef) {
|
|
10
|
+
if (Number.isNaN(aRef))
|
|
11
|
+
return -1;
|
|
12
|
+
if (Number.isNaN(bRef))
|
|
13
|
+
throw new Error("ref may not be Infinity or NaN");
|
|
14
|
+
if (aRef === Infinity)
|
|
15
|
+
return 1;
|
|
16
|
+
return simpleCompare(aRef, bRef);
|
|
17
|
+
}
|
|
18
|
+
function compare(a, b) {
|
|
19
|
+
const [aKey, aRef] = a;
|
|
20
|
+
const [bKey, bRef] = b;
|
|
21
|
+
const comp = simpleCompare(aKey, bKey);
|
|
22
|
+
if (comp !== 0)
|
|
23
|
+
return comp;
|
|
24
|
+
return refCompare(aRef, bRef);
|
|
25
|
+
}
|
|
26
|
+
export const byKeyOpts = { cache, chunker: bf(30), codec, hasher, compare };
|
|
27
|
+
export const byIdOpts = { cache, chunker: bf(30), codec, hasher, compare: simpleCompare };
|
|
28
|
+
export function indexEntriesForChanges(changes, mapFn) {
|
|
29
|
+
const indexEntries = [];
|
|
30
|
+
changes.forEach(({ id: key, value, del }) => {
|
|
31
|
+
if (del || !value)
|
|
32
|
+
return;
|
|
33
|
+
let mapCalled = false;
|
|
34
|
+
const mapReturn = mapFn({ ...value, _id: key }, (k, v) => {
|
|
35
|
+
mapCalled = true;
|
|
36
|
+
if (typeof k === "undefined")
|
|
37
|
+
return;
|
|
38
|
+
indexEntries.push({
|
|
39
|
+
key: [charwise.encode(k), key],
|
|
40
|
+
value: v || null,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
if (!mapCalled && typeof mapReturn !== "undefined") {
|
|
44
|
+
indexEntries.push({
|
|
45
|
+
key: [charwise.encode(mapReturn), key],
|
|
46
|
+
value: null,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return indexEntries;
|
|
51
|
+
}
|
|
52
|
+
function makeProllyGetBlock(blocks) {
|
|
53
|
+
return async (address) => {
|
|
54
|
+
const block = await blocks.get(address);
|
|
55
|
+
if (!block)
|
|
56
|
+
throw new Error(`Missing block ${address.toString()}`);
|
|
57
|
+
const { cid, bytes } = block;
|
|
58
|
+
return asyncBlockCreate({ cid, bytes, hasher, codec });
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export async function bulkIndex(logger, tblocks, inIndex, indexEntries, opts) {
|
|
62
|
+
logger.Debug().Msg("enter bulkIndex");
|
|
63
|
+
if (!indexEntries.length)
|
|
64
|
+
return inIndex;
|
|
65
|
+
if (!inIndex.root) {
|
|
66
|
+
if (!inIndex.cid) {
|
|
67
|
+
let returnRootBlock = undefined;
|
|
68
|
+
let returnNode = undefined;
|
|
69
|
+
for await (const node of (await DbIndex.create({
|
|
70
|
+
get: makeProllyGetBlock(tblocks),
|
|
71
|
+
list: indexEntries,
|
|
72
|
+
...opts,
|
|
73
|
+
}))) {
|
|
74
|
+
const block = await node.block;
|
|
75
|
+
await tblocks.put(await anyBlock2FPBlock(block));
|
|
76
|
+
returnRootBlock = block;
|
|
77
|
+
returnNode = node;
|
|
78
|
+
}
|
|
79
|
+
if (!returnNode || !returnRootBlock)
|
|
80
|
+
throw new Error("failed to create index");
|
|
81
|
+
logger.Debug().Msg("exit !root bulkIndex");
|
|
82
|
+
return { root: returnNode, cid: returnRootBlock.cid };
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
inIndex.root = (await DbIndex.load({ cid: inIndex.cid, get: makeProllyGetBlock(tblocks), ...opts }));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
logger.Debug().Msg("pre bulk bulkIndex");
|
|
89
|
+
const { root, blocks: newBlocks } = await inIndex.root.bulk(indexEntries);
|
|
90
|
+
if (root) {
|
|
91
|
+
logger.Debug().Msg("pre root put bulkIndex");
|
|
92
|
+
for await (const block of newBlocks) {
|
|
93
|
+
await tblocks.put(await anyBlock2FPBlock(block));
|
|
94
|
+
}
|
|
95
|
+
return { root, cid: (await root.block).cid };
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
logger.Debug().Msg("pre !root bulkIndex");
|
|
99
|
+
return { root: undefined, cid: undefined };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export async function loadIndex(tblocks, cid, opts) {
|
|
103
|
+
return (await DbIndex.load({ cid, get: makeProllyGetBlock(tblocks), ...opts }));
|
|
104
|
+
}
|
|
105
|
+
export async function applyQuery(crdt, resp, query) {
|
|
106
|
+
if (query.descending) {
|
|
107
|
+
resp.result = resp.result.reverse();
|
|
108
|
+
}
|
|
109
|
+
if (query.limit) {
|
|
110
|
+
resp.result = resp.result.slice(0, query.limit);
|
|
111
|
+
}
|
|
112
|
+
if (query.includeDocs) {
|
|
113
|
+
resp.result = await Promise.all(resp.result.map(async (row) => {
|
|
114
|
+
const val = await crdt.get(row.id);
|
|
115
|
+
const doc = val ? { ...val.doc, _id: row.id } : undefined;
|
|
116
|
+
return { ...row, doc };
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
const rows = resp.result.map(({ key, ...row }) => {
|
|
120
|
+
const decodedKey = charwise.decode(key);
|
|
121
|
+
const dynamicRow = row;
|
|
122
|
+
if ("row" in dynamicRow && !("value" in dynamicRow)) {
|
|
123
|
+
const normalizedRow = {};
|
|
124
|
+
Object.keys(dynamicRow).forEach((k) => {
|
|
125
|
+
if (k === "row") {
|
|
126
|
+
normalizedRow.value = dynamicRow[k];
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
normalizedRow[k] = dynamicRow[k];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
key: decodedKey,
|
|
134
|
+
...normalizedRow,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
key: decodedKey,
|
|
139
|
+
...row,
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
const typedRows = rows;
|
|
143
|
+
const docs = typedRows.filter((r) => !!r.doc);
|
|
144
|
+
return {
|
|
145
|
+
rows: typedRows,
|
|
146
|
+
docs,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
export function encodeRange(range) {
|
|
150
|
+
return [charwise.encode(range[0]), charwise.encode(range[1])];
|
|
151
|
+
}
|
|
152
|
+
export function encodeKey(key) {
|
|
153
|
+
return charwise.encode(key);
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=indexer-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexer-helpers.js","sourceRoot":"","sources":["indexer-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/// <reference types="@fireproof/core-types-base/prolly-trees.d.ts" />
|
|
2
|
+
import type { Block } from "multiformats";
|
|
3
|
+
import { sha256 as hasher } from "multiformats/hashes/sha2";
|
|
4
|
+
import * as codec from "@ipld/dag-cbor";
|
|
5
|
+
|
|
6
|
+
// @ts-expect-error "charwise" has no types
|
|
7
|
+
import charwise from "charwise";
|
|
8
|
+
import * as DbIndex from "prolly-trees/db-index";
|
|
9
|
+
import { bf, simpleCompare } from "prolly-trees/utils";
|
|
10
|
+
import { nocache as cache } from "prolly-trees/cache";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
DocUpdate,
|
|
14
|
+
MapFn,
|
|
15
|
+
DocFragment,
|
|
16
|
+
IndexUpdate,
|
|
17
|
+
QueryOpts,
|
|
18
|
+
IndexRows,
|
|
19
|
+
DocWithId,
|
|
20
|
+
IndexKeyType,
|
|
21
|
+
IndexKey,
|
|
22
|
+
DocTypes,
|
|
23
|
+
DocObject,
|
|
24
|
+
IndexUpdateString,
|
|
25
|
+
CarTransaction,
|
|
26
|
+
CRDT,
|
|
27
|
+
IndexTree,
|
|
28
|
+
FPIndexRow,
|
|
29
|
+
} from "@fireproof/core-types-base";
|
|
30
|
+
import { BlockFetcher, AnyLink, AnyBlock } from "@fireproof/core-types-blockstore";
|
|
31
|
+
import { Logger } from "@adviser/cement";
|
|
32
|
+
import { anyBlock2FPBlock } from "@fireproof/core-blockstore";
|
|
33
|
+
import { StaticProllyOptions, BaseNode as ProllyNode, IndexRow } from "prolly-trees/base";
|
|
34
|
+
import { asyncBlockCreate } from "@fireproof/core-runtime";
|
|
35
|
+
|
|
36
|
+
type CompareRef = string | number;
|
|
37
|
+
export type CompareKey = [string | number, CompareRef];
|
|
38
|
+
|
|
39
|
+
function refCompare(aRef: CompareRef, bRef: CompareRef) {
|
|
40
|
+
if (Number.isNaN(aRef)) return -1;
|
|
41
|
+
if (Number.isNaN(bRef)) throw new Error("ref may not be Infinity or NaN");
|
|
42
|
+
if (aRef === Infinity) return 1;
|
|
43
|
+
// if (!Number.isFinite(bRef)) throw new Error('ref may not be Infinity or NaN')
|
|
44
|
+
|
|
45
|
+
return simpleCompare(aRef, bRef) as number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function compare(a: CompareKey, b: CompareKey) {
|
|
49
|
+
const [aKey, aRef] = a;
|
|
50
|
+
const [bKey, bRef] = b;
|
|
51
|
+
|
|
52
|
+
const comp: number = simpleCompare(aKey, bKey);
|
|
53
|
+
if (comp !== 0) return comp;
|
|
54
|
+
return refCompare(aRef, bRef);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// declare function bf<T>(factor: number): (entry: T, dist: number) => Promise<boolean>;
|
|
58
|
+
// chunker: (entry: T, distance: number) => Promise<boolean>;
|
|
59
|
+
export const byKeyOpts: StaticProllyOptions<CompareKey> = { cache, chunker: bf(30), codec, hasher, compare };
|
|
60
|
+
|
|
61
|
+
export const byIdOpts: StaticProllyOptions<string | number> = { cache, chunker: bf(30), codec, hasher, compare: simpleCompare };
|
|
62
|
+
|
|
63
|
+
export interface IndexDoc<K extends IndexKeyType> {
|
|
64
|
+
readonly key: IndexKey<K>;
|
|
65
|
+
readonly value: DocFragment;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface IndexDocString {
|
|
69
|
+
readonly key: string;
|
|
70
|
+
readonly value: DocFragment;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function indexEntriesForChanges<T extends DocTypes, K extends IndexKeyType>(
|
|
74
|
+
changes: DocUpdate<T>[],
|
|
75
|
+
mapFn: MapFn<T>,
|
|
76
|
+
): IndexDoc<K>[] {
|
|
77
|
+
const indexEntries: IndexDoc<K>[] = [];
|
|
78
|
+
changes.forEach(({ id: key, value, del }) => {
|
|
79
|
+
if (del || !value) return;
|
|
80
|
+
let mapCalled = false;
|
|
81
|
+
const mapReturn = mapFn({ ...(value as DocWithId<T>), _id: key }, (k: IndexKeyType, v?: DocFragment) => {
|
|
82
|
+
mapCalled = true;
|
|
83
|
+
if (typeof k === "undefined") return;
|
|
84
|
+
indexEntries.push({
|
|
85
|
+
key: [charwise.encode(k) as K, key],
|
|
86
|
+
value: v || null,
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
if (!mapCalled && typeof mapReturn !== "undefined") {
|
|
90
|
+
indexEntries.push({
|
|
91
|
+
key: [charwise.encode(mapReturn) as K, key],
|
|
92
|
+
value: null,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
return indexEntries;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function makeProllyGetBlock(blocks: BlockFetcher): (address: AnyLink) => Promise<AnyBlock> {
|
|
100
|
+
return async (address: AnyLink) => {
|
|
101
|
+
const block = await blocks.get(address);
|
|
102
|
+
if (!block) throw new Error(`Missing block ${address.toString()}`);
|
|
103
|
+
const { cid, bytes } = block;
|
|
104
|
+
return asyncBlockCreate({ cid, bytes, hasher, codec }) as Promise<AnyBlock>;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function bulkIndex<K extends IndexKeyType, T extends DocFragment, CT>(
|
|
109
|
+
logger: Logger,
|
|
110
|
+
tblocks: CarTransaction,
|
|
111
|
+
inIndex: IndexTree<K, T>,
|
|
112
|
+
indexEntries: (IndexUpdate<K> | IndexUpdateString)[],
|
|
113
|
+
opts: StaticProllyOptions<CT>,
|
|
114
|
+
): Promise<IndexTree<K, T>> {
|
|
115
|
+
logger.Debug().Msg("enter bulkIndex");
|
|
116
|
+
if (!indexEntries.length) return inIndex;
|
|
117
|
+
if (!inIndex.root) {
|
|
118
|
+
if (!inIndex.cid) {
|
|
119
|
+
let returnRootBlock: Block | undefined = undefined;
|
|
120
|
+
let returnNode: ProllyNode<K, T> | undefined = undefined;
|
|
121
|
+
|
|
122
|
+
for await (const node of (await DbIndex.create({
|
|
123
|
+
get: makeProllyGetBlock(tblocks),
|
|
124
|
+
list: indexEntries,
|
|
125
|
+
...opts,
|
|
126
|
+
})) as ProllyNode<K, T>[]) {
|
|
127
|
+
const block = await node.block;
|
|
128
|
+
await tblocks.put(await anyBlock2FPBlock(block));
|
|
129
|
+
returnRootBlock = block;
|
|
130
|
+
returnNode = node;
|
|
131
|
+
}
|
|
132
|
+
if (!returnNode || !returnRootBlock) throw new Error("failed to create index");
|
|
133
|
+
logger.Debug().Msg("exit !root bulkIndex");
|
|
134
|
+
return { root: returnNode, cid: returnRootBlock.cid };
|
|
135
|
+
} else {
|
|
136
|
+
inIndex.root = (await DbIndex.load({ cid: inIndex.cid, get: makeProllyGetBlock(tblocks), ...opts })) as ProllyNode<K, T>;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
logger.Debug().Msg("pre bulk bulkIndex");
|
|
140
|
+
const { root, blocks: newBlocks } = await inIndex.root.bulk(indexEntries);
|
|
141
|
+
if (root) {
|
|
142
|
+
logger.Debug().Msg("pre root put bulkIndex");
|
|
143
|
+
for await (const block of newBlocks) {
|
|
144
|
+
await tblocks.put(await anyBlock2FPBlock(block));
|
|
145
|
+
}
|
|
146
|
+
return { root, cid: (await root.block).cid };
|
|
147
|
+
} else {
|
|
148
|
+
logger.Debug().Msg("pre !root bulkIndex");
|
|
149
|
+
return { root: undefined, cid: undefined };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export async function loadIndex<K extends IndexKeyType, T extends DocFragment, CT>(
|
|
154
|
+
tblocks: BlockFetcher,
|
|
155
|
+
cid: AnyLink,
|
|
156
|
+
opts: StaticProllyOptions<CT>,
|
|
157
|
+
): Promise<ProllyNode<K, T>> {
|
|
158
|
+
return (await DbIndex.load({ cid, get: makeProllyGetBlock(tblocks), ...opts })) as ProllyNode<K, T>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export async function applyQuery<T extends DocObject, K extends IndexKeyType, R extends DocFragment>(
|
|
162
|
+
crdt: CRDT,
|
|
163
|
+
resp: { result: IndexRow<K, R>[] },
|
|
164
|
+
query: QueryOpts<K>,
|
|
165
|
+
): Promise<IndexRows<T, K, R>> {
|
|
166
|
+
if (query.descending) {
|
|
167
|
+
resp.result = resp.result.reverse();
|
|
168
|
+
}
|
|
169
|
+
if (query.limit) {
|
|
170
|
+
resp.result = resp.result.slice(0, query.limit);
|
|
171
|
+
}
|
|
172
|
+
if (query.includeDocs) {
|
|
173
|
+
resp.result = await Promise.all(
|
|
174
|
+
resp.result.map(async (row) => {
|
|
175
|
+
const val = await crdt.get(row.id);
|
|
176
|
+
const doc = val ? ({ ...val.doc, _id: row.id } as DocWithId<T>) : undefined;
|
|
177
|
+
return { ...row, doc };
|
|
178
|
+
}),
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
const rows = resp.result.map(({ key, ...row }) => {
|
|
182
|
+
// First decode the key
|
|
183
|
+
const decodedKey = charwise.decode(key);
|
|
184
|
+
|
|
185
|
+
// Use a type-safe approach with Record to check for potentially missing properties
|
|
186
|
+
// This handles the case where some query results use 'row' instead of 'value'
|
|
187
|
+
const dynamicRow = row as Record<string, unknown>;
|
|
188
|
+
if ("row" in dynamicRow && !("value" in dynamicRow)) {
|
|
189
|
+
// We found a result with 'row' property but no 'value' property
|
|
190
|
+
// Create a new normalized object with the 'value' property
|
|
191
|
+
const normalizedRow: Record<string, unknown> = {};
|
|
192
|
+
Object.keys(dynamicRow).forEach((k) => {
|
|
193
|
+
if (k === "row") {
|
|
194
|
+
normalizedRow.value = dynamicRow[k];
|
|
195
|
+
} else {
|
|
196
|
+
normalizedRow[k] = dynamicRow[k];
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
key: decodedKey,
|
|
202
|
+
...normalizedRow,
|
|
203
|
+
} as IndexRow<K, R>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Standard case - use the properties as they are
|
|
207
|
+
return {
|
|
208
|
+
key: decodedKey,
|
|
209
|
+
...row,
|
|
210
|
+
} as IndexRow<K, R>;
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// We need to be explicit about the document types here
|
|
214
|
+
const typedRows = rows as FPIndexRow<K, T, R>[];
|
|
215
|
+
|
|
216
|
+
// Simply filter out null/undefined docs and cast the result
|
|
217
|
+
const docs = typedRows.filter((r) => !!r.doc) as unknown as DocWithId<T>[];
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
rows: typedRows,
|
|
221
|
+
docs,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function encodeRange(range: [IndexKeyType, IndexKeyType]): [string, string] {
|
|
226
|
+
return [charwise.encode(range[0]), charwise.encode(range[1])];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function encodeKey(key: DocFragment): string {
|
|
230
|
+
return charwise.encode(key) as string;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// export interface ProllyIndexRow<K extends IndexKeyType, T extends DocFragment> {
|
|
234
|
+
// readonly id: string;
|
|
235
|
+
// readonly key: IndexKey<K>;
|
|
236
|
+
// readonly value: T;
|
|
237
|
+
// readonly doc?: DocWithId<DocObject>;
|
|
238
|
+
// }
|
|
239
|
+
|
|
240
|
+
// // ProllyNode type based on the ProllyNode from 'prolly-trees/base'
|
|
241
|
+
// interface ProllyNode<K extends IndexKeyType, T extends DocFragment> extends BaseNode<K, T> {
|
|
242
|
+
// getAllEntries(): PromiseLike<{ [x: string]: unknown; result: ProllyIndexRow<K, T>[] }>;
|
|
243
|
+
// getMany<KI extends IndexKeyType>(removeIds: KI[]): Promise<{ /* [x: K]: unknown; */ result: IndexKey<K>[] }>;
|
|
244
|
+
// range(a: string, b: string): Promise<{ result: ProllyIndexRow<K, T>[] }>;
|
|
245
|
+
// get(key: string): Promise<{ result: ProllyIndexRow<K, T>[] }>;
|
|
246
|
+
// bulk(bulk: (IndexUpdate<K> | IndexUpdateString)[]): PromiseLike<{
|
|
247
|
+
// readonly root?: ProllyNode<K, T>;
|
|
248
|
+
// readonly blocks: Block[];
|
|
249
|
+
// }>;
|
|
250
|
+
// readonly address: Promise<Link>;
|
|
251
|
+
// readonly distance: number;
|
|
252
|
+
// compare: (a: unknown, b: unknown) => number;
|
|
253
|
+
// readonly cache: unknown;
|
|
254
|
+
// readonly block: Promise<Block>;
|
|
255
|
+
// }
|
|
256
|
+
|
|
257
|
+
// interface StaticProllyOptions<T> {
|
|
258
|
+
// readonly cache: unknown;
|
|
259
|
+
// chunker: (entry: T, distance: number) => boolean;
|
|
260
|
+
// readonly codec: unknown;
|
|
261
|
+
// readonly hasher: unknown;
|
|
262
|
+
// compare: (a: T, b: T) => number;
|
|
263
|
+
// }
|
package/indexer.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ClockHead, type MapFn, type QueryOpts, type IdxMeta, type DocFragment, type IndexKeyType, type IndexRows, type DocTypes, type IndexTransactionMeta, type SuperThis, type BaseBlockstore, type CRDT, type HasCRDT, type HasLogger, type HasSuperThis, type RefLedger, IndexIf, IndexTree } from "@fireproof/core-types-base";
|
|
2
|
+
import { Logger } from "@adviser/cement";
|
|
3
|
+
export declare function index<T extends DocTypes = DocTypes, K extends IndexKeyType = string, R extends DocFragment = T>(refDb: HasLogger & HasSuperThis & (HasCRDT | RefLedger), name: string, mapFn?: MapFn<T>, meta?: IdxMeta): Index<T, K, R>;
|
|
4
|
+
export declare class Index<T extends DocTypes, K extends IndexKeyType = string, R extends DocFragment = T> implements IndexIf<T, K, R> {
|
|
5
|
+
readonly blockstore: BaseBlockstore;
|
|
6
|
+
readonly crdt: CRDT;
|
|
7
|
+
readonly name: string;
|
|
8
|
+
mapFn?: MapFn<T>;
|
|
9
|
+
mapFnString: string;
|
|
10
|
+
byKey: IndexTree<K, R>;
|
|
11
|
+
byId: IndexTree<K, R>;
|
|
12
|
+
indexHead?: ClockHead;
|
|
13
|
+
initError?: Error;
|
|
14
|
+
ready(): Promise<void>;
|
|
15
|
+
readonly logger: Logger;
|
|
16
|
+
constructor(sthis: SuperThis, crdt: CRDT, name: string, mapFn?: MapFn<T>, meta?: IdxMeta);
|
|
17
|
+
applyMapFn(name: string, mapFn?: MapFn<T>, meta?: IdxMeta): void;
|
|
18
|
+
query(opts?: QueryOpts<K>): Promise<IndexRows<T, K, R>>;
|
|
19
|
+
_resetIndex(): void;
|
|
20
|
+
_hydrateIndex(): Promise<void>;
|
|
21
|
+
_updateIndex(): Promise<IndexTransactionMeta>;
|
|
22
|
+
}
|