-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
.
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 aconnection
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.
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.
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.
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
The driver should use specific exceptions. Off the top of my head I can think of at least 4 different ones:
- ConnectionException: cannot connect/connection closed/timeout
- InvalidAPIException: broken/illegal queries
- DataAccessException: the query failed while executing
- ResourceAccessException: similar to query exception, but used for "administrative" operations (database CRUD, table CRUD, index CRUD, etc.)
There are two ways of accessing the results of a query:
.run(callback)
.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)
.
This can be quite tricky, but I think a behavior that wouldn't be unexpected is to consider the callbacks by their precendence:
- 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:
-
callback_all_results
: should be invoked with the remaining results in the current cursor. If thecallback_each_result
traversed all results, then this would be invoked with an empty result. If thecallback_each_result
thrown, thencallback_all_results
should be called with the remaining results. Or: -
callback_all_results
: should be invoked with all the results completely disregarding that the user already had a chance to navigate all the results incallback_each_result
. Or: -
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.
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.
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.