You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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

Click to expand

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:

  1. Changes to public API - for consumers of any implementation.
  2. 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 through db._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 an options object as its first argument
  • The db argument of the AbstractChainedBatch constructor became mandatory, as well as a public db 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.