diff --git a/async/exercises/ex1/README.md b/async/exercises/ex1/README.md new file mode 100755 index 0000000..1208cfc --- /dev/null +++ b/async/exercises/ex1/README.md @@ -0,0 +1,9 @@ +# Instructions + +1. This exercise calls for you to write some async flow-control code. To start off with, you'll use callbacks only. + +2. Expected behavior: + - Request all 3 files at the same time (in "parallel"). + - Render them ASAP (don't just blindly wait for all to finish loading) + - BUT, render them in proper (obvious) order: "file1", "file2", "file3". + - After all 3 are done, output "Complete!". diff --git a/async/exercises/ex1/ex1.html b/async/exercises/ex1/ex1.html new file mode 100755 index 0000000..63c0e5f --- /dev/null +++ b/async/exercises/ex1/ex1.html @@ -0,0 +1,13 @@ + + + + +Exercise 1 + + +

Exercise 1

+ + + + + diff --git a/async/exercises/ex1/ex1.js b/async/exercises/ex1/ex1.js new file mode 100755 index 0000000..ff964f5 --- /dev/null +++ b/async/exercises/ex1/ex1.js @@ -0,0 +1,65 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** +// The old-n-busted callback way +//this is called each time we getFile +function getFile(file) { + fakeAjax(file,function(text){ + //calls a function to handle the response from the AJAX + handleResponse(file,text); + }); +} +//an object to hold information to see what has returned already +var responses = {}; + +function handleResponse(file,cont) { + //Checks to see if the file exists in the holding object + if (!(file in responses)) { + //if it doesn't exist add it to the object + responses[file] = cont; + } + //holds the order of the ways we want the files to display + var fileOrder = ["file1","file2","file3"]; + //itterates over the array to check if all files are been retrieved + for (var i = 0; i < fileOrder.length; i++) { + //checks if the file has been added to response + console.log(responses); + if (fileOrder[i] in responses) { + //makes sure to only display items that haven't already been displayed + if (typeof responses[fileOrder[i]] == "string") { + //function that just logs the argument + output(responses[fileOrder[i]]); + responses[fileOrder[i]] = false; + } + } + else { + return; + } + } + //function that just logs the argument + output("Complete"); +} + + + +// request all files at once in "parallel" +getFile("file1"); +getFile("file2"); +getFile("file3"); diff --git a/async/exercises/ex2/README.md b/async/exercises/ex2/README.md new file mode 100755 index 0000000..626c49b --- /dev/null +++ b/async/exercises/ex2/README.md @@ -0,0 +1,9 @@ +# Instructions + +1. You'll do the same thing as the previous exercise(s), but now you should use thunks. + +2. Expected behavior: + - Request all 3 files at the same time (in "parallel"). + - Render them ASAP (don't just blindly wait for all to finish loading) + - BUT, render them in proper (obvious) order: "file1", "file2", "file3". + - After all 3 are done, output "Complete!". diff --git a/async/exercises/ex2/ex2.html b/async/exercises/ex2/ex2.html new file mode 100755 index 0000000..f858f4c --- /dev/null +++ b/async/exercises/ex2/ex2.html @@ -0,0 +1,13 @@ + + + + +Exercise 2 + + +

Exercise 2

+ + + + + diff --git a/async/exercises/ex2/ex2.js b/async/exercises/ex2/ex2.js new file mode 100755 index 0000000..1797c87 --- /dev/null +++ b/async/exercises/ex2/ex2.js @@ -0,0 +1,61 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** +//active thunk generator +function getFile(file) { + var text; + var fn; + + fakeAjax(file,function(res){ + if (fn) { + fn(res) + }else { + text = res; + } + }); + + //return this callback for the thunks + return function(cb) { + //if the information has arrived return the cb function + if (text) { + cb(text) + //if not then set fn to cb I think it is undefined + }else { + fn = cb; + } + }; +} + +// generate the thunks before you need to display them +var thunk1 = getFile("file1") +var thunk2 = getFile("file2") +var thunk3 = getFile("file3") + +//won't display the inner nest until the outer nest gets the neccessary arguments +thunk1(function(text1) { + output(text1); + thunk2(function(text2) { + output(text2); + thunk3(function(text3){ + output(text3); + output("completed"); + }) + }) +}) diff --git a/async/exercises/ex3/README.md b/async/exercises/ex3/README.md new file mode 100755 index 0000000..3565e50 --- /dev/null +++ b/async/exercises/ex3/README.md @@ -0,0 +1,9 @@ +# Instructions + +1. You'll do the same thing as the previous exercise(s), but now you should use promises. + +2. Expected behavior: + - Request all 3 files at the same time (in "parallel"). + - Render them ASAP (don't just blindly wait for all to finish loading) + - BUT, render them in proper (obvious) order: "file1", "file2", "file3". + - After all 3 are done, output "Complete!". diff --git a/async/exercises/ex3/ex3.html b/async/exercises/ex3/ex3.html new file mode 100755 index 0000000..33e5265 --- /dev/null +++ b/async/exercises/ex3/ex3.html @@ -0,0 +1,14 @@ + + + + +Exercise 3 + + +

Exercise 3

+ + + + + + diff --git a/async/exercises/ex3/ex3.js b/async/exercises/ex3/ex3.js new file mode 100755 index 0000000..f65d35a --- /dev/null +++ b/async/exercises/ex3/ex3.js @@ -0,0 +1,50 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + // creates a new promise + return new Promise(function(resolve){ + fakeAjax(file,resolve); + }); +} + +//set the variable to the retrieved promise object +var prom1 = getFile("file1"); +var prom2 = getFile("file2"); +var prom3 = getFile("file3"); + +//call the information one after another in order +prom1 +.then(output) +.then(function(){ + return prom2; +}) +.then(output) +.then(function(){ + return prom3; +}) +.then(output) +.then(function(){ + output("Complete") +}) +.catch(function(err){ + output(err) +}) diff --git a/async/exercises/ex3/npo.js b/async/exercises/ex3/npo.js new file mode 100755 index 0000000..c363ed4 --- /dev/null +++ b/async/exercises/ex3/npo.js @@ -0,0 +1,5 @@ +/*! Native Promise Only + v0.8.1 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function(t,n,e){n[t]=n[t]||e(),"undefined"!=typeof module&&module.exports?module.exports=n[t]:"function"==typeof define&&define.amd&&define(function(){return n[t]})}("Promise","undefined"!=typeof global?global:this,function(){"use strict";function t(t,n){l.add(t,n),h||(h=y(l.drain))}function n(t){var n,e=typeof t;return null==t||"object"!=e&&"function"!=e||(n=t.then),"function"==typeof n?n:!1}function e(){for(var t=0;t0&&t(e,u))}catch(a){i.call(new f(u),a)}}}function i(n){var o=this;o.triggered||(o.triggered=!0,o.def&&(o=o.def),o.msg=n,o.state=2,o.chain.length>0&&t(e,o))}function c(t,n,e,o){for(var r=0;r + + + +Exercise 4 + + +

Exercise 4

