nano-repository v1.0.0
nano-repository
Working with CouchDB is a pretty pleasant experience, mostly because of the rather excellent nano library.
There are a couple of rough edges though, so what else could be better but an abstracton on top of an abstraction!
Examples
Create me a repository:
var Nano = require('nano'),
Repository = require('nano-repository');
// set up Nano
var connection = new Nano('http://localhost:5984');
var db = connection.db.create('my_db');
// set up repo
var repository = new Repository(db);
CRUD operations
var document = {foo: 'bar'};
// create
repository.save(document, function(error, result) {
// document now has _id, _rev and created_at properties
});
// retrieve
repository.findById(id, function(error, document) {
// document has been fetched
});
// update
repository.save(document, function(error, result) {
// if previously saved, document now has updated_at properties
// and _rev has been incremented
});
// delete
repository.remove(document, function(error) {
// document has been deleted
});
Attachments
Add files to your documents:
repository.addAttachment(document, attachmentName, pathToFile, mimeType, function(error, body) {
// file has now been attached
});
Retrieve attachments:
repository.findAttachment(document, name, function(error, body) {
// body contains the attachment data
});
Attachment versions
The attachment version is dependent on the document version. E.g if you will pardon the pyramid of doom:
var attachmentName = 'myFile';
// add the first version of the attachment
repository.addAttachment(document, attachmentName, pathToFile, mimeType, function(error, body) {
// now document._rev = 2
// add the second it again:
repository.addAttachment(document, attachmentName, pathToFile, mimeType, function(error, body) {
// now document._rev = 3
// we now have two revisions of 'myFile' that we can access:
repository.findAttachment({_id: document._id, _rev: 2}, attachmentName, function(error, body) {
// body contains the first version of myFile
});
repository.findAttachment({_id: document._id, _rev: 3}, attachmentName, function(error, body) {
// body contains the second version
});
});
});
Streaming attachments
For the performance/memory conscious, stream files to your documents with the 4x argument version of Repository.addAttachment:
var fileStream = fs.createReadStream(pathToFile);
fileStream.pipe(repository.addAttachment(document, attachmentName, mimeType, function(error, body) {
// file has now been attached
}));
...and retrieve them:
repository.streamAttachmentTo(document, name, writeStream);
Views
Views are accessed by extra methods on the Repository. To create your views, first create a view template file, usally with the .json
extension.
The template file looks like this (n.b. feel free to include reduce
functions if you need them):
{
"views": {
"all": {
"map": "function(doc) {if(doc.name) emit(null, doc)}"
},
"byName": {
"map": "function(doc) {if(doc.name) emit(doc.name, doc)}"
}
}
}
Update/create the views:
var repository = new Repository(db);
repository.updateViews('path/to/views.json', function(error) {
// views are now ready to use
});
View methods are dynamically created:
repository.findAll(function(error, list) {
// list contains all documents from this collection
});
Method names are chosen by capitalising the first letter of the view name and prepending find
to it.
So the view mapping file contained a view named all
- this was turned into findAll
, similarly the view named byName
was turned into a method named findByName
.
Arguments are also supported:
repository.findByName('bob', function(error, list) {
// list contains all documents where doc.name == 'bob'
});
The code that makes up your view is hashed - the hash is stored along with the views. The next time you call Repository.updateViews the hashes are compared - it they've changed then the views are recreated automatically.
This means it's save to call Repository.updateViews every time you start your app - they'll only get altered if you change the code in your view file.
Get out of my console.log
You can pass an alternative logging implementation into the constructor and the repository will use that instead, as long as it supports .info
, .warn
, etc methods.
var Nano = require('nano'),
Logger = require('winston').Logger,
logger = new Logger(..);
//.. set up Nano as usual
var repository = new Repository(db, logger);
Todo
- Retrieving specific document versions.
- Work out if I've missed the point somehow. Probably.