Skip to content

Commit f832018

Browse files
authored
Implement explicit snapshots (#16)
See Level/community#118. TLDR: ```js await db.put('example', 'before') const snapshot = db.snapshot() await db.put('example', 'after') await db.get('example', { snapshot })) // Returns 'before' await snapshot.close() ``` Category: addition
1 parent 946a57f commit f832018

File tree

2 files changed

+38
-9
lines changed

2 files changed

+38
-9
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ for await (const [key, value] of db.iterator({ gt: 'a' })) {
4040

4141
## API
4242

43-
The API of `memory-level` follows that of [`abstract-level`](https://github.com/Level/abstract-level) with a one additional constructor option (see below). The `createIfMissing` and `errorIfExists` options of `abstract-level` are not relevant here. Data is discarded when the last reference to the database is released (i.e. `db = null`). Closing or reopening the database has no effect on the data. Data is _not_ copied: when storing a Buffer value for example, subsequent mutations to that Buffer will affect the stored data too.
43+
The API of `memory-level` follows that of [`abstract-level`](https://github.com/Level/abstract-level) with one additional constructor option (see below). The `createIfMissing` and `errorIfExists` options of `abstract-level` are not relevant here. Both implicit and explicit snapshots are supported. Data is discarded when the last reference to the database is released (i.e. `db = null`). Closing or reopening the database has no effect on the data. Data is _not_ copied: when storing a Buffer value for example, subsequent mutations to that Buffer will affect the stored data too.
4444

4545
### `db = new MemoryLevel([options])`
4646

index.js

+37-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const {
44
AbstractLevel,
55
AbstractIterator,
66
AbstractKeyIterator,
7-
AbstractValueIterator
7+
AbstractValueIterator,
8+
AbstractSnapshot
89
} = require('abstract-level')
910

1011
const ModuleError = require('module-error')
@@ -59,7 +60,7 @@ function lte (value) {
5960
class MemoryIterator extends AbstractIterator {
6061
constructor (db, options) {
6162
super(db, options)
62-
this[kInit](db[kTree], options)
63+
this[kInit](db, options)
6364
}
6465

6566
async _next () {
@@ -103,7 +104,7 @@ class MemoryIterator extends AbstractIterator {
103104
class MemoryKeyIterator extends AbstractKeyIterator {
104105
constructor (db, options) {
105106
super(db, options)
106-
this[kInit](db[kTree], options)
107+
this[kInit](db, options)
107108
}
108109

109110
async _next () {
@@ -145,7 +146,7 @@ class MemoryKeyIterator extends AbstractKeyIterator {
145146
class MemoryValueIterator extends AbstractValueIterator {
146147
constructor (db, options) {
147148
super(db, options)
148-
this[kInit](db[kTree], options)
149+
this[kInit](db, options)
149150
}
150151

151152
async _next (options) {
@@ -187,7 +188,11 @@ class MemoryValueIterator extends AbstractValueIterator {
187188
}
188189

189190
for (const Ctor of [MemoryIterator, MemoryKeyIterator, MemoryValueIterator]) {
190-
Ctor.prototype[kInit] = function (tree, options) {
191+
Ctor.prototype[kInit] = function (db, options) {
192+
const tree = options.snapshot != null
193+
? options.snapshot[kTree]
194+
: db[kTree]
195+
191196
this[kReverse] = options.reverse
192197
this[kOptions] = options
193198

@@ -281,6 +286,7 @@ class MemoryLevel extends AbstractLevel {
281286

282287
super({
283288
seek: true,
289+
explicitSnapshots: true,
284290
permanence: false,
285291
createIfMissing: false,
286292
errorIfExists: false,
@@ -305,12 +311,20 @@ class MemoryLevel extends AbstractLevel {
305311
}
306312

307313
async _get (key, options) {
314+
const tree = options.snapshot != null
315+
? options.snapshot[kTree]
316+
: this[kTree]
317+
308318
// Is undefined if not found
309-
return this[kTree].get(key)
319+
return tree.get(key)
310320
}
311321

312322
async _getMany (keys, options) {
313-
return keys.map(key => this[kTree].get(key))
323+
const tree = options.snapshot != null
324+
? options.snapshot[kTree]
325+
: this[kTree]
326+
327+
return keys.map(getFromThis, tree)
314328
}
315329

316330
async _del (key, options) {
@@ -335,7 +349,7 @@ class MemoryLevel extends AbstractLevel {
335349
}
336350

337351
async _clear (options) {
338-
if (options.limit === -1 && !Object.keys(options).some(isRangeOption)) {
352+
if (options.limit === -1 && !Object.keys(options).some(isRangeOption) && !options.snapshot) {
339353
// Delete everything by creating a new empty tree.
340354
this[kTree] = createRBT(compare)
341355
return
@@ -374,6 +388,17 @@ class MemoryLevel extends AbstractLevel {
374388
_values (options) {
375389
return new MemoryValueIterator(this, options)
376390
}
391+
392+
_snapshot (options) {
393+
return new MemorySnapshot(this[kTree], options)
394+
}
395+
}
396+
397+
class MemorySnapshot extends AbstractSnapshot {
398+
constructor (tree, options) {
399+
super(options)
400+
this[kTree] = tree
401+
}
377402
}
378403

379404
exports.MemoryLevel = MemoryLevel
@@ -391,6 +416,10 @@ if (typeof process !== 'undefined' && !process.browser && typeof global !== 'und
391416
breathe = async function () {}
392417
}
393418

419+
function getFromThis (key) {
420+
return this.get(key)
421+
}
422+
394423
function isRangeOption (k) {
395424
return rangeOptions.has(k)
396425
}

0 commit comments

Comments
 (0)