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.
Legacy range options have been removed (Level/community#86). If you previously did:
db.iterator({ start: 'a', end: 'z' })
An error would now be thrown and you must instead do:
db.iterator({ gte: 'a', lte: 'z' })
This release also drops support of legacy runtime environments (Level/community#98):
- Internet Explorer 11
- Safari 9-11.
Lastly, and less likely to be a breaking change, the immediate
browser shim for process.nextTick()
has been replaced with the smaller queue-microtask
.
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
})
})
This is an upgrade to abstract-leveldown@6
which solves long-standing issues around serialization and type support.
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.
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.
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.
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.
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).
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.
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.
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')))
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-' }))
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.
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.
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.
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.
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)
.
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.