+ + + + + diff --git a/async/exercises/ex4/ex4.js b/async/exercises/ex4/ex4.js new file mode 100755 index 0000000..07cc701 --- /dev/null +++ b/async/exercises/ex4/ex4.js @@ -0,0 +1,39 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** +// The old-n-busted callback way + +function getFile(file) { + return new Promise(function(resolve){ + fakeAjax(file,resolve); + }); +} + +["file1","file2","file3"] +//go over the array +.map(getFile) +// transform the file array to an array of promise objects +.reduce(function combine(chain,promise) { + return chain.then(function () { + return promise; + }).then(output) +}, Promise.resolve()).then(function() { + output("complete") +}) diff --git a/async/exercises/ex4/npo.js b/async/exercises/ex4/npo.js new file mode 100755 index 0000000..c363ed4 --- /dev/null +++ b/async/exercises/ex4/npo.js @@ -0,0 +1,5 @@ +/*! Native Promise Only + v0.8.1 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function(t,n,e){n[t]=n[t]||e(),"undefined"!=typeof module&&module.exports?module.exports=n[t]:"function"==typeof define&&define.amd&&define(function(){return n[t]})}("Promise","undefined"!=typeof global?global:this,function(){"use strict";function t(t,n){l.add(t,n),h||(h=y(l.drain))}function n(t){var n,e=typeof t;return null==t||"object"!=e&&"function"!=e||(n=t.then),"function"==typeof n?n:!1}function e(){for(var t=0;t0&&t(e,u))}catch(a){i.call(new f(u),a)}}}function i(n){var o=this;o.triggered||(o.triggered=!0,o.def&&(o=o.def),o.msg=n,o.state=2,o.chain.length>0&&t(e,o))}function c(t,n,e,o){for(var r=0;r0){u=!1,a=s.shift(),c=g.slice(),g.length=0,c.unshift(createStepCompletion());try{a.apply(h,c)}catch(i){l(i)?$=$.concat(i):$.push(i),n=!0,scheduleSequenceTick()}}}function createStepCompletion(){function done(){n||r||u||(u=!0,g.push.apply(g,arguments),$.length=0,scheduleSequenceTick())}return done.fail=function $$step$fail(){n||r||u||(n=!0,g.length=0,$.push.apply($,arguments),scheduleSequenceTick())},done.abort=function $$step$abort(){n||r||(u=!1,r=!0,g.length=$.length=0,scheduleSequenceTick())},done.errfcb=function $$step$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},done}function createGate(e,t,u){function resetGate(){clearTimeout(s),s=d=m=o=null}function scheduleGateTick(){return g?gateTick():void(s||(s=schedule(gateTick)))}function gateTick(){if(!(n||r||$)){var t=[];s=null,p?(e.fail.apply(h,o),resetGate()):g?(e.abort(),resetGate()):checkGate()&&($=!0,d.forEach(function $$each(e,n){t.push(m["s"+n])}),e.apply(h,t),resetGate())}}function checkGate(){if(0!==d.length){var e=!0;return d.some(function $$some(n){return null===n?(e=!1,!0):void 0}),e}}function createSegmentCompletion(){function done(){if(!(n||r||p||g||$||d[e])){var t=c.apply(h,arguments);m["s"+e]=t.length>1?t:t[0],d[e]=!0,scheduleGateTick()}}var e=d.length;return done.fail=function $$segment$fail(){n||r||p||g||$||d[e]||(p=!0,o=f.call(arguments),scheduleGateTick())},done.abort=function $$segment$abort(){n||r||p||g||$||(g=!0,gateTick())},done.errfcb=function $$segment$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},d[e]=null,done}var a,i,o,s,p=!1,g=!1,$=!1,d=[],m={};t.some(function $$some(e){if(p||g)return!0;a=u.slice(),a.unshift(createSegmentCompletion());try{e.apply(h,a)}catch(n){return i=n,p=!0,!0}}),i&&(l(i)?e.fail.apply(h,i):e.fail(i))}function then(){return n||r||0===arguments.length?d:(wrapArgs(arguments,thenWrapper).forEach(function $$each(e){i(e)?seq(e):s.push(e)}),scheduleSequenceTick(),d)}function or(){return r||0===arguments.length?d:(p.push.apply(p,arguments),scheduleSequenceTick(),d)}function gate(){if(n||r||0===arguments.length)return d;var e=f.call(arguments).map(function $$map(e){var n;return i(e)?(n={seq:e},tapSequence(n),function $$segment(e){n.seq.pipe(e)}):e});return then(function $$then(n){var t=f.call(arguments,1);createGate(n,e,t)}),d}function pipe(){return r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){e.apply(h,f.call(arguments,1)),n()}).or(e.fail)}),d)}function seq(){return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){var n={seq:e};i(e)&&tapSequence(n),then(function $$then(e){var t=n.seq;i(t)||(t=n.seq.apply(h,f.call(arguments,1))),t.pipe(e)})}),d)}function val(){return n||r||0===arguments.length?d:(f.call(wrapArgs(arguments,valWrapper)).forEach(function $$each(e){then(function $$then(n){var t=e.apply(h,f.call(arguments,1));l(t)||(t=c(t)),n.apply(h,t)})}),d)}function promise(){function wrap(e){return function $$fn(){e.apply(h,l(arguments[0])?arguments[0]:arguments)}}return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){var t=e;"function"==typeof e&&"function"!=typeof e.then&&(t=e.apply(h,f.call(arguments,1))),t.then(wrap(n),wrap(n.fail))})}),d)}function fork(){var e;return val(function $$val(){return e?e.apply(h,arguments):e=createSequence.apply(h,arguments).defer(),c.apply(h,arguments)}),or(function $$or(){if(e)e.fail.apply(h,arguments);else{var n=f.call(arguments);e=createSequence().then(function $$then(e){e.fail.apply(h,n)}).defer()}}),createSequence().then(function $$then(n){e?e.pipe(n):e=n}).defer()}function abort(){return n?d:(r=!0,sequenceTick(),d)}function duplicate(){var e;return a={then_queue:s.slice(),or_queue:p.slice()},e=createSequence(),a=null,e}function unpause(){g.push.apply(g,arguments),e===!0&&(e=null),scheduleSequenceTick()}function defer(){return p.push(function ignored(){}),d}function internals(e,t){var a=arguments.length>1;switch(e){case"seq_error":if(!a)return n;n=t;break;case"seq_aborted":if(!a)return r;r=t;break;case"then_ready":if(!a)return u;u=t;break;case"then_queue":return s;case"or_queue":return p;case"sequence_messages":return g;case"sequence_errors":return $}}function includeExtensions(){Object.keys(o).forEach(function $$each(e){d[e]=o[e](d,internals)})}var e,n=!1,t=!1,r=!1,u=!0,s=[],p=[],g=[],$=[],d=brandIt({then:then,or:or,onerror:or,gate:gate,all:gate,pipe:pipe,seq:seq,val:val,promise:promise,fork:fork,abort:abort,duplicate:duplicate,defer:defer});return includeExtensions(),a&&(s=a.then_queue.slice(),p=a.or_queue.slice(),d.unpause=unpause,e=!0),d.then.apply(h,arguments),d}function brandIt(e){return Object.defineProperty(e,p,{enumerable:!1,value:!0})}function checkBranding(e){return!(null==e||"object"!=typeof e||!e[p])}function valWrapper(e){return c.apply(h,f.call(arguments).slice(1,e+1))}function thenWrapper(e){arguments[e+1].apply(h,f.call(arguments).slice(1,e+1))}function wrapArgs(e,n){var t,r;for(e=f.call(e),t=0;t 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + var args = orig_args || ARRAY_SLICE.call(arguments,1); + + setTimeout(function $$set$timeout(){ + done.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.after = function $$after() { + return ASQ().after.apply(ø,arguments); +}; +// "any" +ASQ.extend("any",function $$extend(api,internals){ + return function $$any() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as success + success_messages.length = fns.length; + trigger.apply(ø,success_messages); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + success_messages = [], + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "errfcb" +ASQ.extend("errfcb",function $$extend(api,internals){ + return function $$errfcb() { + // create a fake sequence to extract the callbacks + var sq = { + val: function $$then(cb){ sq.val_cb = cb; return sq; }, + or: function $$or(cb){ sq.or_cb = cb; return sq; } + }; + + // trick `seq(..)`s checks for a sequence + sq[brand] = true; + + // immediately register our fake sequence on the + // main sequence + api.seq(sq); + + // provide the "error-first" callback + return function $$errorfirst$callback(err) { + if (err) { + sq.or_cb(err); + } + else { + sq.val_cb.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }; + }; +}); +// "failAfter" +ASQ.extend("failAfter",function $$extend(api,internals){ + return function $$failAfter(num) { + var args = arguments.length > 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + setTimeout(function $$set$timeout(){ + done.fail.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.failAfter = function $$fail$after() { + return ASQ().failAfter.apply(ø,arguments); +}; +// "first" +ASQ.extend("first",function $$extend(api,internals){ + return function $$first() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + error_messages.length = 0; + } + + function success(trigger,idx,args) { + if (!finished) { + finished = true; + + // first successful segment triggers + // main sequence to proceed as success + trigger( + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ); + + reset(); + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete without success? + if (completed === fns.length) { + finished = true; + + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + + reset(); + } + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "go-style CSP" +(function IIFE(){ + + // filter out already-resolved queue entries + function filterResolved(queue) { + return queue.filter(function $$filter(entry){ + return !entry.resolved; + }); + } + + function closeQueue(queue,finalValue) { + queue.forEach(function $$each(iter){ + if (!iter.resolved) { + iter.next(); + iter.next(finalValue); + } + }); + queue.length = 0; + } + + function channel(bufSize) { + var ch = { + close: function $$close(){ + ch.closed = true; + closeQueue(ch.put_queue,false); + closeQueue(ch.take_queue,ASQ.csp.CLOSED); + }, + closed: false, + messages: [], + put_queue: [], + take_queue: [], + buffer_size: +bufSize || 0 + }; + return ch; + } + + function unblock(iter) { + if (iter && !iter.resolved) { + iter.next(iter.next().value); + } + } + + function put(channel,value) { + var ret; + + if (channel.closed) { + return false; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate put? + if (channel.messages.length < channel.buffer_size) { + channel.messages.push(value); + unblock(channel.take_queue.shift()); + return true; + } + // queued put + else { + channel.put_queue.push( + // make a notifiable iterable for 'put' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + channel.messages.push(value); + return true; + } + else { + return false; + } + }) + ); + + // wrap a sequence/promise around the iterable + ret = ASQ( + channel.put_queue[channel.put_queue.length - 1] + ); + + // take waiting on this queued put? + if (channel.take_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return ret; + } + } + + function putAsync(channel,value,cb) { + var ret = ASQ(put(channel,value)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function take(channel) { + var ret; + + try { + ret = takem(channel); + } + catch (err) { + ret = err; + } + + if (ASQ.isSequence(ret)) { + ret.pCatch(function $$pcatch(err){ + return err; + }); + } + + return ret; + } + + function takeAsync(channel,cb) { + var ret = ASQ(take(channel)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function takem(channel) { + var msg; + + if (channel.closed) { + return ASQ.csp.CLOSED; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate take? + if (channel.messages.length > 0) { + msg = channel.messages.shift(); + unblock(channel.put_queue.shift()); + if (msg instanceof Error) { + throw msg; + } + return msg; + } + // queued take + else { + channel.take_queue.push( + // make a notifiable iterable for 'take' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + var v = channel.messages.shift(); + if (v instanceof Error) { + throw v; + } + return v; + } + else { + return ASQ.csp.CLOSED; + } + }) + ); + + // wrap a sequence/promise around the iterable + msg = ASQ( + channel.take_queue[channel.take_queue.length - 1] + ); + + // put waiting on this take? + if (channel.put_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return msg; + } + } + + function takemAsync(channel,cb) { + var ret = ASQ(takem(channel)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret.val(function $$val(v){ + if (v instanceof Error) { + throw v; + } + return v; + }); + } + } + + function alts(actions) { + var closed, open, handlers, i, isq, ret, resolved = false; + + // used `alts(..)` incorrectly? + if (!Array.isArray(actions) || actions.length == 0) { + throw Error("Invalid usage"); + } + + closed = []; + open = []; + handlers = []; + + // separate actions by open/closed channel status + actions.forEach(function $$each(action){ + var channel = Array.isArray(action) ? action[0] : action; + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + if (channel.closed) { + closed.push(channel); + } + else { + open.push(action); + } + }); + + // if no channels are still open, we're done + if (open.length == 0) { + return { value: ASQ.csp.CLOSED, channel: closed }; + } + + // can any channel action be executed immediately? + for (i=0; i 0) { + return { value: take(open[i]), channel: open[i] }; + } + } + + isq = ASQ.iterable(); + var ret = ASQ(isq); + + // setup channel action handlers + for (i=0; i 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + },0); + } + } + // take action? + else { + channel = action; + + // define take handler + handlers.push( + ASQ.iterable() + .then(function $$then(){ + resolved = true; + + // mark all handlers across this `alts(..)` as resolved now + handlers = handlers.filter(function $$filter(handler){ + return !(handler.resolved = true); + }); + + // channel still open? + if (!channel.closed) { + isq.next({ value: channel.messages.shift(), channel: channel }); + } + // channel already closed? + else { + isq.next({ value: ASQ.csp.CLOSED, channel: channel }); + } + }) + ); + + // queue up take handler + channel.take_queue.push(handlers[handlers.length-1]); + + // put waiting on this queued take? + if (channel.put_queue.length > 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + }); + } + } + })(open[i]); + } + + return ret; + } + + function altsAsync(chans,cb) { + var ret = ASQ(alts(chans)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret; + } + } + + function timeout(delay) { + var ch = channel(); + setTimeout(ch.close,delay); + return ch; + } + + function go(gen,args) { + // goroutine arguments passed? + if (arguments.length > 1) { + if (!args || !Array.isArray(args)) { + args = [args]; + } + } + else { + args = []; + } + + return function *$$go(token) { + + // unblock the overall goroutine handling + function unblock() { + token.unblock_count++; + + if (token.block && !token.block.marked) { + token.block.marked = true; + token.block.next(); + } + } + + var ret, msg, err, type, done = false, it; + + // keep track of how many requests for unblocking + // have occurred + token.unblock_count = (token.unblock_count || 0); + + // keep track of how many goroutines are running + // so we can infer when we're done go'ing + token.go_count = (token.go_count || 0) + 1; + + // need to initialize a set of goroutines? + if (token.go_count === 1) { + // create a default channel for these goroutines + token.channel = channel(); + token.channel.messages = token.messages; + token.channel.go = function $$go(){ + // unblock the goroutine handling for this + // new goroutine + unblock(); + // add the goroutine (called with any args) to + // the handling queue + token.add( go.apply(ø,arguments) ); + }; + // starting out with initial channel messages? + if (token.channel.messages.length > 0) { + // fake back-pressure blocking for each + token.channel.put_queue = token.channel.messages.map(function $$map(){ + // make a notifiable iterable for 'put' blocking + return ASQ.iterable() + .then(function $$then(){ + unblock(token.channel.take_queue.shift()); + return !token.channel.closed; + }); + }); + } + } + + // initialize the generator + it = gen.apply(ø,[token.channel].concat(args)); + + (function iterate(){ + + function next() { + // keep going with next step in goroutine? + if (!done) { + iterate(); + } + // unblock overall goroutine handling to + // continue with other goroutines + else { + unblock(); + } + } + + // has a resumption value been achieved yet? + if (!ret) { + // try to resume the goroutine + try { + // resume with injected exception? + if (err) { + ret = it.throw(err); + err = null; + } + // resume normally + else { + ret = it.next(msg); + } + } + // resumption failed, so bail + catch (e) { + done = true; + err = e; + msg = null; + unblock(); + return; + } + + // keep track of the result of the resumption + done = ret.done; + ret = ret.value; + type = typeof ret; + + // if this goroutine is complete, unblock the + // overall goroutine handling + if (done) { + unblock(); + } + + // received a thenable/promise back? + if (isPromise(ret)) { + ret = ASQ().promise(ret); + } + + // wait for the value? + if (ASQ.isSequence(ret)) { + ret.val(function $$val(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + next(); + }) + .or(function $$or(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + if (msg instanceof Error) { + err = msg; + msg = null; + } + next(); + }); + } + // immediate value, prepare it to go right back in + else { + msg = ret; + ret = null; + next(); + } + } + })(); + + // keep this goroutine alive until completion + while (!done) { + // transfer control to another goroutine + yield token; + + // need to block overall goroutine handling + // while idle? + if (!done && !token.block && token.unblock_count === 0) { + // wait here while idle + yield (token.block = ASQ.iterable()); + + token.block = false; + } + + if (token.unblock_count > 0) token.unblock_count--; + } + + // this goroutine is done now + token.go_count--; + + // all goroutines done? + if (token.go_count === 0) { + // any lingering blocking need to be cleaned up? + unblock(); + + // capture any untaken messages + msg = ASQ.messages.apply(ø,token.messages); + + // need to implicitly force-close channel? + if (token.channel && !token.channel.closed) { + token.channel.closed = true; + token.channel.put_queue.length = token.channel.take_queue.length = 0; + token.channel.close = token.channel.go = token.channel.messages = null; + } + token.channel = null; + } + + // make sure leftover error or message are + // passed along + if (err) { + throw err; + } + else if (token.go_count === 0) { + return msg; + } + else { + return token; + } + }; + } + + ASQ.csp = { + chan: channel, + put: put, + putAsync: putAsync, + take: take, + takeAsync: takeAsync, + takem: takem, + takemAsync: takemAsync, + alts: alts, + altsAsync: altsAsync, + timeout: timeout, + go: go, + CLOSED: {} + }; + +})(); +// "ASQ.iterable()" +(function IIFE(){ + var template; + + ASQ.iterable = function $$iterable() { + function throwSequenceErrors() { + throw (sequence_errors.length === 1 ? sequence_errors[0] : sequence_errors); + } + + function notifyErrors() { + var fn; + + seq_tick = null; + + if (seq_error) { + if (or_queue.length === 0 && !error_reported) { + error_reported = true; + throwSequenceErrors(); + } + + while (or_queue.length > 0) { + error_reported = true; + fn = or_queue.shift(); + try { + fn.apply(ø,sequence_errors); + } + catch (err) { + if (checkBranding(err)) { + sequence_errors = sequence_errors.concat(err); + } + else { + sequence_errors.push(err); + } + if (or_queue.length === 0) { + throwSequenceErrors(); + } + } + } + } + } + + function val() { + if (seq_error || seq_aborted || arguments.length === 0) { + return sequence_api; + } + + var args = ARRAY_SLICE.call(arguments).map(function mapper(arg){ + if (typeof arg != "function") return function $$val() { return arg; }; + else return arg; + }); + + val_queue.push.apply(val_queue,args); + + return sequence_api; + } + + function or() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + or_queue.push.apply(or_queue,arguments); + + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function pipe() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + ARRAY_SLICE.call(arguments) + .forEach(function $$each(fn){ + val(fn).or(fn.fail); + }); + + return sequence_api; + } + + function next() { + if (seq_error || seq_aborted || val_queue.length === 0) { + if (val_queue.length > 0) { + $throw$("Sequence cannot be iterated"); + } + return { done: true }; + } + + try { + return { value: val_queue.shift().apply(ø,arguments) }; + } + catch (err) { + if (ASQ.isMessageWrapper(err)) { + $throw$.apply(ø,err); + } + else { + $throw$(err); + } + + return {}; + } + } + + function $throw$() { + if (seq_error || seq_aborted) { + return sequence_api; + } + + sequence_errors.push.apply(sequence_errors,arguments); + seq_error = true; + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function $return$(val) { + if (seq_error || seq_aborted) { + val = void 0; + } + + abort(); + + return { done: true, value: val }; + } + + function abort() { + if (seq_error || seq_aborted) { + return; + } + + seq_aborted = true; + + clearTimeout(seq_tick); + seq_tick = null; + val_queue.length = or_queue.length = sequence_errors.length = 0; + } + + function duplicate() { + var isq; + + template = { + val_queue: val_queue.slice(), + or_queue: or_queue.slice() + }; + isq = ASQ.iterable(); + template = null; + + return isq; + } + + // opt-out of global error reporting for this sequence + function defer() { + or_queue.push(function $$ignored(){}); + return sequence_api; + } + + // *********************************************** + // Object branding utilities + // *********************************************** + function brandIt(obj) { + Object.defineProperty(obj,brand,{ + enumerable: false, + value: true + }); + + return obj; + } + + var sequence_api, + + seq_error = false, + error_reported = false, + seq_aborted = false, + + seq_tick, + + val_queue = [], + or_queue = [], + + sequence_errors = [] + ; + + // *********************************************** + // Setup the ASQ.iterable() public API + // *********************************************** + sequence_api = brandIt({ + val: val, + then: val, + or: or, + pipe: pipe, + next: next, + "throw": $throw$, + "return": $return$, + abort: abort, + duplicate: duplicate, + defer: defer + }); + + // useful for ES6 `for..of` loops, + // add `@@iterator` to simply hand back + // our iterable sequence itself! + sequence_api[(typeof Symbol == "function" && Symbol.iterator) || "@@iterator"] = function $$iter() { + return sequence_api; + }; + + // templating the iterable-sequence setup? + if (template) { + val_queue = template.val_queue.slice(0); + or_queue = template.or_queue.slice(0); + } + + // treat ASQ.iterable() constructor parameters as having been + // passed to `val()` + sequence_api.val.apply(ø,arguments); + + return sequence_api; + }; + +})(); +// "last" +ASQ.extend("last",function $$extend(api,internals){ + return function $$last() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages = null; + } + + function complete(trigger) { + if (success_messages != null) { + // last successful segment's message(s) sent + // to main sequence to proceed as success + trigger( + success_messages.length > 1 ? + ASQ.messages.apply(ø,success_messages) : + success_messages[0] + ); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages = args; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "map" +ASQ.extend("map",function $$extend(api,internals){ + return function $$map(pArr,pEach) { + if (internals("seq_error") || internals("seq_aborted")) { + return api; + } + + api.seq(function $$seq(){ + var tmp, args = ARRAY_SLICE.call(arguments), + arr = pArr, each = pEach; + + // if missing `map(..)` args, use value-messages (if any) + if (!each) each = args.shift(); + if (!arr) arr = args.shift(); + + // if arg types in reverse order (each,arr), swap + if (typeof arr === "function" && Array.isArray(each)) { + tmp = arr; + arr = each; + each = tmp; + } + + return ASQ.apply(ø,args) + .gate.apply(ø,arr.map(function $$map(item){ + return function $$segment(){ + each.apply(ø,[item].concat(ARRAY_SLICE.call(arguments))); + }; + })); + }) + .val(function $$val(){ + // collect all gate segment output into one value-message + // Note: return a normal array here, not a message wrapper! + return ARRAY_SLICE.call(arguments); + }); + + return api; + }; +}); +// "none" +ASQ.extend("none",function $$extend(api,internals){ + return function $$none() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as **error** + success_messages.length = fns.length; + trigger.fail.apply(ø,success_messages); + } + else { + // send errors as **success** to main sequence + error_messages.length = fns.length; + trigger.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages = [] + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "pThen" +ASQ.extend("pThen",function $$extend(api,internals){ + return function $$pthen(success,failure) { + if (internals("seq_aborted")) { + return api; + } + + var ignore_success_handler = false, ignore_failure_handler = false; + + if (typeof success === "function") { + api.then(function $$then(done){ + if (!ignore_success_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments); + msgs.shift(); + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_failure_handler = true; + + try { + ret = success(msgs); + } + catch (err) { + if (!ASQ.isMessageWrapper(err)) { + err = [err]; + } + done.fail.apply(ø,err); + return; + } + + // returned a sequence? + if (ASQ.isSequence(ret)) { + ret.pipe(done); + } + // returned a message wrapper? + else if (ASQ.isMessageWrapper(ret)) { + done.apply(ø,ret); + } + // returned a promise/thenable? + else if (isPromise(ret)) { + ret.then(done,done.fail); + } + // just a normal value to pass along + else { + done(ret); + } + } + else { + done.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }); + } + if (typeof failure === "function") { + api.or(function $$or(){ + if (!ignore_failure_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments), smgs, + or_queue = ARRAY_SLICE.call(internals("or_queue")) + ; + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_success_handler = true; + + // NOTE: if this call throws, that'll automatically + // be handled by core as we'd want it to be + ret = failure(msgs); + + // if we get this far: + // first, inject return value (if any) as + // next step's sequence messages + smgs = internals("sequence_messages"); + smgs.length = 0; + if (typeof ret !== "undefined") { + if (!ASQ.isMessageWrapper(ret)) { + ret = [ret]; + } + smgs.push.apply(smgs,ret); + } + + // reset internal error state, because we've exclusively + // handled any errors up to this point of the sequence + internals("sequence_errors").length = 0; + internals("seq_error",false); + internals("then_ready",true); + + // temporarily empty the or-queue + internals("or_queue").length = 0; + + // make sure to schedule success-procession on the chain + api.val(function $$val(){ + // pass thru messages + return ASQ.messages.apply(ø,arguments); + }); + + // at next cycle, reinstate the or-queue (if any) + if (or_queue.length > 0) { + schedule(function $$schedule(){ + api.or.apply(ø,or_queue); + }); + } + } + }); + } + return api; + }; +}); + +// "pCatch" +ASQ.extend("pCatch",function $$extend(api,internals){ + return function $$pcatch(failure) { + if (internals("seq_aborted")) { + return api; + } + + api.pThen(void 0,failure); + + return api; + }; +}); +// "race" +ASQ.extend("race",function $$extend(api,internals){ + return function $$race() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(v){ + var def; + // tap any directly-provided sequences immediately + if (ASQ.isSequence(v)) { + def = { seq: v }; + tapSequence(def); + return function $$fn(done) { + def.seq.pipe(done); + }; + } + else return v; + }); + + api.then(function $$then(done){ + var args = ARRAY_SLICE.call(arguments); + + fns.forEach(function $$each(fn){ + fn.apply(ø,args); + }); + }); + + return api; + }; +}); +// "react" (reactive sequences) +ASQ.react = function $$react(reactor) { + function next() { + if (!paused) { + if (template) { + var sq = template.duplicate(); + sq.unpause.apply(ø,arguments); + return sq; + } + return ASQ(function $$asq(){ throw "Disabled Sequence"; }); + } + } + + function registerTeardown(fn) { + if (template && typeof fn === "function") { + teardowns.push(fn); + } + } + + var template = ASQ().duplicate(), + teardowns = [], paused = false + ; + + // add reactive sequence kill switch + template.stop = function $$stop() { + if (template) { + template = null; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.pause = function $$pause() { + if (!paused && template) { + paused = true; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.resume = function $$resume() { + if (paused && template) { + paused = false; + reactor.call(template,next,registerTeardown); + } + }; + + template.push = next; + + next.onStream = function $$onStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.on("data",next); + stream.on("error",next); + }); + }; + + next.unStream = function $$unStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.removeListener("data",next); + stream.removeListener("error",next); + }); + }; + + // make sure `reactor(..)` is called async + ASQ.__schedule(function $$schedule(){ + reactor.call(template,next,registerTeardown); + }); + + return template; +}; +// "react" helpers +(function IIFE(){ + + var Ar = ASQ.react; + + Ar.of = function $$react$of() { + function reactor(next) { + if (!started) { + started = true; + if (args.length > 0) { + args.shift().val(function val(){ + next.apply(ø,arguments); + if (args.length > 0) { + args.shift().val(val); + } + }); + } + } + } + + var started, args = ARRAY_SLICE.call(arguments) + .map(function wrapper(arg){ + if (!ASQ.isSequence(arg)) arg = ASQ(arg); + return arg; + }); + + return Ar(reactor); + }; + + Ar.all = Ar.zip = makeReactOperator(/*buffer=*/true); + Ar.allLatest = makeReactOperator(/*buffer=false*/); + Ar.latest = Ar.combineLatest = makeReactOperator(/*buffer=*/false,/*keep=*/true); + + Ar.any = Ar.merge = function $$react$any(){ + function reactor(next,registerTeardown){ + function processSequence(def){ + function trigger(){ + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // fire off reactive sequence instance + next.apply(ø,args); + } + // keep sequence going + return args; + } + + // sequence-stream event listener + def.seq.val(trigger); + } + + // observe all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = null; + }); + } + + // observe all sequence-streams + var seqs = tapSequences.apply(null,arguments); + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + + Ar.distinct = function $$react$distinct(seq){ + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/true)); + }; + + Ar.distinctConsecutive = Ar.distinctUntilChanged = function $$react$distinct$consecutive(seq) { + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/false)); + }; + + Ar.filter = function $$react$filter(seq,filterer){ + function reactor(next,registerTeardown) { + function trigger(){ + var messages = ASQ.messages.apply(ø,arguments); + + if (filterer && filterer.apply(ø,messages)) { + // fire off reactive sequence instance + next.apply(ø,messages); + } + + // keep sequence going + return messages; + } + + // sequence-stream event listener + def.seq.val(trigger); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + def = filterer = null; + }); + } + + // observe sequence-stream + var def = tapSequences(seq)[0]; + + if (!def) return; + + return Ar(reactor); + }; + + Ar.fromObservable = function $$react$from$observable(obsv){ + function reactor(next,registerTeardown){ + // process buffer (if any) + buffer.forEach(next); + buffer.length = 0; + + // start non-buffered notifications? + if (!buffer.complete) { + notify = next; + } + + registerTeardown(function $$teardown(){ + obsv.dispose(); + }); + } + + function notify(v) { + buffer.push(v); + } + + var buffer = []; + + obsv.subscribe( + function $$on$next(v){ + notify(v); + }, + function $$on$error(){}, + function $$on$complete(){ + buffer.complete = true; + obsv.dispose(); + } + ); + + return Ar(reactor); + }; + + ASQ.extend("toObservable",function $$extend(api,internals){ + return function $$to$observable(){ + function init(observer) { + function define(pair){ + function listen(){ + var args = ASQ.messages.apply(ø,arguments); + observer[pair[1]].apply(observer, + args.length == 1 ? [args[0]] : args + ); + return args; + } + + api[pair[0]](listen); + } + + [["val","onNext"],["or","onError"]] + .forEach(define); + } + + return Rx.Observable.create(init); + }; + }); + + function tapSequences() { + function tapSequence(seq) { + // temporary `trigger` which, if called before being replaced + // below, creates replacement proxy sequence with the + // event message(s) re-fired + function trigger() { + var args = ARRAY_SLICE.call(arguments); + def.seq = Ar(function $$react(next){ + next.apply(ø,args); + }); + } + + if (ASQ.isSequence(seq)) { + var def = { seq: seq }; + + // listen for events from the sequence-stream + seq.val(function $$val(){ + trigger.apply(ø,arguments); + return ASQ.messages.apply(ø,arguments); + }); + + // make a reactive sequence to act as a proxy to the original + // sequence + def.seq = Ar(function $$react(next){ + // replace the temporary trigger (created above) + // with this proxy's trigger + trigger = next; + }); + + return def; + } + } + + return ARRAY_SLICE.call(arguments) + .map(tapSequence) + .filter(Boolean); + } + + function makeReactOperator(buffer,keep) { + return function $$react$operator(){ + function reactor(next,registerTeardown){ + function processSequence(def) { + // sequence-stream event listener + function trigger() { + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // store event message(s), if any + seq_events[seq_id] = + (buffer ? seq_events[seq_id] : []).concat( + args.length > 0 ? (args.length > 1 ? [args] : args[0]) : undefined + ); + + // collect event message(s) across the + // sequence-stream sources + var messages = seq_events.reduce(function reducer(msgs,eventList,idx){ + if (eventList.length > 0) msgs.push(eventList[0]); + return msgs; + },[]); + + // did all sequence-streams get an event? + if (messages.length == seq_events.length) { + if (messages.length == 1) messages = messages[0]; + + // fire off reactive sequence instance + next.apply(ø,messages); + + // discard stored event message(s)? + if (!keep) { + seq_events.forEach(function $$each(eventList){ + eventList.shift(); + }); + } + } + } + // keep sequence going + return args; + } + + var seq_id = seq_events.length; + seq_events.push([]); + def.seq.val(trigger); + } + + // process all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = seq_events = null; + }); + } + + var seq_events = [], + // observe all sequence-streams + seqs = tapSequences.apply(null,arguments) + ; + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + } + + function makeDistinctFilterer(keepAll) { + function filterer() { + function isDuplicate(msgSet) { + return ( + msgSet.length == message_set.length && + msgSet.every(function $$every(val,idx){ + return val === message_set[idx]; + }) + ); + } + + var message_set = ASQ.messages.apply(ø,arguments); + + // any messages in message-set to check against? + if (message_set.length > 0) { + // duplicate message-set? + if (msg_sets.some(isDuplicate)) { + return false; + } + + // remember all message-sets for future distinct checking? + if (keepAll) { + msg_sets.push(message_set); + } + // only keep the last message-set for distinct-consecutive + // checking + else { + msg_sets[0] = message_set; + } + } + + // allow distinct non-duplicate value through + return true; + } + + var msg_sets = []; + + return filterer; + } + +})(); +// "runner" +ASQ.extend("runner",function $$extend(api,internals){ + + return function $$runner() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var args = ARRAY_SLICE.call(arguments); + + api + .then(function $$then(mainDone){ + + function wrap(v) { + // function? expected to produce an iterator + // (like a generator) or a promise + if (typeof v === "function") { + // call function passing in the control token + // note: neutralize `this` in call to prevent + // unexpected behavior + v = v.call(ø,token); + + // promise returned (ie, from async function)? + if (isPromise(v)) { + // wrap it in iterable sequence + v = ASQ.iterable(v); + } + } + // an iterable sequence? duplicate it (in case of multiple runs) + else if (ASQ.isSequence(v) && "next" in v) { + v = v.duplicate(); + } + // wrap anything else in iterable sequence + else { + v = ASQ.iterable(v); + } + + // a sequence to tap for errors? + if (ASQ.isSequence(v)) { + // listen for any sequence failures + v.or(function $$or(){ + // signal iteration-error + mainDone.fail.apply(ø,arguments); + }); + } + + return v; + } + + function addWrapped() { + iterators.push.apply( + iterators, + ARRAY_SLICE.call(arguments).map(wrap) + ); + } + + function iterateOrQuit(iterFn,now) { + // still have some co-routine runs to process? + if (iterators.length > 0) { + if (now) iterFn(); + else schedule(iterFn); + } + // all done! + else { + // previous value message? + if (typeof next_val !== "undefined") { + // not a message wrapper array? + if (!ASQ.isMessageWrapper(next_val)) { + // wrap value for the subsequent `apply(..)` + next_val = [next_val]; + } + } + else { + // nothing to affirmatively pass along + next_val = []; + } + + // signal done with all co-routine runs + mainDone.apply(ø,next_val); + } + } + + var iterators = args, + token = { + messages: ARRAY_SLICE.call(arguments,1), + add: addWrapped + }, + iter, ret, next_val = token + ; + + // map co-routines to round-robin list of iterators + iterators = iterators.map(wrap); + + // async iteration of round-robin list + (function iterate(){ + // get next co-routine in list + iter = iterators.shift(); + + // process the iteration + try { + // multiple messages to send to an iterable + // sequence? + if (ASQ.isMessageWrapper(next_val) && + ASQ.isSequence(iter) + ) { + ret = iter.next.apply(iter,next_val); + } + else { + ret = iter.next(next_val); + } + } + catch (err) { + return mainDone.fail(err); + } + + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + // was the control token yielded? + if (ret.value === token) { + // round-robin: put co-routine back into the list + // at the end where it was so it can be processed + // again on next loop-iteration + if (!ret.done) { + iterators.push(iter); + } + next_val = token; + iterateOrQuit(iterate,/*now=*/false); + } + else { + // not a recognized ASQ instance returned? + if (!ASQ.isSequence(ret.value)) { + // received a thenable/promise back? + if (isPromise(ret.value)) { + // wrap in a sequence + ret.value = ASQ().promise(ret.value); + } + // thunk yielded? + else if (typeof ret.value === "function") { + // wrap thunk call in a sequence + var fn = ret.value; + ret.value = ASQ(function $$ASQ(done){ + fn(done.errfcb); + }); + } + // message wrapper returned? + else if (ASQ.isMessageWrapper(ret.value)) { + // wrap message(s) in a sequence + ret.value = ASQ.apply(ø, + // don't let `apply(..)` discard an empty message + // wrapper! instead, pass it along as its own value + // itself. + ret.value.length > 0 ? ret.value : ASQ.messages(undefined) + ); + } + // non-undefined value returned? + else if (typeof ret.value !== "undefined") { + // wrap the value in a sequence + ret.value = ASQ(ret.value); + } + else { + // make an empty sequence + ret.value = ASQ(); + } + } + + ret.value + .val(function $$val(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + if (arguments.length > 0) { + // save any return messages for input + // to next iteration + next_val = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + } + + // still more to iterate? + if (!ret.done) { + // was the control token passed along? + if (next_val === token) { + // round-robin: put co-routine back into the list + // at the end, so that the the next iterator can be + // processed on next loop-iteration + iterators.push(iter); + } + else { + // put co-routine back in where it just + // was so it can be processed again on + // next loop-iteration + iterators.unshift(iter); + } + } + + iterateOrQuit(iterate,/*now=*/true); + }) + .or(function $$or(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + try { + // if an error occurs in the step-continuation + // promise or sequence, throw it back into the + // generator or iterable-sequence + iter["throw"].apply(iter,arguments); + } + catch (err) { + // if an error comes back out of after the throw, + // pass it out to the main sequence, as iteration + // must now be complete + mainDone.fail(err); + } + }); + } + })(); + }); + + return api; + }; +}); +// "toPromise" +ASQ.extend("toPromise",function $$extend(api,internals){ + return function $$to$promise() { + return new Promise(function $$executor(resolve,reject){ + api + .val(function $$val(){ + var args = ARRAY_SLICE.call(arguments); + resolve.call(ø,args.length > 1 ? args : args[0]); + return ASQ.messages.apply(ø,args); + }) + .or(function $$or(){ + var args = ARRAY_SLICE.call(arguments); + reject.call(ø,args.length > 1 ? args : args[0]); + }); + }); + }; +}); +// "try" +ASQ.extend("try",function $$extend(api,internals){ + return function $$try() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + fn.apply(ø,arguments); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + var msgs = ASQ.messages.apply(ø,arguments); + // failed, so map error(s) as `catch` + mainDone({ + "catch": msgs.length > 1 ? msgs : msgs[0] + }); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "until" +ASQ.extend("until",function $$extend(api,internals){ + return function $$until() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + var args = ARRAY_SLICE.call(arguments); + args[0]["break"] = function $$break(){ + mainDone.fail.apply(ø,arguments); + sq.abort(); + }; + + fn.apply(ø,args); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + // failed, retry + $$then.apply(ø,main_args); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "waterfall" +ASQ.extend("waterfall",function $$extend(api,internals){ + return function $$waterfall() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + var msgs = ASQ.messages(), + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + fns.forEach(function $$each(fn){ + sq.then(fn) + .val(function $$val(){ + var args = ASQ.messages.apply(ø,arguments); + msgs.push(args.length > 1 ? args : args[0]); + return msgs; + }); + }); + + sq.pipe(done); + }); + + return api; + }; +}); +// "wrap" +ASQ.wrap = function $$wrap(fn,opts) { + function checkThis(t,o) { + return (!t || + (typeof window != "undefined" && t === window) || + (typeof global != "undefined" && t === global) + ) ? o : t; + } + + function paramSpread(gen) { + return function *paramSpread(token) { + yield *gen.apply(this,token.messages); + }; + } + + var errfcb, params_first, act, this_obj; + + opts = (opts && typeof opts == "object") ? opts : {}; + + if ( + (opts.errfcb && opts.splitcb) || + (opts.errfcb && opts.simplecb) || + (opts.splitcb && opts.simplecb) || + ("errfcb" in opts && !opts.errfcb && !opts.splitcb && !opts.simplecb) || + (opts.params_first && opts.params_last) || + (opts.spread && !opts.gen) + ) { + throw Error("Invalid options"); + } + + // initialize default flags + this_obj = (opts["this"] && typeof opts["this"] == "object") ? opts["this"] : ø; + errfcb = opts.errfcb || !(opts.splitcb || opts.simplecb); + params_first = !!opts.params_first || + (!opts.params_last && !("params_first" in opts || opts.params_first)) || + ("params_last" in opts && !opts.params_first && !opts.params_last) + ; + + if (params_first) { + act = "push"; + } + else { + act = "unshift"; + } + + if (opts.gen) { + if (opts.spread) { + fn = paramSpread(fn); + } + return function $$wrapped$gen() { + return ASQ.apply(ø,arguments).runner(fn); + }; + } + if (errfcb) { + return function $$wrapped$errfcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done.errfcb); + fn.apply(_this,args); + }); + }; + } + if (opts.splitcb) { + return function $$wrapped$splitcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done,done.fail); + fn.apply(_this,args); + }); + }; + } + if (opts.simplecb) { + return function $$wrapped$simplecb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done); + fn.apply(_this,args); + }); + }; + } +}; + + + // just return `ASQ` itself for convenience sake + return ASQ; +}); diff --git a/async/exercises/ex5/ex5.html b/async/exercises/ex5/ex5.html new file mode 100755 index 0000000..04171dd --- /dev/null +++ b/async/exercises/ex5/ex5.html @@ -0,0 +1,14 @@ + + + + +Exercise 5 + + +

