Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to abstract leveldown@6 #155

Merged
merged 10 commits into from
Dec 25, 2018
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ Note that this behavior is slightly different from values due to the way that In
If the environment does not support a type, it will throw an error which `level-js` catches and passes to the callbacks of `get`, `put`, `del`, `batch` or an iterator. Exceptions are:

- `null` and `undefined`: rejected early by `abstract-leveldown`
- Boolean and `NaN`: though invalid per the IndexedDB specification, they are converted to strings for `abstract-leveldown` compatibility;
- Binary and array keys: if not supported by the environment, `level-js` falls back to `String(key)`.

### Normalization
Expand Down
15 changes: 8 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ var DEFAULT_PREFIX = 'level-js-'

function Level (location, opts) {
if (!(this instanceof Level)) return new Level(location, opts)
AbstractLevelDOWN.call(this, location)
AbstractLevelDOWN.call(this)
opts = opts || {}

if (typeof location !== 'string') {
throw new Error('constructor requires a location string argument')
}

this.location = location
this.prefix = opts.prefix || DEFAULT_PREFIX
this.version = parseInt(opts.version || 1, 10)
}
Expand Down Expand Up @@ -140,21 +145,17 @@ Level.prototype._serializeKey = function (key) {
return Level.binaryKeys ? key : key.toString()
} else if (Array.isArray(key)) {
return Level.arrayKeys ? key.map(this._serializeKey, this) : String(key)
} else if (typeof key === 'boolean' || (typeof key === 'number' && isNaN(key))) {
// These types are invalid per the IndexedDB spec and ideally we'd treat
// them that way, but they're valid per the current abstract test suite.
return String(key)
} else {
return key
}
}

Level.prototype._serializeValue = function (value) {
return value == null ? '' : value
return value
}

Level.prototype._iterator = function (options) {
return new Iterator(this.db, this.location, options)
return new Iterator(this, this.location, options)
}

