All files / src stat.js

91.67% Statements 55/60
70% Branches 14/20
100% Functions 13/13
91.38% Lines 53/58

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 1105x       10x 34x 34x 34x 34x     10x 20x   20x   18x 30x     30x 18x 18x 18x   4x 2x   20x         146x 146x     146x 146x   146x 146x   146x       110x       110x       110x 110x       103x       103x       103x 103x 103x 103x       25x 25x       18x 18x       5x       81x     81x 80x 79x 79x 79x 79x   1x 1x 1x   1x       5x 5x  
const NS_PER_SEC = 1e9
 
export default class Stat {
  static compactStats(stats) {
    const groups = stats.reduce((groups, stat) => {
      const key = [stat.name, stat.type].join(',')
      groups[key] = groups[key] || []
      groups[key].push(stat)
      return groups
    }, {})
 
    return Object.values(groups).map(stats => {
      const newStat = new Stat(stats[0].name, stats[0].type)
      let totalDuration, totalCount
      switch (newStat.type) {
        case Stat.TYPE_DURATION:
          totalDuration = stats.reduce(
            (duration, stat) => duration + stat.averageDuration * stat.count,
            0
          )
          totalCount = stats.reduce((count, stat) => count + stat.count, 0)
          newStat.setAverageDuration(totalDuration / totalCount)
          newStat.setCount(totalCount)
          break
        case Stat.TYPE_COUNT:
          newStat.setCount(stats.reduce((count, stat) => count + stat.count, 0))
          break
      }
      return newStat
    })
  }
 
  constructor(name, type) {
    const allowedTypes = [Stat.TYPE_DURATION, Stat.TYPE_COUNT]
    Iif (allowedTypes.indexOf(type) === -1) {
      throw 'Invalid stat type passed'
    }
    this.name = name
    this.type = type
 
    this.count = 0
    this.startTime = null
 
    this.averageDuration = 0
  }
 
  start() {
    Iif (this.averageDuration !== 0) {
      throw 'Duration already calculated'
    }
 
    Iif (this.startTime !== null) {
      throw 'Stat start() already called'
    }
 
    this.startTime = process.hrtime()
    return this
  }
 
  stop() {
    Iif (this.averageDuration !== 0) {
      throw 'Duration already calculated'
    }
 
    Iif (this.startTime === null) {
      throw 'Stat start() has not been called'
    }
 
    const stopTime = process.hrtime(this.startTime)
    this.averageDuration = stopTime[0] * NS_PER_SEC + stopTime[1]
    this.count = 1
    return this
  }
 
  setCount(n) {
    this.count = n
    return this
  }
 
  setAverageDuration(t) {
    this.averageDuration = t
    return this
  }
 
  getDuration() {
    return this.averageDuration
  }
 
  getStatsObj() {
    const statsObj = {
      name: this.name
    }
    if (this.type === Stat.TYPE_DURATION) {
      if (this.averageDuration !== 0) {
        statsObj.duration = this.averageDuration
        statsObj.unit = 'ns'
        statsObj.count = this.count
        return statsObj
      }
    } else Eif (this.type === Stat.TYPE_COUNT) {
      statsObj.count = this.count
      return statsObj
    }
    return null
  }
}
 
Stat.TYPE_DURATION = 'stat_type__duration'
Stat.TYPE_COUNT = 'stat_type__count'