async-deco
Advanced tools
Comparing version 4.3.0 to 5.0.0
var _cache = require('../src/cache'); | ||
var wrapper = require('../src/noop'); | ||
function cache(cache) { | ||
return _cache(wrapper, cache); | ||
function cache(cache, opts) { | ||
return _cache(wrapper, cache, opts); | ||
} | ||
module.exports = cache; |
var _fallbackCache = require('../src/fallback-cache'); | ||
var wrapper = require('../src/noop'); | ||
function fallbackCache(cache, error) { | ||
return _fallbackCache(wrapper, cache, error); | ||
function fallbackCache(cache, opts) { | ||
return _fallbackCache(wrapper, cache, opts); | ||
} | ||
module.exports = fallbackCache; |
{ | ||
"name": "async-deco", | ||
"version": "4.3.0", | ||
"version": "5.0.0", | ||
"description": "A collection of decorators for adding features to asynchronous functions (callback or promise based).", | ||
@@ -28,3 +28,3 @@ "main": "index.js", | ||
"husky": "^0.10.2", | ||
"memoize-cache": "^1.0.2", | ||
"memoize-cache": "^3.0.0", | ||
"mocha": "^2.1.0", | ||
@@ -36,4 +36,5 @@ "npm-release": "^1.0.0" | ||
"require-all": "^2.0.0", | ||
"setimmediate": "^1.0.4" | ||
"setimmediate": "^1.0.4", | ||
"uuid": "^2.0.2" | ||
} | ||
} |
var _cache = require('../src/cache'); | ||
var wrapper = require('../src/promise-translator'); | ||
function cache(cache) { | ||
return _cache(wrapper, cache); | ||
function cache(cache, opts) { | ||
return _cache(wrapper, cache, opts); | ||
} | ||
module.exports = cache; |
var _fallbackCache = require('../src/fallback-cache'); | ||
var wrapper = require('../src/promise-translator'); | ||
function fallbackCache(cache, error) { | ||
return _fallbackCache(wrapper, cache, error); | ||
function fallbackCache(cache, opts) { | ||
return _fallbackCache(wrapper, cache, opts); | ||
} | ||
module.exports = fallbackCache; |
@@ -157,3 +157,3 @@ async-deco | ||
It logs "cachehit" with {key: cache key, result: cache result} | ||
It logs "memoize-hit" with {key: cache key, result: cache result} | ||
@@ -169,6 +169,7 @@ Cache | ||
``` | ||
It takes 1 argument: | ||
It takes 2 arguments: | ||
* a cache object [mandatory]. The interface should be compatible with memoize-cache (https://github.com/sithmel/memoize-cache) | ||
* an "options" object [optional]: | ||
It logs "cachehit" with {key: cache key, result: cache result}. | ||
It logs "cache-hit" with {key: cache key, result: cache result} or "cache-error" (when the cache fails) with {cacheErr: error object from the cache}. | ||
@@ -191,3 +192,3 @@ Proxy | ||
It logs "access denied" with { err: error returned by the guard function} | ||
It logs "proxy-denied" with { err: error returned by the guard function} | ||
@@ -232,3 +233,3 @@ Fallback | ||
var fallback = fallbackCacheDecorator(cache, Error); | ||
var fallback = fallbackCacheDecorator(cache, options); | ||
var myfunc = fallback(function (..., cb) { .... }); | ||
@@ -238,5 +239,8 @@ ``` | ||
* a cache object [mandatory]. The interface should be compatible with memoize-cache (https://github.com/sithmel/memoize-cache) | ||
* error instance for deciding to fallback, or a function taking the error and result (if it returns true it'll trigger the fallback) [optional, it falls back on any error by default] | ||
* an options object with this optional attributes: | ||
* error: the error instance for deciding to fallback, or a function taking the error and result (if it returns true it'll trigger the fallback) [optional, it falls back on any error by default] | ||
* useStale: if true it will use "stale" cache items as valid [optional, defaults to false] | ||
* noPush: it true it won't put anything in the cache [optional, defaults to false] | ||
It logs "fallback-cache" with {key: cache key, result: cache result, actualResult: {err: error returned, res: result returned}} | ||
It logs "fallback-cache-hit" with {key: cache key, result: cache object, actualResult: {err: error returned, res: result returned}} or "fallback-cache-error" with {err: error returned by the function, cacheErr: error returned by the cache}. | ||
@@ -303,3 +307,3 @@ Timeout | ||
It logs "deduping" whenever is calling more than one callback with the same results. | ||
It logs "dedupe" whenever is calling more than one callback with the same results. | ||
{len: number of function call saved, key: cache key} | ||
@@ -326,7 +330,7 @@ | ||
--------------------- | ||
This special decorator add a couple of important checks to your callback based asynchronous function. | ||
It capture any unhandled exception that has been throwed and it uses as "err" argument of the callback. | ||
If the callback is fired twice, the second time it will be fire a "Callback fired twice" exception. | ||
This special decorator adds a couple of important checks to your callback based asynchronous functions. | ||
It captures any unhandled exception that has been throwed, and it uses it as "err" argument of the callback. | ||
If the callback is fired twice, the second time it will fire a "Callback fired twice" exception. | ||
```js | ||
var callbackify = require('async-deco/utils/sanitizeAsyncFunction'); | ||
var sanitizeAsyncFunction = require('async-deco/utils/sanitizeAsyncFunction'); | ||
@@ -410,2 +414,63 @@ var func = sanitizeAsyncFunction(function () { | ||
Parallel - Waterfall - Race | ||
--------------------------- | ||
These special utilities can be used to manage the execution of a group of functions (callback based). | ||
"parallel" executes every function in parallel. If a function returns an error the execution stops immediatly returning the error. | ||
The functions will get the same arguments and the result will be an array of all the results. | ||
```js | ||
var func = parallel([ | ||
function (x, cb) { | ||
cb(null, x + 1); | ||
}, | ||
function (x, cb) { | ||
cb(null, x + 2); | ||
} | ||
]); | ||
func(3, function (err, values) { | ||
// values contains [4, 5] | ||
}); | ||
``` | ||
"waterfall" executes the functions in series. The first function will get the arguments and the others will use the arguments passed by the previous one: | ||
```js | ||
var func = waterfall([ | ||
function (x, cb) { | ||
cb(null, x + ' world'); | ||
}, | ||
function (x, cb) { | ||
cb(null, x + '!'); | ||
} | ||
]); | ||
func('hello', function (err, value) { | ||
// value === 'hello world!' | ||
}); | ||
``` | ||
"race" will execute all functions in parallel but it will return the first valid result. | ||
It is very easy to combine these functions to create a more complex flow: | ||
```js | ||
var func = waterfall([ | ||
parallel([ | ||
function (x, cb) { | ||
cb(null, x * 2); | ||
}, | ||
function (x, cb) { | ||
cb(null, x * 3); | ||
} | ||
]), | ||
function (numbers, cb) { | ||
cb(null, numbers.reduce(function (acc, item) { | ||
return acc + item; | ||
}, 0)); | ||
}, | ||
function (x, cb) { | ||
cb(null, x - 5); | ||
} | ||
]); | ||
func(5, function (err, value) { | ||
// value === 20; | ||
}); | ||
``` | ||
Examples and use cases | ||
@@ -412,0 +477,0 @@ ====================== |
var defaultLogger = require('../utils/default-logger'); | ||
function cacheDecorator(wrapper, cache) { | ||
function cacheDecorator(wrapper, cache, opts) { | ||
opts = opts || {}; | ||
return wrapper(function (func) { | ||
@@ -11,14 +13,18 @@ return function () { | ||
args[args.length - 1] = function (err, dep) { | ||
if (!err) { | ||
cache.push(args, dep); | ||
} | ||
cb(undefined, dep); | ||
}; | ||
cache.query(args, function (err, cacheQuery) { | ||
if (!err && cacheQuery.cached === true) { | ||
logger('cachehit', {key: cacheQuery.key, result: cacheQuery.hit}); | ||
cb(undefined, cacheQuery.hit); | ||
if (err) { | ||
logger('cache-error', {cacheErr: err}); | ||
func.apply(context, args); | ||
} | ||
else if (cacheQuery.cached === true && !cacheQuery.stale) { | ||
logger('cache-hit', {key: cacheQuery.key, result: cacheQuery}); | ||
cb(null, cacheQuery.hit); | ||
} | ||
else { | ||
args[args.length - 1] = function (err, res) { | ||
if (!err) { | ||
cache.push(args, res); | ||
} | ||
cb(err, res); | ||
}; | ||
func.apply(context, args); | ||
@@ -25,0 +31,0 @@ } |
var defaultLogger = require('../utils/default-logger'); | ||
var keyGetter = require('memoize-cache/key-getter'); | ||
function dedupeDecorator(wrapper, getKey) { | ||
getKey = getKey || function () { return '_default'; }; | ||
getKey = keyGetter(getKey || function () { return '_default'; }); | ||
@@ -14,3 +15,3 @@ return wrapper(function (func) { | ||
var cb = args[args.length - 1]; | ||
var cacheKey = getKey.apply(context, args).toString(); | ||
var cacheKey = getKey.apply(context, args); | ||
@@ -20,3 +21,3 @@ function runQueue(cacheKey, err, dep) { | ||
if (len > 1) { | ||
logger('deduping', {len: len, key: cacheKey}); | ||
logger('dedupe', {len: len, key: cacheKey}); | ||
} | ||
@@ -29,3 +30,6 @@ for (var i = 0; i < len; i++) { | ||
if (!(cacheKey in callback_queues)) { | ||
if (cacheKey === null) { | ||
func.apply(context, args); | ||
} | ||
else if (!(cacheKey in callback_queues)) { | ||
// creating callback | ||
@@ -32,0 +36,0 @@ args[args.length - 1] = (function (cacheKey) { |
var defaultLogger = require('../utils/default-logger'); | ||
function fallbackCacheDecorator(wrapper, cache, error) { | ||
function fallbackCacheDecorator(wrapper, cache, opts) { | ||
var condition; | ||
error = error || Error; | ||
opts = opts || {}; | ||
var error = opts.error || Error; | ||
var useStale = opts.useStale; | ||
var noPush = opts.noPush; | ||
if (error === Error || Error.isPrototypeOf(error)) { | ||
@@ -23,6 +27,11 @@ condition = function (err, dep) { return err instanceof error; }; | ||
cache.query(args, function (e, cacheQuery) { | ||
if (!e && cacheQuery.cached === true) { | ||
logger('fallback-cachehit', {key: cacheQuery.key, result: cacheQuery.hit, actualResult: {err: err, res: dep}}); | ||
cb(undefined, cacheQuery.hit); | ||
if (e) { | ||
logger('fallback-cache-error', {err: err, cacheErr: e}); | ||
cb(err, dep); | ||
} | ||
else if (cacheQuery.cached === true && | ||
(!cacheQuery.stale || (useStale && cacheQuery.stale))) { | ||
logger('fallback-cache-hit', {key: cacheQuery.key, result: cacheQuery, actualResult: {err: err, res: dep}}); | ||
cb(null, cacheQuery.hit); | ||
} | ||
else { | ||
@@ -34,4 +43,4 @@ cb(err, dep); | ||
else { | ||
cache.push(args, dep); | ||
cb(undefined, dep); | ||
!noPush && cache.push(args, dep); | ||
cb(null, dep); | ||
} | ||
@@ -38,0 +47,0 @@ }; |
@@ -22,3 +22,3 @@ var defaultLogger = require('../utils/default-logger'); | ||
logger('fallback', {actualResult: {err: err, res: dep}}); | ||
cb(undefined, fallbackValue); | ||
cb(null, fallbackValue); | ||
} | ||
@@ -25,0 +25,0 @@ else { |
require('setimmediate'); | ||
var defaultLogger = require('../utils/default-logger'); | ||
var keyGetter = require('memoize-cache/key-getter'); | ||
function limitDecorator(wrapper, max, getKey) { | ||
getKey = getKey || function () { return '_default'; }; | ||
getKey = keyGetter(getKey || function () { return '_default'; }); | ||
@@ -16,3 +17,3 @@ return wrapper(function (func) { | ||
var cb = args[args.length - 1]; | ||
var cacheKey = getKey.apply(context, args).toString(); | ||
var cacheKey = getKey.apply(context, args); | ||
@@ -19,0 +20,0 @@ function runQueues() { |
var buildLogger = require('../utils/build-logger'); | ||
var defaultLogger = require('../utils/default-logger'); | ||
var uuid = require('uuid'); | ||
@@ -10,3 +11,3 @@ function logDecorator(wrapper, log, name) { | ||
if (log) { | ||
id = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10); | ||
id = uuid.v4(); | ||
context = buildLogger(this, name, id, log); | ||
@@ -22,3 +23,3 @@ } else { | ||
if (err) { | ||
logger('error', { | ||
logger('log-error', { | ||
err: err | ||
@@ -28,3 +29,3 @@ }); | ||
else { | ||
logger('end', { | ||
logger('log-end', { | ||
result: dep | ||
@@ -35,3 +36,3 @@ }); | ||
}; | ||
logger('start'); | ||
logger('log-start', {args: args.slice(0, -1), context: context}); | ||
func.apply(context, args); | ||
@@ -38,0 +39,0 @@ }; |
var defaultLogger = require('../utils/default-logger'); | ||
var keyGetter = require('memoize-cache/key-getter'); | ||
function memoizeDecorator(wrapper, getKey) { | ||
getKey = getKey || function () { return '_default'; }; | ||
getKey = keyGetter(getKey || function () { return '_default'; }); | ||
return wrapper(function (func) { | ||
@@ -12,5 +13,5 @@ var cache = {}; | ||
var cb = args[args.length - 1]; | ||
var cacheKey = getKey.apply(context, args).toString(); | ||
var cacheKey = getKey.apply(context, args); | ||
args[args.length - 1] = function (err, dep) { | ||
if (!err) { | ||
if (!err && cacheKey !== null) { | ||
cache[cacheKey] = dep; | ||
@@ -20,5 +21,5 @@ } | ||
}; | ||
if (cacheKey in cache) { | ||
logger('cachehit', {key: cacheKey, result: cache[cacheKey]}); | ||
return cb(undefined, cache[cacheKey]); | ||
if (cacheKey !== null && cacheKey in cache) { | ||
logger('memoize-hit', {key: cacheKey, result: cache[cacheKey]}); | ||
return cb(null, cache[cacheKey]); | ||
} | ||
@@ -25,0 +26,0 @@ else { |
@@ -14,3 +14,3 @@ var defaultLogger = require('../utils/default-logger'); | ||
if (err) { | ||
logger('access denied', { | ||
logger('proxy-denied', { | ||
err: err | ||
@@ -17,0 +17,0 @@ }); |
@@ -10,2 +10,3 @@ var assert = require('chai').assert; | ||
dedupeKey = dedupeDecorator(function (n) { return n % 2 === 0 ? 'even' : 'odd'; }); | ||
noDedupe = dedupeDecorator(function (n) { return null; }); | ||
}); | ||
@@ -100,2 +101,46 @@ | ||
}); | ||
it('must dedupe a function using a key', function (done) { | ||
var numberRuns = 0; | ||
var numberCBRuns = 0; | ||
var f = noDedupe(function (a, next) { | ||
numberRuns++; | ||
setTimeout(function () { | ||
next(undefined, a); | ||
}, 0); | ||
}); | ||
f(1, function (err, res) { | ||
numberCBRuns++; | ||
assert.equal(res, 1); | ||
}); | ||
f(2, function (err, res) { | ||
numberCBRuns++; | ||
assert.equal(res, 2); | ||
}); | ||
f(3, function (err, res) { | ||
numberCBRuns++; | ||
assert.equal(res, 3); | ||
}); | ||
f(4, function (err, res) { | ||
numberCBRuns++; | ||
assert.equal(res, 4); | ||
}); | ||
f(5, function (err, res) { | ||
numberCBRuns++; | ||
assert.equal(res, 5); | ||
}); | ||
setTimeout(function () { | ||
assert.equal(numberRuns, 5); | ||
assert.equal(numberCBRuns, 5); | ||
done(); | ||
}, 60); | ||
}); | ||
}); |
@@ -24,4 +24,4 @@ var assert = require('chai').assert; | ||
assert.deepEqual(log, [ | ||
{type: 'start', obj: undefined}, | ||
{type: 'end', obj: {result: 6}} | ||
{type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context}}, | ||
{type: 'log-end', obj: {result: 6}} | ||
]); | ||
@@ -39,4 +39,4 @@ done(); | ||
assert.deepEqual(log, [ | ||
{type: 'start', obj: undefined}, | ||
{type: 'error', obj: {err: new Error('error!')}} | ||
{type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context}}, | ||
{type: 'log-error', obj: {err: new Error('error!')}} | ||
]); | ||
@@ -43,0 +43,0 @@ done(); |
@@ -27,4 +27,4 @@ var assert = require('chai').assert; | ||
assert.deepEqual(log, [ | ||
{type: 'start', obj: undefined}, | ||
{type: 'end', obj: {result: 6}} | ||
{type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context}}, | ||
{type: 'log-end', obj: {result: 6}} | ||
]); | ||
@@ -44,4 +44,4 @@ done(); | ||
assert.deepEqual(log, [ | ||
{type: 'start', obj: undefined}, | ||
{type: 'error', obj: {err: new Error('error!')}} | ||
{type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context}}, | ||
{type: 'log-error', obj: {err: new Error('error!')}} | ||
]); | ||
@@ -48,0 +48,0 @@ done(); |
@@ -40,4 +40,4 @@ var assert = require('chai').assert; | ||
assert.deepEqual(log, [ | ||
{ type: 'start', obj: undefined }, | ||
{ type: 'end', obj: { result: 6 } } | ||
{type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context}}, | ||
{ type: 'log-end', obj: { result: 6 } } | ||
]); | ||
@@ -59,3 +59,4 @@ done(); | ||
assert.equal(dep, 'no value'); | ||
assert.deepEqual(log[0], { type: 'start', obj: undefined }); | ||
assert.deepEqual(log[0], { type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context} }); | ||
assert.deepEqual(log[1], { type: 'timeout', obj: { ms: 20 }}); | ||
@@ -72,3 +73,3 @@ | ||
assert.instanceOf(log[4].obj.actualResult.err, TimeoutError); | ||
assert.deepEqual(log[5], { type: 'end', obj: { result: 'no value' } }); | ||
assert.deepEqual(log[5], { type: 'log-end', obj: { result: 'no value' } }); | ||
done(); | ||
@@ -92,3 +93,3 @@ }); | ||
assert.equal(dep, 6); | ||
assert.deepEqual(log[0], { type: 'start', obj: undefined }); | ||
assert.deepEqual(log[0], { type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context} }); | ||
assert.deepEqual(log[1], { type: 'timeout', obj: { ms: 20 }}); | ||
@@ -99,3 +100,3 @@ assert.equal(log[2].type, 'retry'); | ||
assert.instanceOf(log[2].obj.actualResult.err, TimeoutError); | ||
assert.deepEqual(log[3], { type: 'end', obj: { result: 6 } }); | ||
assert.deepEqual(log[3], { type: 'log-end', obj: { result: 6 } }); | ||
done(); | ||
@@ -102,0 +103,0 @@ }); |
@@ -62,4 +62,4 @@ var assert = require('chai').assert; | ||
assert.deepEqual(log, [ | ||
{ type: 'start', obj: undefined }, | ||
{ type: 'end', obj: { result: 6 } } | ||
{ type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context} }, | ||
{ type: 'log-end', obj: { result: 6 } } | ||
]); | ||
@@ -79,3 +79,3 @@ done(); | ||
assert.equal(dep, 'no value'); | ||
assert.deepEqual(log[0], { type: 'start', obj: undefined }); | ||
assert.deepEqual(log[0], { type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context} }); | ||
assert.deepEqual(log[1], { type: 'timeout', obj: { ms: 20 }}); | ||
@@ -92,3 +92,3 @@ | ||
assert.instanceOf(log[4].obj.actualResult.err, TimeoutError); | ||
assert.deepEqual(log[5], { type: 'end', obj: { result: 'no value' } }); | ||
assert.deepEqual(log[5], { type: 'log-end', obj: { result: 'no value' } }); | ||
done(); | ||
@@ -111,3 +111,3 @@ }); | ||
assert.deepEqual(log[0], { type: 'start', obj: undefined }); | ||
assert.deepEqual(log[0], { type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context} }); | ||
assert.deepEqual(log[1], { type: 'timeout', obj: { ms: 20 }}); | ||
@@ -118,3 +118,3 @@ assert.equal(log[2].type, 'retry'); | ||
assert.instanceOf(log[2].obj.actualResult.err, TimeoutError); | ||
assert.deepEqual(log[3], { type: 'end', obj: { result: 6 } }); | ||
assert.deepEqual(log[3], { type: 'log-end', obj: { result: 6 } }); | ||
done(); | ||
@@ -121,0 +121,0 @@ }); |
@@ -43,4 +43,4 @@ var assert = require('chai').assert; | ||
assert.deepEqual(log, [ | ||
{ type: 'start', obj: undefined }, | ||
{ type: 'end', obj: { result: 6 } } | ||
{ type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context} }, | ||
{ type: 'log-end', obj: { result: 6 } } | ||
]); | ||
@@ -87,4 +87,4 @@ done(); | ||
assert.deepEqual(log, [ | ||
{ type: 'start', obj: undefined }, | ||
{ type: 'end', obj: { result: 6 } } | ||
{ type: 'log-start', obj: {args: [1, 2, 3], context: log[0].obj.context} }, | ||
{ type: 'log-end', obj: { result: 6 } } | ||
]); | ||
@@ -91,0 +91,0 @@ done(); |
@@ -20,3 +20,3 @@ function isPromise(obj) { | ||
output.then(function (res) { // onfulfilled | ||
cb(undefined, res); | ||
cb(null, res); | ||
}, | ||
@@ -28,3 +28,3 @@ function (error) { // onrejected | ||
else { | ||
cb(undefined, output); | ||
cb(null, output); | ||
} | ||
@@ -31,0 +31,0 @@ }; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
97483
87
2640
505
4
+ Addeduuid@^2.0.2
+ Addeduuid@2.0.3(transitive)