Exercise 5

+ + + + + + diff --git a/async/exercises/ex5/ex5.js b/async/exercises/ex5/ex5.js new file mode 100755 index 0000000..361b423 --- /dev/null +++ b/async/exercises/ex5/ex5.js @@ -0,0 +1,39 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** +//Using ASQ for this exercise +var getFile = ASQ.wrap(fakeAjax, { simplecb: true }); + +function getFile(file) { + return ASQ(function(done){ + fakeAjax(file,done); + }); +} + + +getFile("file1") +.val(output) +.seq(getFile("file2")) +.val(output) +.seq(getFile("file3")) +.val(output) +.val(function functionName() { + output("complete") +}); diff --git a/async/exercises/ex6/README.md b/async/exercises/ex6/README.md new file mode 100755 index 0000000..476a277 --- /dev/null +++ b/async/exercises/ex6/README.md @@ -0,0 +1,9 @@ +# Instructions + +1. You'll do the same thing as the previous exercise(s), but now you should use map/reduce, asynquence, and an array of files. + +2. Expected behavior: + - Request all 3 files at the same time (in "parallel"). + - Render them ASAP (don't just blindly wait for all to finish loading) + - BUT, render them in proper (obvious) order: "file1", "file2", "file3". + - After all 3 are done, output "Complete!". diff --git a/async/exercises/ex6/asq.bundle.js b/async/exercises/ex6/asq.bundle.js new file mode 100755 index 0000000..93c9ada --- /dev/null +++ b/async/exercises/ex6/asq.bundle.js @@ -0,0 +1,2333 @@ +/*! asynquence + v0.8.2 (c) Kyle Simpson + MIT License: http://getify.mit-license.org +*/ +!function UMD(e,n,t){"function"==typeof define&&define.amd?define(t):"undefined"!=typeof module&&module.exports?module.exports=t():n[e]=t(e,n)}("ASQ",this,function DEF(e,n){"use strict";function Queue(){function Item(e){this.fn=e,this.next=void 0}var e,n,r;return{add:function $$add(t){r=new Item(t),n?n.next=r:e=r,n=r,r=void 0},drain:function $$drain(){var r=e;for(e=n=t=null;r;)r.fn(),r=r.next}}}function schedule(e){r.add(e),t||(t=u(r.drain))}function tapSequence(e){function trigger(){e.seq=createSequence.apply(h,arguments).defer()}trigger.fail=function $$trigger$fail(){var n=f.call(arguments);e.seq=createSequence(function $$create$sequence(e){e.fail.apply(h,n)}).defer()},e.seq.val(function $$val(){return trigger.apply(h,arguments),c.apply(h,arguments)}).or(function $$or(){trigger.fail.apply(h,arguments)}),e.seq=createSequence(function $$create$sequence(e){trigger=e}).defer()}function createSequence(){function scheduleSequenceTick(){r?sequenceTick():e||(e=schedule(sequenceTick))}function throwSequenceErrors(){throw 1===$.length?$[0]:$}function sequenceTick(){var a,c;if(e=null,delete d.unpause,r)clearTimeout(e),e=null,s.length=p.length=g.length=$.length=0;else if(n)for(0!==p.length||t||(t=!0,throwSequenceErrors());p.length;){t=!0,a=p.shift();try{a.apply(h,$)}catch(i){l(i)?$=$.concat(i):($.push(i),i.stack&&$.push(i.stack)),0===p.length&&throwSequenceErrors()}}else if(u&&s.length>0){u=!1,a=s.shift(),c=g.slice(),g.length=0,c.unshift(createStepCompletion());try{a.apply(h,c)}catch(i){l(i)?$=$.concat(i):$.push(i),n=!0,scheduleSequenceTick()}}}function createStepCompletion(){function done(){n||r||u||(u=!0,g.push.apply(g,arguments),$.length=0,scheduleSequenceTick())}return done.fail=function $$step$fail(){n||r||u||(n=!0,g.length=0,$.push.apply($,arguments),scheduleSequenceTick())},done.abort=function $$step$abort(){n||r||(u=!1,r=!0,g.length=$.length=0,scheduleSequenceTick())},done.errfcb=function $$step$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},done}function createGate(e,t,u){function resetGate(){clearTimeout(s),s=d=m=o=null}function scheduleGateTick(){return g?gateTick():void(s||(s=schedule(gateTick)))}function gateTick(){if(!(n||r||$)){var t=[];s=null,p?(e.fail.apply(h,o),resetGate()):g?(e.abort(),resetGate()):checkGate()&&($=!0,d.forEach(function $$each(e,n){t.push(m["s"+n])}),e.apply(h,t),resetGate())}}function checkGate(){if(0!==d.length){var e=!0;return d.some(function $$some(n){return null===n?(e=!1,!0):void 0}),e}}function createSegmentCompletion(){function done(){if(!(n||r||p||g||$||d[e])){var t=c.apply(h,arguments);m["s"+e]=t.length>1?t:t[0],d[e]=!0,scheduleGateTick()}}var e=d.length;return done.fail=function $$segment$fail(){n||r||p||g||$||d[e]||(p=!0,o=f.call(arguments),scheduleGateTick())},done.abort=function $$segment$abort(){n||r||p||g||$||(g=!0,gateTick())},done.errfcb=function $$segment$errfcb(e){e?done.fail(e):done.apply(h,f.call(arguments,1))},d[e]=null,done}var a,i,o,s,p=!1,g=!1,$=!1,d=[],m={};t.some(function $$some(e){if(p||g)return!0;a=u.slice(),a.unshift(createSegmentCompletion());try{e.apply(h,a)}catch(n){return i=n,p=!0,!0}}),i&&(l(i)?e.fail.apply(h,i):e.fail(i))}function then(){return n||r||0===arguments.length?d:(wrapArgs(arguments,thenWrapper).forEach(function $$each(e){i(e)?seq(e):s.push(e)}),scheduleSequenceTick(),d)}function or(){return r||0===arguments.length?d:(p.push.apply(p,arguments),scheduleSequenceTick(),d)}function gate(){if(n||r||0===arguments.length)return d;var e=f.call(arguments).map(function $$map(e){var n;return i(e)?(n={seq:e},tapSequence(n),function $$segment(e){n.seq.pipe(e)}):e});return then(function $$then(n){var t=f.call(arguments,1);createGate(n,e,t)}),d}function pipe(){return r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){e.apply(h,f.call(arguments,1)),n()}).or(e.fail)}),d)}function seq(){return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){var n={seq:e};i(e)&&tapSequence(n),then(function $$then(e){var t=n.seq;i(t)||(t=n.seq.apply(h,f.call(arguments,1))),t.pipe(e)})}),d)}function val(){return n||r||0===arguments.length?d:(f.call(wrapArgs(arguments,valWrapper)).forEach(function $$each(e){then(function $$then(n){var t=e.apply(h,f.call(arguments,1));l(t)||(t=c(t)),n.apply(h,t)})}),d)}function promise(){function wrap(e){return function $$fn(){e.apply(h,l(arguments[0])?arguments[0]:arguments)}}return n||r||0===arguments.length?d:(f.call(arguments).forEach(function $$each(e){then(function $$then(n){var t=e;"function"==typeof e&&"function"!=typeof e.then&&(t=e.apply(h,f.call(arguments,1))),t.then(wrap(n),wrap(n.fail))})}),d)}function fork(){var e;return val(function $$val(){return e?e.apply(h,arguments):e=createSequence.apply(h,arguments).defer(),c.apply(h,arguments)}),or(function $$or(){if(e)e.fail.apply(h,arguments);else{var n=f.call(arguments);e=createSequence().then(function $$then(e){e.fail.apply(h,n)}).defer()}}),createSequence().then(function $$then(n){e?e.pipe(n):e=n}).defer()}function abort(){return n?d:(r=!0,sequenceTick(),d)}function duplicate(){var e;return a={then_queue:s.slice(),or_queue:p.slice()},e=createSequence(),a=null,e}function unpause(){g.push.apply(g,arguments),e===!0&&(e=null),scheduleSequenceTick()}function defer(){return p.push(function ignored(){}),d}function internals(e,t){var a=arguments.length>1;switch(e){case"seq_error":if(!a)return n;n=t;break;case"seq_aborted":if(!a)return r;r=t;break;case"then_ready":if(!a)return u;u=t;break;case"then_queue":return s;case"or_queue":return p;case"sequence_messages":return g;case"sequence_errors":return $}}function includeExtensions(){Object.keys(o).forEach(function $$each(e){d[e]=o[e](d,internals)})}var e,n=!1,t=!1,r=!1,u=!0,s=[],p=[],g=[],$=[],d=brandIt({then:then,or:or,onerror:or,gate:gate,all:gate,pipe:pipe,seq:seq,val:val,promise:promise,fork:fork,abort:abort,duplicate:duplicate,defer:defer});return includeExtensions(),a&&(s=a.then_queue.slice(),p=a.or_queue.slice(),d.unpause=unpause,e=!0),d.then.apply(h,arguments),d}function brandIt(e){return Object.defineProperty(e,p,{enumerable:!1,value:!0})}function checkBranding(e){return!(null==e||"object"!=typeof e||!e[p])}function valWrapper(e){return c.apply(h,f.call(arguments).slice(1,e+1))}function thenWrapper(e){arguments[e+1].apply(h,f.call(arguments).slice(1,e+1))}function wrapArgs(e,n){var t,r;for(e=f.call(e),t=0;t 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + var args = orig_args || ARRAY_SLICE.call(arguments,1); + + setTimeout(function $$set$timeout(){ + done.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.after = function $$after() { + return ASQ().after.apply(ø,arguments); +}; +// "any" +ASQ.extend("any",function $$extend(api,internals){ + return function $$any() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as success + success_messages.length = fns.length; + trigger.apply(ø,success_messages); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + success_messages = [], + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "errfcb" +ASQ.extend("errfcb",function $$extend(api,internals){ + return function $$errfcb() { + // create a fake sequence to extract the callbacks + var sq = { + val: function $$then(cb){ sq.val_cb = cb; return sq; }, + or: function $$or(cb){ sq.or_cb = cb; return sq; } + }; + + // trick `seq(..)`s checks for a sequence + sq[brand] = true; + + // immediately register our fake sequence on the + // main sequence + api.seq(sq); + + // provide the "error-first" callback + return function $$errorfirst$callback(err) { + if (err) { + sq.or_cb(err); + } + else { + sq.val_cb.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }; + }; +}); +// "failAfter" +ASQ.extend("failAfter",function $$extend(api,internals){ + return function $$failAfter(num) { + var args = arguments.length > 1 ? + ARRAY_SLICE.call(arguments,1) : + void 0 + ; + num = +num || 0; + + api.then(function $$then(done){ + setTimeout(function $$set$timeout(){ + done.fail.apply(ø,args); + },num); + }); + + return api; + }; +}); + +ASQ.failAfter = function $$fail$after() { + return ASQ().failAfter.apply(ø,arguments); +}; +// "first" +ASQ.extend("first",function $$extend(api,internals){ + return function $$first() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + error_messages.length = 0; + } + + function success(trigger,idx,args) { + if (!finished) { + finished = true; + + // first successful segment triggers + // main sequence to proceed as success + trigger( + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ); + + reset(); + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete without success? + if (completed === fns.length) { + finished = true; + + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + + reset(); + } + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "go-style CSP" +(function IIFE(){ + + // filter out already-resolved queue entries + function filterResolved(queue) { + return queue.filter(function $$filter(entry){ + return !entry.resolved; + }); + } + + function closeQueue(queue,finalValue) { + queue.forEach(function $$each(iter){ + if (!iter.resolved) { + iter.next(); + iter.next(finalValue); + } + }); + queue.length = 0; + } + + function channel(bufSize) { + var ch = { + close: function $$close(){ + ch.closed = true; + closeQueue(ch.put_queue,false); + closeQueue(ch.take_queue,ASQ.csp.CLOSED); + }, + closed: false, + messages: [], + put_queue: [], + take_queue: [], + buffer_size: +bufSize || 0 + }; + return ch; + } + + function unblock(iter) { + if (iter && !iter.resolved) { + iter.next(iter.next().value); + } + } + + function put(channel,value) { + var ret; + + if (channel.closed) { + return false; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate put? + if (channel.messages.length < channel.buffer_size) { + channel.messages.push(value); + unblock(channel.take_queue.shift()); + return true; + } + // queued put + else { + channel.put_queue.push( + // make a notifiable iterable for 'put' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + channel.messages.push(value); + return true; + } + else { + return false; + } + }) + ); + + // wrap a sequence/promise around the iterable + ret = ASQ( + channel.put_queue[channel.put_queue.length - 1] + ); + + // take waiting on this queued put? + if (channel.take_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return ret; + } + } + + function putAsync(channel,value,cb) { + var ret = ASQ(put(channel,value)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function take(channel) { + var ret; + + try { + ret = takem(channel); + } + catch (err) { + ret = err; + } + + if (ASQ.isSequence(ret)) { + ret.pCatch(function $$pcatch(err){ + return err; + }); + } + + return ret; + } + + function takeAsync(channel,cb) { + var ret = ASQ(take(channel)); + + if (cb && typeof cb == "function") { + ret.val(cb); + } + else { + return ret; + } + } + + function takem(channel) { + var msg; + + if (channel.closed) { + return ASQ.csp.CLOSED; + } + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + // immediate take? + if (channel.messages.length > 0) { + msg = channel.messages.shift(); + unblock(channel.put_queue.shift()); + if (msg instanceof Error) { + throw msg; + } + return msg; + } + // queued take + else { + channel.take_queue.push( + // make a notifiable iterable for 'take' blocking + ASQ.iterable() + .then(function $$then(){ + if (!channel.closed) { + var v = channel.messages.shift(); + if (v instanceof Error) { + throw v; + } + return v; + } + else { + return ASQ.csp.CLOSED; + } + }) + ); + + // wrap a sequence/promise around the iterable + msg = ASQ( + channel.take_queue[channel.take_queue.length - 1] + ); + + // put waiting on this take? + if (channel.put_queue.length > 0) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + + return msg; + } + } + + function takemAsync(channel,cb) { + var ret = ASQ(takem(channel)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret.val(function $$val(v){ + if (v instanceof Error) { + throw v; + } + return v; + }); + } + } + + function alts(actions) { + var closed, open, handlers, i, isq, ret, resolved = false; + + // used `alts(..)` incorrectly? + if (!Array.isArray(actions) || actions.length == 0) { + throw Error("Invalid usage"); + } + + closed = []; + open = []; + handlers = []; + + // separate actions by open/closed channel status + actions.forEach(function $$each(action){ + var channel = Array.isArray(action) ? action[0] : action; + + // remove already-resolved entries + channel.put_queue = filterResolved(channel.put_queue); + channel.take_queue = filterResolved(channel.take_queue); + + if (channel.closed) { + closed.push(channel); + } + else { + open.push(action); + } + }); + + // if no channels are still open, we're done + if (open.length == 0) { + return { value: ASQ.csp.CLOSED, channel: closed }; + } + + // can any channel action be executed immediately? + for (i=0; i 0) { + return { value: take(open[i]), channel: open[i] }; + } + } + + isq = ASQ.iterable(); + var ret = ASQ(isq); + + // setup channel action handlers + for (i=0; i 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + },0); + } + } + // take action? + else { + channel = action; + + // define take handler + handlers.push( + ASQ.iterable() + .then(function $$then(){ + resolved = true; + + // mark all handlers across this `alts(..)` as resolved now + handlers = handlers.filter(function $$filter(handler){ + return !(handler.resolved = true); + }); + + // channel still open? + if (!channel.closed) { + isq.next({ value: channel.messages.shift(), channel: channel }); + } + // channel already closed? + else { + isq.next({ value: ASQ.csp.CLOSED, channel: channel }); + } + }) + ); + + // queue up take handler + channel.take_queue.push(handlers[handlers.length-1]); + + // put waiting on this queued take? + if (channel.put_queue.length > 0) { + schedule(function handleUnblocking(){ + if (!resolved) { + unblock(channel.put_queue.shift()); + unblock(channel.take_queue.shift()); + } + }); + } + } + })(open[i]); + } + + return ret; + } + + function altsAsync(chans,cb) { + var ret = ASQ(alts(chans)); + + if (cb && typeof cb == "function") { + ret.pThen(cb,cb); + } + else { + return ret; + } + } + + function timeout(delay) { + var ch = channel(); + setTimeout(ch.close,delay); + return ch; + } + + function go(gen,args) { + // goroutine arguments passed? + if (arguments.length > 1) { + if (!args || !Array.isArray(args)) { + args = [args]; + } + } + else { + args = []; + } + + return function *$$go(token) { + + // unblock the overall goroutine handling + function unblock() { + token.unblock_count++; + + if (token.block && !token.block.marked) { + token.block.marked = true; + token.block.next(); + } + } + + var ret, msg, err, type, done = false, it; + + // keep track of how many requests for unblocking + // have occurred + token.unblock_count = (token.unblock_count || 0); + + // keep track of how many goroutines are running + // so we can infer when we're done go'ing + token.go_count = (token.go_count || 0) + 1; + + // need to initialize a set of goroutines? + if (token.go_count === 1) { + // create a default channel for these goroutines + token.channel = channel(); + token.channel.messages = token.messages; + token.channel.go = function $$go(){ + // unblock the goroutine handling for this + // new goroutine + unblock(); + // add the goroutine (called with any args) to + // the handling queue + token.add( go.apply(ø,arguments) ); + }; + // starting out with initial channel messages? + if (token.channel.messages.length > 0) { + // fake back-pressure blocking for each + token.channel.put_queue = token.channel.messages.map(function $$map(){ + // make a notifiable iterable for 'put' blocking + return ASQ.iterable() + .then(function $$then(){ + unblock(token.channel.take_queue.shift()); + return !token.channel.closed; + }); + }); + } + } + + // initialize the generator + it = gen.apply(ø,[token.channel].concat(args)); + + (function iterate(){ + + function next() { + // keep going with next step in goroutine? + if (!done) { + iterate(); + } + // unblock overall goroutine handling to + // continue with other goroutines + else { + unblock(); + } + } + + // has a resumption value been achieved yet? + if (!ret) { + // try to resume the goroutine + try { + // resume with injected exception? + if (err) { + ret = it.throw(err); + err = null; + } + // resume normally + else { + ret = it.next(msg); + } + } + // resumption failed, so bail + catch (e) { + done = true; + err = e; + msg = null; + unblock(); + return; + } + + // keep track of the result of the resumption + done = ret.done; + ret = ret.value; + type = typeof ret; + + // if this goroutine is complete, unblock the + // overall goroutine handling + if (done) { + unblock(); + } + + // received a thenable/promise back? + if (isPromise(ret)) { + ret = ASQ().promise(ret); + } + + // wait for the value? + if (ASQ.isSequence(ret)) { + ret.val(function $$val(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + next(); + }) + .or(function $$or(){ + ret = null; + msg = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + if (msg instanceof Error) { + err = msg; + msg = null; + } + next(); + }); + } + // immediate value, prepare it to go right back in + else { + msg = ret; + ret = null; + next(); + } + } + })(); + + // keep this goroutine alive until completion + while (!done) { + // transfer control to another goroutine + yield token; + + // need to block overall goroutine handling + // while idle? + if (!done && !token.block && token.unblock_count === 0) { + // wait here while idle + yield (token.block = ASQ.iterable()); + + token.block = false; + } + + if (token.unblock_count > 0) token.unblock_count--; + } + + // this goroutine is done now + token.go_count--; + + // all goroutines done? + if (token.go_count === 0) { + // any lingering blocking need to be cleaned up? + unblock(); + + // capture any untaken messages + msg = ASQ.messages.apply(ø,token.messages); + + // need to implicitly force-close channel? + if (token.channel && !token.channel.closed) { + token.channel.closed = true; + token.channel.put_queue.length = token.channel.take_queue.length = 0; + token.channel.close = token.channel.go = token.channel.messages = null; + } + token.channel = null; + } + + // make sure leftover error or message are + // passed along + if (err) { + throw err; + } + else if (token.go_count === 0) { + return msg; + } + else { + return token; + } + }; + } + + ASQ.csp = { + chan: channel, + put: put, + putAsync: putAsync, + take: take, + takeAsync: takeAsync, + takem: takem, + takemAsync: takemAsync, + alts: alts, + altsAsync: altsAsync, + timeout: timeout, + go: go, + CLOSED: {} + }; + +})(); +// "ASQ.iterable()" +(function IIFE(){ + var template; + + ASQ.iterable = function $$iterable() { + function throwSequenceErrors() { + throw (sequence_errors.length === 1 ? sequence_errors[0] : sequence_errors); + } + + function notifyErrors() { + var fn; + + seq_tick = null; + + if (seq_error) { + if (or_queue.length === 0 && !error_reported) { + error_reported = true; + throwSequenceErrors(); + } + + while (or_queue.length > 0) { + error_reported = true; + fn = or_queue.shift(); + try { + fn.apply(ø,sequence_errors); + } + catch (err) { + if (checkBranding(err)) { + sequence_errors = sequence_errors.concat(err); + } + else { + sequence_errors.push(err); + } + if (or_queue.length === 0) { + throwSequenceErrors(); + } + } + } + } + } + + function val() { + if (seq_error || seq_aborted || arguments.length === 0) { + return sequence_api; + } + + var args = ARRAY_SLICE.call(arguments).map(function mapper(arg){ + if (typeof arg != "function") return function $$val() { return arg; }; + else return arg; + }); + + val_queue.push.apply(val_queue,args); + + return sequence_api; + } + + function or() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + or_queue.push.apply(or_queue,arguments); + + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function pipe() { + if (seq_aborted || arguments.length === 0) { + return sequence_api; + } + + ARRAY_SLICE.call(arguments) + .forEach(function $$each(fn){ + val(fn).or(fn.fail); + }); + + return sequence_api; + } + + function next() { + if (seq_error || seq_aborted || val_queue.length === 0) { + if (val_queue.length > 0) { + $throw$("Sequence cannot be iterated"); + } + return { done: true }; + } + + try { + return { value: val_queue.shift().apply(ø,arguments) }; + } + catch (err) { + if (ASQ.isMessageWrapper(err)) { + $throw$.apply(ø,err); + } + else { + $throw$(err); + } + + return {}; + } + } + + function $throw$() { + if (seq_error || seq_aborted) { + return sequence_api; + } + + sequence_errors.push.apply(sequence_errors,arguments); + seq_error = true; + if (!seq_tick) { + seq_tick = schedule(notifyErrors); + } + + return sequence_api; + } + + function $return$(val) { + if (seq_error || seq_aborted) { + val = void 0; + } + + abort(); + + return { done: true, value: val }; + } + + function abort() { + if (seq_error || seq_aborted) { + return; + } + + seq_aborted = true; + + clearTimeout(seq_tick); + seq_tick = null; + val_queue.length = or_queue.length = sequence_errors.length = 0; + } + + function duplicate() { + var isq; + + template = { + val_queue: val_queue.slice(), + or_queue: or_queue.slice() + }; + isq = ASQ.iterable(); + template = null; + + return isq; + } + + // opt-out of global error reporting for this sequence + function defer() { + or_queue.push(function $$ignored(){}); + return sequence_api; + } + + // *********************************************** + // Object branding utilities + // *********************************************** + function brandIt(obj) { + Object.defineProperty(obj,brand,{ + enumerable: false, + value: true + }); + + return obj; + } + + var sequence_api, + + seq_error = false, + error_reported = false, + seq_aborted = false, + + seq_tick, + + val_queue = [], + or_queue = [], + + sequence_errors = [] + ; + + // *********************************************** + // Setup the ASQ.iterable() public API + // *********************************************** + sequence_api = brandIt({ + val: val, + then: val, + or: or, + pipe: pipe, + next: next, + "throw": $throw$, + "return": $return$, + abort: abort, + duplicate: duplicate, + defer: defer + }); + + // useful for ES6 `for..of` loops, + // add `@@iterator` to simply hand back + // our iterable sequence itself! + sequence_api[(typeof Symbol == "function" && Symbol.iterator) || "@@iterator"] = function $$iter() { + return sequence_api; + }; + + // templating the iterable-sequence setup? + if (template) { + val_queue = template.val_queue.slice(0); + or_queue = template.or_queue.slice(0); + } + + // treat ASQ.iterable() constructor parameters as having been + // passed to `val()` + sequence_api.val.apply(ø,arguments); + + return sequence_api; + }; + +})(); +// "last" +ASQ.extend("last",function $$extend(api,internals){ + return function $$last() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages = null; + } + + function complete(trigger) { + if (success_messages != null) { + // last successful segment's message(s) sent + // to main sequence to proceed as success + trigger( + success_messages.length > 1 ? + ASQ.messages.apply(ø,success_messages) : + success_messages[0] + ); + } + else { + // send errors into main sequence + error_messages.length = fns.length; + trigger.fail.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages = args; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "map" +ASQ.extend("map",function $$extend(api,internals){ + return function $$map(pArr,pEach) { + if (internals("seq_error") || internals("seq_aborted")) { + return api; + } + + api.seq(function $$seq(){ + var tmp, args = ARRAY_SLICE.call(arguments), + arr = pArr, each = pEach; + + // if missing `map(..)` args, use value-messages (if any) + if (!each) each = args.shift(); + if (!arr) arr = args.shift(); + + // if arg types in reverse order (each,arr), swap + if (typeof arr === "function" && Array.isArray(each)) { + tmp = arr; + arr = each; + each = tmp; + } + + return ASQ.apply(ø,args) + .gate.apply(ø,arr.map(function $$map(item){ + return function $$segment(){ + each.apply(ø,[item].concat(ARRAY_SLICE.call(arguments))); + }; + })); + }) + .val(function $$val(){ + // collect all gate segment output into one value-message + // Note: return a normal array here, not a message wrapper! + return ARRAY_SLICE.call(arguments); + }); + + return api; + }; +}); +// "none" +ASQ.extend("none",function $$extend(api,internals){ + return function $$none() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + function reset() { + finished = true; + error_messages.length = 0; + success_messages.length = 0; + } + + function complete(trigger) { + if (success_messages.length > 0) { + // any successful segment's message(s) sent + // to main sequence to proceed as **error** + success_messages.length = fns.length; + trigger.fail.apply(ø,success_messages); + } + else { + // send errors as **success** to main sequence + error_messages.length = fns.length; + trigger.apply(ø,error_messages); + } + + reset(); + } + + function success(trigger,idx,args) { + if (!finished) { + completed++; + success_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + + // all segments complete? + if (completed === fns.length) { + finished = true; + + complete(trigger); + } + } + } + + function failure(trigger,idx,args) { + if (!finished && + !(idx in error_messages) + ) { + completed++; + error_messages[idx] = + args.length > 1 ? + ASQ.messages.apply(ø,args) : + args[0] + ; + } + + // all segments complete? + if (!finished && + completed === fns.length + ) { + finished = true; + + complete(trigger); + } + } + + var completed = 0, error_messages = [], finished = false, + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)), + success_messages = [] + ; + + wrapGate(sq,fns,success,failure,reset); + + sq.pipe(done); + }); + + return api; + }; +}); +// "pThen" +ASQ.extend("pThen",function $$extend(api,internals){ + return function $$pthen(success,failure) { + if (internals("seq_aborted")) { + return api; + } + + var ignore_success_handler = false, ignore_failure_handler = false; + + if (typeof success === "function") { + api.then(function $$then(done){ + if (!ignore_success_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments); + msgs.shift(); + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_failure_handler = true; + + try { + ret = success(msgs); + } + catch (err) { + if (!ASQ.isMessageWrapper(err)) { + err = [err]; + } + done.fail.apply(ø,err); + return; + } + + // returned a sequence? + if (ASQ.isSequence(ret)) { + ret.pipe(done); + } + // returned a message wrapper? + else if (ASQ.isMessageWrapper(ret)) { + done.apply(ø,ret); + } + // returned a promise/thenable? + else if (isPromise(ret)) { + ret.then(done,done.fail); + } + // just a normal value to pass along + else { + done(ret); + } + } + else { + done.apply(ø,ARRAY_SLICE.call(arguments,1)); + } + }); + } + if (typeof failure === "function") { + api.or(function $$or(){ + if (!ignore_failure_handler) { + var ret, msgs = ASQ.messages.apply(ø,arguments), smgs, + or_queue = ARRAY_SLICE.call(internals("or_queue")) + ; + + if (msgs.length === 1) { + msgs = msgs[0]; + } + + ignore_success_handler = true; + + // NOTE: if this call throws, that'll automatically + // be handled by core as we'd want it to be + ret = failure(msgs); + + // if we get this far: + // first, inject return value (if any) as + // next step's sequence messages + smgs = internals("sequence_messages"); + smgs.length = 0; + if (typeof ret !== "undefined") { + if (!ASQ.isMessageWrapper(ret)) { + ret = [ret]; + } + smgs.push.apply(smgs,ret); + } + + // reset internal error state, because we've exclusively + // handled any errors up to this point of the sequence + internals("sequence_errors").length = 0; + internals("seq_error",false); + internals("then_ready",true); + + // temporarily empty the or-queue + internals("or_queue").length = 0; + + // make sure to schedule success-procession on the chain + api.val(function $$val(){ + // pass thru messages + return ASQ.messages.apply(ø,arguments); + }); + + // at next cycle, reinstate the or-queue (if any) + if (or_queue.length > 0) { + schedule(function $$schedule(){ + api.or.apply(ø,or_queue); + }); + } + } + }); + } + return api; + }; +}); + +// "pCatch" +ASQ.extend("pCatch",function $$extend(api,internals){ + return function $$pcatch(failure) { + if (internals("seq_aborted")) { + return api; + } + + api.pThen(void 0,failure); + + return api; + }; +}); +// "race" +ASQ.extend("race",function $$extend(api,internals){ + return function $$race() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(v){ + var def; + // tap any directly-provided sequences immediately + if (ASQ.isSequence(v)) { + def = { seq: v }; + tapSequence(def); + return function $$fn(done) { + def.seq.pipe(done); + }; + } + else return v; + }); + + api.then(function $$then(done){ + var args = ARRAY_SLICE.call(arguments); + + fns.forEach(function $$each(fn){ + fn.apply(ø,args); + }); + }); + + return api; + }; +}); +// "react" (reactive sequences) +ASQ.react = function $$react(reactor) { + function next() { + if (!paused) { + if (template) { + var sq = template.duplicate(); + sq.unpause.apply(ø,arguments); + return sq; + } + return ASQ(function $$asq(){ throw "Disabled Sequence"; }); + } + } + + function registerTeardown(fn) { + if (template && typeof fn === "function") { + teardowns.push(fn); + } + } + + var template = ASQ().duplicate(), + teardowns = [], paused = false + ; + + // add reactive sequence kill switch + template.stop = function $$stop() { + if (template) { + template = null; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.pause = function $$pause() { + if (!paused && template) { + paused = true; + teardowns.forEach(Function.call,Function.call); + teardowns.length = 0; + } + }; + + template.resume = function $$resume() { + if (paused && template) { + paused = false; + reactor.call(template,next,registerTeardown); + } + }; + + template.push = next; + + next.onStream = function $$onStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.on("data",next); + stream.on("error",next); + }); + }; + + next.unStream = function $$unStream() { + ARRAY_SLICE.call(arguments) + .forEach(function $$each(stream){ + stream.removeListener("data",next); + stream.removeListener("error",next); + }); + }; + + // make sure `reactor(..)` is called async + ASQ.__schedule(function $$schedule(){ + reactor.call(template,next,registerTeardown); + }); + + return template; +}; +// "react" helpers +(function IIFE(){ + + var Ar = ASQ.react; + + Ar.of = function $$react$of() { + function reactor(next) { + if (!started) { + started = true; + if (args.length > 0) { + args.shift().val(function val(){ + next.apply(ø,arguments); + if (args.length > 0) { + args.shift().val(val); + } + }); + } + } + } + + var started, args = ARRAY_SLICE.call(arguments) + .map(function wrapper(arg){ + if (!ASQ.isSequence(arg)) arg = ASQ(arg); + return arg; + }); + + return Ar(reactor); + }; + + Ar.all = Ar.zip = makeReactOperator(/*buffer=*/true); + Ar.allLatest = makeReactOperator(/*buffer=false*/); + Ar.latest = Ar.combineLatest = makeReactOperator(/*buffer=*/false,/*keep=*/true); + + Ar.any = Ar.merge = function $$react$any(){ + function reactor(next,registerTeardown){ + function processSequence(def){ + function trigger(){ + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // fire off reactive sequence instance + next.apply(ø,args); + } + // keep sequence going + return args; + } + + // sequence-stream event listener + def.seq.val(trigger); + } + + // observe all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = null; + }); + } + + // observe all sequence-streams + var seqs = tapSequences.apply(null,arguments); + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + + Ar.distinct = function $$react$distinct(seq){ + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/true)); + }; + + Ar.distinctConsecutive = Ar.distinctUntilChanged = function $$react$distinct$consecutive(seq) { + return Ar.filter(seq,makeDistinctFilterer(/*keepAll=*/false)); + }; + + Ar.filter = function $$react$filter(seq,filterer){ + function reactor(next,registerTeardown) { + function trigger(){ + var messages = ASQ.messages.apply(ø,arguments); + + if (filterer && filterer.apply(ø,messages)) { + // fire off reactive sequence instance + next.apply(ø,messages); + } + + // keep sequence going + return messages; + } + + // sequence-stream event listener + def.seq.val(trigger); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + def = filterer = null; + }); + } + + // observe sequence-stream + var def = tapSequences(seq)[0]; + + if (!def) return; + + return Ar(reactor); + }; + + Ar.fromObservable = function $$react$from$observable(obsv){ + function reactor(next,registerTeardown){ + // process buffer (if any) + buffer.forEach(next); + buffer.length = 0; + + // start non-buffered notifications? + if (!buffer.complete) { + notify = next; + } + + registerTeardown(function $$teardown(){ + obsv.dispose(); + }); + } + + function notify(v) { + buffer.push(v); + } + + var buffer = []; + + obsv.subscribe( + function $$on$next(v){ + notify(v); + }, + function $$on$error(){}, + function $$on$complete(){ + buffer.complete = true; + obsv.dispose(); + } + ); + + return Ar(reactor); + }; + + ASQ.extend("toObservable",function $$extend(api,internals){ + return function $$to$observable(){ + function init(observer) { + function define(pair){ + function listen(){ + var args = ASQ.messages.apply(ø,arguments); + observer[pair[1]].apply(observer, + args.length == 1 ? [args[0]] : args + ); + return args; + } + + api[pair[0]](listen); + } + + [["val","onNext"],["or","onError"]] + .forEach(define); + } + + return Rx.Observable.create(init); + }; + }); + + function tapSequences() { + function tapSequence(seq) { + // temporary `trigger` which, if called before being replaced + // below, creates replacement proxy sequence with the + // event message(s) re-fired + function trigger() { + var args = ARRAY_SLICE.call(arguments); + def.seq = Ar(function $$react(next){ + next.apply(ø,args); + }); + } + + if (ASQ.isSequence(seq)) { + var def = { seq: seq }; + + // listen for events from the sequence-stream + seq.val(function $$val(){ + trigger.apply(ø,arguments); + return ASQ.messages.apply(ø,arguments); + }); + + // make a reactive sequence to act as a proxy to the original + // sequence + def.seq = Ar(function $$react(next){ + // replace the temporary trigger (created above) + // with this proxy's trigger + trigger = next; + }); + + return def; + } + } + + return ARRAY_SLICE.call(arguments) + .map(tapSequence) + .filter(Boolean); + } + + function makeReactOperator(buffer,keep) { + return function $$react$operator(){ + function reactor(next,registerTeardown){ + function processSequence(def) { + // sequence-stream event listener + function trigger() { + var args = ASQ.messages.apply(ø,arguments); + // still observing sequence-streams? + if (seqs && seqs.length > 0) { + // store event message(s), if any + seq_events[seq_id] = + (buffer ? seq_events[seq_id] : []).concat( + args.length > 0 ? (args.length > 1 ? [args] : args[0]) : undefined + ); + + // collect event message(s) across the + // sequence-stream sources + var messages = seq_events.reduce(function reducer(msgs,eventList,idx){ + if (eventList.length > 0) msgs.push(eventList[0]); + return msgs; + },[]); + + // did all sequence-streams get an event? + if (messages.length == seq_events.length) { + if (messages.length == 1) messages = messages[0]; + + // fire off reactive sequence instance + next.apply(ø,messages); + + // discard stored event message(s)? + if (!keep) { + seq_events.forEach(function $$each(eventList){ + eventList.shift(); + }); + } + } + } + // keep sequence going + return args; + } + + var seq_id = seq_events.length; + seq_events.push([]); + def.seq.val(trigger); + } + + // process all sequence-streams + seqs.forEach(processSequence); + + // listen for stop() of reactive sequence + registerTeardown(function $$teardown(){ + seqs = seq_events = null; + }); + } + + var seq_events = [], + // observe all sequence-streams + seqs = tapSequences.apply(null,arguments) + ; + + if (seqs.length == 0) return; + + return Ar(reactor); + }; + } + + function makeDistinctFilterer(keepAll) { + function filterer() { + function isDuplicate(msgSet) { + return ( + msgSet.length == message_set.length && + msgSet.every(function $$every(val,idx){ + return val === message_set[idx]; + }) + ); + } + + var message_set = ASQ.messages.apply(ø,arguments); + + // any messages in message-set to check against? + if (message_set.length > 0) { + // duplicate message-set? + if (msg_sets.some(isDuplicate)) { + return false; + } + + // remember all message-sets for future distinct checking? + if (keepAll) { + msg_sets.push(message_set); + } + // only keep the last message-set for distinct-consecutive + // checking + else { + msg_sets[0] = message_set; + } + } + + // allow distinct non-duplicate value through + return true; + } + + var msg_sets = []; + + return filterer; + } + +})(); +// "runner" +ASQ.extend("runner",function $$extend(api,internals){ + + return function $$runner() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var args = ARRAY_SLICE.call(arguments); + + api + .then(function $$then(mainDone){ + + function wrap(v) { + // function? expected to produce an iterator + // (like a generator) or a promise + if (typeof v === "function") { + // call function passing in the control token + // note: neutralize `this` in call to prevent + // unexpected behavior + v = v.call(ø,token); + + // promise returned (ie, from async function)? + if (isPromise(v)) { + // wrap it in iterable sequence + v = ASQ.iterable(v); + } + } + // an iterable sequence? duplicate it (in case of multiple runs) + else if (ASQ.isSequence(v) && "next" in v) { + v = v.duplicate(); + } + // wrap anything else in iterable sequence + else { + v = ASQ.iterable(v); + } + + // a sequence to tap for errors? + if (ASQ.isSequence(v)) { + // listen for any sequence failures + v.or(function $$or(){ + // signal iteration-error + mainDone.fail.apply(ø,arguments); + }); + } + + return v; + } + + function addWrapped() { + iterators.push.apply( + iterators, + ARRAY_SLICE.call(arguments).map(wrap) + ); + } + + function iterateOrQuit(iterFn,now) { + // still have some co-routine runs to process? + if (iterators.length > 0) { + if (now) iterFn(); + else schedule(iterFn); + } + // all done! + else { + // previous value message? + if (typeof next_val !== "undefined") { + // not a message wrapper array? + if (!ASQ.isMessageWrapper(next_val)) { + // wrap value for the subsequent `apply(..)` + next_val = [next_val]; + } + } + else { + // nothing to affirmatively pass along + next_val = []; + } + + // signal done with all co-routine runs + mainDone.apply(ø,next_val); + } + } + + var iterators = args, + token = { + messages: ARRAY_SLICE.call(arguments,1), + add: addWrapped + }, + iter, ret, next_val = token + ; + + // map co-routines to round-robin list of iterators + iterators = iterators.map(wrap); + + // async iteration of round-robin list + (function iterate(){ + // get next co-routine in list + iter = iterators.shift(); + + // process the iteration + try { + // multiple messages to send to an iterable + // sequence? + if (ASQ.isMessageWrapper(next_val) && + ASQ.isSequence(iter) + ) { + ret = iter.next.apply(iter,next_val); + } + else { + ret = iter.next(next_val); + } + } + catch (err) { + return mainDone.fail(err); + } + + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + // was the control token yielded? + if (ret.value === token) { + // round-robin: put co-routine back into the list + // at the end where it was so it can be processed + // again on next loop-iteration + if (!ret.done) { + iterators.push(iter); + } + next_val = token; + iterateOrQuit(iterate,/*now=*/false); + } + else { + // not a recognized ASQ instance returned? + if (!ASQ.isSequence(ret.value)) { + // received a thenable/promise back? + if (isPromise(ret.value)) { + // wrap in a sequence + ret.value = ASQ().promise(ret.value); + } + // thunk yielded? + else if (typeof ret.value === "function") { + // wrap thunk call in a sequence + var fn = ret.value; + ret.value = ASQ(function $$ASQ(done){ + fn(done.errfcb); + }); + } + // message wrapper returned? + else if (ASQ.isMessageWrapper(ret.value)) { + // wrap message(s) in a sequence + ret.value = ASQ.apply(ø, + // don't let `apply(..)` discard an empty message + // wrapper! instead, pass it along as its own value + // itself. + ret.value.length > 0 ? ret.value : ASQ.messages(undefined) + ); + } + // non-undefined value returned? + else if (typeof ret.value !== "undefined") { + // wrap the value in a sequence + ret.value = ASQ(ret.value); + } + else { + // make an empty sequence + ret.value = ASQ(); + } + } + + ret.value + .val(function $$val(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + if (arguments.length > 0) { + // save any return messages for input + // to next iteration + next_val = arguments.length > 1 ? + ASQ.messages.apply(ø,arguments) : + arguments[0] + ; + } + + // still more to iterate? + if (!ret.done) { + // was the control token passed along? + if (next_val === token) { + // round-robin: put co-routine back into the list + // at the end, so that the the next iterator can be + // processed on next loop-iteration + iterators.push(iter); + } + else { + // put co-routine back in where it just + // was so it can be processed again on + // next loop-iteration + iterators.unshift(iter); + } + } + + iterateOrQuit(iterate,/*now=*/true); + }) + .or(function $$or(){ + // bail on run in aborted sequence + if (internals("seq_aborted")) return; + + try { + // if an error occurs in the step-continuation + // promise or sequence, throw it back into the + // generator or iterable-sequence + iter["throw"].apply(iter,arguments); + } + catch (err) { + // if an error comes back out of after the throw, + // pass it out to the main sequence, as iteration + // must now be complete + mainDone.fail(err); + } + }); + } + })(); + }); + + return api; + }; +}); +// "toPromise" +ASQ.extend("toPromise",function $$extend(api,internals){ + return function $$to$promise() { + return new Promise(function $$executor(resolve,reject){ + api + .val(function $$val(){ + var args = ARRAY_SLICE.call(arguments); + resolve.call(ø,args.length > 1 ? args : args[0]); + return ASQ.messages.apply(ø,args); + }) + .or(function $$or(){ + var args = ARRAY_SLICE.call(arguments); + reject.call(ø,args.length > 1 ? args : args[0]); + }); + }); + }; +}); +// "try" +ASQ.extend("try",function $$extend(api,internals){ + return function $$try() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + fn.apply(ø,arguments); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + var msgs = ASQ.messages.apply(ø,arguments); + // failed, so map error(s) as `catch` + mainDone({ + "catch": msgs.length > 1 ? msgs : msgs[0] + }); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "until" +ASQ.extend("until",function $$extend(api,internals){ + return function $$until() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments) + .map(function $$map(fn){ + return function $$then(mainDone) { + var main_args = ARRAY_SLICE.call(arguments), + sq = ASQ.apply(ø,main_args.slice(1)) + ; + + sq + .then(function $$inner$then(){ + var args = ARRAY_SLICE.call(arguments); + args[0]["break"] = function $$break(){ + mainDone.fail.apply(ø,arguments); + sq.abort(); + }; + + fn.apply(ø,args); + }) + .val(function $$val(){ + mainDone.apply(ø,arguments); + }) + .or(function $$inner$or(){ + // failed, retry + $$then.apply(ø,main_args); + }); + }; + }); + + api.then.apply(ø,fns); + + return api; + }; +}); +// "waterfall" +ASQ.extend("waterfall",function $$extend(api,internals){ + return function $$waterfall() { + if (internals("seq_error") || internals("seq_aborted") || + arguments.length === 0 + ) { + return api; + } + + var fns = ARRAY_SLICE.call(arguments); + + api.then(function $$then(done){ + var msgs = ASQ.messages(), + sq = ASQ.apply(ø,ARRAY_SLICE.call(arguments,1)) + ; + + fns.forEach(function $$each(fn){ + sq.then(fn) + .val(function $$val(){ + var args = ASQ.messages.apply(ø,arguments); + msgs.push(args.length > 1 ? args : args[0]); + return msgs; + }); + }); + + sq.pipe(done); + }); + + return api; + }; +}); +// "wrap" +ASQ.wrap = function $$wrap(fn,opts) { + function checkThis(t,o) { + return (!t || + (typeof window != "undefined" && t === window) || + (typeof global != "undefined" && t === global) + ) ? o : t; + } + + function paramSpread(gen) { + return function *paramSpread(token) { + yield *gen.apply(this,token.messages); + }; + } + + var errfcb, params_first, act, this_obj; + + opts = (opts && typeof opts == "object") ? opts : {}; + + if ( + (opts.errfcb && opts.splitcb) || + (opts.errfcb && opts.simplecb) || + (opts.splitcb && opts.simplecb) || + ("errfcb" in opts && !opts.errfcb && !opts.splitcb && !opts.simplecb) || + (opts.params_first && opts.params_last) || + (opts.spread && !opts.gen) + ) { + throw Error("Invalid options"); + } + + // initialize default flags + this_obj = (opts["this"] && typeof opts["this"] == "object") ? opts["this"] : ø; + errfcb = opts.errfcb || !(opts.splitcb || opts.simplecb); + params_first = !!opts.params_first || + (!opts.params_last && !("params_first" in opts || opts.params_first)) || + ("params_last" in opts && !opts.params_first && !opts.params_last) + ; + + if (params_first) { + act = "push"; + } + else { + act = "unshift"; + } + + if (opts.gen) { + if (opts.spread) { + fn = paramSpread(fn); + } + return function $$wrapped$gen() { + return ASQ.apply(ø,arguments).runner(fn); + }; + } + if (errfcb) { + return function $$wrapped$errfcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done.errfcb); + fn.apply(_this,args); + }); + }; + } + if (opts.splitcb) { + return function $$wrapped$splitcb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done,done.fail); + fn.apply(_this,args); + }); + }; + } + if (opts.simplecb) { + return function $$wrapped$simplecb() { + var args = ARRAY_SLICE.call(arguments), + _this = checkThis(this,this_obj) + ; + + return ASQ(function $$asq(done){ + args[act](done); + fn.apply(_this,args); + }); + }; + } +}; + + + // just return `ASQ` itself for convenience sake + return ASQ; +}); diff --git a/async/exercises/ex6/ex6.html b/async/exercises/ex6/ex6.html new file mode 100755 index 0000000..2b24736 --- /dev/null +++ b/async/exercises/ex6/ex6.html @@ -0,0 +1,14 @@ + + + + +Exercise 6 + + +

