mon-entreprise/selectors/usedVariables.js

176 lines
4.6 KiB
JavaScript

import R from 'ramda'
import removeDiacritics from '../utils/remove-diacritics'
import { createSelector } from 'reselect'
import {variablesSelector} from './selectors'
import traversalGuide from './traversalGuide'
/* AIM : Parse all the variables and extract their references to other variables.
Rank the results by count. */
// Use http://regexr.com/ to understand and write regexps !!
let credits = 3 // 5 complex variables
// let GETAdHocVariable = id =>
// new Promise((resolve, reject) =>
// setTimeout(() =>
// resolve(
// Math.random() > 0.6 && credits ?
// credits -- && {calls: ['myVar' + Math.random(), 'myVar2' + Math.random()]}
// : 'myInputVariable' + Math.random()
// ),
// Math.random() * 2000 + 1000
// )
// )
let GETAdHocVariable = name =>
new Promise(resolve =>
window.fetch('https://api.openfisca.fr/api/1/variables/?name=' + name.trim().replace(/\s/g, '_'))
.then(res => res.json())
.then(json => {
let {error, variables} = json
if (error && JSON.stringify(error).indexOf('Variable does not exist') + 1){
resolve('TODO ' + name)
}
if (variables) {
let {name, formula} = variables[0]
if (formula && formula['input_variables']) {
resolve({calls: formula['input_variables']})
} else {
resolve(name)
}
}
})
)
async function getAdHocVariables(id) {
let variable = await GETAdHocVariable(id)
if (R.is(String, variable))
return variable
else
return Promise.all(
variable.calls.map(getAdHocVariables)
)
}
// Returns a list of list of used variables
// recursive function
let findUsedVariables = (variables, schema, toAnalyse) =>
/*TODO
If instruction of GET call -> return Promise
1) input var OK return string
2) call to other variables -> list of promises
*/
R.cond([
[R.isNil, () => []],
[R.has('adHoc'), ({id}) => getAdHocVariables(id)],
// The traversal of variables has found a parsable variable attribute.
// Parse it to extract variables
[R.is(Function), extractor =>
R.pipe(
extractor,
R.unless(R.isArrayLike, R.of),
R.map(R.cond([
[R.is(String), name => findVariables(variables, name)],
[R.is(Object), tags => findVariables(variables, null, tags)]
])),
R.unnest,
R.map(
/*TODO
if instruction of GET call findUsedVariables(GET CALL)
*/
R.cond([
[R.has('adHoc'), adHocSpec => findUsedVariables(variables, adHocSpec)],
[R.is(String), R.identity],
[R.T, found => findUsedVariables(variables, traversalGuide, found)]
])
)
)(toAnalyse)
],
// Walk the graph using the guiding object until you find a parsable attribute
[R.is(Object), traversalObject =>
R.toPairs(traversalObject).reduce(
(res, [key, value]) => {
return toAnalyse[key] != null ?
[...res, ...findUsedVariables(variables, value, toAnalyse[key])] :
res
}, []
)],
[R.T, () => []]
])(schema)
let calculableVariables = createSelector(
[variablesSelector],
R.pipe(R.pluck('calculable'), R.unnest)
)
/************************************
Functions to find variables */
let findVariablesByName = name =>
R.filter(variable => removeDiacritics(variable.variable) == name)
let findVariablesByTags = tags =>
R.filter(R.pipe(
R.prop('tags'),
R.whereEq(tags)
))
let findVariables = (variables, name, tags) =>
R.pipe(
variables => R.is(String, name)
? findVariablesByName(name)(variables)
: variables,
variables => R.is(Object, tags)
? findVariablesByTags(tags)(variables)
: variables,
R.cond([
[ R.isEmpty, () => variableNotFound(name)],
[ (variables) => R.is(String, name) && variables.length > 1,
() => variableNameCollision(name, tags)],
[ R.T,
R.identity]
]),
)(variables)
let variableNotFound = name =>
// Should do a query to openfisca web api
({adHoc: true, id: name})
let variableNameCollision = (name, tags) =>
`More than one variable corresponds to this name, tags tuple : ${name}, ${tags}`
/*****************************************/
let accum = [] //aaw
setTimeout(() => console.log(R.countBy(R.identity)(accum)), 10000)
let resolvePromisesRec =
R.pipe(
R.unless(R.isArrayLike, R.of),
R.map(R.cond([
[R.is(Promise), p => p.then(resolvePromisesRec)],
[R.is(String), string => accum.push(string)]
]))
)
export let usedVariables = createSelector(
[state => state.rootVariables, calculableVariables],
(roots, variables) => {
// get all variables from these roots, rec !
return R.compose(
// R.uniq,
resolvePromisesRec,
R.flatten,
R.map(rootObject => findUsedVariables(variables, traversalGuide, rootObject)),
R.map(root => findVariables(variables, removeDiacritics(root))[0])
)(roots)
}
)