Created
July 5, 2017 20:57
-
-
Save maggiben/1eb38b1ff0b01603204fe1032d0e909c to your computer and use it in GitHub Desktop.
Template combiner
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @desc Manufacture KPI Parser /api/situationroom/posters/manufacture/ShipmentByPlan | |
* Author: Benjamin at [email protected] | |
* Version: 0.1.0 | |
*/ | |
'use strict' | |
const debug = require('debug')(`esa:situationroom2:models:transport:v4:KpiParser`) | |
const _ = require('lodash') | |
const type = require('type-detect') | |
const uuidv4 = require('uuid/v4') | |
const DEFAULT_TIME_RANGES = ['MONTH', 'WEEK', 'DAY'] | |
const KIP_DOMAINS = ['site', 'range', 'product'] | |
const HashMap = function(...args) { | |
const transformParams = function(...args) { | |
const [initializr, defaultValue = null] = args; | |
debug('HashMap from: ', type(initializr)) | |
switch (type(initializr)) { | |
case 'Set': | |
return Array.from(initializr.values()).map(key => ([key, defaultValue])); | |
case 'Object': | |
return Object.keys(initializr).map((key) => ([key, initializr[key]])) | |
default: | |
return initializr; | |
} | |
} | |
const hashMap = new Map(transformParams(...args)) | |
Object.defineProperties(hashMap, { | |
toObject: { | |
writable: false, | |
enumerable: true, | |
configurable: true, | |
value: function(calc) { | |
return Reflect.apply(function(hashMap, object) { | |
hashMap.forEach((value, key) => (Object.assign(object, { | |
[key]: value | |
}))); | |
return object; | |
}, undefined, [this, {}]); | |
} | |
}, | |
toArray: { | |
writable: false, | |
value: function() { | |
return Array.from(this.values()); | |
} | |
}, | |
pushKpi: { | |
writable: false, | |
value: function(key, value) { | |
return this.set(key, Array.from(this.get(key) || 0).concat(value)); | |
} | |
}, | |
getKpi: { | |
writable: false, | |
value(key) { | |
return this.get(key); | |
} | |
} | |
}) | |
this.hashMap = hashMap; | |
return this.hashMap; | |
} | |
const Formula = Object.create(Math); | |
Formula.flatten = function(...args) { return Array.prototype.concat(...args); }; | |
Formula.sum = function(...args) { return Array.prototype.reduce.call(Formula.flatten(...args), (acc, curr) => (acc + curr)); }; | |
Formula.avg = function(...args) { return Array.prototype.reduce.call([Formula.sum(...args)], (size, sum) => (sum / size), Formula.flatten(...args).length); }; | |
Formula.sort = function(...args) { return Array.prototype.sort.apply(Formula.flatten(...args), [(a, b) => a - b]); }; | |
const kpiFormulas = { | |
goal: { | |
value: [], | |
typeCheck: n => !isNaN(parseFloat(n)) && isFinite(n), | |
defaultValue: 0, | |
formula: (newValue, oldValue) => oldValue.concat(newValue || 0), | |
post: Formula.avg | |
}, | |
value: { | |
value: [], | |
defaultValue: 0, | |
typeCheck: n => !isNaN(parseFloat(n)) && isFinite(n), | |
formula: (newValue, oldValue) => oldValue.concat(newValue || 0), | |
post: Formula.avg | |
}, | |
totalValue: { | |
value: [], | |
defaultValue: 0, | |
typeCheck: n => !isNaN(parseFloat(n)) && isFinite(n), | |
formula: (newValue, oldValue) => oldValue.concat(newValue || 0), | |
post: Formula.avg | |
}, | |
previouslyShipped: { | |
value: [], | |
defaultValue: 0, | |
typeCheck: n => !isNaN(parseFloat(n)) && isFinite(n), | |
formula: (newValue, oldValue) => oldValue.concat(newValue || 0), | |
post: Formula.avg | |
}, | |
kpiPercentage: { | |
value: [], | |
defaultValue: 0, | |
typeCheck: n => !isNaN(parseFloat(n)) && isFinite(n), | |
formula: (newValue, oldValue) => oldValue.concat(newValue || 0), | |
post: (...args) => Math.floor(Formula.avg(args)) | |
} | |
} | |
class KpiParser { | |
constructor () { | |
// Make a local copy | |
debug('KpiParser instance created') | |
} | |
buildSlides (collection, siteLables) { | |
const slides = [] | |
siteLables = siteLables.reduce((hash, site) => Object.assign({}, hash, { [site.siteBid]: site.label }), {}) | |
const rangeBucket = this.groupBy(collection, 'range', DEFAULT_TIME_RANGES); | |
for (let [range, kpis] of rangeBucket) { | |
const siteBuket = this.groupBy(kpis, 'site'); | |
const combination = this.combine(siteBuket); | |
rangeBucket.set(range, combination.toObject()); | |
// do the slides | |
const siteMap = combination.toObject(); | |
slides.push({ | |
range, | |
sites: Object.keys(siteMap).map(site => Object.assign({}, siteMap[site], { label: siteLables[site] })) | |
}) | |
} | |
return slides; | |
} | |
combine (collection) { | |
debug(collection) | |
const combination = new HashMap(collection); | |
for (let [key, value] of combination) { | |
const template = this.buildKpiTemplate(kpiFormulas); | |
if(value.length > 1) { | |
let summary = this.runKpiFormulas(value, kpiFormulas, template); | |
combination.set(key, summary); | |
} else { | |
let summary = this.cleanSummary(value.pop(), kpiFormulas, template); | |
combination.set(key, summary); | |
} | |
} | |
return combination; | |
} | |
groupBy (collection, property, domains) { | |
// Transform to Set to ensure uniqueness | |
debug(collection, property, domains) | |
domains = Array.isArray(domains) ? new Set(domains) : new Set(collection.map(element => element[property])); | |
// const hashMap = new HashMap.create(Array.from(domains).map((v,i)=>([v,[]]))); | |
// const hashMap = new HashMap(Array.from(domains).map((v,i)=>([v,[]]))); | |
const hashMap = new HashMap(domains, []) | |
return collection.reduce(function (group, element) { | |
const key = element[property]; | |
group.pushKpi(key, element); | |
return group; | |
}, hashMap) | |
} | |
runKpiFormulas (collection, formulas, template) { | |
const keys = Object.keys(formulas) | |
const kpis = Object.assign({}, ...keys.map(key => ({[key]: []}))); | |
const extract = collection.reduce((hash, element) => { | |
debug('FROMULA FOR:', hash) | |
return Object.assign({}, hash, ...keys.map(function (key) { | |
const { formula, post } = formulas[key]; | |
return { | |
[key]: formula.apply(this, [element[key], hash[key]]) | |
} | |
})); | |
}, kpis); | |
const summary = this.cleanSummary(extract, formulas, template); | |
return Object.assign({}, [...collection].pop(), summary); | |
} | |
cleanSummary (siteKpi, formulas, template) { | |
const keys = Object.keys(formulas) | |
return keys.reduce((template, key) => { | |
return Object.assign({}, template, ...keys.map(function (key) { | |
const { formula, post, typeCheck, defaultValue } = formulas[key]; | |
return { | |
[key]: typeCheck(siteKpi[key]) ? post.apply(this, [siteKpi[key]]) : defaultValue | |
} | |
})); | |
}, template); | |
} | |
buildKpiTemplate (formulas) { | |
return Object.keys(formulas).reduce(function (template, key) { | |
return Object.assign(template, { [key]: formulas[key].value }); | |
}, {}); | |
} | |
emptyCopy (object, formulas) { | |
return Object.keys(object).reduce(function(hash, key) { | |
const value = formulas[key] ? formulas[key].value : object[key]; | |
return Object.assign(hash, { [key]: value }); | |
}, {}); | |
} | |
} | |
module.exports = KpiParser |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const KPITEMPLATE = function (...args) { | |
const interceptor = function () { | |
return new Proxy(this, { | |
preventExtensions: function(target) { | |
return true; | |
}, | |
defineProperty(target, prop, descriptor) { | |
console.log(descriptor); | |
return Reflect.defineProperty(target, prop, descriptor); | |
}, | |
get: function (target, property, receiver) { | |
const { handler, value, formula } = target[property]; | |
return handler.get(value); | |
}, | |
set: function(target, property, newValue, receiver) { | |
const { handler, value, formula } = target[property]; | |
return target[property].value = handler.set(newValue, value); | |
} | |
}) | |
} | |
const props = { | |
goal: 'avg', | |
value: 'avg', | |
totalValue: 'avg', | |
previouslyShipped: 'avg', | |
kpiPercentage: 'avg', | |
}; | |
const recipeFactory = function (property) { | |
const recipe = props[property] | |
const recipes = { | |
avg: { | |
stack: [0], | |
default: 0, | |
type: Number, | |
typeCheck: n => !isNaN(parseFloat(n)) && isFinite(n), | |
id: Array.from({length: 4}, (v,i) => (parseInt(Math.random() * Number.MAX_SAFE_INTEGER)).toString(16).slice(0,6).toUpperCase()).join('-'), | |
descriptor: { | |
enumerable: true, | |
configurable: true, | |
get: function (...args) { | |
let { stack, id } = recipes[recipe]; | |
return stack.reduce((acc, curr) => acc + curr, 0 ) / stack.length | |
}, | |
set: function (newValue) { | |
let { stack, id } = recipes[recipe]; | |
stack.push(newValue || 0); | |
return true; | |
} | |
} | |
} | |
} | |
return recipes[recipe]; | |
} | |
const recipes = Object.keys(props).reduce((hash, key) => { | |
return Object.assign(hash, { | |
[key]: recipeFactory(key).descriptor | |
}) | |
}, {}); | |
const buildKpiTemplate = function (formulas) { | |
return Object.keys(formulas).reduce(function (template, key) { | |
return Object.assign(template, { [key]: formulas[key].value }); | |
}, {}); | |
} | |
const clean = function (object, preserve = true) { | |
return Object.keys(object).reduce(function(hash, key) { | |
if (key in props) { | |
return Object.assign(hash, { [key]: recipeFactory(key).default }); | |
} else { | |
return Object.assign(hash, ( preserve ? { [key]: object[key] } : {})); | |
} | |
}, {}); | |
} | |
const combine = function (...args) { | |
const template = new KPITEMPLATE(); | |
args.forEach(element => { | |
Object.keys(props).forEach(prop => { | |
template[prop] = element[prop]; | |
console.log('x:', props) | |
}) | |
}) | |
return template; | |
} | |
const template = (...args) => Object.assign(this, ...args) | |
Object.defineProperties(this, recipes); | |
// return this.interceptor(); | |
const [ initial ] = args; | |
console.log(initial) | |
if(args.length < 2 && typeof args === 'object') { | |
// console.log(clean(args)) | |
return Object.assign(this, clean(args)) | |
} | |
return this; | |
} | |
module.exports = KPITEMPLATE; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment