Git Product home page Git Product logo

cradle's Introduction

Framework components for node.js and the browser

Example HTTP Server:

var flatiron = require('flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.http);

app.router.get('/', function () {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' });
  this.res.end('Hello world!\n');
});

app.start(8080);

Example HTTPS Server:

var flatiron = require('flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.http, {
  https: {
    cert: 'path/to/cert.pem',
    key: 'path/to/key.pem',
    ca: 'path/to/ca.pem'
  }
});

app.router.get('/', function () {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' });
  this.res.end('Hello world!\n');
});

app.start(8080);

Example CLI Application:

// example.js

var flatiron = require('flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli, {
  dir: __dirname,
  usage: [
    'This is a basic flatiron cli application example!',
    '',
    'hello - say hello to somebody.'
  ]
});

app.cmd('hello', function () {
  app.prompt.get('name', function (err, result) {
    app.log.info('hello '+result.name+'!');
  })
})

app.start();

Run It:

% node example.js hello
prompt: name: world
info:   hello world!

Installation

Installing NPM (Node Package Manager)

  curl http://npmjs.org/install.sh | sh

Installing Flatiron

  [sudo] npm install flatiron

Installing Union (Required for flatiron.plugins.http)

  npm install union

Usage:

Start With flatiron.app:

flatiron.app is a broadway injection container. To be brief, what it does is allow plugins to modify the app object directly:

var flatiron = require('flatiron'),
    app = flatiron.app;

var hello = {
  attach: function (options) {
    this.hello = options.message || 'Why hello!';
  }
};

app.use(hello, {
  message: "Hi! How are you?"
});

// Will print, "Hi! How are you?"
console.log(app.hello);

Virtually all additional functionality in flatiron comes from broadway plugins, such as flatiron.plugins.http and flatiron.plugins.cli.

app.config

flatiron.app comes with a config plugin pre-loaded, which adds configuration management courtesy nconf. app.config has the same api as the nconf object.

The literal store is configured by default. If you want to use different stores you can easily attach them to the app.config instance.

// add the `env` store to the config
app.config.use('env');

// add the `file` store the the config
app.config.use('file', { file: 'path/to/config.json' });

// or using an alternate syntax
app.config.env().file({ file: 'path/to/config.json' });

// and removing stores
app.config.remove('literal');

app.log

flatiron.app will also load a log plugin during the init phase, which attaches a winston container to app.log. This logger is configured by combining the app.options.log property with the configuration retrieved from app.config.get('log').

Create An HTTP Server with flatiron.plugins.http(options):

This plugin adds http serving functionality to your flatiron app by attaching the following properties and methods:

Define Routes with app.router:

This is a director router configured to route http requests after the middlewares in app.http.before are applied. Example routes include:

// GET /
app.router.get('/', function () {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' });
  this.res.end('Hello world!\n');
});

// POST to /
app.router.post('/', function () {
  this.res.writeHead(200, { 'Content-Type': 'text/plain' });
  this.res.write('Hey, you posted some cool data!\n');
  this.res.end(util.inspect(this.req.body, true, 2, true) + '\n');
});

// Parameterized routes
app.router.get('/sandwich/:type', function (type) {
  if (~['bacon', 'burger'].indexOf(type)) {
    this.res.writeHead(200, { 'Content-Type': 'text/plain' });
    this.res.end('Serving ' + type + ' sandwich!\n');
  }
  else {
    this.res.writeHead(404, { 'Content-Type': 'text/plain' });
    this.res.end('No such sandwich, sorry!\n');
  }
});

app.router can also route against regular expressions and more! To learn more about director's advanced functionality, visit director's project page.

Access The Server with app.server:

This is a union middleware kernel.

Modify the Server Options with app.http:

This object contains options that are passed to the union server, including app.http.before, app.http.after and app.http.headers.

These properties may be set by passing them through as options:

app.use(flatiron.plugins.http, {
  before: [],
  after: []
});

You can read more about these options on the union project page.

Start The Server with app.start(port, <host>, <callback(err)>)

This method will both call app.init (which will call any asynchronous initialization steps on loaded plugins) and start the http server with the given arguments. For example, the following will start your flatiron http server on port 8080:

app.start(8080);

Create a CLI Application with flatiron.plugins.cli(options)

