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
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
|
|
|