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.
211 lines
5.2 KiB
211 lines
5.2 KiB
var hooks = require('./hooks') |
|
var ltgt = require('ltgt') |
|
|
|
function isFunction (f) { |
|
return 'function' === typeof f |
|
} |
|
|
|
function getPrefix (db) { |
|
if(db == null) return db |
|
if(isFunction(db.prefix)) return db.prefix() |
|
return db |
|
} |
|
|
|
function has(obj, name) { |
|
return Object.hasOwnProperty.call(obj, name) |
|
} |
|
|
|
function clone (_obj) { |
|
var obj = {} |
|
for(var k in _obj) |
|
obj[k] = _obj[k] |
|
return obj |
|
} |
|
|
|
module.exports = function (db, precodec, codec, compare) { |
|
var prehooks = hooks(compare) |
|
var posthooks = hooks(compare) |
|
var waiting = [], ready = false |
|
|
|
function encodePrefix(prefix, key, opts1, opts2) { |
|
return precodec.encode([ prefix, codec.encodeKey(key, opts1, opts2 ) ]) |
|
} |
|
|
|
function decodePrefix(data) { |
|
return precodec.decode(data) |
|
} |
|
|
|
function addEncodings(op, prefix) { |
|
if(prefix && prefix.options) { |
|
op.keyEncoding = |
|
op.keyEncoding || prefix.options.keyEncoding |
|
op.valueEncoding = |
|
op.valueEncoding || prefix.options.valueEncoding |
|
} |
|
return op |
|
} |
|
|
|
function start () { |
|
ready = true |
|
while(waiting.length) |
|
waiting.shift()() |
|
} |
|
|
|
if(isFunction(db.isOpen)) { |
|
if(db.isOpen()) |
|
ready = true |
|
else |
|
db.open(start) |
|
} else { |
|
db.open(start) |
|
} |
|
|
|
return { |
|
location: db.location, |
|
apply: function (ops, opts, cb) { |
|
//apply prehooks here. |
|
for(var i = 0; i < ops.length; i++) { |
|
var op = ops[i] |
|
|
|
function add(op) { |
|
if(op === false) return delete ops[i] |
|
ops.push(op) |
|
} |
|
|
|
addEncodings(op, op.prefix) |
|
op.prefix = getPrefix(op.prefix) |
|
prehooks.trigger([op.prefix, op.key], [op, add, ops]) |
|
} |
|
|
|
opts = opts || {} |
|
|
|
if('object' !== typeof opts) throw new Error('opts must be object, was:'+ opts) |
|
|
|
if('function' === typeof opts) cb = opts, opts = {} |
|
|
|
if(ops.length) |
|
(db.db || db).batch( |
|
ops.map(function (op) { |
|
return { |
|
key: encodePrefix(op.prefix, op.key, opts, op), |
|
value: |
|
op.type !== 'del' |
|
? codec.encodeValue( |
|
op.value, |
|
opts, |
|
op |
|
) |
|
: undefined, |
|
type: |
|
op.type || (op.value === undefined ? 'del' : 'put') |
|
} |
|
}), |
|
opts, |
|
function (err) { |
|
if(err) return cb(err) |
|
ops.forEach(function (op) { |
|
posthooks.trigger([op.prefix, op.key], [op]) |
|
}) |
|
cb() |
|
} |
|
) |
|
else |
|
cb() |
|
}, |
|
get: function (key, prefix, opts, cb) { |
|
opts.asBuffer = codec.isValueAsBuffer(opts) |
|
return (db.db || db).get( |
|
encodePrefix(prefix, key, opts), |
|
opts, |
|
function (err, value) { |
|
if(err) cb(err) |
|
else cb(null, codec.decodeValue(value, opts)) |
|
} |
|
) |
|
}, |
|
pre: prehooks.add, |
|
post: posthooks.add, |
|
createDecoder: function (opts) { |
|
if(opts.keys !== false && opts.values !== false) |
|
return function (key, value) { |
|
return { |
|
key: codec.decodeKey(precodec.decode(key)[1], opts), |
|
value: codec.decodeValue(value, opts) |
|
} |
|
} |
|
if(opts.values !== false) |
|
return function (_, value) { |
|
return codec.decodeValue(value, opts) |
|
} |
|
if(opts.keys !== false) |
|
return function (key) { |
|
return codec.decodeKey(precodec.decode(key)[1], opts) |
|
} |
|
return function () {} |
|
}, |
|
isOpen: function isOpen() { |
|
if (db.db && isFunction(db.db.isOpen)) |
|
return db.db.isOpen() |
|
|
|
return db.isOpen() |
|
}, |
|
isClosed: function isClosed() { |
|
if (db.db && isFunction(db.db.isClosed)) |
|
return db.db.isClosed() |
|
|
|
return db.isClosed() |
|
}, |
|
close: function close (cb) { |
|
return db.close(cb) |
|
}, |
|
iterator: function (_opts, cb) { |
|
var opts = clone(_opts || {}) |
|
var prefix = _opts.prefix || [] |
|
|
|
function encodeKey(key) { |
|
return encodePrefix(prefix, key, opts, {}) |
|
} |
|
|
|
ltgt.toLtgt(_opts, opts, encodeKey, precodec.lowerBound, precodec.upperBound) |
|
|
|
// if these legacy values are in the options, remove them |
|
|
|
opts.prefix = null |
|
|
|
//************************************************ |
|
//hard coded defaults, for now... |
|
//TODO: pull defaults and encoding out of levelup. |
|
opts.keyAsBuffer = opts.valueAsBuffer = false |
|
//************************************************ |
|
|
|
|
|
//this is vital, otherwise limit: undefined will |
|
//create an empty stream. |
|
if ('number' !== typeof opts.limit) |
|
opts.limit = -1 |
|
|
|
opts.keyAsBuffer = precodec.buffer |
|
opts.valueAsBuffer = codec.isValueAsBuffer(opts) |
|
|
|
function wrapIterator (iterator) { |
|
return { |
|
next: function (cb) { |
|
return iterator.next(cb) |
|
}, |
|
end: function (cb) { |
|
iterator.end(cb) |
|
} |
|
} |
|
} |
|
|
|
if(ready) |
|
return wrapIterator((db.db || db).iterator(opts)) |
|
else |
|
waiting.push(function () { |
|
cb(null, wrapIterator((db.db || db).iterator(opts))) |
|
}) |
|
|
|
} |
|
} |
|
|
|
}
|
|
|