Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

abstract-leveldown

Package Overview
Dependencies
Maintainers
3
Versions
79
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

abstract-leveldown - npm Package Compare versions

Comparing version 7.1.0 to 7.2.0

lib/common.js

68

abstract-leveldown.js

@@ -5,4 +5,8 @@ 'use strict'

const isBuffer = require('is-buffer')
const catering = require('catering')
const AbstractIterator = require('./abstract-iterator')
const AbstractChainedBatch = require('./abstract-chained-batch')
const getCallback = require('./lib/common').getCallback
const getOptions = require('./lib/common').getOptions
const hasOwnProperty = Object.prototype.hasOwnProperty

@@ -94,2 +98,47 @@ const rangeOptions = ['lt', 'lte', 'gt', 'gte']

AbstractLevelDOWN.prototype.getMany = function (keys, options, callback) {
callback = getCallback(options, callback)
callback = catering.fromCallback(callback)
options = getOptions(options)
if (maybeError(this, callback)) {
return callback.promise
}
if (!Array.isArray(keys)) {
this._nextTick(callback, new Error('getMany() requires an array argument'))
return callback.promise
}
if (keys.length === 0) {
this._nextTick(callback, null, [])
return callback.promise
}
if (typeof options.asBuffer !== 'boolean') {
options = { ...options, asBuffer: true }
}
const serialized = new Array(keys.length)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const err = this._checkKey(key)
if (err) {
this._nextTick(callback, err)
return callback.promise
}
serialized[i] = this._serializeKey(key)
}
this._getMany(serialized, options, callback)
return callback.promise
}
AbstractLevelDOWN.prototype._getMany = function (keys, options, callback) {
this._nextTick(callback, null, new Array(keys.length).fill(undefined))
}
AbstractLevelDOWN.prototype.put = function (key, value, options, callback) {

@@ -320,2 +369,12 @@ if (typeof options === 'function') callback = options

// TODO: docs and tests
AbstractLevelDOWN.prototype.isOperational = function () {
return this.status === 'open' || this._isOperational()
}
// Implementation may accept operations in other states too
AbstractLevelDOWN.prototype._isOperational = function () {
return false
}
// Expose browser-compatible nextTick for dependents

@@ -327,1 +386,10 @@ // TODO: rename _nextTick to _queueMicrotask

module.exports = AbstractLevelDOWN
function maybeError (db, callback) {
if (!db.isOperational()) {
db._nextTick(callback, new Error('Database is not open'))
return true
}
return false
}
# Changelog
## [7.2.0] - 2021-09-28
### Added
- Add `db.getMany(keys)` ([#381](https://github.com/Level/abstract-leveldown/issues/381)) ([`e4445a7`](https://github.com/Level/abstract-leveldown/commit/e4445a7)) (Vincent Weevers).
## [7.1.0] - 2021-09-21

@@ -850,2 +856,4 @@

[7.2.0]: https://github.com/Level/abstract-leveldown/releases/tag/v7.2.0
[7.1.0]: https://github.com/Level/abstract-leveldown/releases/tag/v7.1.0

@@ -852,0 +860,0 @@

6

package.json
{
"name": "abstract-leveldown",
"version": "7.1.0",
"version": "7.2.0",
"description": "An abstract prototype matching the LevelDOWN API",

@@ -24,2 +24,3 @@ "license": "MIT",

"index.js",
"lib",
"next-tick-browser.js",

@@ -34,5 +35,6 @@ "next-tick.js",

"buffer": "^6.0.3",
"catering": "^2.0.0",
"is-buffer": "^2.0.5",
"level-concat-iterator": "^3.0.0",
"level-supports": "^2.0.0",
"level-supports": "^2.0.1",
"queue-microtask": "^1.2.3"

@@ -39,0 +41,0 @@ },

@@ -28,2 +28,3 @@ # abstract-leveldown

- [`db.get(key[, options], callback)`](#dbgetkey-options-callback)
- [`db.getMany(keys[, options][, callback])`](#dbgetmanykeys-options-callback)
- [`db.put(key, value[, options], callback)`](#dbputkey-value-options-callback)

@@ -55,2 +56,3 @@ - [`db.del(key[, options], callback)`](#dbdelkey-options-callback)

- [`db._get(key, options, callback)`](#db_getkey-options-callback)
- [`db._getMany(keys, options, callback)`](#db_getmanykeys-options-callback)
- [`db._put(key, value, options, callback)`](#db_putkey-value-options-callback)

@@ -223,4 +225,14 @@ - [`db._del(key, options, callback)`](#db_delkey-options-callback)

The `callback` function will be called with an `Error` if the operation failed for any reason. If successful the first argument will be `null` and the second argument will be the value.
The `callback` function will be called with an `Error` if the operation failed for any reason, including if the key was not found. If successful the first argument will be `null` and the second argument will be the value.
### `db.getMany(keys[, options][, callback])`
Get multiple values from the store by an array of `keys`. The optional `options` object may contain:
- `asBuffer` _(boolean, default: `true`)_: Whether to return the `value` as a Buffer. If `false`, the returned type depends on the implementation.
The `callback` function will be called with an `Error` if the operation failed for any reason. If successful the first argument will be `null` and the second argument will be an array of values with the same order as `keys`. If a key was not found, the relevant value will be `undefined`.
If no callback is provided, a promise is returned.
### `db.put(key, value[, options], callback)`

@@ -441,2 +453,10 @@

### `db._getMany(keys, options, callback)`
**This new method is optional for the time being. To enable its tests, set the [`getMany` option of the test suite](#excluding-tests) to `true`.**
Get multiple values by an array of `keys`. The `options` object will always have the following properties: `asBuffer`. If an error occurs, call the `callback` function with an `Error`. Otherwise call `callback` with `null` as the first argument and an array of values as the second. If a key does not exist, set the relevant value to `undefined`.
The default `_getMany()` invokes `callback` on a next tick with an array of values that is equal in length to `keys` and is filled with `undefined`. It must be overridden to support `getMany()` but this is currently an opt-in feature. If the implementation does support `getMany()` then `db.supports.getMany` must be set to true via the [constructor](#db--abstractleveldownmanifest).
### `db._put(key, value, options, callback)`

@@ -588,2 +608,3 @@

- `clear`: defaults to `false` until a next major release. Set to `true` if your implementation either implements `_clear()` itself or is suitable to use the default implementation of `_clear()` (which requires binary key support).
- `getMany`: defaults to `false` until a next major release. Set to `true` if your implementation implements `_getMany()`.
- `snapshots`: set to `false` if any of the following is true:

@@ -590,0 +611,0 @@ - Reads don't operate on a [snapshot](#iterator)

@@ -34,2 +34,3 @@ 'use strict'

clear: !!options.clear,
getMany: !!options.getMany,

@@ -46,3 +47,2 @@ // Support running test suite on a levelup db. All options below this line

// Not yet used, only here for symmetry with levelup's test suite.
deferredOpen: !!options.deferredOpen,

@@ -49,0 +49,0 @@ streams: !!options.streams

@@ -42,18 +42,2 @@ 'use strict'

})
testCommon.serialize && test('test custom _serialize*', function (t) {
t.plan(3)
const db = testCommon.factory()
db._serializeKey = function (data) { return data }
db._del = function (key, options, callback) {
t.deepEqual(key, { foo: 'bar' })
this._nextTick(callback)
}
db.open(function () {
db.del({ foo: 'bar' }, function (err) {
t.error(err)
db.close(t.error.bind(t))
})
})
})
}

@@ -60,0 +44,0 @@

'use strict'
const isBuffer = require('is-buffer')
const verifyNotFoundError = require('./util').verifyNotFoundError

@@ -43,18 +44,2 @@ const isTypedArray = require('./util').isTypedArray

})
testCommon.serialize && test('test custom _serialize*', function (t) {
t.plan(3)
const db = testCommon.factory()
db._serializeKey = function (data) { return data }
db._get = function (key, options, callback) {
t.deepEqual(key, { foo: 'bar' })
this._nextTick(callback)
}
db.open(function () {
db.get({ foo: 'bar' }, function (err) {
t.error(err)
db.close(t.error.bind(t))
})
})
})
}

@@ -72,3 +57,3 @@

if (!testCommon.encodings) {
t.ok(typeof value !== 'string', 'should not be string by default')
t.isNot(typeof value, 'string', 'should not be string by default')

@@ -78,3 +63,3 @@ if (isTypedArray(value)) {

} else {
t.ok(typeof Buffer !== 'undefined' && value instanceof Buffer)
t.ok(isBuffer(value))
try {

@@ -90,3 +75,3 @@ result = value.toString()

t.equal(result, 'bar')
t.is(result, 'bar')

@@ -104,3 +89,3 @@ db.get('foo', {}, function (err, value) { // same but with {}

} else {
t.ok(typeof Buffer !== 'undefined' && value instanceof Buffer)
t.ok(isBuffer(value))
try {

@@ -116,3 +101,3 @@ result = value.toString()

t.equal(result, 'bar')
t.is(result, 'bar')

@@ -122,3 +107,3 @@ db.get('foo', { asBuffer: false }, function (err, value) {

t.ok(typeof value === 'string', 'should be string if not buffer')
t.equal(value, 'bar')
t.is(value, 'bar')
t.end()

@@ -131,16 +116,14 @@ })

test('test simultaniously get()', function (t) {
test('test simultaneous get()', function (t) {
db.put('hello', 'world', function (err) {
t.error(err)
let r = 0
let completed = 0
const done = function () {
if (++r === 20) { t.end() }
if (++completed === 20) t.end()
}
let i = 0
let j = 0
for (; i < 10; ++i) {
for (let i = 0; i < 10; ++i) {
db.get('hello', function (err, value) {
t.error(err)
t.equal(value.toString(), 'world')
t.is(value.toString(), 'world')
done()

@@ -150,3 +133,3 @@ })

for (; j < 10; ++j) {
for (let i = 0; i < 10; ++i) {
db.get('not found', function (err, value) {

@@ -163,18 +146,14 @@ t.ok(err, 'should error')

test('test get() not found error is asynchronous', function (t) {
t.plan(5)
t.plan(4)
db.put('hello', 'world', function (err) {
t.error(err)
let async = false
let async = false
db.get('not found', function (err, value) {
t.ok(err, 'should error')
t.ok(verifyNotFoundError(err), 'should have correct error message')
t.ok(typeof value === 'undefined', 'value is undefined')
t.ok(async, 'callback is asynchronous')
})
db.get('not found', function (err, value) {
t.ok(err, 'should error')
t.ok(verifyNotFoundError(err), 'should have correct error message')
t.ok(typeof value === 'undefined', 'value is undefined')
t.ok(async, 'callback is asynchronous')
})
async = true
})
async = true
})

@@ -181,0 +160,0 @@ }

@@ -29,2 +29,6 @@ 'use strict'

if (testCommon.getMany) {
require('./get-many-test').all(test, testCommon)
}
require('./batch-test').all(test, testCommon)

@@ -31,0 +35,0 @@ require('./chained-batch-test').all(test, testCommon)

@@ -16,4 +16,4 @@ 'use strict'

const iterator = db.iterator()
// For levelup compat: may return iterator of an underlying db, that's okay.
t.ok(iterator.db === db || iterator.db)
// For levelup & deferred-leveldown compat: may return iterator of an underlying db, that's okay.
t.ok(iterator.db === db || iterator.db === (db.db || db._db || db))
iterator.end(t.end.bind(t))

@@ -20,0 +20,0 @@ })

'use strict'
const verifyNotFoundError = require('./util').verifyNotFoundError
const assertAsync = require('./util').assertAsync
const testBuffer = Buffer.from('testbuffer')

@@ -8,3 +9,3 @@

function makeGetDelErrorTests (test, type, key, expectedError) {
function makeGetDelErrorTests (test, testCommon, type, key, expectedError) {
test('test get() with ' + type + ' causes error', function (t) {

@@ -37,2 +38,19 @@ let async = false

})
testCommon.getMany && test('test getMany() with ' + type + ' causes error', assertAsync.ctx(function (t) {
// Add 1 assertion for every assertAsync()
t.plan(2 * 4)
db.getMany([key], assertAsync(function (err) {
t.ok(err, 'has error')
t.ok(err instanceof Error)
t.ok(err.message.match(expectedError), 'correct error message')
}))
db.getMany(['valid', key], assertAsync(function (err) {
t.ok(err, 'has error')
t.ok(err instanceof Error)
t.ok(err.message.match(expectedError), 'correct error message')
}))
}))
}

@@ -101,4 +119,4 @@

function makeErrorKeyTest (test, type, key, expectedError) {
makeGetDelErrorTests(test, type, key, expectedError)
function makeErrorKeyTest (test, testCommon, type, key, expectedError) {
makeGetDelErrorTests(test, testCommon, type, key, expectedError)
makePutErrorTest(test, type, key, 'foo', expectedError)

@@ -116,7 +134,7 @@ }

exports.errorKeys = function (test, testCommon) {
makeErrorKeyTest(test, 'null key', null, /key cannot be `null` or `undefined`/)
makeErrorKeyTest(test, 'undefined key', undefined, /key cannot be `null` or `undefined`/)
makeErrorKeyTest(test, 'empty String key', '', /key cannot be an empty String/)
makeErrorKeyTest(test, 'empty Buffer key', Buffer.alloc(0), /key cannot be an empty \w*Buffer/)
makeErrorKeyTest(test, 'empty Array key', [], /key cannot be an empty Array/)
makeErrorKeyTest(test, testCommon, 'null key', null, /key cannot be `null` or `undefined`/)
makeErrorKeyTest(test, testCommon, 'undefined key', undefined, /key cannot be `null` or `undefined`/)
makeErrorKeyTest(test, testCommon, 'empty String key', '', /key cannot be an empty String/)
makeErrorKeyTest(test, testCommon, 'empty Buffer key', Buffer.alloc(0), /key cannot be an empty \w*Buffer/)
makeErrorKeyTest(test, testCommon, 'empty Array key', [], /key cannot be an empty Array/)
}

@@ -123,0 +141,0 @@

@@ -51,32 +51,2 @@ 'use strict'

})
testCommon.serialize && test('test _serialize object', function (t) {
t.plan(3)
const db = testCommon.factory()
db._put = function (key, value, opts, callback) {
t.ok(key)
t.ok(value)
this._nextTick(callback)
}
db.put({}, {}, function (err, val) {
t.error(err)
})
})
testCommon.serialize && test('test custom _serialize*', function (t) {
t.plan(4)
const db = testCommon.factory()
db._serializeKey = db._serializeValue = function (data) { return data }
db._put = function (key, value, options, callback) {
t.deepEqual(key, { foo: 'bar' })
t.deepEqual(value, { beep: 'boop' })
this._nextTick(callback)
}
db.open(function () {
db.put({ foo: 'bar' }, { beep: 'boop' }, function (err) {
t.error(err)
db.close(t.error.bind(t))
})
})
})
}

@@ -83,0 +53,0 @@

@@ -39,2 +39,5 @@ 'use strict'

require('./get-many-test').setUp(test, testCommon)
require('./get-many-test').args(test, testCommon)
require('./put-test').setUp(test, testCommon)

@@ -237,2 +240,33 @@ require('./put-test').args(test, testCommon)

test('test getMany() extensibility', function (t) {
const spy = sinon.spy()
const expectedCb = function () {}
const expectedOptions = { asBuffer: true }
const expectedKey = 'a key'
const Test = implement(AbstractLevelDOWN, { _getMany: spy })
const test = new Test('foobar')
test.status = 'open'
test.getMany([expectedKey], expectedCb)
t.equal(spy.callCount, 1, 'got _getMany() call')
t.equal(spy.getCall(0).thisValue, test, '`this` on _getMany() was correct')
t.equal(spy.getCall(0).args.length, 3, 'got three arguments')
t.deepEqual(spy.getCall(0).args[0], [expectedKey], 'got expected keys argument')
t.deepEqual(spy.getCall(0).args[1], expectedOptions, 'got default options argument')
t.equal(spy.getCall(0).args[2], expectedCb, 'got expected cb argument')
test.getMany([expectedKey], { options: 1 }, expectedCb)
expectedOptions.options = 1
t.equal(spy.callCount, 2, 'got _getMany() call')
t.equal(spy.getCall(1).thisValue, test, '`this` on _getMany() was correct')
t.equal(spy.getCall(1).args.length, 3, 'got three arguments')
t.deepEqual(spy.getCall(1).args[0], [expectedKey], 'got expected key argument')
t.deepEqual(spy.getCall(1).args[1], expectedOptions, 'got expected options argument')
t.equal(spy.getCall(1).args[2], expectedCb, 'got expected cb argument')
t.end()
})
test('test del() extensibility', function (t) {

@@ -624,2 +658,40 @@ const spy = sinon.spy()

test('test serialization extensibility (get)', function (t) {
t.plan(2)
const spy = sinon.spy()
const Test = implement(AbstractLevelDOWN, {
_get: spy,
_serializeKey: function (key) {
return key.toUpperCase()
}
})
const test = new Test()
test.get('foo', function () {})
t.is(spy.callCount, 1, 'got _get() call')
t.is(spy.getCall(0).args[0], 'FOO', 'got expected key argument')
})
test('test serialization extensibility (getMany)', function (t) {
t.plan(2)
const spy = sinon.spy()
const Test = implement(AbstractLevelDOWN, {
_getMany: spy,
_serializeKey: function (key) {
return key.toUpperCase()
}
})
const test = new Test()
test.status = 'open'
test.getMany(['foo', 'bar'], function () {})
t.is(spy.callCount, 1, 'got _getMany() call')
t.same(spy.getCall(0).args[0], ['FOO', 'BAR'], 'got expected keys argument')
})
test('test serialization extensibility (put)', function (t) {

@@ -915,2 +987,4 @@ t.plan(5)

})
t.equal(test.status, 'opening')
})

@@ -917,0 +991,0 @@

'use strict'
const nfre = /NotFound/i
const spies = []

@@ -13,1 +14,60 @@ exports.verifyNotFoundError = function verifyNotFoundError (err) {

}
/**
* Wrap a callback to check that it's called asynchronously. Must be
* combined with a `ctx()`, `with()` or `end()` call.
*
* @param {function} cb Callback to check.
* @param {string} name Optional callback name to use in assertion messages.
* @returns {function} Wrapped callback.
*/
exports.assertAsync = function (cb, name) {
const spy = {
called: false,
name: name || cb.name || 'anonymous'
}
spies.push(spy)
return function (...args) {
spy.called = true
return cb.apply(this, args)
}
}
/**
* Verify that callbacks wrapped with `assertAsync()` were not yet called.
* @param {import('tape').Test} t Tape test object.
*/
exports.assertAsync.end = function (t) {
for (const { called, name } of spies.splice(0, spies.length)) {
t.is(called, false, `callback (${name}) is asynchronous`)
}
}
/**
* Wrap a test function to verify `assertAsync()` spies at the end.
* @param {import('tape').TestCase} test Test function to be passed to `tape()`.
* @returns {import('tape').TestCase} Wrapped test function.
*/
exports.assertAsync.ctx = function (test) {
return function (...args) {
const ret = test.call(this, ...args)
exports.assertAsync.end(args[0])
return ret
}
}
/**
* Wrap an arbitrary callback to verify `assertAsync()` spies at the end.
* @param {import('tape').Test} t Tape test object.
* @param {function} cb Callback to wrap.
* @returns {function} Wrapped callback.
*/
exports.assertAsync.with = function (t, cb) {
return function (...args) {
const ret = cb.call(this, ...args)
exports.assertAsync.end(t)
return ret
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc