couchilla is a bundler for packing design documents for CouchDB.
In CouchDB, design documents are special database entries that contain JavaScript functions, such as views and updates. These functions, executed on demand, generate secondary indexes, often termed MapReduce views.
Although CouchDB supports JavaScript and Erlang, design functions themselves are language-independent, which is why CouchDB doesn't include a dedicated tool for creating design documents.
JavaScript support in CouchDB relies on the Mozilla SpiderMonkey engine, which imposes specific module dependency rules and limitations on design function development.
couchilla addresses this by providing a convenient way to bundle design documents with CommonJS support. It aggregates view and filter functions from a JavaScript directory and produces a design document in JSON format.
Directory structure
Here's an example of a basic design document directory structure:
.
├── filters
│ └── quu.js
├── views
│ ├── foo.map.js
│ └── bar.reduce.js
└── validate_doc_update.js
- View functions reside in the
views
directory. Files with.map.js
(or simply.js
) are converted into map functions.- Reduce functions are defined in files with
.reduce.js
extensions.
- Reduce functions are defined in files with
- Filter functions belong in the
filters
directory.
Examples
Map functions
Emit key/value pairs to store them in a view.
views/foo.map.js
export default doc => emit(doc._id, 42)
Reduce functions
Take sum of mapped values:
views/foo.reduce.js
export default (keys, values, rereduce) => {
if (rereduce) {
return sum(values)
} else {
return values.length
}
}
Filter functions
Filter by field:
filters/foo.js
export default (doc, req) => {
if (doc && doc.title && doc.title.startsWith('C')) {
return true
}
return false
}
Validate document update functions
Log incoming requests and respond with forbidden:
export default (newDoc, oldDoc, userCtx, secObj) => {
log(newDoc)
log(oldDoc)
log(userCtx)
log(secObj)
throw { forbidden: 'not able now!' }
}
Builtin reduce functions
You can opt to use Erlang native functions using the builtin
annotation. For example the sum
function above can be rewritten using _sum
.
views/foo.reduce.js
/* builtin _sum */
During compilation this will be replaced with a call to the builtin _sum
function.
Requiring other modules
All code, including require()
statements, must be enclosed within the exported default function.
views/gamma.map.js
export default doc => {
const gamma = require('gamma')
emit(doc._id, gamma(doc.value))
}