This plugin turns your app into a cli application framework. For example, [jitsu] (https://github.com/nodejitsu/jitsu) uses flatiron and the cli plugin.

Valid options include:

{
  "argvOptions": {}, // A configuration hash passed to the cli argv parser.
  "usage": [ "foo", "bar" ], // A message to show for cli usage. Joins arrays with `\n`.
  "dir": require('path').join(__dirname, 'lib', 'commands'), // A directory with commands to lazy-load
  "notFoundUsage": false // Disable help messages when command not found
}

Add lazy-loaded CLI commands with options.dir and app.commands:

Flatiron CLI will automatically lazy-load modules defining commands in the directory specified by options.dir. For example:

// example2.js
var path = require('path'),
    flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli, {
  dir: path.join(__dirname, 'cmds')
});

app.start();
// cmd/highfive.js
var highfive = module.exports = function highfive (person, cb) {
  this.log.info('High five to ' + person + '!');
  cb(null);
};

In the command, you expose a function of arguments and a callback. this is set to app, and the routing is taken care of automatically.

Here it is in action:

% node example2.js highfive Flatiron 
info:   High five to Flatiron!

You can also define these commands by adding them directly to app.commands yourself:

// example2b.js
var flatiron = require('./lib/flatiron'),
    app = flatiron.app;

var path = require('path'),
    flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli);

app.commands.highfive = function (person, cb) {
  this.log.info('High five to ' + person + '!');
  cb(null);
};

app.start();
% node example2b.js highfive Flatiron 
info:   High five to Flatiron!

Callback will always be the last argument provided to a function assigned to command

app.commands.highfive = function (person, cb) {
  this.log.info('High five to ' + person + '!');
  console.log(arguments);
}
% node example2b.js highfive Flatiron lol haha
info:    High five to Flatiron!
{
  '0': 'Flatiron',
  '1': 'lol',
  '2': 'haha',
  '3': [Function]
}

Define Ad-Hoc Commands With app.cmd(path, handler):

This adds the cli routing path path to the app's CLI router, using the director route handler handler, aliasing app.router.on. cmd routes are defined the same way as http routes, except that it uses (a space) for a delimiter instead of /.

For example:

// example.js
var flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli, {
  usage: [
    'usage: node test.js hello <person>',
    '',
    '  This will print "hello <person>"'
  ]
});

app.cmd('hello :person', function (person) {
  app.log.info('hello ' + person + '!');
});

app.start()

When you run this program correctly, it will say hello:

% node example.js hello person
info:   hello person!

If not, you get a friendly usage message:

% node test.js hello
help:   usage: node test.js hello <person>
help:
help:     This will print "hello <person>"

Check CLI Arguments with app.argv:

Once your app is started, app.argv will contain the optimist-parsed argv options hash, ready to go!

Here's an example:

// example3.js
var flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli);

app.start();

app.log.info(JSON.stringify(app.argv));

This prints:

% node example3.js
info:    {"_":[], "$0": "node ./example3.js"}

Awesome!

Add a Default Help Command with options.usage:

When attaching the CLI plugin, just specify options.usage to get a friendly default message for when there aren't any matching routes:

// example4.js
var flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli, {
  usage: [
    'Welcome to my app!',
    'Your command didn\'t do anything.',
    'This is expected.'
  ]
});

app.start();
% node example4.js 
help:   Welcome to my app!
help:   Your command didn't do anything.
help:   This is expected.

Start The Application with app.start(callback):

As seen in these examples, starting your app is as easy as app.start! this method takes a callback, which is called when an app.command completes. Here's a complete example demonstrating this behavior and how it integrates with options.usage:

// example5.js
var path = require('path'),
    flatiron = require('./lib/flatiron'),
    app = flatiron.app;

app.use(flatiron.plugins.cli, {
  usage: [
    '`node example5.js error`: Throws an error.',
    '`node example5.js friendly`: Does not throw an error.'
  ]
});

app.commands.error = function (cb) {
  cb(new Error('I\'m an error!'));
};

app.commands.friendly = function (cb) {
  cb(null);
}

app.start(function (err) {
  if (err) {
    app.log.error(err.message || 'You didn\'t call any commands!');
    app.log.warn('NOT OK.');
    return process.exit(1);
  }
  app.log.info('OK.');
});

