4

The quick overview is this: for my web app I can write most of my functionality using CouchApp and CouchDB views, etc. I love the feature of CouchApp that pushes my code up to the server via replication- this makes the deployment cycle very easy.

However, to do some arbitrary work not supported in couchdb and works around a few limitations, I need to put a web platform in front of CouchDB. I'm considering building this in node.js because it uses JavaScript and I want to continue the easy deployment method of pushing code into the database.

Here's how i imagine it working: - I write a web server/service in node.js using the normal method and the node command to start it. - this sevice connects to couch db and gets a virtual list and a URL mapping list. This list is stored in redis for quick lookup. This list will tell the server, when it gets a request, based on host and path, etc, which handler is to be run. - the server fetches the handler- which is just a document, it could be a design document or an arbitrary json document in couchdb. And then executes that handler to handle the request, as if I'd writte the handler as part of node js.

So the question is, how to get a son data structure that contains a JavaScript function in it, in text form, and execute that function?

This may be blindingly obvious, but i come from a compiled background, so normally there would be a compilation step here that makes this pretty much impossible.

So, what I'm thinking is in pseudo code: Var string thecode = getValueForMapKey(handlerFunctionIWant); somehowmagicallyexecute(thecode)

Is there an exec or run function that will do the magical execution step above in JavaScript?

Jim
  • 57
  • 3
  • Interesting idea -- pulling code from couchdb on the fly -- did you ever go ahead with it? – Nick Perkins Jun 13 '11 at 04:39
  • I have seen people do this successfully. With this technique, you can deploy simultaneous CouchDB and Node.js upgrades. – JasonSmith Feb 01 '12 at 03:08
  • Normally if the javascript does not change, you put the code in _attachments/script and load it using ``. If it changes you can create an ordinary document (outside of the design doc), and fetch it also, with a script tag. To be dynamic, you can load several files and only execute the one you need. Only do ajax, eval, db.get etc if you have to. – ctrl-alt-delor Mar 17 '14 at 10:32

2 Answers2

11

It will run in the node.js context.

You can also use it in node, like this, as a dynamic function:

var cradle = require('cradle');
var db = new(cradle.Connection)().database('db_name');

db.get('_design/node%2Fyour_code', function (err, doc) {
  if (!err){
    var your_code = new Function(doc['arguments'].join(','), doc.code);
    your_code("cool", "also cool");
  }else{
    console.error('error:', err);
  }
});

make your docs look like this:

{
   "_id": "_design/node/your_code",
   "arguments": [
       "nameOfArg1",
       "nameOfArg2"
   ],
   "code": "console.log('arg1', nameOfArg1); console.log('arg2', nameOfArg2);"
}

It's in the same scope as where the new Function is called, so you have access to cradle, or you can require other libs, which will be loaded as if it was an anon function in that scope.

Put it in a design doc, then only admin can make changes, out of the box.

Here is a nicer, but similar approach:

// Format, in db:
doc = {
   "_id": "_design/node",
   "your_function_name": {
       "arguments": [
           "nameOfArg1",
           "nameOfArg2"
       ],
       "code": "console.log('arg1', nameOfArg1); console.log('arg2', nameOfArg2);"
   },
   "your_other_function_name": {
       "arguments": [
           "name"
       ],
       "code": "console.log('hello', name, 'how\\'s it going, bro?');"
   }
};


var cradle = require('cradle');
var db = new(cradle.Connection)().database('db_name');

function run_from_db(name, args){
  db.get('_design/node', function (err, doc) {
    if (!err){
      if (doc[name] !== undefined){
        var fn = new Function(doc[name]['arguments'].join(','), doc[name].code);
        fn.apply(fn, args);
      }else{
        console.error("could not find", name, "in _design/node");
      }
    }else{
      console.error(err);
    }
  });
}


run_from_db('your_other_function_name', ['konsumer']);

this will output:

hello konsumer how's it going, bro?
konsumer
  • 111
  • 1
  • 5
0

eval(handlerFunctionIwant) is the call to execute it. You need to make sure that there's no way for hackers to inject code into that string, of course.

It is not clear to me if this will evaluate it in a context that has access to other javescript resources, such as the rest of node.js or access to your couchdb library.