p-kvstore v1.0.2
p-kvstore
This is a basic promise based Key/Value store, that has the builtin ability to:
- detect write-conflicts / prevent data-clobbering
- provides basic needs to allow for value-based caching.
- can be directed to a local backend as well as to a remote one
- can be easily inherited to implement a new storage backend
- can be easily wrapped to add functionality
The main purpose for this is to serve as an abstract to base other implementations of.
However a basic in Map
-based implementation is there.
This package also provides a test-rig that can run compliance tests on any instance given it using tap.
Consumer API
const MapStore = require('p-kvstore').MapStore;
const store = new MapStore();
store.has(key).then((result)=>{ 'booolean' === typeof result });
store.get(key).then((result)=>{ result instanceof stream.Readable; });
store.set(key, <stream.Readable>).then((result)=> { ctag === result; });
store.force(key, <stream.Readable>).then((result)=>{ ctag === result; });
store.delete(key).then((result)=> { undefined === result; });
Methods
has(key)
=> Promise.resolve(<boolean>)
get(key)
=> Promise.resolve(<stream.Readable>)
get(key, <ctag|null>)
=> Promise.resolve({ ctag, content:<stream.Readable> })
set(key, value[, ctag])
=> Promise.resolve(ctag)
force(key, value)
=> Promise.resolve(ctag)
delete(key)
=> Promise.resolve(undefined)
Implementor API
const AbstractStore = require('p-kvstore').Abstract;
const MyImplementation = AbstractStore({
name: 'MyImplementation', // optional must be JavaScript identifier compatible
initialize: function() {...}, // optional called from constructor with the constructor args and this set
has: function(id) {...},
get: function(id, ctag) {...},
set: function(id, value, ctag) {...},
delete: function(id) {...}
});
is equivalent to:
const AbstractStore = require('p-kvstore').Abstract;
function MyImplementation () {...}
MyImplementation.prototye = Object.create(AbstractStore.prototype);
MyImplementation.prototye._has = function(id) {...};
MyImplementation.prototye._get = function(id, ctag) {...};
MyImplementation.prototye._set = function(id, value, ctag) {...};
MyImplementation.prototye._delete = function(id) {...};
Methods
The methods can rely on their arguments in the following regard.
- any
id
will be aString
suitable as a file/directory name - any
value
will be astream.Readable
- any
ctag
will be either aString
or undefined
A ctag
is defined as a string that uniquely identifies a value
where identical
value
s will also have identical ctag
s. (think of a sha256 hash for example)
The methods are required to return:
- An array or
Promise
that resolves to an array of no more than 2 elements. - All item of a result must be defined and valid
- The first member of the result (if present) is the valid ctag of the relevant content
- The second member of the result (if present) is a
stream.Readable
has(id)
=> [ ctag ]
If an element is present its ctag
is returned. Otherwise the return is an empty array.
get(id)
=> [ ctag, value ]
If an element is present its ctag
and a stream.Readable
of its content is returned.
Otherwise the result is a rejection with reason.code
set to Abstract.NOT_FOUND
set(id, value, ctag)
=> [ ctag ]
If ctag
is Abstract.CREATE
and the value exists the operation must result in
a rejection with reason.code
set to Abstract.CONFLICT
.
If ctag
is Abstract.FORCE
any value present must be overwritten.
Otherwise if ctag
does not match the current ctag
(if existing) the operation
must result in a rejection with reason.code
set to Abstract.CONFLICT
.
Only of these check pass must the value
be stored.
The result must be the ctag
of the new value
.
delete(id)
=> []
delete
should always succeed regardless of whether a value exists or not.