I wrote a little application in node with couchdb behind the curtain. I enjoyed the exercise and used nano by Nuno Job. That’s like building a Web application with the ASP.NET pipeline and ADO.NET: a really good exercise to understand the technologies in detail but I wouldn’t want to do it again.

Now, I want to rebuild it bigger and better. And, I need a better way to persist my objects’ states.

The beginning of stork-odm

I started off with the flatiron “adaptable framework for building modern Web applications.” However, the two years since my series of articles on flatiron doesn’t really seem to have made better that specific tool bag.

I found that of the stuff in flatiron, I really had a lot of respect for resourceful, their “engine agnostic interface to JSON document stores.” Unfortunately, the architecture of my application relied on a multitenant database infrastructure, something couchdb does fantastically.

I went poking around the code and found a glaring singleton just sitting there mocking me. One database “connection” in resourceful. So, I went to log an issue to ask them about changing that and found their own issue Remove global state #149. At the time, the issue had an age seven months and commits appeared few and far between. I could fix it for them; however, I only wanted the couchdb target, didn’t want to have to read all of their code, and really didn’t think I’d have the wherewithal to accomplish that reëngineering feat.

So, as all good developers would do…

… I wrote my own object-document mapper. While Bryan didn’t have any direct commits into the code, he did influence it heavily in the design through our conversations. Thanks, Bryan Ray! (And, watch for his involvement in Blog-a-Day May!)

It still uses nano under the covers, but organizes things better. A document in couchdb merely represents the state of an object (or its references) at a moment in time.

Getting rid of the pain

Instead of writing a couchdb design document similar to the following and saving it in source as a separate file and curl-ing it into the database for a deploy…

1
2
3
4
5
6
7
8
9
{
"_id": "_design/org",
"language": "javascript",
"views": {
"byUri": {
"map": "function(doc) {\n var i;\n if(doc.kind === 'org') {\n emit(org._id);\n if (org.domains) {\n for (i = 0; i < org.domains.length; i += 1) {\n emit(org.domains[i]);\n }\n }\n }\n}\n"
}
}
}

… and having to get the results with something like…

1
2
3
4
5
var nano = require('nano')('http://localhost:5984/test_database');

nano.view('org', 'byUri', function (error, results) {
// Do something reall cool, here
});

… I can be object-y.

Using stork, instead

Now, in my project, I declare an entity like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var stork, Org;
stork = require('stork-odm');

Org = stork.deliver('org', function() {
this.string('name', { required: true });
this.number('yearFounded', { greater: 1900 });
this.timestamps();

this.view('byUri', function (org, emitKey) {
var i;
emitKey(org._id);
if (org.domains) {
for (i = 0; i < org.domains.length; i += 1) {
emitKey(org.domains[i]);
}
}
});
});

And, I deploy it like this:

1
2
3
Org.to(couchdbUrl).sync(function (err) {
// Do something error-related, here
});

And I use it like this:

1
2
3
Org.from(couchdbUrl).byUri(function (err, orgs) {
// Do something with orgs, here
});

Now, the problem: binary properties

In couchdb, we store binary stuff as attachments to documents, normally. When I declare a property in stork as binary, how do I attach it? How do I delete it? How do I provie a MIME type?

Right now, I have a crappy implementation. It goes something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var stork, Org, redcross, fs;
stork = require('stork-odm');
fs = require('fs');

Org = stork.deliver('org', function() {
this.string('name', { required: true });
this.binary('logo');
});

fs.readFile('redcross-logo.png', function (e, data) {
redcross = Org.new({
name: 'American Red Cross',
logo: data
});
});

But, that doesn’t specify the MIME type of the binary data. So, it will also accept this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var stork, Org, redcross, fs;
stork = require('stork-odm');
fs = require('fs');

Org = stork.deliver('org', function() {
this.string('name', { required: true });
this.binary('logo');
});

fs.readFile('redcross-logo.png', function (e, data) {
redcross = Org.new({
name: 'American Red Cross',
logo: {
content: data,
type: 'image/png'
}
});
});

which will associate the MIME.

But, I don’t like it. It looks and feels clunky.