1.0.2 • Published 8 years ago

p-kvstore v1.0.2

Weekly downloads
5
License
MIT
Repository
github
Last release
8 years ago

p-kvstore

This is a basic promise based Key/Value store, that has the builtin ability to:

  1. detect write-conflicts / prevent data-clobbering
  2. provides basic needs to allow for value-based caching.
  3. can be directed to a local backend as well as to a remote one
  4. can be easily inherited to implement a new storage backend
  5. 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.

  1. any id will be a String suitable as a file/directory name
  2. any value will be a stream.Readable
  3. any ctag will be either a String or 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:

  1. An array or Promise that resolves to an array of no more than 2 elements.
  2. All item of a result must be defined and valid
  3. The first member of the result (if present) is the valid ctag of the relevant content
  4. 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.