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
idwill be aStringsuitable as a file/directory name - any
valuewill be astream.Readable - any
ctagwill be either aStringor undefined
A ctag is defined as a string that uniquely identifies a value where identical
values will also have identical ctags. (think of a sha256 hash for example)
The methods are required to return:
- An array or
Promisethat 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.