@fireproof/core 0.0.9 → 0.1.0
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 +1 -1
- package/hooks/use-fireproof.ts +14 -8
- package/index.js +2 -1
- package/package.json +3 -1
- package/src/db-index.js +76 -35
- package/src/fireproof.js +18 -30
- package/src/hydrator.js +47 -6
- package/test/db-index.test.js +5 -4
- package/test/fireproof.test.js +2 -2
- package/test/hydrator.test.js +5 -5
- package/test/listener.test.js +2 -1
package/README.md
CHANGED
@@ -6,7 +6,7 @@ to offer a new kind of database that:
|
|
6
6
|
- scales without incurring developer costs, thanks to Filecoin
|
7
7
|
- uses cryptographically verifiable protocols (what plants crave)
|
8
8
|
|
9
|
-
Learn more about the concepts and architecture behind Fireproof
|
9
|
+
Learn more about the [concepts and architecture behind Fireproof](https://fireproof.storage/documentation/how-the-database-engine-works/), or jump to the [quick start](#quick-start) for React and server-side examples.
|
10
10
|
|
11
11
|
### Status
|
12
12
|
|
package/hooks/use-fireproof.ts
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
3
3
|
// @ts-ignore
|
4
4
|
import { useEffect, useState, createContext } from 'react'
|
5
|
-
import { Fireproof, Listener } from '../index'
|
5
|
+
import { Fireproof, Listener, Hydrator } from '../index'
|
6
|
+
|
6
7
|
|
7
8
|
export interface FireproofCtxValue {
|
8
9
|
addSubscriber: (label: String, fn: Function) => void
|
@@ -18,6 +19,7 @@ export const FireproofCtx = createContext<FireproofCtxValue>({
|
|
18
19
|
const inboundSubscriberQueue = new Map()
|
19
20
|
const database = Fireproof.storage()
|
20
21
|
const listener = new Listener(database)
|
22
|
+
let startedSetup = false;
|
21
23
|
|
22
24
|
/**
|
23
25
|
* @function useFireproof
|
@@ -30,16 +32,15 @@ export function useFireproof(defineDatabaseFn: Function, setupDatabaseFn: Functi
|
|
30
32
|
const [ready, setReady] = useState(false)
|
31
33
|
defineDatabaseFn = defineDatabaseFn || (() => {})
|
32
34
|
setupDatabaseFn = setupDatabaseFn || (() => {})
|
35
|
+
// console.log('useFireproof', database, ready)
|
33
36
|
|
34
|
-
if (!ready) {
|
35
|
-
defineDatabaseFn(database)
|
36
|
-
}
|
37
37
|
|
38
38
|
const addSubscriber = (label: String, fn: Function) => {
|
39
39
|
inboundSubscriberQueue.set(label, fn)
|
40
40
|
}
|
41
41
|
|
42
42
|
const listenerCallback = async () => {
|
43
|
+
// console.log ('listenerCallback', JSON.stringify(database))
|
43
44
|
localSet('fireproof', JSON.stringify(database))
|
44
45
|
for (const [, fn] of inboundSubscriberQueue) fn()
|
45
46
|
}
|
@@ -47,20 +48,25 @@ export function useFireproof(defineDatabaseFn: Function, setupDatabaseFn: Functi
|
|
47
48
|
useEffect(() => {
|
48
49
|
const doSetup = async () => {
|
49
50
|
if (ready) return
|
51
|
+
if (startedSetup) return
|
52
|
+
startedSetup = true
|
53
|
+
defineDatabaseFn(database) // define indexes before querying them
|
50
54
|
const fp = localGet('fireproof')
|
51
55
|
if (fp) {
|
52
|
-
const
|
56
|
+
const serialized = JSON.parse(fp)
|
57
|
+
// console.log('serialized', JSON.stringify(serialized.indexes.map(c => c.clock)))
|
53
58
|
console.log("Loading previous database clock. (localStorage.removeItem('fireproof') to reset)")
|
54
|
-
|
59
|
+
Hydrator.fromJSON(serialized, database)
|
60
|
+
// await database.setClock(clock)
|
55
61
|
try {
|
56
62
|
const changes = await database.changesSince()
|
57
63
|
if (changes.rows.length < 2) {
|
58
|
-
console.log('Resetting database')
|
64
|
+
// console.log('Resetting database')
|
59
65
|
throw new Error('Resetting database')
|
60
66
|
}
|
61
67
|
} catch (e) {
|
62
68
|
console.error(`Error loading previous database clock. ${fp} Resetting.`, e)
|
63
|
-
await database.setClock([])
|
69
|
+
await database.setClock([]) // todo this should be resetClock and also reset the indexes
|
64
70
|
await setupDatabaseFn(database)
|
65
71
|
localSet('fireproof', JSON.stringify(database))
|
66
72
|
}
|
package/index.js
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@fireproof/core",
|
3
|
-
"version": "0.0
|
3
|
+
"version": "0.1.0",
|
4
4
|
"description": "Realtime database for IPFS",
|
5
5
|
"main": "index.js",
|
6
6
|
"type": "module",
|
@@ -9,6 +9,8 @@
|
|
9
9
|
"test:mocha": "mocha test/*.test.js",
|
10
10
|
"test:watch": "npm run test:mocha -- -w --parallel test/*.test.js",
|
11
11
|
"coverage": "c8 -r html -r text npm test",
|
12
|
+
"prepublishOnly" : "cp ../../README.md .",
|
13
|
+
"postpublish": "rm README.md",
|
12
14
|
"lint": "standard",
|
13
15
|
"lint:fix": "standard --fix"
|
14
16
|
},
|
package/src/db-index.js
CHANGED
@@ -6,7 +6,6 @@ import { nocache as cache } from 'prolly-trees/cache'
|
|
6
6
|
import { bf, simpleCompare } from 'prolly-trees/utils'
|
7
7
|
import { makeGetBlock } from './prolly.js'
|
8
8
|
import { cidsToProof } from './fireproof.js'
|
9
|
-
import { CID } from 'multiformats'
|
10
9
|
|
11
10
|
import * as codec from '@ipld/dag-cbor'
|
12
11
|
// import { create as createBlock } from 'multiformats/block'
|
@@ -73,16 +72,16 @@ const makeDoc = ({ key, value }) => ({ _id: key, ...value })
|
|
73
72
|
* Transforms a set of changes to DbIndex entries using a map function.
|
74
73
|
*
|
75
74
|
* @param {ChangeEvent[]} changes
|
76
|
-
* @param {Function}
|
75
|
+
* @param {Function} mapFn
|
77
76
|
* @returns {DbIndexEntry[]} The DbIndex entries generated by the map function.
|
78
77
|
* @private
|
79
78
|
* @memberof DbIndex
|
80
79
|
*/
|
81
|
-
const indexEntriesForChanges = (changes,
|
80
|
+
const indexEntriesForChanges = (changes, mapFn) => {
|
82
81
|
const indexEntries = []
|
83
82
|
changes.forEach(({ key, value, del }) => {
|
84
83
|
if (del || !value) return
|
85
|
-
|
84
|
+
mapFn(makeDoc({ key, value }), (k, v) => {
|
86
85
|
indexEntries.push({
|
87
86
|
key: [charwise.encode(k), key],
|
88
87
|
value: v
|
@@ -99,11 +98,12 @@ const indexEntriesForChanges = (changes, mapFun) => {
|
|
99
98
|
* @classdesc An DbIndex can be used to order and filter the documents in a Fireproof database.
|
100
99
|
*
|
101
100
|
* @param {Fireproof} database - The Fireproof database instance to DbIndex.
|
102
|
-
* @param {Function}
|
101
|
+
* @param {Function} mapFn - The map function to apply to each entry in the database.
|
103
102
|
*
|
104
103
|
*/
|
105
104
|
export default class DbIndex {
|
106
|
-
constructor (database,
|
105
|
+
constructor (database, mapFn, clock) {
|
106
|
+
// console.log('DbIndex constructor', database.constructor.name, typeof mapFn, clock)
|
107
107
|
/**
|
108
108
|
* The database instance to DbIndex.
|
109
109
|
* @type {Fireproof}
|
@@ -113,33 +113,62 @@ export default class DbIndex {
|
|
113
113
|
* The map function to apply to each entry in the database.
|
114
114
|
* @type {Function}
|
115
115
|
*/
|
116
|
-
this.mapFun = mapFun
|
117
|
-
|
118
|
-
this.database.indexes.set(mapFun.toString(), this)
|
119
116
|
|
117
|
+
if (typeof mapFn === 'string') {
|
118
|
+
this.mapFnString = mapFn
|
119
|
+
} else {
|
120
|
+
this.mapFn = mapFn
|
121
|
+
this.mapFnString = mapFn.toString()
|
122
|
+
}
|
120
123
|
this.indexById = { root: null, cid: null }
|
121
124
|
this.indexByKey = { root: null, cid: null }
|
122
|
-
|
123
125
|
this.dbHead = null
|
124
|
-
|
126
|
+
if (clock) {
|
127
|
+
this.indexById.cid = clock.byId
|
128
|
+
this.indexByKey.cid = clock.byKey
|
129
|
+
this.dbHead = clock.db
|
130
|
+
}
|
125
131
|
this.instanceId = this.database.instanceId + `.DbIndex.${Math.random().toString(36).substring(2, 7)}`
|
126
|
-
|
127
132
|
this.updateIndexPromise = null
|
133
|
+
DbIndex.registerWithDatabase(this, this.database)
|
134
|
+
}
|
135
|
+
|
136
|
+
static registerWithDatabase (inIndex, database) {
|
137
|
+
// console.log('.reg > in Index', inIndex.instanceId, { live: !!inIndex.mapFn }, inIndex.indexByKey, inIndex.mapFnString)
|
138
|
+
if (database.indexes.has(inIndex.mapFnString)) {
|
139
|
+
// merge our inIndex code with the inIndex clock or vice versa
|
140
|
+
// keep the code instance, discard the clock instance
|
141
|
+
const existingIndex = database.indexes.get(inIndex.mapFnString)
|
142
|
+
// console.log('.reg - existingIndex', existingIndex.instanceId, { live: !!inIndex.mapFn }, existingIndex.indexByKey)
|
143
|
+
if (existingIndex.mapFn) { // this one also has other config
|
144
|
+
existingIndex.dbHead = inIndex.dbHead
|
145
|
+
existingIndex.indexById.cid = inIndex.indexById.cid
|
146
|
+
existingIndex.indexByKey.cid = inIndex.indexByKey.cid
|
147
|
+
} else {
|
148
|
+
// console.log('.reg use inIndex with existingIndex clock')
|
149
|
+
inIndex.dbHead = existingIndex.dbHead
|
150
|
+
inIndex.indexById.cid = existingIndex.indexById.cid
|
151
|
+
inIndex.indexByKey.cid = existingIndex.indexByKey.cid
|
152
|
+
database.indexes.set(inIndex.mapFnString, inIndex)
|
153
|
+
}
|
154
|
+
} else {
|
155
|
+
// console.log('.reg - fresh')
|
156
|
+
database.indexes.set(inIndex.mapFnString, inIndex)
|
157
|
+
}
|
158
|
+
// console.log('.reg after', JSON.stringify([...database.indexes.values()].map(i => [i.instanceId, typeof i.mapFn, i.indexByKey, i.indexById])))
|
128
159
|
}
|
129
160
|
|
130
161
|
toJSON () {
|
131
|
-
|
162
|
+
const indexJson = { code: this.mapFn?.toString(), clock: { db: null, byId: null, byKey: null } }
|
163
|
+
indexJson.clock.db = this.dbHead?.map(cid => cid.toString())
|
164
|
+
indexJson.clock.byId = this.indexById.cid?.toString()
|
165
|
+
indexJson.clock.byKey = this.indexByKey.cid?.toString()
|
166
|
+
return indexJson
|
132
167
|
}
|
133
168
|
|
134
|
-
static fromJSON (database, { code, clock
|
135
|
-
|
136
|
-
|
137
|
-
eval("mapFun = "+ code)
|
138
|
-
const index = new DbIndex(database, mapFun)
|
139
|
-
index.indexById.cid = CID.parse(byId)
|
140
|
-
index.indexByKey.cid = CID.parse(byKey)
|
141
|
-
index.dbHead = db.map(cid => CID.parse(cid))
|
142
|
-
return index
|
169
|
+
static fromJSON (database, { code, clock }) {
|
170
|
+
// console.log('DbIndex.fromJSON', database.constructor.name, code, clock)
|
171
|
+
return new DbIndex(database, code, clock)
|
143
172
|
}
|
144
173
|
|
145
174
|
/**
|
@@ -166,6 +195,7 @@ export default class DbIndex {
|
|
166
195
|
|
167
196
|
// }
|
168
197
|
// console.time(callId + '.doIndexQuery')
|
198
|
+
// console.log('query', query)
|
169
199
|
const response = await doIndexQuery(this.database.blocks, this.indexByKey, query)
|
170
200
|
// console.timeEnd(callId + '.doIndexQuery')
|
171
201
|
|
@@ -196,12 +226,12 @@ export default class DbIndex {
|
|
196
226
|
|
197
227
|
async #innerUpdateIndex (inBlocks) {
|
198
228
|
// const callTag = Math.random().toString(36).substring(4)
|
199
|
-
// console.log(`#updateIndex ${callTag} >`, this.instanceId, this.dbHead?.toString(), this.
|
229
|
+
// console.log(`#updateIndex ${callTag} >`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
|
200
230
|
// todo remove this hack
|
201
231
|
if (ALWAYS_REBUILD) {
|
202
|
-
this.
|
203
|
-
this.indexByKey = null
|
204
|
-
this.
|
232
|
+
this.indexById = { root: null, cid: null }
|
233
|
+
this.indexByKey = { root: null, cid: null }
|
234
|
+
this.dbHead = null
|
205
235
|
}
|
206
236
|
// console.log('dbHead', this.dbHead)
|
207
237
|
// console.time(callTag + '.changesSince')
|
@@ -210,28 +240,34 @@ export default class DbIndex {
|
|
210
240
|
// console.log('result.rows.length', result.rows.length)
|
211
241
|
|
212
242
|
// console.time(callTag + '.doTransaction#updateIndex')
|
243
|
+
// console.log('#updateIndex changes length', result.rows.length)
|
213
244
|
|
214
245
|
if (result.rows.length === 0) {
|
215
|
-
// console.log('#updateIndex < no changes')
|
246
|
+
// console.log('#updateIndex < no changes', result.clock)
|
216
247
|
this.dbHead = result.clock
|
217
248
|
return
|
218
249
|
}
|
219
250
|
await doTransaction('#updateIndex', inBlocks, async (blocks) => {
|
220
251
|
let oldIndexEntries = []
|
221
252
|
let removeByIdIndexEntries = []
|
222
|
-
|
253
|
+
await loadIndex(blocks, this.indexById, idIndexOpts)
|
254
|
+
await loadIndex(blocks, this.indexByKey, dbIndexOpts)
|
255
|
+
if (this.dbHead) {
|
223
256
|
const oldChangeEntries = await this.indexById.root.getMany(result.rows.map(({ key }) => key))
|
224
257
|
oldIndexEntries = oldChangeEntries.result.map((key) => ({ key, del: true }))
|
225
258
|
removeByIdIndexEntries = oldIndexEntries.map(({ key }) => ({ key: key[1], del: true }))
|
226
259
|
}
|
227
|
-
|
260
|
+
if (!this.mapFn) {
|
261
|
+
throw new Error('No live map function installed for index, cannot update. Make sure your index definition runs before any queries.' + (this.mapFnString ? ' Your code should match the stored map function source:\n' + this.mapFnString : ''))
|
262
|
+
}
|
263
|
+
const indexEntries = indexEntriesForChanges(result.rows, this.mapFn)
|
228
264
|
const byIdIndexEntries = indexEntries.map(({ key }) => ({ key: key[1], value: key }))
|
229
265
|
this.indexById = await bulkIndex(blocks, this.indexById, removeByIdIndexEntries.concat(byIdIndexEntries), idIndexOpts)
|
230
266
|
this.indexByKey = await bulkIndex(blocks, this.indexByKey, oldIndexEntries.concat(indexEntries), dbIndexOpts)
|
231
267
|
this.dbHead = result.clock
|
232
268
|
})
|
233
269
|
// console.timeEnd(callTag + '.doTransaction#updateIndex')
|
234
|
-
// console.log(`#updateIndex ${callTag} <`, this.instanceId, this.dbHead?.toString(), this.
|
270
|
+
// console.log(`#updateIndex ${callTag} <`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
|
235
271
|
}
|
236
272
|
}
|
237
273
|
|
@@ -271,13 +307,18 @@ async function bulkIndex (blocks, inIndex, indexEntries, opts) {
|
|
271
307
|
return { root: returnNode, cid: returnRootBlock.cid }
|
272
308
|
}
|
273
309
|
|
274
|
-
async function
|
275
|
-
if (!
|
276
|
-
const cid =
|
277
|
-
if (!cid) return
|
310
|
+
async function loadIndex (blocks, index, indexOpts) {
|
311
|
+
if (!index.root) {
|
312
|
+
const cid = index.cid
|
313
|
+
if (!cid) return
|
278
314
|
const { getBlock } = makeGetBlock(blocks)
|
279
|
-
|
315
|
+
index.root = await load({ cid, get: getBlock, ...indexOpts })
|
280
316
|
}
|
317
|
+
return index.root
|
318
|
+
}
|
319
|
+
|
320
|
+
async function doIndexQuery (blocks, indexByKey, query) {
|
321
|
+
await loadIndex(blocks, indexByKey, dbIndexOpts)
|
281
322
|
if (query.range) {
|
282
323
|
const encodedRange = query.range.map((key) => charwise.encode(key))
|
283
324
|
return indexByKey.root.range(...encodedRange)
|
package/src/fireproof.js
CHANGED
@@ -42,22 +42,27 @@ export default class Fireproof {
|
|
42
42
|
}
|
43
43
|
|
44
44
|
/**
|
45
|
-
*
|
46
|
-
* @
|
47
|
-
* @param {CID[]} clock - The Merkle clock head to use for the snapshot.
|
48
|
-
* @returns {Fireproof}
|
49
|
-
* A new Fireproof instance representing the snapshot.
|
45
|
+
* Renders the Fireproof instance as a JSON object.
|
46
|
+
* @returns {Object} - The JSON representation of the Fireproof instance. Includes clock heads for the database and its indexes.
|
50
47
|
* @memberof Fireproof
|
51
48
|
* @instance
|
52
49
|
*/
|
53
|
-
|
54
|
-
//
|
55
|
-
|
56
|
-
|
50
|
+
toJSON () {
|
51
|
+
// todo this also needs to return the index roots...
|
52
|
+
return {
|
53
|
+
clock: this.clock.map(cid => cid.toString()),
|
54
|
+
name: this.name,
|
55
|
+
indexes: [...this.indexes.values()].map(index => index.toJSON())
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
hydrate ({ clock, name }) {
|
60
|
+
this.name = name
|
61
|
+
this.clock = clock
|
57
62
|
}
|
58
63
|
|
59
64
|
/**
|
60
|
-
*
|
65
|
+
* Triggers a notification to all listeners
|
61
66
|
* of the Fireproof instance so they can repaint UI, etc.
|
62
67
|
* @param {CID[] } clock
|
63
68
|
* Clock to use for the snapshot.
|
@@ -65,25 +70,8 @@ export default class Fireproof {
|
|
65
70
|
* @memberof Fireproof
|
66
71
|
* @instance
|
67
72
|
*/
|
68
|
-
async
|
69
|
-
|
70
|
-
this.clock = clock.map((item) => (item['/'] ? item['/'] : item))
|
71
|
-
await this.#notifyListeners({ reset: true, clock })
|
72
|
-
}
|
73
|
-
|
74
|
-
/**
|
75
|
-
* Renders the Fireproof instance as a JSON object.
|
76
|
-
* @returns {Object} - The JSON representation of the Fireproof instance. Includes clock heads for the database and its indexes.
|
77
|
-
* @memberof Fireproof
|
78
|
-
* @instance
|
79
|
-
*/
|
80
|
-
toJSON () {
|
81
|
-
// todo this also needs to return the index roots...
|
82
|
-
return {
|
83
|
-
clock: this.clock.map(cid => cid.toString()),
|
84
|
-
name: this.name,
|
85
|
-
indexes: [...this.indexes.values()].map((index) => index.toJSON())
|
86
|
-
}
|
73
|
+
async notifyReset () {
|
74
|
+
await this.#notifyListeners({ reset: true, clock: this.clock })
|
87
75
|
}
|
88
76
|
|
89
77
|
/**
|
@@ -295,7 +283,7 @@ export default class Fireproof {
|
|
295
283
|
}
|
296
284
|
|
297
285
|
setCarUploader (carUploaderFn) {
|
298
|
-
console.log('registering car uploader')
|
286
|
+
// console.log('registering car uploader')
|
299
287
|
// https://en.wikipedia.org/wiki/Law_of_Demeter - this is a violation of the law of demeter
|
300
288
|
this.blocks.valet.uploadFunction = carUploaderFn
|
301
289
|
}
|
package/src/hydrator.js
CHANGED
@@ -1,10 +1,51 @@
|
|
1
|
-
import Fireproof from './fireproof.js'
|
2
1
|
import DbIndex from './db-index.js'
|
2
|
+
import Fireproof from './fireproof.js'
|
3
|
+
import { CID } from 'multiformats'
|
4
|
+
|
5
|
+
const parseCID = cid => typeof cid === 'string' ? CID.parse(cid) : cid
|
6
|
+
|
7
|
+
export default class Hydrator {
|
8
|
+
static fromJSON (json, database) {
|
9
|
+
database.hydrate({ clock: json.clock.map(c => parseCID(c)), name: json.name })
|
10
|
+
for (const { code, clock: { byId, byKey, db } } of json.indexes) {
|
11
|
+
DbIndex.fromJSON(database, {
|
12
|
+
clock: {
|
13
|
+
byId: byId ? parseCID(byId) : null,
|
14
|
+
byKey: byKey ? parseCID(byKey) : null,
|
15
|
+
db: db ? db.map(c => parseCID(c)) : null
|
16
|
+
},
|
17
|
+
code
|
18
|
+
})
|
19
|
+
}
|
20
|
+
return database
|
21
|
+
}
|
22
|
+
|
23
|
+
static snapshot (database, clock) {
|
24
|
+
const definition = database.toJSON()
|
25
|
+
const withBlocks = new Fireproof(database.blocks)
|
26
|
+
if (clock) {
|
27
|
+
definition.clock = clock.map(c => parseCID(c))
|
28
|
+
definition.indexes.forEach(index => {
|
29
|
+
index.clock.byId = null
|
30
|
+
index.clock.byKey = null
|
31
|
+
index.clock.db = null
|
32
|
+
})
|
33
|
+
}
|
34
|
+
const snappedDb = this.fromJSON(definition, withBlocks)
|
35
|
+
;([...database.indexes.values()]).forEach(index => {
|
36
|
+
snappedDb.indexes.get(index.mapFnString).mapFn = index.mapFn
|
37
|
+
})
|
38
|
+
return snappedDb
|
39
|
+
}
|
3
40
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
41
|
+
static async zoom (database, clock) {
|
42
|
+
;([...database.indexes.values()]).forEach(index => {
|
43
|
+
index.indexById = { root: null, cid: null }
|
44
|
+
index.indexByKey = { root: null, cid: null }
|
45
|
+
index.dbHead = null
|
46
|
+
})
|
47
|
+
database.clock = clock.map(c => parseCID(c))
|
48
|
+
await database.notifyReset()
|
49
|
+
return database
|
8
50
|
}
|
9
|
-
return fp
|
10
51
|
}
|
package/test/db-index.test.js
CHANGED
@@ -3,6 +3,7 @@ import assert from 'node:assert'
|
|
3
3
|
import Blockstore from '../src/blockstore.js'
|
4
4
|
import Fireproof from '../src/fireproof.js'
|
5
5
|
import DbIndex from '../src/db-index.js'
|
6
|
+
import Hydrator from '../src/hydrator.js'
|
6
7
|
console.x = function () {}
|
7
8
|
|
8
9
|
describe('DbIndex query', () => {
|
@@ -77,7 +78,7 @@ describe('DbIndex query', () => {
|
|
77
78
|
// console.x('bresult.rows', bresult.rows)
|
78
79
|
assert.equal(bresult.rows.length, 6, 'all row matched')
|
79
80
|
|
80
|
-
const
|
81
|
+
const snapClock = database.clock
|
81
82
|
|
82
83
|
const notYet = await database.get('xxxx-3c3a-4b5e-9c1c-8c5c0c5c0c5c').catch((e) => e)
|
83
84
|
assert.equal(notYet.message, 'Not found', 'not yet there')
|
@@ -91,7 +92,7 @@ describe('DbIndex query', () => {
|
|
91
92
|
assert(gotX.name === 'Xander', 'got Xander')
|
92
93
|
console.x('got X')
|
93
94
|
|
94
|
-
const snap =
|
95
|
+
const snap = Hydrator.snapshot(database, snapClock)
|
95
96
|
|
96
97
|
const aliceOld = await snap.get('a1s3b32a-3c3a-4b5e-9c1c-8c5c0c5c0c5c')// .catch((e) => e)
|
97
98
|
console.x('aliceOld', aliceOld)
|
@@ -124,7 +125,7 @@ describe('DbIndex query', () => {
|
|
124
125
|
assert.equal(result.rows.length, 1, '1 row matched')
|
125
126
|
assert(result.rows[0].key === 53, 'correct key')
|
126
127
|
|
127
|
-
const snap =
|
128
|
+
const snap = Hydrator.snapshot(database)
|
128
129
|
|
129
130
|
console.x('--- make Xander 63')
|
130
131
|
const response = await database.put({ _id: DOCID, name: 'Xander', age: 63 })
|
@@ -172,7 +173,7 @@ describe('DbIndex query', () => {
|
|
172
173
|
assert.equal(result.rows.length, 1, '1 row matched')
|
173
174
|
assert(result.rows[0].key === 53, 'correct key')
|
174
175
|
|
175
|
-
const snap =
|
176
|
+
const snap = Hydrator.snapshot(database)
|
176
177
|
|
177
178
|
console.x('--- delete Xander 53')
|
178
179
|
const response = await database.del(DOCID)
|
package/test/fireproof.test.js
CHANGED
@@ -2,6 +2,7 @@ import { describe, it, beforeEach } from 'mocha'
|
|
2
2
|
import assert from 'node:assert'
|
3
3
|
import Blockstore from '../src/blockstore.js'
|
4
4
|
import Fireproof from '../src/fireproof.js'
|
5
|
+
import Hydrator from '../src/hydrator.js'
|
5
6
|
// import * as codec from '@ipld/dag-cbor'
|
6
7
|
|
7
8
|
let database, resp0
|
@@ -130,7 +131,7 @@ describe('Fireproof', () => {
|
|
130
131
|
assert(response.id, 'should have id')
|
131
132
|
assert.equal(response.id, dogKey)
|
132
133
|
assert.equal(value._id, dogKey)
|
133
|
-
const
|
134
|
+
const snapshot = Hydrator.snapshot(database)
|
134
135
|
|
135
136
|
const avalue = await database.get(dogKey)
|
136
137
|
assert.equal(avalue.name, value.name)
|
@@ -147,7 +148,6 @@ describe('Fireproof', () => {
|
|
147
148
|
assert.equal(bvalue.age, 3)
|
148
149
|
assert.equal(bvalue._id, dogKey)
|
149
150
|
|
150
|
-
const snapshot = database.snapshot(oldClock)
|
151
151
|
const snapdoc = await snapshot.get(dogKey)
|
152
152
|
// console.log('snapdoc', snapdoc)
|
153
153
|
// assert(snapdoc.id, 'should have id')
|
package/test/hydrator.test.js
CHANGED
@@ -2,7 +2,7 @@ import { describe, it, beforeEach } from 'mocha'
|
|
2
2
|
import assert from 'node:assert'
|
3
3
|
import Fireproof from '../src/fireproof.js'
|
4
4
|
import DbIndex from '../src/db-index.js'
|
5
|
-
import
|
5
|
+
import Hydrator from '../src/hydrator.js'
|
6
6
|
console.x = function () {}
|
7
7
|
|
8
8
|
describe('DbIndex query', () => {
|
@@ -55,19 +55,19 @@ describe('DbIndex query', () => {
|
|
55
55
|
const serialized = JSON.parse(JSON.stringify(database))
|
56
56
|
// console.log('serialized', JSON.stringify(serialized))
|
57
57
|
// connect it to the same blockstore for testing
|
58
|
-
const newDb = fromJSON(serialized, database
|
58
|
+
const newDb = Hydrator.fromJSON(serialized, database)
|
59
59
|
assert.equal(newDb.name, 'global')
|
60
60
|
assert.equal(newDb.clock.length, 1)
|
61
61
|
assert.equal((await newDb.changesSince()).rows.length, 7)
|
62
62
|
const newIndex = [...newDb.indexes.values()][0]
|
63
|
-
assert.equal(newIndex.
|
63
|
+
assert.equal(newIndex.mapFn, `function (doc, map) {
|
64
64
|
map(doc.age, doc.name)
|
65
65
|
}`)
|
66
66
|
assert.equal(newIndex.indexById.cid, 'bafyreifuz54ugnq77fur47vwv3dwab7p3gpnf5to6hlnbhv5p4kwo7auoi')
|
67
|
-
assert.equal(newIndex.indexById.root, null)
|
67
|
+
// assert.equal(newIndex.indexById.root, null)
|
68
68
|
|
69
69
|
assert.equal(newIndex.indexByKey.cid, 'bafyreicr5rpvsxnqchcwk5rxlmdvd3fah2vexmbsp2dvr4cfdxd2q2ycgu')
|
70
|
-
assert.equal(newIndex.indexByKey.root, null)
|
70
|
+
// assert.equal(newIndex.indexByKey.root, null)
|
71
71
|
|
72
72
|
const newResult = await newIndex.query({ range: [0, 54] })
|
73
73
|
assert.equal(newResult.rows[0].value, 'drate')
|
package/test/listener.test.js
CHANGED
@@ -3,6 +3,7 @@ import assert from 'node:assert'
|
|
3
3
|
import Blockstore from '../src/blockstore.js'
|
4
4
|
import Fireproof from '../src/fireproof.js'
|
5
5
|
import Listener from '../src/listener.js'
|
6
|
+
import Hydrator from '../src/hydrator.js'
|
6
7
|
|
7
8
|
let database, listener, star
|
8
9
|
|
@@ -43,7 +44,7 @@ describe('Listener', () => {
|
|
43
44
|
database.put({ _id: 'k645-87tk', name: 'karl2' }).then((ok) => {
|
44
45
|
assert(ok.id)
|
45
46
|
assert.notEqual(database.clock, startClock)
|
46
|
-
|
47
|
+
Hydrator.zoom(database, startClock)
|
47
48
|
}).catch(done)
|
48
49
|
})
|
49
50
|
})
|