@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 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 [in our plan,](https://hackmd.io/@j-chris/SyoE-Plpj) or jump to the [quick start](#quick-start) for React and server-side examples.
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
 
@@ -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 { clock } = JSON.parse(fp)
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
- await database.setClock(clock)
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
@@ -1,5 +1,6 @@
1
1
  import Fireproof from './src/fireproof'
2
2
  import Index from './src/db-index'
3
3
  import Listener from './src/listener'
4
+ import Hydrator from './src/hydrator'
4
5
 
5
- export { Fireproof, Index, Listener }
6
+ export { Fireproof, Index, Listener, Hydrator }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fireproof/core",
3
- "version": "0.0.9",
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} mapFun
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, mapFun) => {
80
+ const indexEntriesForChanges = (changes, mapFn) => {
82
81
  const indexEntries = []
83
82
  changes.forEach(({ key, value, del }) => {
84
83
  if (del || !value) return
85
- mapFun(makeDoc({ key, value }), (k, v) => {
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} mapFun - The map function to apply to each entry in the database.
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, mapFun) {
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
- return { code: this.mapFun?.toString(), clock: { db: this.dbHead?.map(cid => cid.toString()), byId: this.indexById.cid?.toString(), byKey: this.indexByKey.cid?.toString() } }
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: { byId, byKey, db } }) {
135
- let mapFun
136
- // eslint-disable-next-line
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.dbIndexRoot?.cid.toString(), this.indexByIdRoot?.cid.toString())
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.dbHead = null // hack
203
- this.indexByKey = null // hack
204
- this.dbIndexRoot = null
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
- if (this.dbHead) { // need a maybe load
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
- const indexEntries = indexEntriesForChanges(result.rows, this.mapFun)
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.dbIndexRoot?.cid.toString(), this.indexByIdRoot?.cid.toString())
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 doIndexQuery (blocks, indexByKey, query) {
275
- if (!indexByKey.root) {
276
- const cid = indexByKey.cid
277
- if (!cid) return { result: [] }
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
- indexByKey.root = await load({ cid, get: getBlock, ...dbIndexOpts })
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
- * Returns a snapshot of the current Fireproof instance as a new instance.
46
- * @function snapshot
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
- snapshot (clock) {
54
- // how to handle listeners, views, and config?
55
- // todo needs a test for listeners, views, and config
56
- return new Fireproof(this.blocks, clock || this.clock)
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
- * Move the current instance to a new point in time. This triggers a notification to all listeners
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 setClock (clock) {
69
- // console.log('setClock', this.instanceId, clock)
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
- export function fromJSON (json, blocks) {
5
- const fp = new Fireproof(blocks, json.clock, { name: json.name })
6
- for (const index of json.indexes) {
7
- DbIndex.fromJSON(fp, index)
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
  }
@@ -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 oldHead = database.clock
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 = database.snapshot(oldHead)
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 = database.snapshot(database.clock)
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 = database.snapshot(database.clock)
176
+ const snap = Hydrator.snapshot(database)
176
177
 
177
178
  console.x('--- delete Xander 53')
178
179
  const response = await database.del(DOCID)
@@ -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 oldClock = database.clock
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')
@@ -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 { fromJSON } from '../src/hydrator.js'
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.blocks)
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.mapFun, `function (doc, map) {
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')
@@ -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
- database.setClock(startClock)
47
+ Hydrator.zoom(database, startClock)
47
48
  }).catch(done)
48
49
  })
49
50
  })