You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
6.7 KiB

/* Copyright (c) 2013 Rod Vagg, MIT License */
var xtend = require('xtend')
, AbstractIterator = require('./abstract-iterator')
, AbstractChainedBatch = require('./abstract-chained-batch')
function AbstractLevelDOWN (location) {
if (!arguments.length || location === undefined)
throw new Error('constructor requires at least a location argument')
if (typeof location != 'string')
throw new Error('constructor requires a location string argument')
this.location = location
}
AbstractLevelDOWN.prototype.open = function (options, callback) {
if (typeof options == 'function')
callback = options
if (typeof callback != 'function')
throw new Error('open() requires a callback argument')
if (typeof options != 'object')
options = {}
if (typeof this._open == 'function')
return this._open(options, callback)
process.nextTick(callback)
}
AbstractLevelDOWN.prototype.close = function (callback) {
if (typeof callback != 'function')
throw new Error('close() requires a callback argument')
if (typeof this._close == 'function')
return this._close(callback)
process.nextTick(callback)
}
AbstractLevelDOWN.prototype.get = function (key, options, callback) {
var err
if (typeof options == 'function')
callback = options
if (typeof callback != 'function')
throw new Error('get() requires a callback argument')
if (err = this._checkKeyValue(key, 'key', this._isBuffer))
return callback(err)
if (!this._isBuffer(key))
key = String(key)
if (typeof options != 'object')
options = {}
if (typeof this._get == 'function')
return this._get(key, options, callback)
process.nextTick(function () { callback(new Error('NotFound')) })
}
AbstractLevelDOWN.prototype.put = function (key, value, options, callback) {
var err
if (typeof options == 'function')
callback = options
if (typeof callback != 'function')
throw new Error('put() requires a callback argument')
if (err = this._checkKeyValue(key, 'key', this._isBuffer))
return callback(err)
if (err = this._checkKeyValue(value, 'value', this._isBuffer))
return callback(err)
if (!this._isBuffer(key))
key = String(key)
// coerce value to string in node, don't touch it in browser
// (indexeddb can store any JS type)
if (!this._isBuffer(value) && !process.browser)
value = String(value)
if (typeof options != 'object')
options = {}
if (typeof this._put == 'function')
return this._put(key, value, options, callback)
process.nextTick(callback)
}
AbstractLevelDOWN.prototype.del = function (key, options, callback) {
var err
if (typeof options == 'function')
callback = options
if (typeof callback != 'function')
throw new Error('del() requires a callback argument')
if (err = this._checkKeyValue(key, 'key', this._isBuffer))
return callback(err)
if (!this._isBuffer(key))
key = String(key)
if (typeof options != 'object')
options = {}
if (typeof this._del == 'function')
return this._del(key, options, callback)
process.nextTick(callback)
}
AbstractLevelDOWN.prototype.batch = function (array, options, callback) {
if (!arguments.length)
return this._chainedBatch()
if (typeof options == 'function')
callback = options
if (typeof callback != 'function')
throw new Error('batch(array) requires a callback argument')
if (!Array.isArray(array))
return callback(new Error('batch(array) requires an array argument'))
if (typeof options != 'object')
options = {}
var i = 0
, l = array.length
, e
, err
for (; i < l; i++) {
e = array[i]
if (typeof e != 'object')
continue
if (err = this._checkKeyValue(e.type, 'type', this._isBuffer))
return callback(err)
if (err = this._checkKeyValue(e.key, 'key', this._isBuffer))
return callback(err)
if (e.type == 'put') {
if (err = this._checkKeyValue(e.value, 'value', this._isBuffer))
return callback(err)
}
}
if (typeof this._batch == 'function')
return this._batch(array, options, callback)
process.nextTick(callback)
}
//TODO: remove from here, not a necessary primitive
AbstractLevelDOWN.prototype.approximateSize = function (start, end, callback) {
if ( start == null
|| end == null
|| typeof start == 'function'
|| typeof end == 'function') {
throw new Error('approximateSize() requires valid `start`, `end` and `callback` arguments')
}
if (typeof callback != 'function')
throw new Error('approximateSize() requires a callback argument')
if (!this._isBuffer(start))
start = String(start)
if (!this._isBuffer(end))
end = String(end)
if (typeof this._approximateSize == 'function')
return this._approximateSize(start, end, callback)
process.nextTick(function () {
callback(null, 0)
})
}
AbstractLevelDOWN.prototype._setupIteratorOptions = function (options) {
var self = this
options = xtend(options)
;[ 'start', 'end', 'gt', 'gte', 'lt', 'lte' ].forEach(function (o) {
if (options[o] && self._isBuffer(options[o]) && options[o].length === 0)
delete options[o]
})
options.reverse = !!options.reverse
// fix `start` so it takes into account gt, gte, lt, lte as appropriate
if (options.reverse && options.lt)
options.start = options.lt
if (options.reverse && options.lte)
options.start = options.lte
if (!options.reverse && options.gt)
options.start = options.gt
if (!options.reverse && options.gte)
options.start = options.gte
if ((options.reverse && options.lt && !options.lte)
|| (!options.reverse && options.gt && !options.gte))
options.exclusiveStart = true // start should *not* include matching key
return options
}
AbstractLevelDOWN.prototype.iterator = function (options) {
if (typeof options != 'object')
options = {}
options = this._setupIteratorOptions(options)
if (typeof this._iterator == 'function')
return this._iterator(options)
return new AbstractIterator(this)
}
AbstractLevelDOWN.prototype._chainedBatch = function () {
return new AbstractChainedBatch(this)
}
AbstractLevelDOWN.prototype._isBuffer = function (obj) {
return Buffer.isBuffer(obj)
}
AbstractLevelDOWN.prototype._checkKeyValue = function (obj, type) {
if (obj === null || obj === undefined)
return new Error(type + ' cannot be `null` or `undefined`')
if (this._isBuffer(obj)) {
if (obj.length === 0)
return new Error(type + ' cannot be an empty Buffer')
} else if (String(obj) === '')
return new Error(type + ' cannot be an empty String')
}
module.exports.AbstractLevelDOWN = AbstractLevelDOWN
module.exports.AbstractIterator = AbstractIterator
module.exports.AbstractChainedBatch = AbstractChainedBatch