nosql-memdb
Version:
Nosql database that works in memory only inherits from abstract-nosql
160 lines (140 loc) • 4.44 kB
text/coffeescript
createRBT = require('functional-red-black-tree')
inherits = require('inherits-ex')
AbstractNoSQL = require('abstract-nosql')
AbstractIterator = require('abstract-iterator')
Errors = require('abstract-error')
NotFoundError = Errors.NotFoundError
ltgt = require('ltgt')
setImmediate = global.setImmediate or process.nextTick
globalStore = {}
toKey = (key) ->
if typeof key == 'string' then '$' + key else JSON.stringify(key)
gt = (value) -> value > @_endValue
gte = (value) -> value >= @_endValue
lt = (value) -> value < @_endValue
lte = (value) -> value <= @_endValue
class MemIterator
inherits MemIterator, AbstractIterator
constructor: (db, options) ->
super db, options
options = @options
@_limit = options.limit
if @_limit == -1
@_limit = Infinity
tree = db._store[db._location]
@keyAsBuffer = options.keyAsBuffer == true
@valueAsBuffer = options.valueAsBuffer == true
@_reverse = options.reverse
#this._options = options
@_done = 0
if !@_reverse
@_incr = 'next'
@_start = ltgt.lowerBound(options)
@_endValue = ltgt.upperBound(options)
if @_start == null
@_tree = tree.begin
# if options.gt == null
# @_tree.next()
else if ltgt.lowerBoundInclusive(options)
@_tree = tree.ge(@_start)
else
@_tree = tree.gt(@_start)
if @_endValue
if ltgt.upperBoundInclusive(options)
@_test = lte
else
@_test = lt
else
@_incr = 'prev'
@_start = ltgt.upperBound(options)
@_endValue = ltgt.lowerBound(options)
if @_start == null
@_tree = tree.end
# if options.lt == null
# @_tree.prev()
else if ltgt.upperBoundInclusive(options)
@_tree = tree.le(@_start)
else
@_tree = tree.lt(@_start)
if @_endValue
if ltgt.lowerBoundInclusive(options)
@_test = gte
else
@_test = gt
return
_nextSync: () ->
return false if @_done++ >= @_limit
return false if !@_tree.valid
key = @_tree.key
value = @_tree.value
return false unless @_test(key)
key = new Buffer(key) if @keyAsBuffer
value = new Buffer(value) if @valueAsBuffer
@_tree[@_incr]()
return [
key
value
]
_test: -> true
module.exports = class MemDB
inherits MemDB, AbstractNoSQL
constructor: (location) ->
return new MemDB(location) unless this instanceof MemDB
super if typeof location == 'string' then location else ''
@_location = if @location then toKey(@location) else '_tree'
@_store = if @location then globalStore else this
@_store[@_location] = @_store[@_location] or createRBT()
return
finalize: ->
if @_store != this
delete globalStore[@_location]
return
_openSync: -> true
_putSync: (key, value, options) ->
@_store[@_location] = @_store[@_location].remove(key).insert(key, value)
true
_isExistsSync: (key, options) ->
result = @_store[@_location].get(key)
if result == undefined
result = false
else
result = true
result
_getSync: (key, options) ->
value = @_store[@_location].get(key)
# 'NotFound' error, consistent with LevelDOWN API
throw new NotFoundError if value == undefined
if options.asBuffer == true and !@_isBuffer(value)
value = new Buffer(String(value))
value
_delSync: (key, options) ->
@_store[@_location] = @_store[@_location].remove(key)
true
_batchSync: (array, options) ->
i = -1
len = array.length
tree = @_store[@_location]
while ++i < len
if !array[i]
continue
key = if @_isBuffer(array[i].key) then array[i].key else String(array[i].key)
err = @_checkKey(key, 'key')
if err
throw err
tree = tree.remove(array[i].key)
# we always remove as insert doesn't replace
if array[i].type == 'put'
value = if @_isBuffer(array[i].value) then array[i].value else String(array[i].value)
err = @_checkKey(value, 'value')
if err
throw err
tree = tree.insert(key, value)
@_store[@_location] = tree
true
IteratorClass: MemIterator
_isBuffer: (obj) -> Buffer.isBuffer obj
@destroy: (name, callback) ->
key = toKey(name)
delete globalStore[key] if key of globalStore
setImmediate callback
return