Crudlet is a universal, streamable interface for data stores that works on any platform. Basically you can use just about any database (or even your API) without it being coupled to your application.
Why?
- Decoupled. Crudlet allows you to decouple any store (even your own API) from your front-end / backend application.
- Interoperable. Use Crudlet with just about any library, or framework.
- Tiny. Crudlet is only 11kb minified.
- Isomorphic. Easily use your application code on multiple platforms (client & server-side). Just swap out the database adapter.
- Testable. Crudlet makes it super easy to stub-out any data store for testing purposes. Super useful especially for server-side apps (e.g: stubbing-out mongodb).
- Extensible. Easily add offline-mode & peer-to-peer (realtime) with just a few lines of code.
Installation
npm install crudlet
Adapters
- pubnub - pubnub sync adapter
- socket.io - socket.io sync adapter
- webrtc - webrtc sync adapter
- loki - loki in-memory database
- memory - another in-memory database
- local-storage - local storage database
- http - HTTP adapter
Examples
Example
Below is an example of a realtime DB that uses pubnub, and local storage.
var crud = ;var pubnub = ;var localStorage = ; // store data locally on the users machinevar localdb = ; // pubnub adapter for sending operations to other connected clientsvar pubdb = ; // the actual DB we're going to use. Pass// all operations to localstorage, and pubnubvar db = crud; // tail all operations send to pubnub back into the database. Note// that remote calls won't get re-published to pubnub; // create a child database - collection will get passed to each operationvar peopleDb = crud; // insert some people;
stream.Readable db(operationName, options)
Runs a new operation.
Note that the supported operations & required options may change depending on the data store you're using.
var localStorage = ; var localdb = ;;
stream.Stream crud.open(db)
Creates a new operation stream.
var operationStream = crud; // emitted when the operation is performedoperationStream; operationStream; operationStream;
operation db.operation(name, option)
creates a new operation which can be written to a database stream. See crud.open(db)
.
crud;
operation crud.op(name, options)
shorthand for crud.operation(name options)
.
db crud.top(db)
to operation
- Makes it so that you can simply call db(operationName, options)
instead of passing in the operation
each time.
var db = crudtop; // enables this; // also accepts this;
db crud.child(db, options)
Creates a new child database. options
is essentially just added to each operation performed.
var peopleDb = crudtopcrud; // insert a new person into the people collection;
db crud.tailable(db, reject)
Makes the db tailable. This simply allows you to listen for any operations invoked on a db such as create
, update
, remove
, and load
.
reject
is an array of operations to ignore. Default is [load]
.
var db = crud;; var peopleDb = crudtopcrud; ; // trigger tail; // trigger tail; // trigger tail; // ignored by tail
db crud.parallel(...dbs)
Combines databases and executes operations in parallel.
var db = crud; // execute "load" on localdb at the same time;
db crud.sequence(...dbs)
Combines databases and executes operations in sequence.
var db = crudtopcrud; // load data from localdb first, then move to httpdb;
db crud.first(...dbs)
Runs dbs in sequence, but stops when a result is emitted from a database.
var db = crudtopcrud; // load data from local storage if it exists, or continue// to http storage;
db crud.accept([...operationNames, ]db)
Accepts only the provided operations.
// main DB - api servervar httpdb = crud; // temporary cachevar localdb = ; // main DB - get cached data from local storage before// checking the servervar db = crud; // pipe all persistence operations back to local storage;
db crud.reject([...operationNames, ]db)
Runs all operations except the ones provided.
Building a custom database
Building a custom database is pretty easy. All you need to do
is return a stream when db(opName, options)
is called.
Here's some scaffolding for a custom db:
// slimmed down version of node streams.var stream = ; { // create database here // return fn that executes operations return { var writable = stream; // this is important so that data can be piped to other things process; return writablereader; };}
Keep in mind that there are a few conventions you should follow when writing custom database adapters. These conventions are here to ensure that databases are interoperable with each other.
db(insert, options)
Insert a new item in the database. Note that data
is emitted for each item inserted in the database.
options
- db optionsdata
- data to insert. Accepts 1 or many itemscollection
- collection to insert (optional for dbs that don't have it)
var _ = ;var peopleDb = crudtopcrud; // insert one item; // insert many items & collect the results in 1// array;
db(update, options)
Updates an item in the database. Doesn't return any values.
options
query
- search query for items to updatedata
- data to merge withcollection
- db collectionmulti
-true
to update multiple items.false
is default.
var peopleDb = crudtopcrud; ; // update multiple items;
db(upsert, options)
Updates an item if it exists. Inserts an item if it doesn't.
options
query
- search query for items to updatedata
- data to merge or insertcollection
- db collection
var peopleDb = crudtopcrud; // insert;
db(load, options)
Loads one or many items from the database.
options
query
- search query for itemscollection
- db collectionmulti
-true
if loading multiple.false
is default.
var peopleDb = crudtopcrud; // load one item; // load many items;
db(remove, options)
Removes an item from the database.
options
query
- query to searchcollection
- collection to searchmulti
-true
to remove multiple items
// remove one item; // remove all instances where age = 54;