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.
212 lines
5.2 KiB
212 lines
5.2 KiB
5 years ago
|
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)))
|
||
|
})
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|