Here's how our app behaves:

% node example5.js friendly
info:   OK.

% node example5.js error
error:  I'm an error!
warn:   NOT OK.

% node example5.js
help:   `node example2b.js error`: Throws an error.
help:   `node example2b.js friendly`: Does not throw an error.
error:  You didn't call any commands!
warn:   NOT OK.

Read More About Flatiron!

Articles

Sub-Projects

Tests

Tests are written in vows:

  $ npm test

License: MIT

cradle's People

Contributors

bkw avatar bmeck avatar cakebaker avatar cecchi avatar cgaspard avatar cloudhead avatar davedoesdev avatar dominictarr avatar dtrejo avatar enome avatar estliberitas avatar indexzero avatar janl avatar jchris avatar jcrugzz avatar jfhbrook avatar jongretar avatar kanongil avatar klaemo avatar kxepal avatar litchie avatar mjackson avatar mmalecki avatar nisaacson avatar nullivex avatar optiminimalist avatar panuhorsmalahti avatar rgabo avatar sreuter avatar tanepiper avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cradle's Issues

Cannot db.put('_revs_limit', 1);

There are situations where Couch requires a raw string to be GET/PUT instead of an object, like with _revs_limit. Please add support for that.
...it actually works but breaks afterwards.

Feature request: specify multiple Couches for a connection

We had an outage today at Nodejitsu. The physical hardware for our Couch server at Rackspace went down. We didn't have replication setup, but now we do.

In these doomsday scenarios it would have been nice to be able to specify both the primary and backup CouchDb servers in the cradle.Connection instance and have it automatically begin to failover. I don't see any other way to solve these kinds of problems.

Connecting to a secure host? (cloudant)

Hey,

I'm having some probs with an authenticated couchdb host.

Tried with this piece of code:

var c = new(cradle.Connection)('https://macskolan.cloudant.com/', 5984, {
    cache: true,
    raw: false,
    auth: {
        user: "usern",
        pass: "passwxx"
    }
});
var db = c.database('test');

db.get('testdoc', function (err, doc) {
    console.log(doc);
});

And node throws this:
Error: ENOTFOUND, Domain name not found
at IOWatcher.callback (dns:52:15)
at node.js:773:9

I also tried with the host structure like so: https://user:[email protected]/
Which gave me the same error.

Cheers
Philip

