js-awe
Advanced tools
Comparing version 1.0.7 to 1.0.8
{ | ||
"name": "js-awe", | ||
"version": "1.0.7", | ||
"version": "1.0.8", | ||
"description": "", | ||
@@ -23,2 +23,3 @@ "type": "module", | ||
"node-fetch": "^3.2.10", | ||
"p-limit": "^4.0.0", | ||
"ramda": "^0.28.0", | ||
@@ -25,0 +26,0 @@ "stream": "^0.0.2", |
@@ -249,2 +249,124 @@ 'use strict' | ||
function transition(states, events, transitions) | ||
{ | ||
states.forEach(validateStateFormat) | ||
events.forEach(validateEventFormat) | ||
let state = states[0] | ||
let finalTransitions = Object.entries(transitions).reduce( | ||
(acum, [stateKey, stateValue]) => { | ||
// validations | ||
validateState(stateKey) | ||
let newStateValue = stateValue | ||
if(typeof stateValue === 'string') | ||
{ | ||
validateState(stateValue) | ||
newStateValue = events.reduce( | ||
(acum, current) => { | ||
acum[current] = stateValue | ||
return acum | ||
}, | ||
{} | ||
) | ||
}else | ||
{ | ||
Object.entries(newStateValue).forEach(([key, value])=> { | ||
validateEvent(key) | ||
validateState(value) | ||
}) | ||
} | ||
acum[stateKey] = {...acum[stateKey], ...newStateValue} | ||
return acum | ||
}, | ||
states.reduce( | ||
(acum, current) => { | ||
acum[current] = | ||
events.reduce( | ||
(acum2, el2) => { | ||
acum2[el2] = el2.toUpperCase() | ||
return acum2 | ||
}, | ||
{} | ||
) | ||
return acum | ||
}, | ||
{} | ||
) | ||
) | ||
function sendEvent(event) { | ||
validateEvent(event) | ||
return state = finalTransitions[state][event] | ||
} | ||
sendEvent.valueOf = () => state | ||
return sendEvent | ||
function validateStateFormat(state) | ||
{ | ||
if(state !== state.toUpperCase()) | ||
throw new CustomError('STATE_MUST_BE_UPPERCASE', `The state: ${state} does not have all characters in uppercase`) | ||
} | ||
function validateState(state) | ||
{ | ||
if(states.some(el => el === state) === false) | ||
throw new CustomError('STATE_NOT_FOUND', `The state: ${state} was not found in the list of states supplied: ${states}`) | ||
} | ||
function validateEventFormat(event) | ||
{ | ||
if(event !== event.toLowerCase()) | ||
throw new CustomError('EVENT_MUST_BE_LOWERCASE', `The event: ${event} does not have all characters in lowercase`) | ||
} | ||
function validateEvent(event) | ||
{ | ||
if(events.some(el => el === event) === false) | ||
throw new CustomError('EVENT_NOT_FOUND', `The event: ${event} was not found in the list of events supplied: ${events}`) | ||
} | ||
} | ||
// const tranDef = [ | ||
// ['SYNC', 'PROMISE', 'FUTURE', 'PROMISE_AND_FUTURE'], | ||
// ['sync','promise','future'], | ||
// // STATE:{event:NEW_STATE} | ||
// // if a event is not defined within a STATE then the default value is selected STATE:{missing_event: NEW_STATE(missing_event.toUpperCase())} | ||
// { | ||
// PROMISE:{ | ||
// sync:'PROMISE', | ||
// future: 'PROMISE_AND_FUTURE' | ||
// //by default: promise: 'PROMISE' | ||
// }, | ||
// FUTURE:{ | ||
// sync:'FUTURE', | ||
// promise: 'PROMISE_AND_FUTURE', | ||
// }, | ||
// PROMISE_AND_FUTURE: 'PROMISE_AND_FUTURE' // same as {sync: 'PROMISE_AND_FUTURE', promise: 'PROMISE_AND_FUTURE', future: 'PROMISE_AND_FUTURE'} | ||
// } | ||
// ] | ||
// const typeOfList = transition(...tranDef) | ||
// typeOfList('future') //? | ||
// typeOfList('future') //? | ||
// typeOfList('promise') //? | ||
// typeOfList('sync') //? | ||
// try{ | ||
// typeOfList('sync2') //? | ||
// }catch(e) {console.log(e)} | ||
// typeOfList('sync') //? | ||
// typeOfList.valueOf() //? | ||
function arrayToObject(arr, defaultValueFunction) { | ||
@@ -1457,2 +1579,3 @@ return arr.reduce((acum, current, index) => { | ||
Enum, | ||
transition, | ||
pushUniqueKey, | ||
@@ -1516,2 +1639,3 @@ pushUniqueKeyOrChange, | ||
Enum, | ||
transition, | ||
pushUniqueKey, | ||
@@ -1518,0 +1642,0 @@ pushUniqueKeyOrChange, |
@@ -148,5 +148,6 @@ import { resolve } from 'fluture' | ||
if(isElToAccrue === false && accruingParallel === true) { | ||
// In cases we stopped because next element even though have the grandParent as ancestor but is more | ||
// nested than our current parallelization, then we need to cancel accruing and restore all elements to acum. | ||
if( isAncestorOf(nextToEl)(elGrandparent) && nextToEl?.length > el.path.length ) | ||
// In cases we stopped because next element is more nested than our current parallelization | ||
// even though it has the grandParent as ancestor, then we need to cancel accruing and | ||
// restore all elements to acum. | ||
if( nextToEl?.length > el.path.length && isAncestorOf(nextToEl)(elGrandparent) ) | ||
{ | ||
@@ -153,0 +154,0 @@ acum.push(...stackItemsToParallelize) |
// ts-check | ||
import * as R from 'ramda'; | ||
import { sorterByPaths } from './jsUtils.js' | ||
import { reject, resolve, parallel as RParallel, isFuture } from 'fluture'; | ||
import { transition, sorterByPaths, CustomError } from './jsUtils.js' | ||
import { reject, resolve, parallel as FParallel, isFuture } from 'fluture'; | ||
import { isPromise } from 'util/types'; | ||
import pLimit from 'p-limit'; | ||
@@ -447,2 +449,6 @@ // Only needed for testing | ||
function isAcumAPromiseAndElemAnError(acum, elem) { | ||
return elem instanceof Error && isPromise(acum) | ||
} | ||
const pipeWithChain = function (...func) { | ||
@@ -669,2 +675,4 @@ return function (...params) { | ||
chainFun = acum['fantasy-land/chain'].bind(acum) | ||
else if (isPromise(acum)) | ||
chainFun = acum.then.bind(acum) | ||
//else if (typeof acum?.flatMap === 'function') | ||
@@ -684,3 +692,3 @@ // chainFun = acum.flatMap.bind(acum) | ||
// For flutures we try catch so there will be transformed in a reject, | ||
if (acum?.constructor?.name === 'Future') { | ||
if (acum?.constructor?.name === 'Future' || isPromise(acum)) { | ||
try { | ||
@@ -697,2 +705,6 @@ result = pipeFunc(elem) | ||
if (isAcumAPromiseAndElemAnError(acum, result)) { | ||
return acum.then(()=>Promise.reject(result)) | ||
} | ||
// inside chainFun the return needs to be of the same type as the original acum drag value. | ||
@@ -737,3 +749,50 @@ // else we wrap the result using the constructor. | ||
// // Example with error | ||
// RE.pipe( | ||
// (x,y) => x+y, | ||
// x => resolve([x+8, x+3]), | ||
// x => new Error('My controlled error...'), | ||
// x => x.filter(elem => elem > 15) | ||
// )(5, 6) | ||
// .pipe(fork(RLog('pipeWithChain-Ex3-Err: '))(RLog('pipeWithChain-Ex3-OK: '))) | ||
// // Example with Future reject(error) | ||
// RE.pipe( | ||
// (x,y) => x+y, | ||
// x => reject('my error...'), | ||
// x=>x+3 | ||
// )(5, 6) | ||
// .pipe(fork(RLog('pipe-Ex4-Err: '))(RLog('pipe-Ex4-OK: '))) | ||
// // Example with Promise.reject(error) | ||
// RE.pipe( | ||
// (x,y) => x+y, | ||
// x => Promise.reject('my error...'), | ||
// x=>x+3 | ||
// )(5, 6) | ||
// .then(RLog('pipe-Ex5-OK: '),RLog('pipe-Ex5-Err: ') ) | ||
// // Example with throw error Future | ||
// RE.pipe( | ||
// (x,y) => x+y, | ||
// x => resolve([x+8, x+3]), | ||
// // throw new error for flutures are transform to reject. | ||
// x => {throw new Error('aaaa')}, | ||
// x => x.filter(elem => elem > 15) | ||
// )(5, 6) | ||
// .pipe(fork(RLog('pipeWithChain-Ex6-Err: '))(RLog('pipeWithChain-Ex6-OK: '))) | ||
// // Example with throw error Promise | ||
// RE.pipe( | ||
// (x,y) => x+y, | ||
// x => Promise.resolve([x+8, x+3]), | ||
// // throw new error for flutures are transform to reject. | ||
// x => {throw new Error('aaaa')}, | ||
// x => x.filter(elem => elem > 15) | ||
// )(5, 6) | ||
// .then(RLog('pipe-Ex7-OK: '),RLog('pipe-Ex7-Err: ') ) | ||
const pipeWhile = (funCond, ini) => (...funcs) => (...inputs) => { | ||
@@ -770,11 +829,27 @@ if( | ||
const parallel = | ||
(numberOfthreads=Infinity) => | ||
(futuresOrValues) => | ||
RParallel | ||
(numberOfthreads) | ||
(futuresOrValues.map(elem => isFuture(elem)? elem: resolve(elem)) ) | ||
function parallel(numberOfthreads=Infinity) | ||
{ | ||
return futuresOrValues => | ||
FParallel | ||
(numberOfthreads) | ||
(futuresOrValues.map(elem => isFuture(elem)? elem: resolve(elem)) ) | ||
} | ||
RE.parallel = parallel | ||
function promiseAll(numberOfThreads=Infinity) | ||
{ | ||
return promisesOrValues => | ||
{ | ||
let finalPromisesOrValues = promisesOrValues | ||
if(numberOfThreads !== Infinity) { | ||
const limit = pLimit(numberOfThreads) | ||
finalPromisesOrValues = promisesOrValues.map(prom => limit( ()=> prom)) | ||
} | ||
return Promise.all(finalPromisesOrValues) | ||
} | ||
} | ||
RE.promiseAll = promiseAll | ||
const runFunctionsInParallel = | ||
@@ -824,2 +899,35 @@ (numberOfThreads=Infinity) => | ||
const getTypeSyncFuturePromiseBoth = (list) => | ||
{ | ||
const typeofAsyncList = transition( | ||
['SYNC','PROMISE', 'FUTURE', 'MIX_PROMISE_AND_FUTURE'], | ||
['sync', 'promise','future'], | ||
{ | ||
PROMISE:{ | ||
sync:'PROMISE', | ||
future: 'MIX_PROMISE_AND_FUTURE' | ||
//by default: promise: 'PROMISE' | ||
}, | ||
FUTURE:{ | ||
sync:'FUTURE', | ||
promise: 'MIX_PROMISE_AND_FUTURE', | ||
}, | ||
MIX_PROMISE_AND_FUTURE: 'MIX_PROMISE_AND_FUTURE' // same as {sync: 'MIX_PROMISE_AND_FUTURE', promise: 'MIX_PROMISE_AND_FUTURE', future: 'MIX_PROMISE_AND_FUTURE'} | ||
} | ||
) | ||
list.forEach( | ||
el => | ||
typeofAsyncList( | ||
isPromise(el) | ||
? 'promise' | ||
: isFuture(el) | ||
? 'future' | ||
: 'sync' | ||
) | ||
) | ||
return typeofAsyncList.valueOf() | ||
} | ||
const runFunctionsSyncOrParallel = | ||
@@ -832,3 +940,8 @@ (numberOfThreads=Infinity) => | ||
if(futureOrValues.some(isFuture)) { | ||
const typeSync = getTypeSyncFuturePromiseBoth(futureOrValues) | ||
if(typeSync === 'MIX_PROMISE_AND_FUTURE') | ||
throw new CustomError('MIX_PROMISE_AND_FUTURE', 'Promises and future cannot be mixed') | ||
if(typeSync === 'FUTURE') { | ||
return RE.parallel | ||
@@ -839,2 +952,6 @@ (numberOfThreads) | ||
if(typeSync === 'PROMISE') { | ||
return promiseAll(numberOfThreads)(futureOrValues) | ||
} | ||
return futureOrValues | ||
@@ -844,2 +961,3 @@ } | ||
//runFunctionsSyncOrParallel(2)([()=>Promise.resolve(3), ()=>4])() //? | ||
@@ -947,2 +1065,3 @@ function pickPathsUnc(pickTransformations, obj) { | ||
parallel, | ||
promiseAll, | ||
runFunctionsInParallel, | ||
@@ -949,0 +1068,0 @@ runFunctionsSyncOrParallel, |
@@ -6,3 +6,4 @@ import { strict as assert } from 'assert' | ||
import { R, innerRightJoinWith } from '../src/ramdaExt.js' | ||
import { promise, resolve } from 'fluture' | ||
import { promise, reject, resolve } from 'fluture' | ||
import { CustomError } from '../src/jsUtils.js' | ||
@@ -223,3 +224,71 @@ const bankDB = { | ||
it('Plan without promise and complex nesting', () => { | ||
it('if a piped function reject, the final result will be a reject with the error object', () => { | ||
const returnTestFramework = | ||
plan( | ||
complexPlan, | ||
{ | ||
numberOfThreads: Infinity, | ||
mockupsObj: { | ||
getBankingBalances: reject( | ||
{ | ||
"code": "400", | ||
"message": "bankingToFetch is empty" | ||
} | ||
) | ||
} | ||
} | ||
)('f1') | ||
return promise(returnTestFramework) | ||
.then( | ||
()=>{}, | ||
(error => | ||
assert.deepStrictEqual( | ||
error, | ||
{ | ||
"code": "400", | ||
"message": "bankingToFetch is empty" | ||
} | ||
) | ||
) | ||
) | ||
}) | ||
it('if a piped function return an instance of Error or subclass of Error, the final result will be a resolve with the error object', () => { | ||
const returnTestFramework = | ||
plan( | ||
complexPlan, | ||
{ | ||
numberOfThreads: Infinity, | ||
mockupsObj: { | ||
getBankingBalances: new CustomError( | ||
'GET_BANKING_BALANCE_EXCEPTION', | ||
'Error getting Banking Balances', | ||
{ | ||
"code": "400", | ||
"message": "bankingToFetch is empty" | ||
} | ||
) | ||
} | ||
} | ||
)('f1') | ||
return promise(returnTestFramework) | ||
.then( | ||
(dataError => | ||
assert.deepStrictEqual( | ||
Object.entries(dataError.data), | ||
{ | ||
"code": "400", | ||
"message": "bankingToFetch is empty" | ||
} | ||
) | ||
), | ||
()=>{} | ||
) | ||
}) | ||
it('Plan without Future and complex nesting', () => { | ||
const result= plan( | ||
@@ -248,3 +317,3 @@ [ | ||
it('Plan without promise and complex nesting', () => { | ||
it('Plan without Future and complex nesting', () => { | ||
const result= plan( | ||
@@ -280,3 +349,3 @@ [ | ||
it('Plan without promise and complex nesting', () => { | ||
it('Plan without Future and complex nesting', () => { | ||
const result= plan( | ||
@@ -315,3 +384,3 @@ [ | ||
it('Plan without promise and complex nesting', () => { | ||
it('Plan without Future and complex nesting', () => { | ||
const result= plan( | ||
@@ -344,2 +413,72 @@ [ | ||
// Services | ||
function getCustomerDataProm(customer){ | ||
return Promise.resolve(bankDB.holdings[customer]) | ||
} | ||
function getCreditCardBalancesProm(data) { | ||
return Promise.resolve( | ||
data.creditCardsToFetch.map( | ||
card => ({account:card, ...bankDB.balancesCreditCards[card]}) | ||
) | ||
) | ||
} | ||
function getBankingBalancesProm(data) | ||
{ | ||
return Promise.resolve( | ||
data.bankingToFetch.map( | ||
account => ({account, ...bankDB.balancesBanking[account]}) | ||
) | ||
) | ||
} | ||
const complexPlanWithPromises = | ||
[ // [ 0 ] | ||
getCustomerDataProm, // [ 0, 0 ] | ||
[ // [ 0, 1 ] | ||
R.prop('holdings'), // [ 0, 1, 0 ] | ||
filterActiveAccounts, // [ 0, 1, 1 ] | ||
buildPlaceholderStructure, // [ 0, 1, 2 ] | ||
[ // [ 0, 1, 3 ] | ||
[ // [ 0, 1, 3, 0 ] | ||
getBankingBalancesProm, // [ 0, 1, 3, 0, 0 ] | ||
], | ||
[ // [ 0, 1, 3, 1 ] | ||
getCreditCardBalancesProm, // [ 0, 1, 3, 1, 0 ] | ||
], | ||
mergeCardsAndAccountsInArray // [ 0, 1, 3, 2 ] | ||
], | ||
[ // [ 0, 1, 4 ] | ||
R.prop('resultPlaceholder') // [ 0, 1, 4, 0 ] | ||
], | ||
rightJoinFetchVsResultPlaceholder2, // [ 0, 1, 5 ] | ||
], | ||
[ | ||
R.prop('name') | ||
], | ||
composeNameAndHolders2, | ||
] | ||
it('Complex plan with Promises', () => { | ||
return plan(complexPlanWithPromises)('f1') | ||
.then( | ||
(data => | ||
assert.deepStrictEqual( | ||
data, | ||
{ | ||
name: 'Jose Marin', | ||
holdings: [ | ||
{ account: '2', current: 12, available: 35, uuid: 'u2' }, | ||
{ account: '3', current: 8, available: 1975, uuid: 'u3' } | ||
] | ||
} | ||
) | ||
), | ||
(error => assert.fail('Future was not expected to be rejected with: ' + JSON.stringify(error))) | ||
) | ||
}) | ||
}) |
@@ -35,2 +35,3 @@ export default jsUtils; | ||
export { Enum }; | ||
export { transition }; | ||
export { pushUniqueKey }; | ||
@@ -148,2 +149,6 @@ export { pushUniqueKeyOrChange }; | ||
} | ||
export function transition(states: any, events: any, transitions: any): { | ||
(event: any): any; | ||
valueOf(): any; | ||
}; | ||
export function pushUniqueKey(row: any, table: any, indexes?: number[]): any; | ||
@@ -150,0 +155,0 @@ export function pushUniqueKeyOrChange(newRow: any, table: any, indexes: number[], mergeFun: any): any; |
@@ -17,2 +17,3 @@ export namespace RE { | ||
export { parallel }; | ||
export { promiseAll }; | ||
export { runFunctionsInParallel }; | ||
@@ -129,2 +130,3 @@ export { runFunctionsSyncOrParallel }; | ||
export function parallel(numberOfthreads?: number): (futuresOrValues: any) => import("fluture").FutureInstance<any, any[]>; | ||
export function promiseAll(numberOfThreads?: number): (promisesOrValues: any) => Promise<any[]>; | ||
export function runFunctionsInParallel(numberOfThreads?: number): (functionsToRunInParallel: any) => (data: any) => import("fluture").FutureInstance<any, any[]>; | ||
@@ -131,0 +133,0 @@ export function runFunctionsSyncOrParallel(numberOfThreads?: number): (functionsToRun: any) => (data: any) => any; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
167812
5084
9
45
+ Addedp-limit@^4.0.0
+ Addedp-limit@4.0.0(transitive)
+ Addedyocto-queue@1.1.1(transitive)