Create an async friendly interface around leveldown.
Lightweight, zero dependency, single file alternative to levelup
.
const LevelDown = require('leveldown')
const AsyncLevel = require('async-level')
const leveldown = LevelDown('/db/path')
const db = new AsyncLevel(leveldown, {
encode: JSON.stringify,
decode: JSON.parse
})
const { err: openErr } = await levelDB.open()
if (openErr) throw
const { err } = await levelDB.put('foo#three', {
id: 'user id',
email: 'foo@gmail.com'
})
const { err, data: value } = await levelDB.get('foo#one')
// value is decoded, with JSON.parse.
const LevelDown = require('leveldown')
const AsyncLevel = require('async-level')
const leveldown = LevelDown('/db/path')
const db = new AsyncLevel(leveldown, {
encode: JSON.stringify,
decode: JSON.parse
})
const { err: openErr } = await levelDB.open()
if (openErr) throw
// This returns an AsyncIterator instead of returning a leveldown
// iterator object.
// You can use for await (const pair of itr) loops over it.
const itr1 = levelDB.iterator({
gte: 'foo' + '\x00',
lte: 'foo' + '\xFF',
keyAsBuffer: false
})
const result = await itr.next()
// result.done
// result.value.err
// The data here is decoded with JSON.parse
// result.value.data
const LevelDown = require('leveldown')
const AsyncLevel = require('async-level')
const leveldown = LevelDown('/db/path')
const db = new AsyncLevel(leveldown, {
encode: JSON.stringify,
decode: JSON.parse
})
const { err: openErr } = await levelDB.open()
if (openErr) throw
const { err } = await levelDB.batch([
{
type: 'put',
key: 'foo#one',
value: { any: 'json object' }
},
{
type: 'put',
key: 'foo#two',
value: { your: 'encode func called' }
}
])
const LevelDown = require('leveldown')
const AsyncLevel = require('async-level')
const charwise = require('charwise-compact')
const leveldown = LevelDown('/db/path')
const db = new AsyncLevel(leveldown, {
encode: JSON.stringify,
keyEncode: charwise.encode,
decode: JSON.parse
})
await levelDB.open()
const { err } = await levelDB.put(['foo', 'three'], {
id: 'use id',
email: 'foo@gmail.com'
})
const { err, data: value } = await levelDB.get(['foo', 'one'])
// value is decoded, with JSON.parse.
const itr1 = levelDB.iterator({
gte: ['foo', charwise.LO],
lte: ['foo', charwise.HI],
keyAsBuffer: false
})
A simpler API around leveldown
with basic features like
- async/await support, including
{ err, data } = await
- encode, decode & keyEncode
-
iterator()
method that returnsAsyncIterator
This library returns { err, data }
from all it's promises
like documented in resultify
The alternative library level
has quite a bit of code and weight
in it, including features we do not need like streams and normal
promises that reject/throw.
This alterive library async-level
is single file, zero dependencies
and clocks in at <500 lines of code.
AsyncLevel
provides a class to wrap leveldown
and adds
some quality of life API improvements including promises
,
encode
, decode
& keyEncode
as well as iterator
returning
an AsyncIterator
.
Currently the AsyncIterator
does not support concurrent
calls to next()
Also note that this is a wrapped around leveldown
; so it has
all the same caveats as leveldown, for example if you call
get()
before open()
finishes your node program just segfaults
Calling AsyncLevel
with leveldown
and options creates a db
object.
-
leveldown
must be an instance ofleveldown
-
options.encode
is an optional encoding function likeJSON.stringify
-
options.decode
is an optional decoding function likeJSON.parse
-
options.keyEncode
is an optional key encoding function likerequire('charwise').encode
-
options.valueEncoding
; for backwards compatibility withlevel
you can setoptions.valueEncoding: 'json'
to enableJSON.parse
&JSON.stringify
fordecode
&encode
.
You cannot interact with leveldown
until the database is open.
Calling await db.ensure()
will wait until the database is open.
levelup
had a feature where it would enqueue all your reads
and writes until the database is open.
Instead, with async-level
you can add await db.ensure()
to the top of any method that wants to do any reads or writes
on a potentially un-open database. This will ensure the database
is open.
Open the database and get an err
back if it failed.
Close the database and get an err
back if it failed.
Write a key/value to the database. Get an err
back if it failed.
If you specified encode
, decode
or keyEncode
in the constructor
then those will be respected for encoding of key
and value
.
Retrives a key
from the database. Get an err
or a data
back.
If you specified encode
, decode
or keyEncode
in the constructor
then those will be respected for encoding of key
and data
.
If the key is not found then it will return an err
which has
a err.notFound === true
property on it.
Deletes a key from the database. Get an err
back if it failed.
If you specified keyEncode
in the constructor then it will be
respected for encoding of key
Writes a batch to the database. Get an err
back if it failed.
The operations
parameter must be an Array
of objects with
three properties, type
, key
and value
.
The type
field can be 'put'
or 'del'
If you specified encode
, decode
or keyEncode
in the constructor
then those will be respected for encoding of key
and value
.
Clear a range of key/value pairs in the levelDB database.
Options are passed to leveldown.clear()
and include:
gt
, gte
, lt
, lte
, reverse
, limit
.
Creates an AsyncIterator
for the database. Note that this method
does not return a promise and does not need await
.
The AsyncIterator
returned is compatible with for await
loops.
If you specified encode
, decode
or keyEncode
in the constructor
then those will be respected for encoding of key
and value
.
The options
object is passed to leveldown.iterator()
Gets the next key/value pair from the iterator. This returns
an IteratorResult
with r.done
and r.value
.
If r.done
is true
then the iterator is finished.
The r.value
contains r.value.err
and r.value.data
.
If there was an err
reading from the iterator then you get
r.value.err
otherwise r.value.data
contains a key and a value.
Aka r.value.data.key
and r.value.data.value
are returned
from the iterator for the key and value.
-
r.done
; boolean, if true the iterator is finished -
r.value.err
; optional Error; if it exists then there was an error -
r.value.data.key
; the key for this iterator value -
r.value.data.value
; the value for this iterator value.
This closes the iterator. Must be closed if you do not read the iterator to completion.
Like next()
but returns keys
and values
aka
-
r.value.data.keys
; an array of keys -
r.value.data.values
; an array of values.
If you use batchNext()
we recommend using a decent highWaterMark
const itr = db.iterator({
gt: '...',
lte: '...',
highWaterMark: 1024 * 1024
})
For some applications it's really useful to read a batch of
key value pairs out of the Iterator
in one go.
The AsyncIterator
supports an await batchNext()
method that
returns an array of keys & an array of values.
The maximum length is 1000 and the maximum size is based on the highWaterMark that you pass to leveldown (default 16kb).
% npm install async-level