const redis = require('redis') const invariant = require('invariant') const RedisURL = process.env.OPENREDIS_URL invariant( RedisURL, 'Missing the $OPENREDIS_URL environment variable' ) const db = redis.createClient(RedisURL) const sumValues = (array) => array.reduce((memo, n) => memo + (parseInt(n, 10) || 0), 0) const getKeyValues = (keys) => new Promise((resolve, reject) => { db.mget(keys, (error, values) => { if (error) { reject(error) } else { resolve(values) } }) }) const sumKeys = (keys) => getKeyValues(keys).then(sumValues) const createScoresMap = (array) => { const map = {} for (let i = 0; i < array.length; i += 2) map[array[i]] = parseInt(array[i + 1], 10) return map } const getScoresMap = (key, n = 10) => new Promise((resolve, reject) => { db.zrevrange(key, 0, n, 'withscores', (error, value) => { if (error) { reject(error) } else { resolve(createScoresMap(value)) } }) }) const createTopScores = (map) => Object.keys(map) .reduce((memo, key) => memo.concat([ [ key, map[key] ] ]), []) .sort((a, b) => b[1] - a[1]) const getTopScores = (key, n) => getScoresMap(key, n).then(createTopScores) const sumMaps = (maps) => maps.reduce((memo, map) => { Object.keys(map).forEach(key => { memo[key] = (memo[key] || 0) + map[key] }) return memo }, {}) const sumTopScores = (keys, n) => Promise.all(keys.map(key => getScoresMap(key, n))) .then(sumMaps) .then(createTopScores) const createKey = (...args) => args.join('-') const createDayKey = (date) => createKey(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) const createHourKey = (date) => createKey(createDayKey(date), date.getUTCHours()) const createMinuteKey = (date) => createKey(createHourKey(date), date.getUTCMinutes()) module.exports = { getKeyValues, sumKeys, getTopScores, sumTopScores, createDayKey, createHourKey, createMinuteKey }