Level.prototype._batch = function (operations, options, callback) {
Expand Down
8 changes: 7 additions & 1 deletion iterator.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ Iterator.prototype.createKeyRange = function (options) {
var lowerOpen = ltgt.lowerBoundExclusive(options)
var upperOpen = ltgt.upperBoundExclusive(options)

// Temporary workaround for Level/abstract-leveldown#318
if ((Buffer.isBuffer(lower) || typeof lower === 'string') && lower.length === 0) lower = undefined
if ((Buffer.isBuffer(upper) || typeof upper === 'string') && upper.length === 0) upper = undefined
if ((Buffer.isBuffer(lowerOpen) || typeof lowerOpen === 'string') && lowerOpen.length === 0) lowerOpen = undefined
if ((Buffer.isBuffer(upperOpen) || typeof upperOpen === 'string') && upperOpen.length === 0) upperOpen = undefined

if (lower !== undefined && upper !== undefined) {
return IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen)
} else if (lower !== undefined) {
Expand All @@ -64,7 +70,7 @@ Iterator.prototype.createKeyRange = function (options) {

Iterator.prototype.createIterator = function (location, keyRange, reverse) {
var self = this
var transaction = this.db.transaction([location], 'readonly')
var transaction = this.db.db.transaction([location], 'readonly')
var store = transaction.objectStore(location)
var req = store.openCursor(keyRange, reverse ? 'prev' : 'next')

Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
]
},
"dependencies": {
"abstract-leveldown": "~5.0.0",
"abstract-leveldown": "~6.0.0",
"immediate": "~3.2.3",
"inherits": "^2.0.3",
"ltgt": "^2.1.2",
Expand All @@ -41,9 +41,11 @@
"coveralls": "^3.0.2",
"hallmark": "0.1.0",
"level-community": "~3.0.0",
"level-concat-iterator": "^2.0.0",
"nyc": "^13.1.0",
"standard": "^12.0.1",
"tape": "^4.0.0"
"tape": "^4.0.0",
"uuid": "~3.3.2"
},
"hallmark": {
"community": "level-community"
Expand Down
51 changes: 26 additions & 25 deletions test/custom-test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
'use strict'

var concat = require('level-concat-iterator')

module.exports = function (leveljs, test, testCommon) {
test('setUp', testCommon.setUp)

test('default prefix', function (t) {
var location = testCommon.location()
var db = leveljs(location)
var db = testCommon.factory()

t.is(db.location, location, 'instance has location property')
t.ok(db.location, 'instance has location property')
t.is(db.prefix, 'level-js-', 'instance has prefix property')

db.open(function (err) {
Expand All @@ -17,19 +18,18 @@ module.exports = function (leveljs, test, testCommon) {
var databaseName = idb.name
var storeNames = idb.objectStoreNames

t.is(databaseName, 'level-js-' + location, 'database name is prefixed')
t.is(databaseName, 'level-js-' + db.location, 'database name is prefixed')
t.is(storeNames.length, 1, 'created 1 object store')
t.is(storeNames.item(0), location, 'object store name equals location')
t.is(storeNames.item(0), db.location, 'object store name equals location')

db.close(t.end.bind(t))
})
})

test('custom prefix', function (t) {
var location = testCommon.location()
var db = leveljs(location, { prefix: 'custom-' })
var db = testCommon.factory({ prefix: 'custom-' })

t.is(db.location, location, 'instance has location property')
t.ok(db.location, 'instance has location property')
t.is(db.prefix, 'custom-', 'instance has prefix property')

db.open(function (err) {
Expand All @@ -39,16 +39,16 @@ module.exports = function (leveljs, test, testCommon) {
var databaseName = idb.name
var storeNames = idb.objectStoreNames

t.is(databaseName, 'custom-' + location, 'database name is prefixed')
t.is(databaseName, 'custom-' + db.location, 'database name is prefixed')
t.is(storeNames.length, 1, 'created 1 object store')
t.is(storeNames.item(0), location, 'object store name equals location')
t.is(storeNames.item(0), db.location, 'object store name equals location')

db.close(t.end.bind(t))
})
})

test('put Buffer value, get Buffer value', function (t) {
var level = leveljs(testCommon.location())
var level = testCommon.factory()
level.open(function (err) {
t.notOk(err, 'no error')
level.put('key', Buffer.from('00ff', 'hex'), function (err) {
Expand All @@ -64,7 +64,7 @@ module.exports = function (leveljs, test, testCommon) {
})

test('put Buffer value, get Uint8Array value', function (t) {
var level = leveljs(testCommon.location())
var level = testCommon.factory()
level.open(function (err) {
t.notOk(err, 'no error')
level.put('key', Buffer.from('00ff', 'hex'), function (err) {
Expand All @@ -81,7 +81,7 @@ module.exports = function (leveljs, test, testCommon) {
})

test('put Uint8Array value, get Buffer value', function (t) {
var level = leveljs(testCommon.location())
var level = testCommon.factory()
level.open(function (err) {
t.notOk(err, 'no error')
level.put('key', new Uint8Array(Buffer.from('00ff', 'hex').buffer), function (err) {
Expand All @@ -97,7 +97,7 @@ module.exports = function (leveljs, test, testCommon) {
})

test('put Uint8Array value, get Uint8Array value', function (t) {
var level = leveljs(testCommon.location())
var level = testCommon.factory()
level.open(function (err) {
t.notOk(err, 'no error')
level.put('key', new Uint8Array(Buffer.from('00ff', 'hex').buffer), function (err) {
Expand All @@ -114,7 +114,7 @@ module.exports = function (leveljs, test, testCommon) {
})

test('put ArrayBuffer value, get Buffer value', function (t) {
var level = leveljs(testCommon.location())
var level = testCommon.factory()
level.open(function (err) {
t.notOk(err, 'no error')
level.put('key', Buffer.from('00ff', 'hex').buffer, function (err) {
Expand All @@ -130,7 +130,7 @@ module.exports = function (leveljs, test, testCommon) {
})

test('put ArrayBuffer value, get ArrayBuffer value', function (t) {
var level = leveljs(testCommon.location())
var level = testCommon.factory()
level.open(function (err) {
t.notOk(err, 'no error')
level.put('key', Buffer.from('00ff', 'hex').buffer, function (err) {
Expand All @@ -149,7 +149,7 @@ module.exports = function (leveljs, test, testCommon) {
// prevented by process.browser checks (Level/abstract-leveldown#121).
// This test is adapted from memdown.
leveljs.binaryKeys && test('buffer keys', function (t) {
var db = leveljs(testCommon.location())
var db = testCommon.factory()

db.open(function (err) {
t.ifError(err, 'no open error')
Expand Down Expand Up @@ -188,7 +188,7 @@ module.exports = function (leveljs, test, testCommon) {
// This should be covered by abstract-leveldown tests, but that's
// prevented by process.browser checks (Level/abstract-leveldown#121).
leveljs.binaryKeys && test('iterator yields buffer keys', function (t) {
var db = leveljs(testCommon.location())
var db = testCommon.factory()

db.open(function (err) {
t.ifError(err, 'no open error')
Expand All @@ -200,7 +200,7 @@ module.exports = function (leveljs, test, testCommon) {
t.ifError(err, 'no batch error')

var it = db.iterator({ valueAsBuffer: false })
testCommon.collectEntries(it, function (err, entries) {
concat(it, function (err, entries) {
t.ifError(err, 'no iterator error')

t.same(entries, [
Expand All @@ -221,15 +221,15 @@ module.exports = function (leveljs, test, testCommon) {
test('iterator stringifies buffer input', function (t) {
t.plan(6)

var db = leveljs(testCommon.location())
var db = testCommon.factory()

db.open(function (err) {
t.ifError(err, 'no open error')

db.put(1, 2, function (err) {
t.ifError(err, 'no put error')

testCommon.collectEntries(db.iterator(), function (err, entries) {
concat(db.iterator(), function (err, entries) {
t.ifError(err, 'no iterator error')
t.same(entries[0].key, Buffer.from('1'), 'key is stringified')
t.same(entries[0].value, Buffer.from('2'), 'value is stringified')
Expand All @@ -246,8 +246,8 @@ module.exports = function (leveljs, test, testCommon) {
// then create it again, then try and destroy it again. these avoid doing that

test('test .destroy', function (t) {
var location = testCommon.location()
var db = leveljs(location)
var db = testCommon.factory()
var location = db.location
db.open(function (err) {
t.notOk(err, 'no error')
db.put('key', 'value', function (err) {
Expand Down Expand Up @@ -275,9 +275,10 @@ module.exports = function (leveljs, test, testCommon) {
})

test('test .destroy and custom prefix', function (t) {
var location = testCommon.location()
var prefix = 'custom-'
var db = leveljs(location, { prefix: prefix })
var db = testCommon.factory({ prefix: prefix })
var location = db.location

db.open(function (err) {
t.notOk(err, 'no error')
db.put('key', 'value', function (err) {
Expand Down
31 changes: 18 additions & 13 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,33 @@
// require('./util/idb-shim.js')()

var test = require('tape')
var uuid = require('uuid/v4')
var suite = require('abstract-leveldown/test')
var leveljs = require('..')
var testCommon = require('./util/test-common')

// Test feature detection
require('./support-test')(leveljs, test)

var testCommon = suite.common({
test: test,
factory: function (opts) {
return leveljs(uuid(), opts)
},

// Unsupported features
createIfMissing: false,
errorIfExists: false,
seek: false,

// Support of buffer keys depends on environment
bufferKeys: leveljs.binaryKeys
})

// Test abstract-leveldown compliance
require('abstract-leveldown/abstract/leveldown-test').args(leveljs, test, testCommon)
require('abstract-leveldown/abstract/open-test').open(leveljs, test, testCommon)
require('abstract-leveldown/abstract/put-test').all(leveljs, test, testCommon)
require('abstract-leveldown/abstract/del-test').all(leveljs, test, testCommon)
require('abstract-leveldown/abstract/get-test').all(leveljs, test, testCommon)
require('abstract-leveldown/abstract/put-get-del-test').all(leveljs, test, testCommon)
require('abstract-leveldown/abstract/batch-test').all(leveljs, test, testCommon)
require('abstract-leveldown/abstract/chained-batch-test').all(leveljs, test, testCommon)
require('abstract-leveldown/abstract/close-test').close(leveljs, test, testCommon)
require('abstract-leveldown/abstract/iterator-test').all(leveljs, test, testCommon)
require('abstract-leveldown/abstract/iterator-range-test').all(leveljs, test, testCommon)
suite(testCommon)

// Additional tests for this implementation
require('./custom-test')(leveljs, test, testCommon)
require('./structured-clone-test')(leveljs, test, testCommon)
require('./key-type-test')(leveljs, test, testCommon)
require('./key-type-illegal-test')(leveljs, test, testCommon)
require('./key-type-stringified-test')(leveljs, test, testCommon)
10 changes: 6 additions & 4 deletions test/key-type-illegal-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ var illegalTypes = [
{ name: 'DOMNode', key: global.document, error: 'DataError' },
{ name: 'Boolean(true)', key: new Boolean(true), error: 'DataError' }, // eslint-disable-line
{ name: 'Boolean(false)', key: new Boolean(false), error: 'DataError' }, // eslint-disable-line
{ name: 'true', key: true, error: 'DataError' },
{ name: 'false', key: false, error: 'DataError' },
{ name: 'NaN', key: NaN, error: 'DataError' }
]

// These are only tested if the environment supports array keys.
// Cyclical arrays are not tested because our #_serializeKey goes into a loop.
var illegalArrays = [
// This type gets rejected by abstract-leveldown. As for why the error says
// "empty String" rather than "empty Array", see Level/abstract-leveldown#230.
{ name: 'empty Array', key: [], message: 'key cannot be an empty String' },
// This type gets rejected by abstract-leveldown (and is also illegal in IDB).
{ name: 'empty Array', key: [], message: 'key cannot be an empty Array' },

// These contain a valid element to ensure we don't hit an empty key assertion.
{ name: 'Array w/ null', key: ['a', null], error: 'DataError' },
Expand All @@ -41,7 +43,7 @@ module.exports = function (leveljs, test, testCommon) {
var db

test('open', function (t) {
db = leveljs(testCommon.location())
db = testCommon.factory()
db.open(t.end.bind(t))
})

Expand Down
38 changes: 0 additions & 38 deletions test/key-type-stringified-test.js

This file was deleted.

Loading