diff --git a/modules/engine/lib/engine.js b/modules/engine/lib/engine.js index 915ba37b..1625eae5 100644 --- a/modules/engine/lib/engine.js +++ b/modules/engine/lib/engine.js @@ -187,6 +187,7 @@ util.inherits(Engine, LogEmitter); * }); * }); */ +// this execute wrapper is for logging purpose only. Engine.prototype.execute = function(){ var grandParentEvent = null; if(arguments.length > 1){ @@ -204,6 +205,9 @@ Engine.prototype.execute = function(){ arguments[1].parentEvent = parentEvent; this.doExecute.apply(this,arguments); } +/* +The real logic of engine execution + */ Engine.prototype.doExecute = function() { var script, opts, func; @@ -321,6 +325,8 @@ Engine.prototype.doExecute = function() { // Initialize the exec state var execState = {}; + // initialize variable assignment by walking through the dependency tree. + // Unused variable will be treated as orphans and executed eventually. function init(statement) { function scopeInit(statement) { switch(statement.type){ @@ -373,6 +379,7 @@ Engine.prototype.doExecute = function() { init(plan.rhs); /* Skip assign statement. Make it undefined, and trigger listener + for if/else and try/catch/finally clause only */ function skipVarList(statements){ function skipVar(statement){ @@ -432,7 +439,9 @@ Engine.prototype.doExecute = function() { }); } - // scope is complex to execute, handle separately + // scope is complex to execute, handle separately. + // If any line in the clause is hitted, execute every line of the calus + // for if/else, try/catch/finally only function execScope(statement, arg) { switch(statement.type) { case 'if' : @@ -463,6 +472,10 @@ Engine.prototype.doExecute = function() { } var skip = false; + /* + Sweep a statement, execute it only if all its dependencies are done. + If not, sweep the dependencies first. + */ function sweep(statement) { if(skip) { return; @@ -505,7 +518,8 @@ Engine.prototype.doExecute = function() { execState[todo.id].count === 0 && scopeDone) { execState[todo.id].state = eventTypes.STATEMENT_IN_FLIGHT; - + // step1 is true only if run in debug mode and not the first step. + // put all unexecuted statements into a list and execute them one by one by clicking "step" on console. if (emitterID && !step1) { // only used for debugger unexecuted.push(statement); @@ -587,7 +601,7 @@ Engine.prototype.doExecute = function() { } }, engineEvent.event); } - + // done with all sweep, this is the final wrap up. var fnDone = function(err, results) { execState[plan.rhs.id].state = err ? eventTypes.STATEMENT_ERROR : eventTypes.STATEMENT_SUCCESS; diff --git a/modules/engine/test/join-test.js b/modules/engine/test/join-test.js index 841896b9..3551ed64 100644 --- a/modules/engine/test/join-test.js +++ b/modules/engine/test/join-test.js @@ -26,7 +26,7 @@ module.exports = { on select get from "http://api.bart.gov/api/stn.aspx?cmd=stninfo&orig=12th&key=MW9S-E7SL-26DU-VV8V"\ resultset "root.stations.station" \ create table myg \ - on select get from "http://maps.googleapis.com/maps/api/geocode/json?latlng={lo},{la}&sensor=true". \ + on select get from "https://maps.googleapis.com/maps/api/geocode/json?latlng={lo},{la}&sensor=true" \ select g.results from bart as b, myg as g where b.gtfs_latitude = g.lo and g.la = b.gtfs_longitude' engine.execute(script, function(emitter) { emitter.on('end', function(err, result) { diff --git a/modules/engine/test/mock-routes/connectors/naive_connector.js b/modules/engine/test/mock-routes/connectors/naive_connector.js new file mode 100644 index 00000000..839d57eb --- /dev/null +++ b/modules/engine/test/mock-routes/connectors/naive_connector.js @@ -0,0 +1,47 @@ +/* +example of using pipeline. +On top of library when (https://github.com/cujojs/when.git) +description of pipeline: https://github.com/cujojs/when/blob/master/docs/api.md + +Things must have: + customConnector.connectorName. this field tells the connector loader + .exec that verb.js would like to call when there is an execution for any connectors. + */ +var pipeline = require('/Users/hochang/workspace/ql.io-mp-apis/node_modules/when/pipeline') +var customConnector = module.exports = function(table, statement, type, bag, path){ + var foo = function(n){ + return n+1 + } + var bar = function(n){ + return n+2 + } + var wae = function(n){ + return n*3 + } + var beforePipeline = [foo] + var afterPipeline = [foo, bar,wae] + this.exec = function(args) { + var mypromise = pipeline(beforePipeline, 1); + mypromise.then(function(arg){ + results = send(arg) + var myresult = pipeline(afterPipeline, results) + myresult.then(function(resultbody){ + var result = { + headers: { + 'content-type': 'application/json' + }, + body: resultbody + }; + return args.callback(null, result); + }) + }) + + } + + +function send(arg){ + return arg+1 +} + +} +customConnector.connectorName = 'aaa' diff --git a/modules/engine/test/mock-routes/connectors/pipeline_connector.js b/modules/engine/test/mock-routes/connectors/pipeline_connector.js new file mode 100644 index 00000000..1d058781 --- /dev/null +++ b/modules/engine/test/mock-routes/connectors/pipeline_connector.js @@ -0,0 +1,80 @@ +/* + example of using pipeline to make async calls.. + On top of library when (https://github.com/cujojs/when.git) + description of pipeline: https://github.com/cujojs/when/blob/master/docs/api.md + + put all chained functions into arrays. In my example, beforePipeline and afterPipeline + Calling pipeline to executed tasks in sequence, but without overlap. Result from prior task will be passed as argument to the latter tasks. + The final result can be accessed in the function passed in promise.then. + + + + */ +var pipeline = require('/Users/hochang/workspace/ql.io-mp-apis/node_modules/when/pipeline'), + when = require('/Users/hochang/workspace/ql.io-mp-apis/node_modules/when'), + http = require('http'); +var customConnector = module.exports = function(){ + var foo = function(n){ + foo1(function(err, results){ + + }) + } + /* + This is an aysnc call. In order to put it into pipeline, + a defer() is required to keep the call blocking during I/O + */ + var foo = function(){ + var deferred = when.defer() + var options = { + host: 'localhost', + port: 3000 + } + + callback = function(response) { + var str = ''; + + //another chunk of data has been recieved, so append it to `str` + response.on('data', function (chunk) { + str += chunk; + }); + + //the whole response has been recieved, so we just print it out here + response.on('end', function () { + deferred.resolve(parseInt(str)) + }); + } + + http.request(options, callback).end(); + return deferred.promise + } + var bar = function(n){ + return n+2 + } + var wae = function(n){ + return n*3 + } + + + this.exec = function(args) { + var cb = function(n){ + var asd=args + var result = { + headers: { + 'content-type': 'application/json' + }, + body: n + }; + return args.callback(null, result); + } + var afterPipeline = [foo, bar,wae,cb] + pipeline(afterPipeline, 1); + + + function send(arg){ + return arg+1 + } + + +} +} +customConnector.connectorName = 'bbb'