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.

7.9 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.

5.0.0

Support of keys & values other than strings and Buffers has been dropped. Internally level-js now stores keys & values as binary which solves a number of compatibility issues (Level/memdown#186). If you pass in a key or value that isn't a string or Buffer, it will be irreversibly stringified.

Existing IndexedDB databases created with level-js@4 can be read only if they used binary keys and string or binary values. Other types will come out stringified, and string keys will sort incorrectly. Use the included upgrade() utility to convert stored data to binary (in so far the environment supports it):

var leveljs = require('level-js')
var db = leveljs('my-db')

db.open(function (err) {
  if (err) throw err

  db.upgrade(function (err) {
    if (err) throw err
  })
})

Or with (the upcoming release of) level:

var level = require('level')
var reachdown = require('reachdown')
var db = level('my-db')

db.open(function (err) {
  if (err) throw err

  reachdown(db, 'level-js').upgrade(function (err) {
    if (err) throw err
  })
})

4.0.0

This is an upgrade to abstract-leveldown@6 which solves long-standing issues around serialization and type support.

Range options are now serialized

Previously, range options like lt were passed through as-is by abstract-leveldown, unlike keys. For level-js it means that Buffers and arrays, if not supported by the environment (e.g. Microsoft Edge), will be stringified.

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 abstract-leveldown. This means db.iterator({ gt: undefined }) is not the same as db.iterator({}).

In the case of level-js, when used by itself, the aforementioned change means that db.iterator({ gt: undefined }) will throw an error as undefined is not a valid IndexedDB key type. On the other hand db.iterator({ gt: '' }) is valid and thus now supported. For details on sort order (which is richer than in leveldown) please see the readme.

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.

Zero-length array keys are rejected

Though this was already the case (both in IndexedDB and abstract-leveldown), abstract-leveldown has replaced the behavior with an explicit Array.isArray() check and a new error message.

Boolean and NaN keys (as well as range options) are rejected

Previously, for compliance with abstract-leveldown tests that have since been removed, they were stringified. As of level-js@4 they are rejected (by IndexedDB).

Added mobile browser support

iPhone and Android latest are now officially supported. At the time of writing that's iPhone 12.0 and Android 7.1 (note that's Chrome for Android, not the old stock browser). Older versions (iPhone 10+ and Android 6+) did pass our tests but are not included in the test matrix going forward. Feel free to open an issue if you need/want these versions to be supported.

The value of iterator#db has changed

Though this was undocumented and only for internal use, the db property on an iterator pointed to an IDBDatabase. To comply with abstract-leveldown the db property now points to the level-js instance that created that iterator.

3.0.0

This release brings level-js up to par with latest levelup (v2), abstract-leveldown (v5) and IndexedDB Second Edition. It targets modern browserify preferring Buffer over ArrayBuffer. Lastly, IDBWrapper has been replaced with straight IndexedDB code.

Usage with levelup

Usage has changed to:

const levelup = require('levelup')
const leveljs = require('leveljs')

const db = levelup(leveljs('mydb'))

From the old:

const db = levelup('mydb', { db: leveljs })

Friendly reminder: encodings have moved from levelup to encoding-down. To get identical functionality to levelup < 2 please use the level-browserify convenience package or wrap level-js with encoding-down:

const encode = require('encoding-down')
const db = levelup(encode(leveljs('mydb')))

New database prefix

The default prefix of the IDBDatabase name has changed from IDBWrapper- to level-js-. To access databases created using level-js < 3, pass a custom prefix to the level-js constructor:

const db = levelup(leveljs('mydb', { prefix: 'IDBWrapper-' }))

Browser support

As a result of removing IDBWrapper, only modern browsers with a non-prefixed window.indexedDB are supported in this release. The current test matrix of level-js includes the latest versions of Chrome, Firefox, Safari, Edge and IE.

🔥 Internet Explorer 10 is no longer supported.

Type support

All value types of the structured clone algorithm and all key types of IndexedDB Second Edition are now supported. This means you can store almost any JavaScript type without the need for encoding-down. In addition, you can use Buffer for both keys and values. For details and caveats please see the readme.

No backpressure

In level-js, iterators are powered by IndexedDB cursors. To fulfill abstract-leveldown snapshot guarantees (reads not being affected by simultaneous writes) cursors are started immediately and continuously read from, filling an in-memory cache.

Though level-js now passes the full abstract-leveldown test suite, fulfilling the snapshot guarantee means a loss of backpressure. Memory consumption might increase if an iterator is not consumed fast enough. A future release will have an option to favor backpressure over snapshot guarantees.

Removed raw option

Because level-js no longer stringifies values, the raw option (which bypassed conversion) became unnecessary and has been removed. If you use level-browserify or levelup with encoding-down, you can store and retrieve raw values (as returned by IndexedDB) using the id encoding. Please refer to the readme for an example.

New destroy() function signature

Previously, a level-js instance could be passed to destroy():

leveljs.destroy(db, callback)

This was useful to destroy a database that used a custom prefix. The new signature is destroy(location[, prefix], callback).

Strict .batch(array)

The upgrade to abstract-leveldown comes with a breaking change for the array version of .batch(). This change ensures all elements in the batch array are objects. If you previously passed arrays to .batch() that contained undefined or null, they would be silently ignored. Now this will produce an error.