Skip to content

Commit

Permalink
Merge pull request #155 from Level/abstract-leveldown@6
Browse files Browse the repository at this point in the history
Upgrade to abstract leveldown@6
  • Loading branch information
vweevers committed Dec 25, 2018
2 parents cb0b36f + 2f97b6e commit 0b1507f
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 184 deletions.
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

0 comments on commit 0b1507f

Please sign in to comment.