Skip to content

Instantly share code, notes, and snippets.

@kixxauth
Created March 17, 2011 20:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kixxauth/875079 to your computer and use it in GitHub Desktop.
Save kixxauth/875079 to your computer and use it in GitHub Desktop.
SQLite binding API for milestone 1 for Node.js app.
// Open questions
// --------------
// * Async or synchronous. Which is easier to implment in terms of SQLite for
// milestone 1?
//
// * How will the database be poplulated for milestone 1? I assume through
// another channel during the build process.
//
// * What properties should the connection object/handle passed to the proxy
// functions have so that the proxy functions have all the information they
// need to connect to a SQLite database?
//
// * Should the connection object/handle contain an actual pointer to the
// SQLite DB connection?
//
// SPEC: proxy_get_document()
// * should accept a connection object as the first parameter.
// * should accept a key or array of keys as the second parameter.
// * may accept a function as a callback.
// * the callback function *must* be invoked in a future turn of the event loop.
//
// Open Questions:
// * Should we limit it to just one key per call, or is it easy enough to
// fetch an arry of keys and return an array of results?
function proxy_get_document(connection, keys, callback) {
// * should call the callback with an error object as the first and only
// parameter if an error is encountered.
// * should call the callbace with null as null as the first param and a
// second parame like:
//
// { _id: 'adf34', _rev: '', publisher: 'Some name', pubdate: '123456789' }
//
// '_rev' will not be used yet, so that could be skipped.
}
// SPEC: proxy_query_view()
// * should accept a connection object as the first parameter.
// * should accept a string view name as the second parameter.
// * should accept a mapping of query paramters as the second parameter.
// * may accept a function as a callback.
// * the callback function *must* be invoked in a future turn of the event loop.
//
// Possible values for query parameters:
// 'key': String*
// 'startKey': String (the start of a key range)
// 'endKey': String (the end of a key range)
// 'limit': Number.
//
// * However, the only parameter we need for this milestone is the `key`.
//
// Open Questions:
// * Is it easier to implement this as an async or synchronous operation?
function proxy_query_view(connection, view_name, params, callback) {
// * should call the callback with an error object as the first and only
// parameter if an error is encountered.
// * should call the callback with null as the first param and a
// second parame like:
//
// { total_rows: 1, offset: 0, rows: [{result}, {result}] }
}
// * should return a connection object/handler for use in calls to
// `proxy_query_view()` and `proxy_get_document()`.
//
// Open questions:
// * Should this function accept a filename string rather than hard coding it?
// Maybe a global config could be used?
function proxy_open_connection() {
// * should make a connection.
// * should return a connection object containing properties needed for
// make other queries.
}
// -----------------------------------------------------------------------
/* The table
key result
"local_user" | "{encoded JSON doc}"
"other_user" | "{another encoded JSON doc}"
"third_user" | "{fourth encoded JSON doc}"
"local_user" | "{last JSON doc}"
*/
// Primary use case:
// This query scans the table above for any document with a key of 'local_user'.
// 'local_user' is just a hardcoded string name for the current user on the device.
proxy_query_view(cxn, 'user_feeds', {key: 'local_user'}, function (error, data) {
var feed = data.rows.[0];
assert(feed._id === 'adf34');
assert(feed.publisher === 'Some name');
// The application layer will determine if this is a book, a feed of
// feeds, a Twitter feed or whatever, and then act accordingly.
});
// This query would result in both of the "local_user" rows. But, in our use
// case, we're only going to have 1 row anyway.
// -----------------------------------------------------------------------
/* SQLite
Tables:
documents
---------
key document
"adf3c" | '{"_id": "adf3c", "publisher": "Some name"}'
"local_user" | '{"_id": "local_user", "feeds": ["adf3c"]}'
user_feeds (this is the theoretical result of running the view function below)
----------
key result
"local_user" | '{"_id": "adf3c", "publisher": "Some name"}'
Psuedo code implementation:
if params.key:
SELECT * FROM user_feeds WHERE key = params.key;
else:
throw "other query params not implemented"
*/
// -----------------------------------------------------------------------
// TODO: This is what the 'user_feeds' view function would look like for
// CouchDB to create the `user_feeds` table (what would be a join table
// in most RDMS).
//
// However, I don't think we need to implement this the first time
// around. If the database schema is set up for the app at build time
// and then populated locally, this function is not actually needed until
// CouchDB is used.
var view_fn = (function (doc) {
// the doc.username property tells us this document represents a user
// doc.feeds is a list of foreign keys to feeds this user has subscribed to.
if (doc.username && doc.feeds) {
var i = 0;
for(; i < doc.feeds.length; i += 1) {
// By emitting the special `_id` name we are telling CouchDB to emit
// the document with _id == doc.feeds[i] (which is a foreign key).
emit(doc.username, {_id: doc.feeds[i]});
}
}
}).toString();
// -----------------------------------------------------------------------
// This is the API the application layer will be using. It could be put in a
// different module altogether.
exports.makeConnection = function makeConnection() {
var my = proxy_open_connection()
, connection = {}
;
// Validate and serialize a document object for interoperability with
// CouchDB and SQLite.
function validate_and_serialize(doc) {
doc._id = ''; // immutable
doc._rev = ''; // immutable
}
/**
* Get a document by key.
* @param {String|Array} key One or more document keys.
* @param {Function} callback
*
* Document keys must only be strings.
*/
connection.get = function get(keys, callback) {
// TODO: This will do some validation and then call
// proxy_get_document()
};
/**
* Query a view (index) in the database.
* @param {String} view_name The name of the view index to query.
* @param {Object} params An mapping of query parameters to query.
* @param {Function} callback
*
* The params may be an empty array.
*/
connection.get_view = function get_view(view_name, params, callback) {
// TODO: This will do some validation and then call
// proxy_query_view()
};
/**
* De-Prioritized
* (not needed for milestone 1 if we are populating the db at build time)
*
* Post a document to the db.
* @param {Object} docs A map of key:document pairs.
* @param {String} docs A document key.
* @param {Object} [value] A document body.
* @param {Function} callback
*
* If the docs param is a string it is treated as a document key and the
* value parameter is treated as the document body.
*
* The key for each document must be a string, and each value must be a
* JSON serializable object.
*/
connection.post = function post(docs, value, callback) {
};
return connnection;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment