Skip to content
Snippets Groups Projects
queryRunnerService.ts 7.98 KiB
Newer Older
  • Learn to ignore specific revisions
  • Hugo NOUTS's avatar
    Hugo NOUTS committed
    import { Client, QueryDefinition } from 'cozy-client'
    import { DateTime, Interval } from 'luxon'
    import {
      ENEDIS_DAY_DOCTYPE,
      ENEDIS_MONTH_DOCTYPE,
      ENEDIS_YEAR_DOCTYPE,
      GRDF_DAY_DOCTYPE,
      GRDF_MONTH_DOCTYPE,
      GRDF_YEAR_DOCTYPE,
      EGL_DAY_DOCTYPE,
      EGL_MONTH_DOCTYPE,
      EGL_YEAR_DOCTYPE,
      ENEDIS_MINUTE_DOCTYPE,
      GRDF_HOUR_DOCTYPE,
    } from 'doctypes'
    import { FluidType } from 'enum/fluid.enum'
    import { TimeStep, ITimePeriod, IDataload } from './dataConsumptionContracts'
    
    export class QueryRunner {
      // TODO to be clean up
      private readonly _max_limit = 1000
      private readonly _default_months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
      private readonly _default_days = [
        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,
      ]
    
      private readonly _client: Client
    
      constructor(_client: Client) {
        this._client = _client
      }
    
      public async fetchFluidData(
        timePeriod: ITimePeriod,
        timeStep: TimeStep,
        fluidType: FluidType
      ): Promise<IDataload[] | null> {
        const result = await this.fetchData(
          this.buildListQuery(timeStep, timePeriod, fluidType, this._max_limit)
        )
    
        if (result && result.data) {
          const filteredResult = this.filterDataList(result, timePeriod)
          const mappedResult = this.mapDataList(filteredResult)
          return mappedResult
        }
    
        return null
      }
    
      public async getLastDateData(fluidType: FluidType): Promise<DateTime | null> {
        const result = await this.fetchData(this.buildLastDateQuery(fluidType, 1))
    
        if (
          result &&
          result.data &&
          result.data[0] &&
          result.data[0].year &&
          result.data[0].month &&
          result.data[0].day
        ) {
          return DateTime.local(
            result.data[0].year,
            result.data[0].month,
            result.data[0].day
          )
        }
    
        return null
      }
    
      private async fetchData(query: QueryDefinition) {
        let result = null
        try {
          result = await this._client.query(query)
        } catch (error) {
          // log stuff
          //throw new Error("Cozy Cient Error");
    
          return null
        }
        return result
      }
    
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      public async getEntries(fluidType: FluidType, timeStep: TimeStep) {
    
        let result = null
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
        const doctype = this.getRelevantDoctype(fluidType, timeStep)
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
          result = await this._client.query(this._client.find(doctype).where({}))
    
        } catch (error) {
          return null
        }
        return result
      }
    
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      private filterDataList(data, timePeriod: ITimePeriod) {
        const filteredResult = data.data.filter(entry =>
          this.withinDateBoundaries(
            DateTime.local(
              entry.year,
              entry.month === 0 ? 1 : entry.month,
              entry.day === 0 ? 1 : entry.day
            ),
            timePeriod
          )
        )
    
        return filteredResult
      }
    
      private mapDataList(data) {
        const mappedResult = data.map(entry => ({
          date: DateTime.local(
            entry.year,
            entry.month == 0 ? 1 : entry.month,
            entry.day === 0 ? 1 : entry.day,
            entry.hour,
            entry.minute
          ),
          value: entry.load,
        }))
    
        return mappedResult
      }
    
      private buildListQuery(
        timeStep: TimeStep,
        timePeriod: ITimePeriod,
        fluidType: FluidType,
        limit: number
      ) {
        const doctype = this.getRelevantDoctype(fluidType, timeStep)
    
        return this._client
          .find(doctype)
          .where(this.getPredicate(timePeriod, timeStep))
          .limitBy(limit)
      }
    
      private withinDateBoundaries(dateTime: DateTime, timePeriod: ITimePeriod) {
        return dateTime <= timePeriod.endDate && dateTime >= timePeriod.startDate
      }
    
      private getInBetweenMonths(timePeriod: ITimePeriod) {
        const intervalCount = Interval.fromDateTimes(
          timePeriod.startDate,
          timePeriod.endDate
        ).count('month')
        if (intervalCount >= 12) return this._default_months
        const monthList = []
        let offset = 0
    
        if (timePeriod.startDate.year !== timePeriod.endDate.year) offset = 12
    
        for (
          let m = timePeriod.startDate.month;
          m <= timePeriod.endDate.month + offset;
          m++
        )
          monthList.push(m > offset ? m - offset : m)
    
        return monthList
      }
    
      private getInBetweenDays(timePeriod: ITimePeriod) {
        const intervalCount = Interval.fromDateTimes(
          timePeriod.startDate,
          timePeriod.endDate
        ).count('day')
        if (intervalCount >= 31) return this._default_days
        const dayList = []
        let offset = 0
    
        if (timePeriod.startDate.month !== timePeriod.endDate.month) offset = 31
    
        for (
          let d = timePeriod.startDate.day;
          d <= timePeriod.endDate.day + offset;
          d++
        )
          dayList.push(d > offset ? d - offset : d)
    
        return dayList
      }
    
      private buildLastDateQuery(fluidType: FluidType, limit: number) {
        const doctype = this.getRelevantDoctype(fluidType, TimeStep.DAY)
    
        return this._client
          .find(doctype)
          .where({})
          .indexFields(['year', 'month', 'day'])
          .sortBy([{ year: 'desc' }, { month: 'desc' }, { day: 'desc' }])
          .limitBy(1)
      }
    
      private getPredicate(timePeriod: ITimePeriod, timeStep: TimeStep) {
        let predicate = {}
    
        switch (timeStep) {
          case TimeStep.HALF_AN_HOUR:
            predicate = {
              year: {
                $eq: timePeriod.startDate.year,
              },
              month: {
                $eq: timePeriod.startDate.month,
              },
              day: {
                $eq: timePeriod.startDate.day,
              },
            }
            break
    
          case TimeStep.DAY:
            predicate = {
              year: {
                $lte: timePeriod.endDate.year,
                $gte: timePeriod.startDate.year,
              },
              month: {
                $in: this.getInBetweenMonths(timePeriod),
              },
              day: {
                $in: this.getInBetweenDays(timePeriod),
              },
            }
            break
          case TimeStep.MONTH:
            predicate = {
              year: {
                $lte: timePeriod.endDate.year,
                $gte: timePeriod.startDate.year,
              },
              month: {
                $in: this.getInBetweenMonths(timePeriod),
              },
            }
            break
          case TimeStep.YEAR:
            predicate = {
              year: {
                $lte: timePeriod.endDate.year,
                $gte: timePeriod.startDate.year,
              },
            }
            break
        }
        return predicate
      }
    
      private getRelevantDoctype(fluidType: FluidType, timeStep: TimeStep) {
        let doctype = ''
    
        switch (fluidType) {
          case FluidType.ELECTRICITY:
            {
              switch (timeStep) {
                case TimeStep.HALF_AN_HOUR:
                  doctype = ENEDIS_MINUTE_DOCTYPE
                  break
                case TimeStep.DAY:
                  doctype = ENEDIS_DAY_DOCTYPE
                  break
                case TimeStep.MONTH:
                  doctype = ENEDIS_MONTH_DOCTYPE
                  break
                case TimeStep.YEAR:
                  doctype = ENEDIS_YEAR_DOCTYPE
                  break
                default:
                  doctype = ENEDIS_DAY_DOCTYPE
              }
            }
            break
    
          case FluidType.WATER:
            {
              switch (timeStep) {
                case TimeStep.DAY:
                  doctype = EGL_DAY_DOCTYPE
                  break
                case TimeStep.MONTH:
                  doctype = EGL_MONTH_DOCTYPE
                  break
                case TimeStep.YEAR:
                  doctype = EGL_YEAR_DOCTYPE
                  break
                default:
                  doctype = EGL_DAY_DOCTYPE
              }
            }
            break
    
          case FluidType.GAS:
            {
              switch (timeStep) {
                case TimeStep.HOUR:
                  doctype = GRDF_HOUR_DOCTYPE
                  break
                case TimeStep.DAY:
                  doctype = GRDF_DAY_DOCTYPE
                  break
                case TimeStep.MONTH:
                  doctype = GRDF_MONTH_DOCTYPE
                  break
                case TimeStep.YEAR:
                  doctype = GRDF_YEAR_DOCTYPE
                  break
                default:
                  doctype = GRDF_DAY_DOCTYPE
              }
            }
            break
    
          default:
            break
        }
    
        return doctype
      }
    }