Exercise 6

+ + + + + + diff --git a/async/exercises/ex6/ex6.js b/async/exercises/ex6/ex6.js new file mode 100755 index 0000000..676a0ea --- /dev/null +++ b/async/exercises/ex6/ex6.js @@ -0,0 +1,40 @@ +function fakeAjax(url,cb) { + var fake_responses = { + "file1": "The first text", + "file2": "The middle text", + "file3": "The last text" + }; + var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000; + + console.log("Requesting: " + url); + + setTimeout(function(){ + cb(fake_responses[url]); + },randomDelay); +} + +function output(text) { + console.log(text); +} + +// ************************************** + +function getFile(file) { + return ASQ(function(done){ + fakeAjax(file,done); + }); +} + +ASQ() +.seq( + ...["file1","file2","file3"] + .map(getFile) + .map(function(sq) { + return function () { + return sq.val(output); + } + }) +) +.val(function() { + output("complete") +}) diff --git a/async/slides.key b/async/slides.key new file mode 100755 index 0000000..6e812a9 Binary files /dev/null and b/async/slides.key differ diff --git a/async/slides.pdf b/async/slides.pdf new file mode 100755 index 0000000..f9e0f63 Binary files /dev/null and b/async/slides.pdf differ diff --git a/pg-promise-exercises/exercises.js b/pg-promise-exercises/exercises.js index c154c5b..3fb4df9 100644 --- a/pg-promise-exercises/exercises.js +++ b/pg-promise-exercises/exercises.js @@ -5,7 +5,7 @@ const postgresConfig = { host: 'localhost', port: 5432, database: 'pg-promise-exercises', - user: '', // replace this with your username + user: 'alexreany', // replace this with your username password: '' // replace this if you have set a password for your username (this is unlikely) }; diff --git a/pg-promise-exercises/schema.sql b/pg-promise-exercises/schema.sql index 4cdba1f..3bd96ee 100644 --- a/pg-promise-exercises/schema.sql +++ b/pg-promise-exercises/schema.sql @@ -19,364 +19,364 @@ CREATE TABLE "books" ( -- Name: "plpgsql_call_handler" () Type: FUNCTION Owner: postgres -- -CREATE FUNCTION "plpgsql_call_handler" () RETURNS opaque AS '/usr/local/pgsql/lib/plpgsql.so', 'plpgsql_call_handler' LANGUAGE 'C'; - --- --- TOC Entry ID 48 (OID 2991734) --- --- Name: plpgsql Type: PROCEDURAL LANGUAGE Owner: --- - -CREATE TRUSTED PROCEDURAL LANGUAGE 'plpgsql' HANDLER "plpgsql_call_handler" LANCOMPILER 'PL/pgSQL'; - --- --- TOC Entry ID 51 (OID 2991735) --- --- Name: "audit_bk" (integer) Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "audit_bk" (integer) RETURNS integer AS ' - DECLARE - key ALIAS FOR $1; - table_data inventory%ROWTYPE; - BEGIN - INSERT INTO inventory_audit SELECT table_data WHERE sort_key=key; - - IF NOT FOUND THEN - RAISE EXCEPTION ''View'' || key || '' not found ''; - END IF; - - return 1; -end; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 52 (OID 2991736) --- --- Name: "audit" (integer) Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "audit" (integer) RETURNS integer AS ' - DECLARE - key ALIAS FOR $1; - table_data inventory%ROWTYPE; - BEGIN - INSERT INTO inventory_audit SELECT table_data WHERE sort_key=key; - - IF NOT FOUND THEN - RAISE EXCEPTION ''View'' || key || '' not found ''; - END IF; - - return 1; -end; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 53 (OID 2991737) --- --- Name: "auditbk" () Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "auditbk" () RETURNS integer AS ' - DECLARE - key ALIAS FOR $1; - table_data inventory%ROWTYPE; - BEGIN - INSERT INTO inventory_audit SELECT table_data WHERE sort_key=key; - - IF NOT FOUND THEN - RAISE EXCEPTION ''View'' || key || '' not found ''; - END IF; - - return 1; -end; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 54 (OID 2991738) --- --- Name: "audit_bk1" () Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "audit_bk1" () RETURNS opaque AS ' - DECLARE - key ALIAS FOR $1; - table_data inventory%ROWTYPE; - BEGIN - INSERT INTO inventory_audit SELECT table_data WHERE sort_key=key; - - IF NOT FOUND THEN - RAISE EXCEPTION ''View'' || key || '' not found ''; - END IF; - - return 1; -end; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 73 (OID 2991835) --- --- Name: "test_check_a_id" () Type: FUNCTION Owner: example --- - -CREATE FUNCTION "test_check_a_id" () RETURNS opaque AS ' - BEGIN - -- checks to make sure the author id - -- inserted is not left blank or less than 100 - - IF NEW.a_id ISNULL THEN - RAISE EXCEPTION - ''The author id cannot be left blank!''; - ELSE - IF NEW.a_id < 100 THEN - RAISE EXCEPTION - ''Please insert a valid author id.''; - ELSE - RETURN NEW; - END IF; - END IF; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 66 (OID 2992619) --- --- Name: "audit_test" () Type: FUNCTION Owner: example --- - -CREATE FUNCTION "audit_test" () RETURNS opaque AS ' - BEGIN - - IF TG_OP = ''INSERT'' OR TG_OP = ''UPDATE'' THEN - - NEW.user_aud := current_user; - NEW.mod_time := ''NOW''; - - INSERT INTO inventory_audit SELECT * FROM inventory WHERE prod_id=NEW.prod_id; - - RETURN NEW; - - ELSE if TG_OP = ''DELETE'' THEN - INSERT INTO inventory_audit SELECT *, current_user, ''NOW'' FROM inventory WHERE prod_id=OLD.prod_id; - - RETURN OLD; - END IF; - END IF; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 67 (OID 3000878) --- --- Name: "first" () Type: FUNCTION Owner: example --- - -CREATE FUNCTION "first" () RETURNS integer AS ' - DecLarE - oNe IntEgER := 1; - bEGiN - ReTUrn oNE; - eNd; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 68 (OID 3000881) --- --- Name: "test" (integer) Type: FUNCTION Owner: example --- - -CREATE FUNCTION "test" (integer) RETURNS integer AS ' - - DECLARE - -- defines the variable as ALIAS - variable ALIAS FOR $1; - BEGIN - -- displays the variable after multiplying it by two - return variable * 2.0; - END; - ' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 69 (OID 3000991) --- --- Name: "you_me" (integer) Type: FUNCTION Owner: example --- - -CREATE FUNCTION "you_me" (integer) RETURNS integer AS ' - DECLARE - RENAME $1 TO user_no; - --you INTEGER := 5; - BEGIN - return user_no; - END;' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 62 (OID 3001136) --- --- Name: "count_by_two" (integer) Type: FUNCTION Owner: example --- - -CREATE FUNCTION "count_by_two" (integer) RETURNS integer AS ' - DECLARE - userNum ALIAS FOR $1; - i integer; - BEGIN - i := 1; - WHILE userNum[1] < 20 LOOP - i = i+1; - return userNum; - END LOOP; - - END; - ' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 63 (OID 3001139) --- --- Name: "me" () Type: FUNCTION Owner: example +-- CREATE FUNCTION "plpgsql_call_handler" () RETURNS opaque AS '/usr/local/Cellar/postgresql/9.6.2/lib/postgresql/plpgsql.so', 'plpgsql_call_handler' LANGUAGE 'c'; +-- +-- -- +-- -- TOC Entry ID 48 (OID 2991734) +-- -- +-- -- Name: plpgsql Type: PROCEDURAL LANGUAGE Owner: +-- -- +-- +-- CREATE TRUSTED PROCEDURAL LANGUAGE 'plpgsql' HANDLER "plpgsql_call_handler" LANCOMPILER 'PL/pgSQL'; +-- +-- -- +-- -- TOC Entry ID 51 (OID 2991735) +-- -- +-- -- Name: "audit_bk" (integer) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "audit_bk" (integer) RETURNS integer AS ' +-- DECLARE +-- key ALIAS FOR $1; +-- table_data inventory%ROWTYPE; +-- BEGIN +-- INSERT INTO inventory_audit SELECT table_data WHERE sort_key=key; +-- +-- IF NOT FOUND THEN +-- RAISE EXCEPTION ''View'' || key || '' not found ''; +-- END IF; +-- +-- return 1; +-- end; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 52 (OID 2991736) +-- -- +-- -- Name: "audit" (integer) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "audit" (integer) RETURNS integer AS ' +-- DECLARE +-- key ALIAS FOR $1; +-- table_data inventory%ROWTYPE; +-- BEGIN +-- INSERT INTO inventory_audit SELECT table_data WHERE sort_key=key; +-- +-- IF NOT FOUND THEN +-- RAISE EXCEPTION ''View'' || key || '' not found ''; +-- END IF; +-- +-- return 1; +-- end; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 53 (OID 2991737) +-- -- +-- -- Name: "auditbk" () Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "auditbk" () RETURNS integer AS ' +-- DECLARE +-- key ALIAS FOR $1; +-- table_data inventory%ROWTYPE; +-- BEGIN +-- INSERT INTO inventory_audit SELECT table_data WHERE sort_key=key; +-- +-- IF NOT FOUND THEN +-- RAISE EXCEPTION ''View'' || key || '' not found ''; +-- END IF; +-- +-- return 1; +-- end; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 54 (OID 2991738) +-- -- +-- -- Name: "audit_bk1" () Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "audit_bk1" () RETURNS opaque AS ' +-- DECLARE +-- key ALIAS FOR $1; +-- table_data inventory%ROWTYPE; +-- BEGIN +-- INSERT INTO inventory_audit SELECT table_data WHERE sort_key=key; +-- +-- IF NOT FOUND THEN +-- RAISE EXCEPTION ''View'' || key || '' not found ''; +-- END IF; +-- +-- return 1; +-- end; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 73 (OID 2991835) +-- -- +-- -- Name: "test_check_a_id" () Type: FUNCTION Owner: example +-- -- +-- +-- CREATE FUNCTION "test_check_a_id" () RETURNS opaque AS ' +-- BEGIN +-- -- checks to make sure the author id +-- -- inserted is not left blank or less than 100 +-- +-- IF NEW.a_id ISNULL THEN +-- RAISE EXCEPTION +-- ''The author id cannot be left blank!''; +-- ELSE +-- IF NEW.a_id < 100 THEN +-- RAISE EXCEPTION +-- ''Please insert a valid author id.''; +-- ELSE +-- RETURN NEW; +-- END IF; +-- END IF; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 66 (OID 2992619) +-- -- +-- -- Name: "audit_test" () Type: FUNCTION Owner: example +-- -- +-- +-- CREATE FUNCTION "audit_test" () RETURNS opaque AS ' +-- BEGIN +-- +-- IF TG_OP = ''INSERT'' OR TG_OP = ''UPDATE'' THEN +-- +-- NEW.user_aud := current_user; +-- NEW.mod_time := ''NOW''; +-- +-- INSERT INTO inventory_audit SELECT * FROM inventory WHERE prod_id=NEW.prod_id; +-- +-- RETURN NEW; +-- +-- ELSE if TG_OP = ''DELETE'' THEN +-- INSERT INTO inventory_audit SELECT *, current_user, ''NOW'' FROM inventory WHERE prod_id=OLD.prod_id; +-- +-- RETURN OLD; +-- END IF; +-- END IF; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 67 (OID 3000878) +-- -- +-- -- Name: "first" () Type: FUNCTION Owner: example +-- -- +-- +-- CREATE FUNCTION "first" () RETURNS integer AS ' +-- DecLarE +-- oNe IntEgER := 1; +-- bEGiN +-- ReTUrn oNE; +-- eNd; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 68 (OID 3000881) +-- -- +-- -- Name: "test" (integer) Type: FUNCTION Owner: example +-- -- +-- +-- CREATE FUNCTION "test" (integer) RETURNS integer AS ' +-- +-- DECLARE +-- -- defines the variable as ALIAS +-- variable ALIAS FOR $1; +-- BEGIN +-- -- displays the variable after multiplying it by two +-- return variable * 2.0; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 69 (OID 3000991) +-- -- +-- -- Name: "you_me" (integer) Type: FUNCTION Owner: example +-- -- +-- +-- CREATE FUNCTION "you_me" (integer) RETURNS integer AS ' +-- DECLARE +-- RENAME $1 TO user_no; +-- --you INTEGER := 5; +-- BEGIN +-- return user_no; +-- END;' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 62 (OID 3001136) +-- -- +-- -- Name: "count_by_two" (integer) Type: FUNCTION Owner: example +-- -- +-- +-- CREATE FUNCTION "count_by_two" (integer) RETURNS integer AS ' +-- DECLARE +-- userNum ALIAS FOR $1; +-- i integer; +-- BEGIN +-- i := 1; +-- WHILE userNum[1] < 20 LOOP +-- i = i+1; +-- return userNum; +-- END LOOP; +-- +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 63 (OID 3001139) +-- -- +-- -- Name: "me" () Type: FUNCTION Owner: example +-- -- +-- +-- CREATE FUNCTION "me" () RETURNS text AS ' +-- DECLARE +-- you text := ''testing''; +-- RENAME you to me; +-- BEGIN +-- return me; +-- END;' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 64 (OID 3001149) +-- -- +-- -- Name: "display_cust" (integer) Type: FUNCTION Owner: example +-- -- +-- +-- CREATE FUNCTION "display_cust" (integer) RETURNS text AS ' +-- DECLARE +-- -- declares an alias name for input +-- cust_num ALIAS FOR $1; +-- +-- -- declares a row type +-- cust_info customer%ROWTYPE; +-- BEGIN +-- -- puts information into the newly declared rowtype +-- SELECT into cust_info * +-- FROM customer +-- WHERE cust_id=cust_num; +-- +-- -- displays the customer lastname +-- -- extracted from the rowtype +-- return cust_info.lastname; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 65 (OID 3001151) +-- -- +-- -- Name: "mixed" () Type: FUNCTION Owner: example +-- -- +-- +-- CREATE FUNCTION "mixed" () RETURNS integer AS ' +-- DecLarE +-- --assigns 1 to the oNe variable +-- oNe IntEgER +-- := 1; +-- +-- bEGiN +-- +-- --displays the value of oNe +-- ReTUrn oNe; +-- eNd; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 12 (OID 3117548) +-- -- +-- -- Name: publishers Type: TABLE Owner: postgres +-- -- -- - -CREATE FUNCTION "me" () RETURNS text AS ' - DECLARE - you text := ''testing''; - RENAME you to me; - BEGIN - return me; - END;' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 64 (OID 3001149) --- --- Name: "display_cust" (integer) Type: FUNCTION Owner: example --- - -CREATE FUNCTION "display_cust" (integer) RETURNS text AS ' - DECLARE - -- declares an alias name for input - cust_num ALIAS FOR $1; - - -- declares a row type - cust_info customer%ROWTYPE; - BEGIN - -- puts information into the newly declared rowtype - SELECT into cust_info * - FROM customer - WHERE cust_id=cust_num; - - -- displays the customer lastname - -- extracted from the rowtype - return cust_info.lastname; - END; - ' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 65 (OID 3001151) --- --- Name: "mixed" () Type: FUNCTION Owner: example --- - -CREATE FUNCTION "mixed" () RETURNS integer AS ' - DecLarE - --assigns 1 to the oNe variable - oNe IntEgER - := 1; - - bEGiN - - --displays the value of oNe - ReTUrn oNe; - eNd; - ' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 12 (OID 3117548) --- --- Name: publishers Type: TABLE Owner: postgres --- - CREATE TABLE "publishers" ( "id" integer NOT NULL, "name" text, "address" text, Constraint "publishers_pkey" Primary Key ("id") ); - --- --- TOC Entry ID 55 (OID 3117729) --- --- Name: "compound_word" (text,text) Type: FUNCTION Owner: example --- - -CREATE FUNCTION "compound_word" (text,text) RETURNS text AS ' - DECLARE - -- defines an alias name for the two input values - word1 ALIAS FOR $1; - word2 ALIAS FOR $2; - BEGIN - -- displays the resulting joined words - RETURN word1 || word2; - END; - ' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 56 (OID 3117787) --- --- Name: "givename" () Type: FUNCTION Owner: example -- - -CREATE FUNCTION "givename" () RETURNS opaque AS ' - DECLARE - tablename text; - BEGIN - - tablename = TG_RELNAME; - INSERT INTO INVENTORY values (123, tablename); - return old; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 14 (OID 3389594) --- --- Name: authors Type: TABLE Owner: manager +-- -- +-- -- TOC Entry ID 55 (OID 3117729) +-- -- +-- -- Name: "compound_word" (text,text) Type: FUNCTION Owner: example +-- -- +-- +-- CREATE FUNCTION "compound_word" (text,text) RETURNS text AS ' +-- DECLARE +-- -- defines an alias name for the two input values +-- word1 ALIAS FOR $1; +-- word2 ALIAS FOR $2; +-- BEGIN +-- -- displays the resulting joined words +-- RETURN word1 || word2; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 56 (OID 3117787) +-- -- +-- -- Name: "givename" () Type: FUNCTION Owner: example +-- -- +-- +-- CREATE FUNCTION "givename" () RETURNS opaque AS ' +-- DECLARE +-- tablename text; +-- BEGIN +-- +-- tablename = TG_RELNAME; +-- INSERT INTO INVENTORY values (123, tablename); +-- return old; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 14 (OID 3389594) +-- -- +-- -- Name: authors Type: TABLE Owner: manager +-- -- -- - CREATE TABLE "authors" ( "id" integer NOT NULL, "last_name" text, "first_name" text, Constraint "authors_pkey" Primary Key ("id") ); - -- --- TOC Entry ID 15 (OID 3389632) +-- -- +-- -- TOC Entry ID 15 (OID 3389632) +-- -- +-- -- Name: states Type: TABLE Owner: postgres +-- -- -- --- Name: states Type: TABLE Owner: postgres --- - CREATE TABLE "states" ( "id" integer NOT NULL, "name" text, "abbreviation" character(2), Constraint "state_pkey" Primary Key ("id") ); - --- --- TOC Entry ID 16 (OID 3389702) -- --- Name: my_list Type: TABLE Owner: postgres +-- -- +-- -- TOC Entry ID 16 (OID 3389702) +-- -- +-- -- Name: my_list Type: TABLE Owner: postgres +-- -- -- - CREATE TABLE "my_list" ( "todos" text ); +-- -- +-- -- TOC Entry ID 17 (OID 3390348) +-- -- +-- -- Name: stock Type: TABLE Owner: postgres +-- -- -- --- TOC Entry ID 17 (OID 3390348) --- --- Name: stock Type: TABLE Owner: postgres --- - CREATE TABLE "stock" ( "isbn" text NOT NULL, "cost" numeric(5,2), @@ -384,577 +384,577 @@ CREATE TABLE "stock" ( "stock" integer, Constraint "stock_pkey" Primary Key ("isbn") ); - --- --- TOC Entry ID 4 (OID 3390416) -- --- Name: subject_ids Type: SEQUENCE Owner: postgres +-- -- +-- -- TOC Entry ID 4 (OID 3390416) +-- -- +-- -- Name: subject_ids Type: SEQUENCE Owner: postgres +-- -- -- - CREATE SEQUENCE "subject_ids" start 0 increment 1 maxvalue 2147483647 minvalue 0 cache 1 ; - -- --- TOC Entry ID 19 (OID 3390653) +-- -- +-- -- TOC Entry ID 19 (OID 3390653) +-- -- +-- -- Name: numeric_values Type: TABLE Owner: postgres +-- -- -- --- Name: numeric_values Type: TABLE Owner: postgres --- - CREATE TABLE "numeric_values" ( "num" numeric(30,6) ); - -- --- TOC Entry ID 20 (OID 3390866) +-- -- +-- -- TOC Entry ID 20 (OID 3390866) +-- -- +-- -- Name: daily_inventory Type: TABLE Owner: postgres +-- -- -- --- Name: daily_inventory Type: TABLE Owner: postgres --- - CREATE TABLE "daily_inventory" ( "isbn" text, "is_stocked" boolean ); - --- --- TOC Entry ID 21 (OID 3391084) -- --- Name: money_example Type: TABLE Owner: postgres +-- -- +-- -- TOC Entry ID 21 (OID 3391084) +-- -- +-- -- Name: money_example Type: TABLE Owner: postgres +-- -- -- - CREATE TABLE "money_example" ( "money_cash" money, "numeric_cash" numeric(6,2) ); - -- --- TOC Entry ID 22 (OID 3391184) +-- -- +-- -- TOC Entry ID 22 (OID 3391184) +-- -- +-- -- Name: shipments Type: TABLE Owner: postgres +-- -- -- --- Name: shipments Type: TABLE Owner: postgres --- - CREATE TABLE "shipments" ( "id" integer DEFAULT nextval('"shipments_ship_id_seq"'::text) NOT NULL, "customer_id" integer, "isbn" text, "ship_date" timestamp with time zone ); - -- --- TOC Entry ID 24 (OID 3391454) +-- -- +-- -- TOC Entry ID 24 (OID 3391454) +-- -- +-- -- Name: customers Type: TABLE Owner: manager +-- -- -- --- Name: customers Type: TABLE Owner: manager --- - CREATE TABLE "customers" ( "id" integer NOT NULL, "last_name" text, "first_name" text, Constraint "customers_pkey" Primary Key ("id") ); - --- --- TOC Entry ID 6 (OID 3574018) -- --- Name: book_ids Type: SEQUENCE Owner: postgres +-- -- +-- -- TOC Entry ID 6 (OID 3574018) +-- -- +-- -- Name: book_ids Type: SEQUENCE Owner: postgres +-- -- -- - CREATE SEQUENCE "book_ids" start 0 increment 1 maxvalue 2147483647 minvalue 0 cache 1 ; - -- --- TOC Entry ID 26 (OID 3574043) +-- -- +-- -- TOC Entry ID 26 (OID 3574043) +-- -- +-- -- Name: book_queue Type: TABLE Owner: postgres +-- -- -- --- Name: book_queue Type: TABLE Owner: postgres --- - CREATE TABLE "book_queue" ( "title" text NOT NULL, "author_id" integer, "subject_id" integer, "approved" boolean ); - -- --- TOC Entry ID 78 (OID 3574403) +-- -- +-- -- TOC Entry ID 78 (OID 3574403) +-- -- +-- -- Name: "title" (integer) Type: FUNCTION Owner: postgres +-- -- -- --- Name: "title" (integer) Type: FUNCTION Owner: postgres +-- CREATE FUNCTION "title" (integer) RETURNS text AS 'SELECT title from books where id = $1' LANGUAGE 'sql'; -- - -CREATE FUNCTION "title" (integer) RETURNS text AS 'SELECT title from books where id = $1' LANGUAGE 'sql'; - +-- -- +-- -- TOC Entry ID 27 (OID 3574983) +-- -- +-- -- Name: stock_backup Type: TABLE Owner: postgres +-- -- -- --- TOC Entry ID 27 (OID 3574983) --- --- Name: stock_backup Type: TABLE Owner: postgres --- - CREATE TABLE "stock_backup" ( "isbn" text, "cost" numeric(5,2), "retail" numeric(5,2), "stock" integer ); - -- --- TOC Entry ID 89 (OID 3625934) --- --- Name: "double_price" (double precision) Type: FUNCTION Owner: postgres +-- -- +-- -- TOC Entry ID 89 (OID 3625934) +-- -- +-- -- Name: "double_price" (double precision) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "double_price" (double precision) RETURNS double precision AS ' +-- DECLARE +-- BEGIN +-- return $1 * 2; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 90 (OID 3625935) +-- -- +-- -- Name: "triple_price" (double precision) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "triple_price" (double precision) RETURNS double precision AS ' +-- DECLARE +-- -- Declare input_price as an alias for the +-- -- argument variable normally referenced with +-- -- the $1 identifier. +-- input_price ALIAS FOR $1; +-- +-- BEGIN +-- -- Return the input price multiplied by three. +-- RETURN input_price * 3; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 87 (OID 3625944) +-- -- +-- -- Name: "stock_amount" (integer,integer) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "stock_amount" (integer,integer) RETURNS integer AS ' +-- DECLARE +-- -- Declare aliases for function arguments. +-- b_id ALIAS FOR $1; +-- b_edition ALIAS FOR $2; +-- -- Declare variable to store the ISBN number. +-- b_isbn TEXT; +-- -- Declare variable to store the stock amount. +-- stock_amount INTEGER; +-- BEGIN +-- -- This SELECT INTO statement retrieves the ISBN +-- -- number of the row in the editions table that had +-- -- both the book ID number and edition number that +-- -- were provided as function arguments. +-- SELECT INTO b_isbn isbn FROM editions WHERE +-- book_id = b_id AND edition = b_edition; +-- +-- -- Check to see if the ISBN number retrieved +-- -- is NULL. This will happen if there is not an +-- -- existing book with both the ID number and edition +-- -- number specified in the function arguments. +-- -- If the ISBN is null, the function returns a +-- -- value of -1 and ends. +-- IF b_isbn IS NULL THEN +-- RETURN -1; +-- END IF; +-- +-- -- Retrieve the amount of books available from the +-- -- stock table and record the number in the +-- -- stock_amount variable. +-- SELECT INTO stock_amount stock FROM stock WHERE isbn = b_isbn; +-- +-- -- Return the amount of books available. +-- RETURN stock_amount; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 86 (OID 3625946) +-- -- +-- -- Name: "in_stock" (integer,integer) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "in_stock" (integer,integer) RETURNS boolean AS ' +-- DECLARE +-- b_id ALIAS FOR $1; +-- b_edition ALIAS FOR $2; +-- b_isbn TEXT; +-- stock_amount INTEGER; +-- BEGIN +-- -- This SELECT INTO statement retrieves the ISBN +-- -- number of the row in the editions table that had +-- -- both the book ID number and edition number that +-- -- were provided as function arguments. +-- SELECT INTO b_isbn isbn FROM editions WHERE +-- book_id = b_id AND edition = b_edition; +-- +-- -- Check to see if the ISBN number retrieved +-- -- is NULL. This will happen if there is not an +-- -- existing book with both the ID number and edition +-- -- number specified in the function arguments. +-- -- If the ISBN is null, the function returns a +-- -- FALSE value and ends. +-- IF b_isbn IS NULL THEN +-- RETURN FALSE; +-- END IF; +-- +-- -- Retrieve the amount of books available from the +-- -- stock table and record the number in the +-- -- stock_amount variable. +-- SELECT INTO stock_amount stock FROM stock WHERE isbn = b_isbn; +-- +-- -- Use an IF/THEN/ELSE check to see if the amount +-- -- of books available is less than, or equal to 0. +-- -- If so, return FALSE. If not, return TRUE. +-- IF stock_amount <= 0 THEN +-- RETURN FALSE; +-- ELSE +-- RETURN TRUE; +-- END IF; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 82 (OID 3626013) +-- -- +-- -- Name: "extract_all_titles" () Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "extract_all_titles" () RETURNS text AS ' +-- DECLARE +-- sub_id INTEGER; +-- text_output TEXT = '' ''; +-- sub_title TEXT; +-- row_data books%ROWTYPE; +-- BEGIN +-- FOR i IN 0..15 LOOP +-- SELECT INTO sub_title subject FROM subjects WHERE id = i; +-- text_output = text_output || '' +-- '' || sub_title || '': +-- ''; +-- +-- FOR row_data IN SELECT * FROM books +-- WHERE subject_id = i LOOP +-- +-- IF NOT FOUND THEN +-- text_output := text_output || ''None. +-- ''; +-- ELSE +-- text_output := text_output || row_data.title || '' +-- ''; +-- END IF; +-- +-- END LOOP; +-- END LOOP; +-- RETURN text_output; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 79 (OID 3626052) +-- -- +-- -- Name: "books_by_subject" (text) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "books_by_subject" (text) RETURNS text AS ' +-- DECLARE +-- sub_title ALIAS FOR $1; +-- sub_id INTEGER; +-- found_text TEXT :=''''; +-- BEGIN +-- SELECT INTO sub_id id FROM subjects WHERE subject = sub_title; +-- RAISE NOTICE ''sub_id = %'',sub_id; +-- IF sub_title = ''all'' THEN +-- found_text := extract_all_titles(); +-- RETURN found_text; +-- ELSE IF sub_id >= 0 THEN +-- found_text := extract_title(sub_id); +-- RETURN '' +-- '' || sub_title || '': +-- '' || found_text; +-- END IF; +-- END IF; +-- RETURN ''Subject not found.''; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 81 (OID 3626590) +-- -- +-- -- Name: "add_two_loop" (integer,integer) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "add_two_loop" (integer,integer) RETURNS integer AS ' +-- DECLARE +-- +-- -- Declare aliases for function arguments. +-- +-- low_number ALIAS FOR $1; +-- high_number ALIAS FOR $2; +-- +-- -- Declare a variable to hold the result. +-- +-- result INTEGER = 0; +-- +-- BEGIN +-- +-- WHILE result != high_number LOOP +-- result := result + 1; +-- END LOOP; +-- +-- RETURN result; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 92 (OID 3627916) +-- -- +-- -- Name: "extract_all_titles2" () Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "extract_all_titles2" () RETURNS text AS ' +-- DECLARE +-- sub_id INTEGER; +-- text_output TEXT = '' ''; +-- sub_title TEXT; +-- row_data books%ROWTYPE; +-- BEGIN +-- FOR i IN 0..15 LOOP +-- SELECT INTO sub_title subject FROM subjects WHERE id = i; +-- text_output = text_output || '' +-- '' || sub_title || '': +-- ''; +-- +-- FOR row_data IN SELECT * FROM books +-- WHERE subject_id = i LOOP +-- +-- text_output := text_output || row_data.title || '' +-- ''; +-- +-- END LOOP; +-- END LOOP; +-- RETURN text_output; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 94 (OID 3627974) +-- -- +-- -- Name: "extract_title" (integer) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "extract_title" (integer) RETURNS text AS ' +-- DECLARE +-- sub_id ALIAS FOR $1; +-- text_output TEXT :='' +-- ''; +-- row_data RECORD; +-- BEGIN +-- FOR row_data IN SELECT * FROM books +-- WHERE subject_id = sub_id ORDER BY title LOOP +-- text_output := text_output || row_data.title || '' +-- ''; +-- END LOOP; +-- RETURN text_output; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 95 (OID 3628021) +-- -- +-- -- Name: "raise_test" () Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "raise_test" () RETURNS integer AS ' +-- DECLARE +-- +-- -- Declare an integer variable for testing. +-- +-- an_integer INTEGER = 1; +-- +-- BEGIN +-- +-- -- Raise a debug level message. +-- +-- RAISE DEBUG ''The raise_test() function began.''; +-- +-- an_integer = an_integer + 1; +-- +-- -- Raise a notice stating that the an_integer +-- -- variable was changed, then raise another notice +-- -- stating its new value. +-- +-- RAISE NOTICE ''Variable an_integer was changed.''; +-- RAISE NOTICE ''Variable an_integer value is now %.'',an_integer; +-- +-- -- Raise an exception. +-- +-- RAISE EXCEPTION ''Variable % changed. Aborting transaction.'',an_integer; +-- +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 93 (OID 3628069) +-- -- +-- -- Name: "add_shipment" (integer,text) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "add_shipment" (integer,text) RETURNS timestamp with time zone AS ' +-- DECLARE +-- customer_id ALIAS FOR $1; +-- isbn ALIAS FOR $2; +-- shipment_id INTEGER; +-- right_now timestamp; +-- BEGIN +-- right_now := ''now''; +-- SELECT INTO shipment_id id FROM shipments ORDER BY id DESC; +-- shipment_id := shipment_id + 1; +-- INSERT INTO shipments VALUES ( shipment_id, customer_id, isbn, right_now ); +-- RETURN right_now; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 102 (OID 3628076) +-- -- +-- -- Name: "ship_item" (text,text,text) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "ship_item" (text,text,text) RETURNS integer AS ' +-- DECLARE +-- l_name ALIAS FOR $1; +-- f_name ALIAS FOR $2; +-- book_isbn ALIAS FOR $3; +-- book_id INTEGER; +-- customer_id INTEGER; +-- +-- BEGIN +-- +-- SELECT INTO customer_id get_customer_id(l_name,f_name); +-- +-- IF customer_id = -1 THEN +-- RETURN -1; +-- END IF; +-- +-- SELECT INTO book_id book_id FROM editions WHERE isbn = book_isbn; +-- +-- IF NOT FOUND THEN +-- RETURN -1; +-- END IF; -- - -CREATE FUNCTION "double_price" (double precision) RETURNS double precision AS ' - DECLARE - BEGIN - return $1 * 2; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 90 (OID 3625935) --- --- Name: "triple_price" (double precision) Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "triple_price" (double precision) RETURNS double precision AS ' - DECLARE - -- Declare input_price as an alias for the - -- argument variable normally referenced with - -- the $1 identifier. - input_price ALIAS FOR $1; - - BEGIN - -- Return the input price multiplied by three. - RETURN input_price * 3; - END; - ' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 87 (OID 3625944) --- --- Name: "stock_amount" (integer,integer) Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "stock_amount" (integer,integer) RETURNS integer AS ' - DECLARE - -- Declare aliases for function arguments. - b_id ALIAS FOR $1; - b_edition ALIAS FOR $2; - -- Declare variable to store the ISBN number. - b_isbn TEXT; - -- Declare variable to store the stock amount. - stock_amount INTEGER; - BEGIN - -- This SELECT INTO statement retrieves the ISBN - -- number of the row in the editions table that had - -- both the book ID number and edition number that - -- were provided as function arguments. - SELECT INTO b_isbn isbn FROM editions WHERE - book_id = b_id AND edition = b_edition; - - -- Check to see if the ISBN number retrieved - -- is NULL. This will happen if there is not an - -- existing book with both the ID number and edition - -- number specified in the function arguments. - -- If the ISBN is null, the function returns a - -- value of -1 and ends. - IF b_isbn IS NULL THEN - RETURN -1; - END IF; - - -- Retrieve the amount of books available from the - -- stock table and record the number in the - -- stock_amount variable. - SELECT INTO stock_amount stock FROM stock WHERE isbn = b_isbn; - - -- Return the amount of books available. - RETURN stock_amount; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 86 (OID 3625946) --- --- Name: "in_stock" (integer,integer) Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "in_stock" (integer,integer) RETURNS boolean AS ' - DECLARE - b_id ALIAS FOR $1; - b_edition ALIAS FOR $2; - b_isbn TEXT; - stock_amount INTEGER; - BEGIN - -- This SELECT INTO statement retrieves the ISBN - -- number of the row in the editions table that had - -- both the book ID number and edition number that - -- were provided as function arguments. - SELECT INTO b_isbn isbn FROM editions WHERE - book_id = b_id AND edition = b_edition; - - -- Check to see if the ISBN number retrieved - -- is NULL. This will happen if there is not an - -- existing book with both the ID number and edition - -- number specified in the function arguments. - -- If the ISBN is null, the function returns a - -- FALSE value and ends. - IF b_isbn IS NULL THEN - RETURN FALSE; - END IF; - - -- Retrieve the amount of books available from the - -- stock table and record the number in the - -- stock_amount variable. - SELECT INTO stock_amount stock FROM stock WHERE isbn = b_isbn; - - -- Use an IF/THEN/ELSE check to see if the amount - -- of books available is less than, or equal to 0. - -- If so, return FALSE. If not, return TRUE. - IF stock_amount <= 0 THEN - RETURN FALSE; - ELSE - RETURN TRUE; - END IF; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 82 (OID 3626013) --- --- Name: "extract_all_titles" () Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "extract_all_titles" () RETURNS text AS ' - DECLARE - sub_id INTEGER; - text_output TEXT = '' ''; - sub_title TEXT; - row_data books%ROWTYPE; - BEGIN - FOR i IN 0..15 LOOP - SELECT INTO sub_title subject FROM subjects WHERE id = i; - text_output = text_output || '' -'' || sub_title || '': -''; - - FOR row_data IN SELECT * FROM books - WHERE subject_id = i LOOP - - IF NOT FOUND THEN - text_output := text_output || ''None. -''; - ELSE - text_output := text_output || row_data.title || '' -''; - END IF; - - END LOOP; - END LOOP; - RETURN text_output; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 79 (OID 3626052) --- --- Name: "books_by_subject" (text) Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "books_by_subject" (text) RETURNS text AS ' - DECLARE - sub_title ALIAS FOR $1; - sub_id INTEGER; - found_text TEXT :=''''; - BEGIN - SELECT INTO sub_id id FROM subjects WHERE subject = sub_title; - RAISE NOTICE ''sub_id = %'',sub_id; - IF sub_title = ''all'' THEN - found_text := extract_all_titles(); - RETURN found_text; - ELSE IF sub_id >= 0 THEN - found_text := extract_title(sub_id); - RETURN '' -'' || sub_title || '': -'' || found_text; - END IF; - END IF; - RETURN ''Subject not found.''; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 81 (OID 3626590) --- --- Name: "add_two_loop" (integer,integer) Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "add_two_loop" (integer,integer) RETURNS integer AS ' - DECLARE - - -- Declare aliases for function arguments. - - low_number ALIAS FOR $1; - high_number ALIAS FOR $2; - - -- Declare a variable to hold the result. - - result INTEGER = 0; - - BEGIN - - WHILE result != high_number LOOP - result := result + 1; - END LOOP; - - RETURN result; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 92 (OID 3627916) --- --- Name: "extract_all_titles2" () Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "extract_all_titles2" () RETURNS text AS ' - DECLARE - sub_id INTEGER; - text_output TEXT = '' ''; - sub_title TEXT; - row_data books%ROWTYPE; - BEGIN - FOR i IN 0..15 LOOP - SELECT INTO sub_title subject FROM subjects WHERE id = i; - text_output = text_output || '' -'' || sub_title || '': -''; - - FOR row_data IN SELECT * FROM books - WHERE subject_id = i LOOP - - text_output := text_output || row_data.title || '' -''; - - END LOOP; - END LOOP; - RETURN text_output; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 94 (OID 3627974) --- --- Name: "extract_title" (integer) Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "extract_title" (integer) RETURNS text AS ' - DECLARE - sub_id ALIAS FOR $1; - text_output TEXT :='' -''; - row_data RECORD; - BEGIN - FOR row_data IN SELECT * FROM books - WHERE subject_id = sub_id ORDER BY title LOOP - text_output := text_output || row_data.title || '' -''; - END LOOP; - RETURN text_output; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 95 (OID 3628021) --- --- Name: "raise_test" () Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "raise_test" () RETURNS integer AS ' - DECLARE - - -- Declare an integer variable for testing. - - an_integer INTEGER = 1; - - BEGIN - - -- Raise a debug level message. - - RAISE DEBUG ''The raise_test() function began.''; - - an_integer = an_integer + 1; - - -- Raise a notice stating that the an_integer - -- variable was changed, then raise another notice - -- stating its new value. - - RAISE NOTICE ''Variable an_integer was changed.''; - RAISE NOTICE ''Variable an_integer value is now %.'',an_integer; - - -- Raise an exception. - - RAISE EXCEPTION ''Variable % changed. Aborting transaction.'',an_integer; - - END; -' LANGUAGE 'plpgsql'; - +-- PERFORM add_shipment(customer_id,book_isbn); +-- +-- RETURN 1; +-- END; +-- ' LANGUAGE 'plpgsql'; -- --- TOC Entry ID 93 (OID 3628069) +-- -- +-- -- TOC Entry ID 103 (OID 3628114) +-- -- +-- -- Name: "check_book_addition" () Type: FUNCTION Owner: postgres +-- -- -- --- Name: "add_shipment" (integer,text) Type: FUNCTION Owner: postgres +-- CREATE FUNCTION "check_book_addition" () RETURNS opaque AS ' +-- DECLARE +-- id_number INTEGER; +-- book_isbn TEXT; +-- BEGIN -- - -CREATE FUNCTION "add_shipment" (integer,text) RETURNS timestamp with time zone AS ' - DECLARE - customer_id ALIAS FOR $1; - isbn ALIAS FOR $2; - shipment_id INTEGER; - right_now timestamp; - BEGIN - right_now := ''now''; - SELECT INTO shipment_id id FROM shipments ORDER BY id DESC; - shipment_id := shipment_id + 1; - INSERT INTO shipments VALUES ( shipment_id, customer_id, isbn, right_now ); - RETURN right_now; - END; -' LANGUAGE 'plpgsql'; - +-- SELECT INTO id_number id FROM customers WHERE id = NEW.customer_id; -- --- TOC Entry ID 102 (OID 3628076) +-- IF NOT FOUND THEN +-- RAISE EXCEPTION ''Invalid customer ID number.''; +-- END IF; -- --- Name: "ship_item" (text,text,text) Type: FUNCTION Owner: postgres +-- SELECT INTO book_isbn isbn FROM editions WHERE isbn = NEW.isbn; -- - -CREATE FUNCTION "ship_item" (text,text,text) RETURNS integer AS ' - DECLARE - l_name ALIAS FOR $1; - f_name ALIAS FOR $2; - book_isbn ALIAS FOR $3; - book_id INTEGER; - customer_id INTEGER; - - BEGIN - - SELECT INTO customer_id get_customer_id(l_name,f_name); - - IF customer_id = -1 THEN - RETURN -1; - END IF; - - SELECT INTO book_id book_id FROM editions WHERE isbn = book_isbn; - - IF NOT FOUND THEN - RETURN -1; - END IF; - - PERFORM add_shipment(customer_id,book_isbn); - - RETURN 1; - END; -' LANGUAGE 'plpgsql'; - +-- IF NOT FOUND THEN +-- RAISE EXCEPTION ''Invalid ISBN.''; +-- END IF; -- --- TOC Entry ID 103 (OID 3628114) +-- UPDATE stock SET stock = stock -1 WHERE isbn = NEW.isbn; -- --- Name: "check_book_addition" () Type: FUNCTION Owner: postgres +-- RETURN NEW; +-- END; +-- ' LANGUAGE 'plpgsql'; -- - -CREATE FUNCTION "check_book_addition" () RETURNS opaque AS ' - DECLARE - id_number INTEGER; - book_isbn TEXT; - BEGIN - - SELECT INTO id_number id FROM customers WHERE id = NEW.customer_id; - - IF NOT FOUND THEN - RAISE EXCEPTION ''Invalid customer ID number.''; - END IF; - - SELECT INTO book_isbn isbn FROM editions WHERE isbn = NEW.isbn; - - IF NOT FOUND THEN - RAISE EXCEPTION ''Invalid ISBN.''; - END IF; - - UPDATE stock SET stock = stock -1 WHERE isbn = NEW.isbn; - - RETURN NEW; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 28 (OID 3628246) --- --- Name: stock_view Type: VIEW Owner: postgres +-- -- +-- -- TOC Entry ID 28 (OID 3628246) +-- -- +-- -- Name: stock_view Type: VIEW Owner: postgres +-- -- +-- +-- CREATE VIEW "stock_view" as SELECT stock.isbn, stock.retail, stock.stock FROM stock; -- - -CREATE VIEW "stock_view" as SELECT stock.isbn, stock.retail, stock.stock FROM stock; - --- --- TOC Entry ID 30 (OID 3628247) +-- -- +-- -- TOC Entry ID 30 (OID 3628247) +-- -- +-- -- Name: favorite_books Type: TABLE Owner: manager +-- -- -- --- Name: favorite_books Type: TABLE Owner: manager --- - CREATE TABLE "favorite_books" ( "employee_id" integer, "books" text[] ); - --- --- TOC Entry ID 8 (OID 3628626) -- --- Name: shipments_ship_id_seq Type: SEQUENCE Owner: manager +-- -- +-- -- TOC Entry ID 8 (OID 3628626) +-- -- +-- -- Name: shipments_ship_id_seq Type: SEQUENCE Owner: manager +-- -- -- - CREATE SEQUENCE "shipments_ship_id_seq" start 0 increment 1 maxvalue 2147483647 minvalue 0 cache 1 ; +-- -- +-- -- TOC Entry ID 74 (OID 3628648) +-- -- +-- -- Name: "check_shipment_addition" () Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "check_shipment_addition" () RETURNS opaque AS ' +-- DECLARE +-- -- Declare a variable to hold the customer ID. +-- id_number INTEGER; +-- +-- -- Declare a variable to hold the ISBN. +-- book_isbn TEXT; +-- BEGIN +-- +-- -- If there is an ID number that matches the customer ID in +-- -- the new table, retrieve it from the customers table. +-- SELECT INTO id_number id FROM customers WHERE id = NEW.customer_id; +-- +-- -- If there was no matching ID number, raise an exception. +-- IF NOT FOUND THEN +-- RAISE EXCEPTION ''Invalid customer ID number.''; +-- END IF; +-- +-- -- If there is an ISBN that matches the ISBN specified in the +-- -- new table, retrieve it from the editions table. +-- SELECT INTO book_isbn isbn FROM editions WHERE isbn = NEW.isbn; +-- +-- -- If there is no matching ISBN, raise an exception. +-- IF NOT FOUND THEN +-- RAISE EXCEPTION ''Invalid ISBN.''; +-- END IF; +-- +-- -- If the previous checks succeeded, update the stock amount +-- -- for INSERT commands. +-- IF TG_OP = ''INSERT'' THEN +-- UPDATE stock SET stock = stock -1 WHERE isbn = NEW.isbn; +-- END IF; +-- +-- RETURN NEW; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 31 (OID 3628899) +-- -- +-- -- Name: employees Type: TABLE Owner: postgres +-- -- -- --- TOC Entry ID 74 (OID 3628648) --- --- Name: "check_shipment_addition" () Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "check_shipment_addition" () RETURNS opaque AS ' - DECLARE - -- Declare a variable to hold the customer ID. - id_number INTEGER; - - -- Declare a variable to hold the ISBN. - book_isbn TEXT; - BEGIN - - -- If there is an ID number that matches the customer ID in - -- the new table, retrieve it from the customers table. - SELECT INTO id_number id FROM customers WHERE id = NEW.customer_id; - - -- If there was no matching ID number, raise an exception. - IF NOT FOUND THEN - RAISE EXCEPTION ''Invalid customer ID number.''; - END IF; - - -- If there is an ISBN that matches the ISBN specified in the - -- new table, retrieve it from the editions table. - SELECT INTO book_isbn isbn FROM editions WHERE isbn = NEW.isbn; - - -- If there is no matching ISBN, raise an exception. - IF NOT FOUND THEN - RAISE EXCEPTION ''Invalid ISBN.''; - END IF; - - -- If the previous checks succeeded, update the stock amount - -- for INSERT commands. - IF TG_OP = ''INSERT'' THEN - UPDATE stock SET stock = stock -1 WHERE isbn = NEW.isbn; - END IF; - - RETURN NEW; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 31 (OID 3628899) --- --- Name: employees Type: TABLE Owner: postgres --- - CREATE TABLE "employees" ( "id" integer NOT NULL, "last_name" text NOT NULL, @@ -962,13 +962,13 @@ CREATE TABLE "employees" ( CONSTRAINT "employees_id" CHECK ((id > 100)), Constraint "employees_pkey" Primary Key ("id") ); - -- --- TOC Entry ID 32 (OID 3629174) +-- -- +-- -- TOC Entry ID 32 (OID 3629174) +-- -- +-- -- Name: editions Type: TABLE Owner: manager +-- -- -- --- Name: editions Type: TABLE Owner: manager --- - CREATE TABLE "editions" ( "isbn" text NOT NULL, "book_id" integer, @@ -979,188 +979,188 @@ CREATE TABLE "editions" ( CONSTRAINT "integrity" CHECK (((book_id NOTNULL) AND (edition NOTNULL))), Constraint "pkey" Primary Key ("isbn") ); - --- --- TOC Entry ID 10 (OID 3629402) -- --- Name: author_ids Type: SEQUENCE Owner: manager +-- -- +-- -- TOC Entry ID 10 (OID 3629402) +-- -- +-- -- Name: author_ids Type: SEQUENCE Owner: manager +-- -- -- - CREATE SEQUENCE "author_ids" start 0 increment 1 maxvalue 2147483647 minvalue 0 cache 1 ; - --- --- TOC Entry ID 35 (OID 3629424) -- --- Name: distinguished_authors Type: TABLE Owner: manager +-- -- +-- -- TOC Entry ID 35 (OID 3629424) +-- -- +-- -- Name: distinguished_authors Type: TABLE Owner: manager +-- -- -- - CREATE TABLE "distinguished_authors" ( "award" text ) INHERITS ("authors"); - -- --- TOC Entry ID 107 (OID 3726476) --- --- Name: "isbn_to_title" (text) Type: FUNCTION Owner: manager --- - -CREATE FUNCTION "isbn_to_title" (text) RETURNS text AS 'SELECT title FROM books - JOIN editions AS e (isbn, id) - USING (id) - WHERE isbn = $1' LANGUAGE 'sql'; - +-- -- +-- -- TOC Entry ID 107 (OID 3726476) +-- -- +-- -- Name: "isbn_to_title" (text) Type: FUNCTION Owner: manager +-- -- -- --- TOC Entry ID 36 (OID 3727889) +-- CREATE FUNCTION "isbn_to_title" (text) RETURNS text AS 'SELECT title FROM books +-- JOIN editions AS e (isbn, id) +-- USING (id) +-- WHERE isbn = $1' LANGUAGE 'sql'; -- --- Name: favorite_authors Type: TABLE Owner: manager +-- -- +-- -- TOC Entry ID 36 (OID 3727889) +-- -- +-- -- Name: favorite_authors Type: TABLE Owner: manager +-- -- -- - CREATE TABLE "favorite_authors" ( "employee_id" integer, "authors_and_titles" text[] ); +-- -- +-- -- TOC Entry ID 99 (OID 3728728) +-- -- +-- -- Name: "get_customer_name" (integer) Type: FUNCTION Owner: postgres +-- -- -- --- TOC Entry ID 99 (OID 3728728) --- --- Name: "get_customer_name" (integer) Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "get_customer_name" (integer) RETURNS text AS ' - DECLARE - - -- Declare aliases for user input. - customer_id ALIAS FOR $1; - - -- Declare variables to hold the customer name. - customer_fname TEXT; - customer_lname TEXT; - - BEGIN - - -- Retrieve the customer first and last name for the customer whose - -- ID matches the value supplied as a function argument. - SELECT INTO customer_fname, customer_lname - first_name, last_name FROM customers - WHERE id = customer_id; - - -- Return the name. - RETURN customer_fname || '' '' || customer_lname; - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 100 (OID 3728729) --- --- Name: "get_customer_id" (text,text) Type: FUNCTION Owner: postgres +-- CREATE FUNCTION "get_customer_name" (integer) RETURNS text AS ' +-- DECLARE -- - -CREATE FUNCTION "get_customer_id" (text,text) RETURNS integer AS ' - DECLARE - - -- Declare aliases for user input. - l_name ALIAS FOR $1; - f_name ALIAS FOR $2; - - -- Declare a variable to hold the customer ID number. - customer_id INTEGER; - - BEGIN - - -- Retrieve the customer ID number of the customer whose first and last - -- name match the values supplied as function arguments. - SELECT INTO customer_id id FROM customers - WHERE last_name = l_name AND first_name = f_name; - - -- Return the ID number. - RETURN customer_id; - END; -' LANGUAGE 'plpgsql'; - +-- -- Declare aliases for user input. +-- customer_id ALIAS FOR $1; -- --- TOC Entry ID 101 (OID 3728730) +-- -- Declare variables to hold the customer name. +-- customer_fname TEXT; +-- customer_lname TEXT; -- --- Name: "get_author" (text) Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "get_author" (text) RETURNS text AS ' - DECLARE - - -- Declare an alias for the function argument, - -- which should be the first name of an author. - f_name ALIAS FOR $1; - - -- Declare a variable with the same type as - -- the last_name field of the authors table. - l_name authors.last_name%TYPE; - - BEGIN - - -- Retrieve the last name of an author from the - -- authors table whose first name matches the - -- argument received by the function, and - -- insert it into the l_name variable. - SELECT INTO l_name last_name FROM authors WHERE first_name = f_name; - - -- Return the first name and last name, separated - -- by a space. - return f_name || '' '' || l_name; - - END; -' LANGUAGE 'plpgsql'; - +-- BEGIN -- --- TOC Entry ID 97 (OID 3728759) +-- -- Retrieve the customer first and last name for the customer whose +-- -- ID matches the value supplied as a function argument. +-- SELECT INTO customer_fname, customer_lname +-- first_name, last_name FROM customers +-- WHERE id = customer_id; -- --- Name: "get_author" (integer) Type: FUNCTION Owner: postgres +-- -- Return the name. +-- RETURN customer_fname || '' '' || customer_lname; +-- END; +-- ' LANGUAGE 'plpgsql'; -- - -CREATE FUNCTION "get_author" (integer) RETURNS text AS ' - DECLARE - - -- Declare an alias for the function argument, - -- which should be the id of the author. - author_id ALIAS FOR $1; - - -- Declare a variable that uses the structure of - -- the authors table. - found_author authors%ROWTYPE; - - BEGIN - - -- Retrieve a row of author information for - -- the author whose id number matches - -- the argument received by the function. - SELECT INTO found_author * FROM authors WHERE id = author_id; - - -- Return the first - RETURN found_author.first_name || '' '' || found_author.last_name; - - END; -' LANGUAGE 'plpgsql'; - --- --- TOC Entry ID 70 (OID 3743412) --- --- Name: "html_linebreaks" (text) Type: FUNCTION Owner: postgres --- - -CREATE FUNCTION "html_linebreaks" (text) RETURNS text AS ' - DECLARE - formatted_string text := ''''; - BEGIN - FOR i IN 0 .. length($1) LOOP - IF substr($1, i, 1) = '' -'' THEN - formatted_string := formatted_string || ''
''; - ELSE - formatted_string := formatted_string || substr($1, i, 1); - END IF; - END LOOP; - RETURN formatted_string; - END; -' LANGUAGE 'plpgsql'; +-- -- +-- -- TOC Entry ID 100 (OID 3728729) +-- -- +-- -- Name: "get_customer_id" (text,text) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "get_customer_id" (text,text) RETURNS integer AS ' +-- DECLARE +-- +-- -- Declare aliases for user input. +-- l_name ALIAS FOR $1; +-- f_name ALIAS FOR $2; +-- +-- -- Declare a variable to hold the customer ID number. +-- customer_id INTEGER; +-- +-- BEGIN +-- +-- -- Retrieve the customer ID number of the customer whose first and last +-- -- name match the values supplied as function arguments. +-- SELECT INTO customer_id id FROM customers +-- WHERE last_name = l_name AND first_name = f_name; +-- +-- -- Return the ID number. +-- RETURN customer_id; +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 101 (OID 3728730) +-- -- +-- -- Name: "get_author" (text) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "get_author" (text) RETURNS text AS ' +-- DECLARE +-- +-- -- Declare an alias for the function argument, +-- -- which should be the first name of an author. +-- f_name ALIAS FOR $1; +-- +-- -- Declare a variable with the same type as +-- -- the last_name field of the authors table. +-- l_name authors.last_name%TYPE; +-- +-- BEGIN +-- +-- -- Retrieve the last name of an author from the +-- -- authors table whose first name matches the +-- -- argument received by the function, and +-- -- insert it into the l_name variable. +-- SELECT INTO l_name last_name FROM authors WHERE first_name = f_name; +-- +-- -- Return the first name and last name, separated +-- -- by a space. +-- return f_name || '' '' || l_name; +-- +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 97 (OID 3728759) +-- -- +-- -- Name: "get_author" (integer) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "get_author" (integer) RETURNS text AS ' +-- DECLARE +-- +-- -- Declare an alias for the function argument, +-- -- which should be the id of the author. +-- author_id ALIAS FOR $1; +-- +-- -- Declare a variable that uses the structure of +-- -- the authors table. +-- found_author authors%ROWTYPE; +-- +-- BEGIN +-- +-- -- Retrieve a row of author information for +-- -- the author whose id number matches +-- -- the argument received by the function. +-- SELECT INTO found_author * FROM authors WHERE id = author_id; +-- +-- -- Return the first +-- RETURN found_author.first_name || '' '' || found_author.last_name; +-- +-- END; +-- ' LANGUAGE 'plpgsql'; +-- +-- -- +-- -- TOC Entry ID 70 (OID 3743412) +-- -- +-- -- Name: "html_linebreaks" (text) Type: FUNCTION Owner: postgres +-- -- +-- +-- CREATE FUNCTION "html_linebreaks" (text) RETURNS text AS ' +-- DECLARE +-- formatted_string text := ''''; +-- BEGIN +-- FOR i IN 0 .. length($1) LOOP +-- IF substr($1, i, 1) = '' +-- '' THEN +-- formatted_string := formatted_string || ''
''; +-- ELSE +-- formatted_string := formatted_string || substr($1, i, 1); +-- END IF; +-- END LOOP; +-- RETURN formatted_string; +-- END; +-- ' LANGUAGE 'plpgsql'; -- -- TOC Entry ID 37 (OID 3751599) @@ -1191,7 +1191,7 @@ CREATE TABLE "subjects" ( -- Name: sum(text) Type: AGGREGATE Owner: postgres -- -CREATE AGGREGATE sum ( BASETYPE = text, SFUNC = textcat, STYPE = text, INITCOND = '' ); +-- CREATE AGGREGATE sum ( BASETYPE = text, SFUNC = textcat, STYPE = text, INITCOND = '' ); -- -- TOC Entry ID 39 (OID 3751975) @@ -1225,14 +1225,14 @@ CREATE TABLE "book_backup" ( -- Name: "sync_authors_and_books" () Type: FUNCTION Owner: postgres -- -CREATE FUNCTION "sync_authors_and_books" () RETURNS opaque AS ' - BEGIN - IF TG_OP = ''UPDATE'' THEN - UPDATE books SET author_id = new.id WHERE author_id = old.id; - END IF; - RETURN new; - END; -' LANGUAGE 'plpgsql'; +-- CREATE FUNCTION "sync_authors_and_books" () RETURNS opaque AS ' +-- BEGIN +-- IF TG_OP = ''UPDATE'' THEN +-- UPDATE books SET author_id = new.id WHERE author_id = old.id; +-- END IF; +-- RETURN new; +-- END; +-- ' LANGUAGE 'plpgsql'; -- -- TOC Entry ID 41 (OID 4063343) @@ -1251,8 +1251,8 @@ CREATE TABLE "schedules" ( -- -- Name: recent_shipments Type: VIEW Owner: postgres -- - -CREATE VIEW "recent_shipments" as SELECT count(*) AS num_shipped, max(shipments.ship_date) AS max, b.title FROM ((shipments JOIN editions USING (isbn)) NATURAL JOIN books b(book_id)) GROUP BY b.title ORDER BY count(*) DESC; +-- +-- CREATE VIEW "recent_shipments" as SELECT count(*) AS num_shipped, max(shipments.ship_date) AS max, b.title FROM ((shipments JOIN editions USING (isbn)) NATURAL JOIN books b(book_id)) GROUP BY b.title ORDER BY count(*) DESC; -- -- Data for TOC Entry ID 112 (OID 3117548) @@ -1774,7 +1774,7 @@ CREATE INDEX "text_idx" on "text_sorting" using btree ( "letter" "bpchar_ops" ) -- Name: check_shipment Type: TRIGGER Owner: postgres -- -CREATE TRIGGER "check_shipment" BEFORE INSERT OR UPDATE ON "shipments" FOR EACH ROW EXECUTE PROCEDURE "check_shipment_addition" (); +-- CREATE TRIGGER "check_shipment" BEFORE INSERT OR UPDATE ON "shipments" FOR EACH ROW EXECUTE PROCEDURE "check_shipment_addition" (); -- -- TOC Entry ID 135 (OID 3752103) @@ -1782,15 +1782,15 @@ CREATE TRIGGER "check_shipment" BEFORE INSERT OR UPDATE ON "shipments" FOR EACH -- Name: sync_authors_books Type: TRIGGER Owner: manager -- -CREATE TRIGGER "sync_authors_books" BEFORE UPDATE ON "authors" FOR EACH ROW EXECUTE PROCEDURE "sync_authors_and_books" (); +-- CREATE TRIGGER "sync_authors_books" BEFORE UPDATE ON "authors" FOR EACH ROW EXECUTE PROCEDURE "sync_authors_and_books" (); -- -- TOC Entry ID 139 (OID 4063374) -- -- Name: "RI_ConstraintTrigger_4063373" Type: TRIGGER Owner: postgres -- - -CREATE CONSTRAINT TRIGGER "valid_employee" AFTER INSERT OR UPDATE ON "schedules" FROM "employees" NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_check_ins" ('valid_employee', 'schedules', 'employees', 'FULL', 'employee_id', 'id'); +-- +-- CREATE CONSTRAINT TRIGGER "valid_employee" AFTER INSERT OR UPDATE ON "schedules" FROM "employees" NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_check_ins" ('valid_employee', 'schedules', 'employees', 'FULL', 'employee_id', 'id'); -- -- TOC Entry ID 137 (OID 4063376) @@ -1798,7 +1798,7 @@ CREATE CONSTRAINT TRIGGER "valid_employee" AFTER INSERT OR UPDATE ON "schedules" -- Name: "RI_ConstraintTrigger_4063375" Type: TRIGGER Owner: postgres -- -CREATE CONSTRAINT TRIGGER "valid_employee" AFTER DELETE ON "employees" FROM "schedules" NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_noaction_del" ('valid_employee', 'schedules', 'employees', 'FULL', 'employee_id', 'id'); +-- CREATE CONSTRAINT TRIGGER "valid_employee" AFTER DELETE ON "employees" FROM "schedules" NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_noaction_del" ('valid_employee', 'schedules', 'employees', 'FULL', 'employee_id', 'id'); -- -- TOC Entry ID 138 (OID 4063378) @@ -1806,7 +1806,7 @@ CREATE CONSTRAINT TRIGGER "valid_employee" AFTER DELETE ON "employees" FROM "sc -- Name: "RI_ConstraintTrigger_4063377" Type: TRIGGER Owner: postgres -- -CREATE CONSTRAINT TRIGGER "valid_employee" AFTER UPDATE ON "employees" FROM "schedules" NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_noaction_upd" ('valid_employee', 'schedules', 'employees', 'FULL', 'employee_id', 'id'); +-- CREATE CONSTRAINT TRIGGER "valid_employee" AFTER UPDATE ON "employees" FROM "schedules" NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_noaction_upd" ('valid_employee', 'schedules', 'employees', 'FULL', 'employee_id', 'id'); -- -- TOC Entry ID 140 (OID 3752079) @@ -1821,15 +1821,15 @@ CREATE RULE sync_stock_with_editions AS ON UPDATE TO editions DO UPDATE stock SE -- Name: subject_ids Type: SEQUENCE SET Owner: -- -SELECT setval ('"subject_ids"', 15, 't'); +-- SELECT setval ('"subject_ids"', 15, 't'); -- -- TOC Entry ID 7 (OID 3574018) -- -- Name: book_ids Type: SEQUENCE SET Owner: -- - -SELECT setval ('"book_ids"', 41478, 't'); +-- +-- SELECT setval ('"book_ids"', 41478, 't'); -- -- TOC Entry ID 9 (OID 3628626)