11 KiB
Upgrade Guide
This document describes breaking changes and how to upgrade. For a complete list of changes including minor and patch releases, please refer to the changelog.
Table of Contents
v6
This release brings a major refactoring of the test suite, decouples abstract-leveldown
from disk-based implementations and solves long-standing issues around serialization and type support. Because the changes are substantial, this guide has two sections:
- Changes to public API - for consumers of any implementation.
- Changes to private API - intended for implementors.
Changes to public API
Nullish values are rejected
In addition to rejecting null
and undefined
as keys, abstract-leveldown
now also rejects these types as values, due to preexisting significance in streams and iterators.
Before this, the behavior of these types depended on a large number of factors: _serializeValue
and type support of the underlying storage, whether get()
, iterator()
or a stream was used to retrieve values, the keys
and asBuffer
options of iterator()
and finally, which encoding was selected.
Range options are serialized
Previously, range options like lt
were passed through as-is, unlike keys.
The rules for range options have been relaxed
Because null
, undefined
, zero-length strings and zero-length buffers are significant types in encodings like bytewise
and charwise
, they became valid as range options. In fact, any type is now valid. This means db.iterator({ gt: undefined })
is not the same as db.iterator({})
.
Furthermore, abstract-leveldown
makes no assumptions about the meaning of these types. Range tests that assumed null
meant "not defined" have been removed.
Zero-length array keys are rejected
Though this was already the case because _checkKey
stringified its input before checking the length, that behavior has been replaced with an explicit Array.isArray()
check and a new error message.
No longer assumes support of boolean and NaN
keys
A test that asserted boolean and NaN
keys were valid has been removed.
Browser support
IE10 has been dropped.
Changes to private API
location
was removed
AbstractLevelDOWN
is no longer associated with a location
. It's up to the implementation to handle it if it's required.
If your implementation has a location
and you previously did:
function YourDOWN (location) {
AbstractLevelDOWN.call(this, location)
}
You must now do:
function YourDOWN (location) {
this.location = location
AbstractLevelDOWN.call(this)
}
Be sure to include appropriate type checks. If you relied on the default AbstractLevelDOWN
behavior that would be:
if (typeof location !== 'string') {
throw new Error('constructor requires a location string argument')
}
Abstract test suite has moved to a single entry point
Instead of including test files individually, you can and should include the test suite with one require()
statement. If you previously did:
const test = require('tape')
const testCommon = require('abstract-leveldown/testCommon')
const YourDOWN = require('.')
require('abstract-leveldown/abstract/get-test').all(YourDOWN, test, testCommon)
require('abstract-leveldown/abstract/put-test').all(YourDOWN, test, testCommon)
// etc
You must now do:
const test = require('tape')
const suite = require('abstract-leveldown/test')
const YourDOWN = require('.')
suite({
test: test,
factory: function () {
return new YourDOWN()
}
})
The input to the test suite is a new form of testCommon
. Should you need to reuse testCommon
for your own (additional) tests, use the included utility to create a testCommon
with defaults:
const test = require('tape')
const suite = require('abstract-leveldown/test')
const YourDOWN = require('.')
const testCommon = suite.common({
test: test,
factory: function () {
return new YourDOWN()
}
})
suite(testCommon)
As part of removing location
, the abstract tests no longer use testCommon.location()
. Instead an implementation must implement factory()
which must return a unique and isolated database instance. This allows implementations to pass options to their constructor.
The testCommon.cleanup
method has been removed. Because factory()
returns a unique database instance, cleanup should no longer be necessary. The testCommon.lastLocation
method has also been removed as there is no remaining use of it in abstract tests.
Previously, implementations using the default testCommon
had to include rimraf
in their devDependencies
and browser-based implementations had to exclude rimraf
from browserify builds. This is no longer the case.
If your implementation is disk-based we recommend using tempy
(or similar) to create unique temporary directories. Together with factory()
your setup could now look something like:
const test = require('tape')
const tempy = require('tempy')
const suite = require('abstract-leveldown/test')
const YourDOWN = require('.')
suite({
test: test,
factory: function () {
return new YourDOWN(tempy.directory())
}
})
The collectEntries
utility has moved
The testCommon.collectEntries
method has moved to the npm package level-concat-iterator
. If your (additional) tests depend on collectEntries
and you previously did:
testCommon.collectEntries(iterator, function (err, entries) {})
You must now do:
const concat = require('level-concat-iterator')
concat(iterator, function (err, entries) {})
Setup and teardown became noops
Because cleanup is no longer necessary, the testCommon.setUp
and testCommon.tearDown
methods are now noops by default. If you do need to perform (a)synchronous work before or after each test, setUp
and tearDown
can be overridden:
suite({
// ..
setUp: function (t) {
t.end()
},
tearDown: function (t) {
t.end()
}
})
Optional tests have been separated
If your implementation does not support snapshots or other optional features, the relevant tests may be skipped. For example:
suite({
// ..
snapshots: false
})
Please see the README for a list of options. Note that some of these have replaced process.browser
checks.
Iterator must have a db
reference
The db
argument of the AbstractIterator
constructor became mandatory, as well as a public db
property on the instance. Its existence is not new; the test suite now asserts that your implementation also has it.
Seeking became part of official API
If your implementation previously defined the public iterator.seek(target)
, it must now define the private iterator._seek(target)
. The new public API is equal to the reference implementation of leveldown
except for two differences:
- The
target
argument is not type checked, this is up to the implementation. - The
target
argument is passed throughdb._serializeKey
.
Please see the README for details.
Chained batch has been refactored
- The default
_clear
method is no longer a noop; instead it clears the operations queued by_put
and/or_del
- The
_write
method now takes anoptions
object as its first argument - The
db
argument of theAbstractChainedBatch
constructor became mandatory, as well as a publicdb
property on the instance, which was previously named_db
.
Default _serializeKey
and _serializeValue
became identity functions
They return whatever is given. Previously they were opinionated and mostly geared towards string- and Buffer-based storages. Implementations that didn't already define their own serialization should now do so, according to the types that they support. Please refer to the README for recommended behavior.
v5
Dropped support for node 4. No other breaking changes.
v4
default testCommon
parameter
The testCommon
parameter will now default to abstract-leveldown/testCommon.js
. You can omit this parameter, unless your implementation needs a custom version.
If your code today looks something like:
const test = require('tape')
const testCommon = require('abstract-leveldown/testCommon')
const leveldown = require('./your-leveldown')
const abstract = require('abstract-leveldown/abstract/get-test')
abstract.all(leveldown, test, testCommon)
You can simplify it to:
const test = require('tape')
const leveldown = require('./your-leveldown')
const abstract = require('abstract-leveldown/abstract/get-test')
abstract.all(leveldown, test)
testBuffer
parameter removed
The abstract/put-get-del-test.js
previously took a custom testBuffer
parameter. After an analysis of various implementations we came to the conclusion that the parameter has no use.
If your implementation is using this abstract test, change from:
const test = require('tape')
const testCommon = require('abstract-leveldown/testCommon')
const leveldown = require('./your-leveldown')
const fs = require('fs')
const path = require('path')
const testBuffer = fs.readFileSync(path.join(__dirname, 'data/testdata.bin'))
const abstract = require('abstract-leveldown/abstract/put-get-del-test')
abstract.all(leveldown, test, testBuffer, testCommon)
to:
const test = require('tape')
const testCommon = require('abstract-leveldown/testCommon')
const leveldown = require('./your-leveldown')
const abstract = require('abstract-leveldown/abstract/put-get-del-test')
abstract.all(leveldown, test, testCommon)
or if testCommon
is also redundant, to:
const test = require('tape')
const leveldown = require('./your-leveldown')
const abstract = require('abstract-leveldown/abstract/put-get-del-test')
abstract.all(leveldown, test)
.approximateSize
method removed
The .approximateSize
method has been removed from the public API. It is heavily related to LevelDB
and more often than not, other stores lack the native primitives to implement this. If you did implement the internal _approximateSize
method, that is now dead code. To preserve the method in your public API, rename it to approximateSize
and also take care of the initialization code. Look to leveldown
for inspiration.
Also, the corresponding abstract tests have been removed, so your implementation can no longer require abstract/approximate-size-test
.
._isBuffer
method removed
Because Buffer
is available in all environments nowadays, there is no need for alternatives like typed arrays. It is preferred to use Buffer
and Buffer.isBuffer()
directly.
isLevelDOWN
function removed
This was a legacy function.
ranges-test.js
renamed
We have refactored a lot of the tests. Specifically the iterator tests were split in two and in that process we renamed ranges-test.js
to iterator-range-test.js
.
If your implementation is using these tests then change from:
const abstract = require('abstract-leveldown/abstract/ranges-test')
to:
const abstract = require('abstract-leveldown/abstract/iterator-range-test')
v3
No changes to the API. New major version because support for node 0.12 was dropped.