Skip to content

Node.js Driver Improvements

al3xandru edited this page Jan 21, 2013 · 6 revisions

Node.js Driver Improvements

Update: After re-reading the Follow node.js conventions for callbacks · Issue #221 thread, I've learned that there are different approaches suggested by Node.js people. There is a part that argues against my proposal below. Basically the suggestion is to use run(callback) and run().collect(callback) for 2 different scenarios: 1) returning a single result/error; 2) returning multiple results.

This indeed could make the API cleaner, but could run into the issue of having all the returned data in memory when using collect.


Connection handling

After looking around at what other drivers and doing and also trying to build an example application myself, I cannot stress enough how right the people in the thread Follow node.js conventions for callbacks · Issue #221 are.

Basically, the way it should work:

r.connect(function(err, connection) {})

Plus:

  • r.connect should not return a connection object. It is not initialized and it leads to a lot of confusion.

Note: Issue Error handling for Node.js · Issue #140 seems to converge to the same conclusions as Issue #221.

Connection object

Connection identifier

Feature: for tracking/debugging purposes being able to identify a specific connection is critical. Even if the connection['id'] would use a random integer it would be good enough.

Connection status

Feature: the connection object should have an isAlive() method. People might try to make a connection global or store them for reuse. Considering there might be timeouts involved, an isAlive() function would simplify the way to reuse this object.

connection.close should never throw

I cannot find any good reason why connection.close() would throw an exception. Even if the connection is not alive, the close function could still work.


Update: I like how node-mysql is handling server disconnects: here


Exceptions

The driver should use specific exceptions. Off the top of my head I can think of at least 4 different ones:

  1. ConnectionException: cannot connect/connection closed/timeout
  2. InvalidAPIException: broken/illegal queries
  3. DataAccessException: the query failed while executing
  4. ResourceAccessException: similar to query exception, but used for "administrative" operations (database CRUD, table CRUD, index CRUD, etc.)

Query execution

There are two ways of accessing the results of a query:

  1. .run(callback)
  2. .run().collect(callback)

For the 1st case, callback should be invoked for every result. The user can decide not to receive further callback invocations by throwing an exception. Every other value returned from the callback means the callback will continue.

The syntax of the callback should be the same as for connect: function(error, result)

For the 2nd case, the callback should be invoked once with either an error or an array of results. The syntax is the same as above: function(error, result).

What happens if someone writes run(callback_each_result).collect(callback_all_results)?

This can be quite tricky, but I think a behavior that wouldn't be unexpected is to consider the callbacks by their precendence:

  1. invoke the callback_each_result for all results or until the user's callback throws

What about the callback_all_results? In order of (my) preference:

  1. callback_all_results: should be invoked with the remaining results in the current cursor. If the callback_each_result traversed all results, then this would be invoked with an empty result. If the callback_each_result thrown, then callback_all_results should be called with the remaining results. Or:

  2. callback_all_results: should be invoked with all the results completely disregarding that the user already had a chance to navigate all the results in callback_each_result. Or:

  3. callback_all_results: should be invoked with an error that the cursor has already iterated through all the results.

I'm pretty sure that preserving the behavior of callback_each_result and picking any of the above options would not generate confusion.

Query Debug/Tracing/Logging Representation

Feature: It could prove to be very useful to be able to log a query in a readable form. Even after we get rid of the minification.

Conclusion

Except the last part (which might be tricky implementation wise), I don't think these are very radical changes and once we support them, using the Node.js driver would be as clear and pleasant as we want it to be.