Skip to content

Commit

Permalink
now using orlandos async node-sqlite and flow.js
Browse files Browse the repository at this point in the history
  • Loading branch information
mrjjwright committed Apr 2, 2010
1 parent 323d196 commit ecac378
Show file tree
Hide file tree
Showing 6 changed files with 935 additions and 583 deletions.
14 changes: 8 additions & 6 deletions README.md
Expand Up @@ -21,18 +21,20 @@ Other goals
How to use How to use
------------------- -------------------


Put `nosqlite.js`, `sql.js` and `uuid.js` in your node.requires path. # Put all the NoSQLite files together in one directory in your node.requires.path.


You will also need an HTML5 compatible sqlite driver. [Node-sql](http://github.com/mrjjwright/node-sqlite) is what I (mrjjwright) use and is the only one tested with NoSQLite at the moment. If you want to use it, download it, compile it for node and put it in the node.requires. path. # NoSQLite uses my fork (temporarily) of the new async [node-sqlite](http://github.com/mrjjwright/node-sqlite) and it is the only sqlite driver. tested with NoSQLite at the moment. You will need to download it, run `node-waf configure` and `node-waf build` and copy the `sqlite.js` and `build/default/sqlite3_bindings.node` into the NoSQLite directory.


Add necessary requires to the top of your JS (examples are shown in CoffeeScript): Add necessary requires to the top of your JS (examples are shown in CoffeeScript):


sqlite: require("node-sqlite") nosqlite: require("nosqlite")
nosql: require("nosqlite")


Open up a reference to your database and pass it to NoSQLite Open up a reference to your database and pass it to NoSQLite


db: nosqlite.connect(sqlite.openDatabaseSync("my_db.sqlite3")) db: nosqlite.connect("/mypath/my_db.sqlite3", ->
#start your work in a callback
)



Now you are ready to start working with NoSQLite. NoSQLite is motivated by the idea that if we work simply with a one-to-one mapping between a JS object and a SQLite table (no joins), we can get an awful lot for free, and better querying capabilities than other NoSQL stores out there. Now you are ready to start working with NoSQLite. NoSQLite is motivated by the idea that if we work simply with a one-to-one mapping between a JS object and a SQLite table (no joins), we can get an awful lot for free, and better querying capabilities than other NoSQL stores out there.


Expand Down Expand Up @@ -124,5 +126,5 @@ Currently Requires


* [node](http://nodejs.org) * [node](http://nodejs.org)
* [CoffeeScript](http://jashkenas.github.com/coffee-script/) - fun, clean way to write JavaScript. Includes Cake to run the Cakefile and tests. * [CoffeeScript](http://jashkenas.github.com/coffee-script/) - fun, clean way to write JavaScript. Includes Cake to run the Cakefile and tests.
* [node-sqlite](http://github.com/grumdrig/node-sqlite) or another HTML5 compatible database - I am working on rewriting this to be async and be more HTML 5 compatible. You will have to get it and compile the node bindings and put it in your node require path * [node-sqlite](http://github.com/orlandov/node-sqlite) You will have to get it and compile the node bindings and put it in your node requires path.
* [restler](http://github.com/danwrong/restler) - only needed to execute the tests for web API. Not needed otherwise. * [restler](http://github.com/danwrong/restler) - only needed to execute the tests for web API. Not needed otherwise.
142 changes: 142 additions & 0 deletions flow.js
@@ -0,0 +1,142 @@
// Javascript Library for Multi-step Asynchronous Logic
// Version 0.2
// Copyright (c) 2010 William R. Conant, WillConant.com
// Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php

(function(){
// converts native arguments object to an array and applies function
function applyArgs(func, thisObj, args) {
return func.apply(thisObj, Array.prototype.slice.call(args));
}

// defines a flow given any number of functions as arguments
function define() {
var thisFlow = function() {
applyArgs(thisFlow.exec, thisFlow, arguments);
}

thisFlow.blocks = arguments;

thisFlow.exec = function() {
// The flowState is the actual object each step in the flow is applied to. It acts as a
// callback to the next function. It also maintains the internal state of each execution
// and acts as a place for users to save values between steps of the flow.
var flowState = function() {
if (flowState.__frozen) return;

if (flowState.__timeoutId) {
clearTimeout(flowState.__timeoutId);
delete flowState.__timeoutId;
}

var blockIdx = flowState.__nextBlockIdx ++;
var block = thisFlow.blocks[blockIdx];

if (block === undefined) {
return;
}
else {
applyArgs(block, flowState, arguments);
}
}

// __nextBlockIdx specifies which function is the next step in the flow.
flowState.__nextBlockIdx = 0;

// __multiCount is incremented every time MULTI is used to createa a multiplexed callback
flowState.__multiCount = 0;

// __multiOutputs accumulates the arguments of each call to callbacks generated by MULTI
flowState.__multiOutputs = [];

// REWIND signals that the next call to thisFlow should repeat this step. It allows you
// to create serial loops.
flowState.REWIND = function() {
flowState.__nextBlockIdx -= 1;
}

// MULTI can be used to generate callbacks that must ALL be called before the next step
// in the flow is executed. Arguments to those callbacks are accumulated, and an array of
// of those arguments objects is sent as the one argument to the next step in the flow.
flowState.MULTI = function() {
flowState.__multiCount += 1;
return function() {
flowState.__multiCount -= 1;
flowState.__multiOutputs.push(arguments);

if (flowState.__multiCount === 0) {
var multiOutputs = flowState.__multiOutputs;
flowState.__multiOutputs = [];
flowState(multiOutputs);
}
}
}

// TIMEOUT sets a timeout that freezes a flow and calls the provided callback. This
// timeout is cleared if the next flow step happens first.
flowState.TIMEOUT = function(milliseconds, timeoutCallback) {
if (flowState.__timeoutId !== undefined) {
throw new Error("timeout already set for this flow step");
}

flowState.__timeoutId = setTimeout(function() {
flowState.__frozen = true;
timeoutCallback();
}, milliseconds);
}

applyArgs(flowState, this, arguments);
}

return thisFlow;
}

// defines a flow and evaluates it immediately. The first flow function won't receive any arguments.
function exec() {
applyArgs(exports.define, exports, arguments)();
}

// a very useful flow for serial execution of asynchronous functions over a list of values
// (idea suggested by John Wright, http://github.com/mrjjwright)
var serialForEach = define(
function(items, job, between, finish) {
this.items = items;
this.curItem = 0;
this.job = job;
this.between = between;
this.finish = finish;
this();

},function() {
if (this.curItem > 0 && this.between) {
applyArgs(this.between, this, arguments);
}

if (this.curItem >= this.items.length) {
this();
}
else {
this.REWIND();
this.curItem += 1;
this.job(this.items[this.curItem - 1]);
}

},function() {
if (this.finish) this.finish();
}
);

// export our functions
if (exports !== undefined) {
exports.define = define;
exports.exec = exec;
exports.serialForEach = serialForEach;
}
else if (window !== undefined) {
window.flow = {
define: define,
exec: exec,
serialForEach: serialForEach
};
}
})();

0 comments on commit ecac378

Please sign in to comment.