AllOrNothing bulk updates should be controllable on a per save basis.

       _save: function (id, rev, doc, callback) {
            var options = connection.options;
            var document = {}, that = this;

            // Bulk Insert
            if (Array.isArray(doc)) {
                document.docs = doc;
                if (options.allOrNothing) { document.all_or_nothing = true }
                this.query('POST', '/_bulk_docs', {}, document, callback);

This bit of code really should allow me to override the connection default. I don't think its a connection-wide decision that I'll want to use AllOrNothing, it feels more like a case by case configuration. Whats your take on the matter?

DNS errors when using cradle with both hostname and IP address

Having a problem when using cradle with any hostname or IP address. Oddly enough, the errors are always DNS related, which doesn't make a whole lot of sense.

When using a hostname (including localhost), the following error occurs:

events:12
        throw arguments[1];
                       ^
Error: ECONNREFUSED, Could not contact DNS servers
    at IOWatcher.callback (dns:52:15)
    at node.js:773:9

When using an IP address (including 127.0.0.1), the following error occurs:

events:12
        throw arguments[1];
                       ^
Error: ENOTFOUND, Domain name not found
    at IOWatcher.callback (dns:52:15)
    at node.js:773:9

At first I thought that the errors might be with the CouchDB installations so I tried two different ones (local and remote) and cradle fails with both of them. Cradle has been run from both a Mac and Linux box and same failures occur. Additionally, I have tested with save operations, as well as info() requests on both the db and server objects. This has been confirmed with dbs both requiring and not requiring authentication. Node is able to make HTTP requests using the regular HTTP libraries without an error.

The following code demonstrates usage (just replace localhost with any ip or remote hostname):

var cradle = require('cradle');

var couch = new(cradle.Connection)('http://localhost', 5984, {
    cache: true,
    raw: false,

});

var db = couch.database('scratch');

setInterval( function () {
    console.log(db.info());
    console.log(couch.info());
}, 1500);

Since these errors don't make a whole lot of sense, it's tough for me to figure out what the issue is. If there is any additional information with which I might provide you, please let me know. Thanks!

Implement CouchDB replication

We should implement replication features so users can programatically replicate data. It seems there is a very simple couchdb API for this and it should be relatively easy to implement.

replication method on both the connection, and the database
the database method being a wrapper around the connection one

 client.database('foo').replicate('http://bar')

 client.replicate('foo', 'bar')

support for cloudant

Using cloudant couchdb for storage. Unable to make requests as the host name is not accepted. https requests?

Improve Performance

Lately I started profiling our node.js application that heavily uses cradle. Unfortunately, it turned out that cradle is one of our main bottlenecks in a heavy load simulation. In our scenario, it is based on that fact that cradle uses only one HTTP client interally and also that view results are not cached.

I checked for various possible improvements and want to start a little discussion here, what can be added in order to provide better general performance.

My first approach was to create multiple cradle conenctions, which is a good starting point as this also introduces multiple HTTP clients for executing requests. This is okay as long as the major advantage of cradle, caching, is disabled. As soon as you use multipe distinct cradle connections, each one has it's own cache, which is really bad. So this is no valid approach.

The next step would be something like a thread pool inside of cradle. Ideally, with configurable max size and intelligent strategies like removing connections if the requests decline.

Also HTTP pipeling would heavily increase performance, sadly that's not yet available for the node.js HTTP client. But this should be on the radar for cradle.

Furthermore, also caching could be improved. I'd suggest a progressive cache with leases. This would mean that the items would be saved to the cache with timeouts. Within the first cycle, the cache entry is always valid (except it has been altered using that cradle instance). After the timeout, at least a conditional GET should be executed against the CouchDB server in order to check that this entry is still unchanged. After another timeout, the entry should be purged out of the cache. As this is a feature that is only necessary if there are multiple clients to the CouchDB and also increases complexity, this might also be an optional feature. Additionally, I'd like to have new methods, where I can circumvent the cache when I want to retrieve an item or automatically get the latest revision if make partial changes to it.

Of course some of these changes are rather difficult, especially if they are combined. For instance, a more sophisticated cache with multiple HTTP request workers must reflect MVCC and also store _revs of items in order to ensure that only the latest entry is stored and not replaced by an older one. But I think these ideas might help cradle to become a more mature library, especially for heavy use scenarios.

What do you think about these ideas?

No remote->local replication?

Hi, it would seem that cradle doesn't support replication from a remote database to local one,

that.replicate(cradle.merge({ source: name, target: target }, options), callback);

It's an easy enough fix ( source: target, target : name), just thought you should be aware

Thanks
James

parse failed in change api

when change api is called, value returned from couchdb is parsed to json.

(in cradle.js line:452)

res.on('data', function (data) { data.trim() && response.emit('data', JSON.parse(data)) })

but, when data is too long, couchdb return separated value.
each is an invalid json value.

value 1
{hoge: "abc",

value 2
foo: "def"}\n

as a result, parsing is faild.

when couchdb finishes returning one json value, value last returned includes line feed character.
therefore, good look to parse value only when data include line feed...

adhoc fix example
var valid_data = "";
res.on('data', function (data) {
if (! data.trim()) {
return;
}
valid_data += data;
if (valid_data.indexOf("\n") != -1) {
valid_data.trim() && response.emit('data', JSON.parse(valid_data));
valid_data = "";
}
})

How to properly use "Other Methods"

I'm trying to use the "other methods", like info(), config(), databases(), etc., at the server level. They all return void. I've tried passing them a callback function but was not sure about the signature the callback function should have. At any rate, I gave the callback function one argument, which always evaluated to NULL upon execution. Am I doing something wrong? How are these methods supposed to be used correctly?

Admin tool for the DB?

Hi guys

Is there a way to inspect the databases cradle is creating through an admin tool? Something like futon? I googled around but couldn't find anything that's working.

Thanks for any hints,
Michael

Don't stringify when options are []

Hello,

when setting certain types of options (eg endkey : ["something", {}] ) you don't want to stringify this ("["something", {}]" won't get the required result).

Adding a check to line 458 fixes this
if (k in options && options[k].charAt(0)!='[')

Thanks
James

TypeError: Object.keys called on non-object

I've been getting this error for a while... not sure what's causing it.

TypeError: Object.keys called on non-object
at Function.keys (native)
at /home/jca/local/node/lib/node/.npm/cradle/0.5.3/package/lib/cradle.js:615:16
at Array.forEach (native)
at Object.merge (/home/jca/local/node/lib/node/.npm/cradle/0.5.3/package/lib/cradle.js:614:10)
at Object.callback (/home/jca/local/node/lib/node/.npm/cradle/0.5.3/package/lib/cradle.js:354:30)
at /home/jca/local/node/lib/node/.npm/cradle/0.5.3/package/lib/cradle.js:276:26
at IncomingMessage. (/home/jca/local/node/lib/node/.npm/cradle/0.5.3/package/lib/cradle.js:214:72)
at IncomingMessage.emit (events.js:59:20)
at HTTPParser.onMessageComplete (http.js:111:23)
at Socket.ondata (http.js:1183:22)

Darth Vader

It's always bugged me that the README examples spell it "vador" instead of "vader." Is that on purpose?

Inconsistency in saving/updating design views

Consider the following gist: https://gist.github.com/a81a93c5b050bfe249b0

This is a small script I wrote to help manage designs for my couchdb instance. As you can see, in lines 35-37, depending on if it's an insert or a save I need to wrap my views variable in an object for a save, or just as it is for an insert.

Inserting a design view also assumes the user only wants to create views - it doesn't consider show/lists or other parts that can be in a design document.

I think it would be better to make it more like save, where you need to wrap the object completely and pass it to insert, making no assumptions that it is views only.

Express + changes stream

I have a strange issue in an Express app: From the point when I create a changes stream via database().changes().on('response' ..., no further database().get request will be served. Am I alone with this issue?

Emit ETag header to result

It would be useful to get the ETag header in all reading requests. Thus, caching information can be used on application level.

Perhaps you could add a third optional parameter to the result callback: function(err, doc, metadata).
This could encapsulate additional meta data like the request ETag header value.

One vow broken... occasionally?

Most of the time all the tests pass, but occasionally (and worryingly) I am seeing ...

Connection getting the list of databases
✗ should contain the 'rabbits' and 'pigs' databases
» expected [
'pigs',
'test_suite_db/with_slashes',
'test_suite_db',
'test_suite_users',
'test_suite_db_a',
'test_suite_db_b'
] to include 'rabbits' // cradle-test.js:278

exists() needs a callback

... but in the documentation this isn't mentioned. That's why node.js crashed with CALL_NON_FUNCTION.

So, mention that a callback is required in the doc, thanks.

cached on rev error

Sorry for not adding code, but the problem is so simple I don't think it's necessary .

I used db.save to save my document and tested for err.error='conflict', which happens when the document has a different revision.
After that I used a db.get to get the new document, but what I received was not the document from couch, but the one I tried to save (but failed) !!!
This error might have been caused by me because I tested with a rev number that never existed.

After switching cache off I get the doc. from couch, and everything works like a charm.

db.insert() can't serialize umlauts

db.insert() seems to have problems with strings that contain Umlauts (ä,ö, ü) and perhaps other special chars. How can I overcome this?

// Store the document
db.insert({
  "name": "Österreich"
}, function (err, res) {
    err // => { error: 'bad_request', reason: 'invalid UTF-8 JSON' }
});

Thanks, Michael

Cradle does not recover from a CouchDb instance restart

Hello,

I've noticed that Cradle does not recover if you restart the CouchDb instance it's pointing at (after an initial connection is made). Is this a configuration option I'm missing or a bug?
At the moment I have to restart the application every time CouchDb is restarted or the connection drops out for whatever reason.

Thanks!

Load - modify - save broken

I observe unexpected behavior when loading a document, modifying it then saving it.

I can track the problem down to basePrototype.toJSON().

  1. Load a document with get().
  2. Modify it: change values of existing keys, add values at new keys.
  3. Save it with save()
  4. In some situations only changes to existing keys will be saved, in some cases no changes at all will be saved.

save() returns a Response object which has a method toJSON() that returns values previously retrieved from the database rather than the modified ones. When saving, toJSON() is invoked when cradle.Connection.prototype.request() calls JSON.stringify() [1] on the data to be saved (= the Response object). This effectively blows away any new keys or changes to scalars in this portion of cradle.Connection.prototype.request():

    data = JSON.stringify(data, function (k, val) {
        if (typeof(val) === 'function') {
            return val.toString();
        } else { return val }
    });

What is the proper course of action here?

[1] See toJSON() https://developer.mozilla.org/en/json

View query with 'keys' doesn't work on reduced view

Querying a view with keys still requires all other options to be encoded in URL. Only keys are expected by Couch in POSTed data. The following change seems to resolve the issue:

        if (options && options.keys) {
            var keys = options.keys;
            delete options.keys;
            this.query('POST', path, options, {keys: keys}, args.callback);
        } else {
            this.query('GET', path, options, args.callback);
        }

How to deal with errors from cradle?

I'm not so sure how to deal with errors from cradle. Have a look at this example:

  db.view('hero/all', function(error, result) {
    if (error)
      throw new Error(JSON.stringify(error));

    response.send(result);
  });

Here I throw the error from cradle within a new Error object. But the stack trace is wrong that way. I can't get more error information.

How should I do this so that I can see the correct stack trace in the console?

client-side support?

I use jquery.couch.js for accessing couch from a client browser. I also wrote a thin jquery that implemented just enough for jquery.couch.js to work in node. Now I can write code that works identically in either the server or the client. This has been in production for months.

However, jquery.couch.js is not wonderful. I would really like to use cradle, but I'm trying to use all tools that are transparent to whether they are in the client or server. How hard would it be to do a client version of cradle?

I would take anything but ideally it would work with jquery and ajax. Websockets is a little immature right now.

I haven't looked at cradle's code yet. Does all traffic flow through a single http-client routine? If so I would think hooking it up to jquery would be pretty easy. As I mentioned above I did the opposite and it only took me a day or so.

URL escape codes not supported

The current Regex for determining a view is too restrictive. I have views in my db to search for files with a certain mimetype. For example, I have a view that looks like this: "audio/ogg". In order to query this, I use the escape sequence %2F for /. For a list of all URL escape sequences, see this link: http://www.december.com/html/spec/esccodes.html

The Regex currently used is: /^_design/\w+$/ (line 307 of cradle.js)
This unneccessarily leaves out the % sign. What could be done instead is something like this: /^_design/(\w|%)+$/

Incompatible with ExpressJS ?

Are there any known issues with cradle and expressjs?

when I use the view method in a route i get an error. i think it has something todo with the emit call in the couchdb view query.

what i did:

creating a view:
database.insert("_design/users", {
all: {
map: function(doc) {
if(doc.type && (doc.type == 'user'))
emit(doc.name, doc)
}
}
})

==> get all rows with type=='user' and store it under the name

view-call:

outside of a route:
database.view("users/all", function(err, res) {
log(res)
})

===> works

inside of a route:

get("/", function() {
  database.view("users/all", function(err, res) {
    log(res)
  })
})

===>

TypeError: Cannot call method 'replace' of undefined
    at Object.normalizePath (/Users/xxx/.kiwi/current/seeds/express/0.9.0/lib/express/request.js:28:15)
    at new <anonymous> (/Users/xxx/.kiwi/current/seeds/express/0.9.0/lib/express/request.js:54:33)
    at Server.<anonymous> (/Users/xxx/.kiwi/current/seeds/express/0.9.0/lib/express/core.js:221:19)
    at Server.emit (events:32:26)
    at HTTPParser.onIncoming (http:597:10)
    at HTTPParser.onHeadersComplete (http:84:14)
    at Client.ondata (http:636:30)
    at IOWatcher.callback (net:369:33)
    at node.js:176:9

Callback blues

Me again ...

I'm not so sure about the callbacks.The first time I'm using the app I want the programm to initialise the CouchDB itself. So I call create(), then save() etc. Since node.js is async I assume I have to implement nested callbacks for that.

Here my code:

exports.initDB = function(callback) {
var cradle = require('cradle');
var db = new cradle.Connection().database('hero');

db.exists(function(error, exists) {
if (error)
throw new Error(JSON.stringify(error));

if (!exists) {
  db.create(function() {
    db.save('_design/hero', {
      all: {
        map: function(hero) {
          emit(null, {type: hero.type, offset: hero.offset});
        }
      }
    }, callback(db));
  });
} else
  callback(db);

});
};

Then in the application I call that like:

bootstrapper.initDB(function(db) {
  db.view('hero/all', function(error, result) {
    if (error)
      throw new Error(JSON.stringify(error));

    response.send(result);
  });
});

But the console is throwing this error:

/cygdrive/d/code/binarykitchen.no.de/node_modules/cradle/lib/cradle.js:3
if (/^_design/(\w|%)+$/.test(id) && !('views' in do
^

TypeError: Cannot use 'in' operator to search for 'views' in undefined
at String.IN (native)
at Object._save (/cygdrive/d/code/binarykitchen.no.de/node_modules/c
at Object.save (/cygdrive/d/code/binarykitchen.no.de/node_modules/cr
at /cygdrive/d/code/binarykitchen.no.de/app/bootstrapper.js:11:12

I assume I am implementing the callbacks the wrong way or cradle has a bug?

No way to create a _design document with a validation function?

This code in "save" method

                if (/^_design\/\w+$/.test(id) && !('views' in doc)) {
                    document.language = "javascript";
                    document.views = doc;
                }

Seems to make it impossible to save a design document with a view & a validate_doc_update function. Perhaps a breaking change to set views with an option?

Otherwise, cradle has been awesome to use. Thanks so much.

jr

Pagination on all() or list()

Hey All,

Thanks for the great work on the project! Keep it up!

I was wondering what the preferred method to implement paging is.

It seems like Couchdb (the HTTP/API supports paging via the "startkey" and "count" parameters. I wonder if these could be added as optional arguments on either all() or list().

Cheers,

-Rob

nginx+ssl proxy pass and content length

When using nginx as the front end for couchdb to provide SSL access to the database there is an issue when creating a database where nginx sends a 411 Content Length Required response, as there is no JSON data to send in the body of the request the current cradle code does not add a content length header. The fix I have implemented for this is simple:

if (data) {
    data = JSON.stringify(data, function (k, val) {
        if (typeof(val) === 'function') {
            return val.toString();
        } else { return val }
    });
    headers["Content-Length"] = Buffer.byteLength(data);
    headers["Content-Type"]   = "application/json";
}else
{
    headers["Content-Length"] = 0;
}

Simply applying a zero content length header in this situation appears to fix the problem. I would have attached a patch file but unfortunately github issues doesn't accept attachments.

For the moment I'm going to fork the code, use as a git sub-module in my project and send a pull request.

No way to handle connection error

Cannot handle connection error gracefully in case e.g. couch instance is not available.
This is due to no callback given to http.request. The callback is not optional here!
This seems to be accepted by node for backward compatibility, however when no callback is provided the exception is thrown asynchronously, so there is no way to catch or handle error.

Compact bug

if i try to run a db.compact I get:

{ error: 'bad_content_type',
reason: 'Content-Type must be application/json' }
undefined

I believe the bug is here:

if (data) {
    data = JSON.stringify(data, function (k, val) {
        if (typeof(val) === 'function') {
            return val.toString();
        } else { return val }
    });
    headers["Content-Length"] = Buffer.byteLength(data);
    headers["Content-Type"] = "application/json";
}

There is no data on a compact request so the Content-Type doesn't get set.

no way to stop listening to changes

if you're streaming changes, node will not exit normally if the connection is still open, as the event loop is still going around.

the user needs access to the pause method on the HttpResponse object. if pause is called node is allowed to exit normally.

cheers. great project!

Nested callbacks getting called twice

Okay I have a weird problem where I'm getting callbacks called twice with different objects.
Not sure what's up here.

var sys = require('sys')
require.paths.unshift("./lib/");
var cradle = require('cradle');
var c = new (cradle.Connection);
var db = c.database('fail');

function get(cb)
{
db.get('skywalker',function(err1,res1)
{
sys.puts("CALLED BACK")
if(err1)
{
sys.puts("Error: " + sys.inspect(err1))
//db.destroy();
} else {
sys.puts("Success: " + sys.inspect(res1));
if(cb)cb();
}
})
}

get(function(){
get();
});

OUTPUT:
Chase-Sechrists-MacBook-Pro:linkapp mcs$ node cradleplay.js

CALLED BACK
Success: { doc: [Getter]
, _id: 'skywalker'
, id: [Getter]
, _rev: '1-e8774424284eef1526f5cd4dfb022bf0'
, rev: [Getter]
, force: 'light'
, name: 'Luke Skywalker'
}

CALLED BACK
Success: { _id: 'skywalker'
, _rev: '1-e8774424284eef1526f5cd4dfb022bf0'
, force: 'light'
, name: 'Luke Skywalker'
}

CALLED BACK
Success: { doc: [Getter]
, _id: 'skywalker'
, id: [Getter]
, _rev: '1-e8774424284eef1526f5cd4dfb022bf0'
, rev: [Getter]
, force: 'light'
, name: 'Luke Skywalker'
}

That partial reply shouldn't be there as far as I know. Is this a feature or something?

Problems querying view (numeric key values are URL encoded)

I have a CouchDB view that I am querying from Cradle. The beginning of the view function looks like this:

db.view('app/accountLicenceList', { "key": req.params.licenceNumber }, function (err, dbresult) {
...
});

When this query is run through node.js, the CouchDB log reads

[Thu, 16 Dec 2010 03:40:23 GMT] [info] [<0.17998.4>] 127.0.0.1 - - 'GET' /informonline /_design/app/_view/accountLicenceList?key=%2212345%22 200

and CouchDB returns no results.

However, if I query the view directly from curl the CouchDB log reads

[Thu, 16 Dec 2010 03:42:06 GMT] [info] [<0.18100.4>] 127.0.1.1 - - 'GET' /informonline/_design/app/_view/accountLicenceList?key=12345 200

and I receive the expected results:

curl http://arthur:5984/informonline/_design/app/_view/accountLicenceList?key=12345; echo
{"total_rows":1,"offset":0,"rows":[
{"id":"exampleaccount","key":12345,"value":"12345abcde"}
]}

The problem with the Cradle query appears to be the extra URL-encoded quotes (%22). Why are these added? They don't appear to work with Couch. I am using CouchDB 1.0.1.

Thanks!

Matt

Should it be called "update"?

I wonder if it would not be confusing in the long run to have the "update" function be a helper on saving existing documents as update is actually a separate request that can be on a couchdb document. (as in /mydb/_design/mydesigndoc/_update/bump-counter/mydocid).

It would probably be better to have it named "merge-save" or something leaving the "update" function free to be assigned to update requests.

I'm happy to make the changes if you are in agreement.

Example code doesn't work, unable to use cradle

I've been struggling to get cradle to work, and perhaps it's general incompetence on my behalf when it comes to CouchDB resulting in me missing something.

I'm using node v0.2.5, cradle 0.2.3 and installed via npm.

Running the example:

var assert = require('assert');
var cradle = require('cradle');

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

db.get('vador', function (err, doc) {
    doc.name; // 'Darth Vador'
    assert.equal(doc.force, 'dark');
});

db.save('skywalker', {
    force: 'light',
    name: 'Luke Skywalker'
}, function (err, res) {
    if (err) {
        // Handle error
    } else {
        // Handle success
    }
});

Results in:

node.js:63
    throw e;
    ^
TypeError: undefined is not a function
    at CALL_NON_FUNCTION_AS_CONSTRUCTOR (native)
    at Object.<anonymous> (/home/celc/Dropbox/freelance/mysterious collective/cradle-test.js:4:10)
    at Module._compile (node.js:462:23)
    at Module._loadScriptSync (node.js:469:10)
    at Module.loadSync (node.js:338:12)
    at Object.runMain (node.js:522:24)
    at Array.<anonymous> (node.js:756:12)
    at EventEmitter._tickCallback (node.js:55:22)
    at node.js:773:9

Changing line 4 to:
var db = new cradle.Connection().database('starwars');

Results in:
node.js:63
throw e;
^
Error: Couldn't save without a _rev
at Object.save (/usr/local/lib/node/.npm/cradle/0.2.3/package/lib/cradle.js:262:27)
at Object. (/home/celc/Dropbox/freelance/mysterious collective/cradle-test.js:11:4)
at Module._compile (node.js:462:23)
at Module._loadScriptSync (node.js:469:10)
at Module.loadSync (node.js:338:12)
at Object.runMain (node.js:522:24)
at Array. (node.js:756:12)
at EventEmitter._tickCallback (node.js:55:22)
at node.js:773:9

Let me know if there's anything else I can do to help narrow the issue down.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.