Newer
Older

Guilhem CARRON
committed
/* eslint-disable @typescript-eslint/no-explicit-any */
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,
} from 'doctypes'
import { TimeStep } from 'enum/timeStep.enum'
import { Dataload, TimePeriod } from 'models'

Hugo SUBTIL
committed
import { QueryResult } from 'cozy-client/types/types'
import log from 'utils/logger'
import { DataloadState } from 'enum/dataload.enum'
// 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
}
timePeriod: TimePeriod,
fluidType: FluidType,
limit: number
) {
const doctype = this.getRelevantDoctype(fluidType, timeStep)
return Q(doctype)
.where(this.getPredicate(timePeriod, timeStep))
.limitBy(limit)
maxTimePeriod: TimePeriod,
fluidType: FluidType,
limit: number
) {
const doctype = this.getRelevantDoctype(fluidType, timeStep)
if (timeStep === TimeStep.HALF_AN_HOUR) {
return Q(doctype)
.where(this.getPredicate(maxTimePeriod, TimeStep.HALF_AN_HOUR))
return Q(doctype)
.where(this.getPredicate(maxTimePeriod, timeStep))
.limitBy(limit)
.sortBy([{ load: 'desc' }])
private buildFirstDateQuery(fluidType: FluidType, limit: number) {
const doctype = this.getRelevantDoctype(fluidType, TimeStep.DAY)
return Q(doctype)
.where({})
.indexFields(['year', 'month', 'day'])
.sortBy([{ year: 'asc' }, { month: 'asc' }, { day: 'asc' }])
.limitBy(limit)
}
private buildLastDateQuery(fluidType: FluidType, limit: number) {
const doctype = this.getRelevantDoctype(fluidType, TimeStep.DAY)
return Q(doctype)
.where({})
.indexFields(['year', 'month', 'day'])
.sortBy([{ year: 'desc' }, { month: 'desc' }, { day: 'desc' }])
.limitBy(limit)
}
private async fetchData(query: QueryDefinition) {
let result = null
try {
result = await this._client.query(query)
} catch (error) {
// log stuff
// throw new Error('Fetch data failed in query runner')

Hugo SUBTIL
committed
log.error('QueryRunner error: ', error)
private filterDataList(data: any, timePeriod: TimePeriod) {
const filteredResult = data.data.filter((entry: any) =>
this.withinDateBoundaries(
DateTime.local(
entry.year,
entry.month === 0 ? 1 : entry.month,
entry.day === 0 ? 1 : entry.day
).setZone('utc', {
keepLocalTime: true,
}),
timePeriod
)
)
return filteredResult
}
private mapDataList(data: any): Dataload[] {
const mappedResult = data.map((entry: any) => ({
date: DateTime.local(
entry.year,
entry.month == 0 ? 1 : entry.month,
entry.day === 0 ? 1 : entry.day,
entry.hour,
entry.minute
).setZone('utc', {
keepLocalTime: true,
}),
state: DataloadState.VALID,

Hugo SUBTIL
committed
price: entry.price,
private withinDateBoundaries(dateTime: DateTime, timePeriod: TimePeriod) {
return dateTime <= timePeriod.endDate && dateTime >= timePeriod.startDate
}
private getInBetweenMonths(timePeriod: TimePeriod) {
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++
private getInBetweenDays(timePeriod: TimePeriod) {
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++
private getPredicate(timePeriod: TimePeriod, 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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
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.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
}
public async fetchFluidData(
timePeriod: TimePeriod,
timeStep: TimeStep,
fluidType: FluidType
): Promise<Dataload[] | null> {
const query: QueryDefinition = this.buildListQuery(
timeStep,
timePeriod,
fluidType,
this._max_limit
)
const result = await this.fetchData(query)

Hugo SUBTIL
committed
if (result && result.data) {
const filteredResult = this.filterDataList(result, timePeriod)
const mappedResult: Dataload[] = this.mapDataList(filteredResult)
return mappedResult
}
return null
}

Hugo SUBTIL
committed
public async fetchFluidRawDoctype(
timePeriod: TimePeriod,
timeStep: TimeStep,
fluidType: FluidType
): Promise<QueryResult> {
const query: QueryDefinition = this.buildListQuery(
timeStep,
timePeriod,
fluidType,
this._max_limit
)
return this.fetchData(query)
}
public async fetchFluidMaxData(
maxTimePeriod: TimePeriod,
timeStep: TimeStep,
fluidType: FluidType,
withDate?: boolean
): Promise<number | Dataload | null> {
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
const query: QueryDefinition = this.buildMaxQuery(
timeStep,
maxTimePeriod,
fluidType,
this._max_limit
)
const result = await this.fetchData(query)
if (timeStep === TimeStep.HALF_AN_HOUR) {
const lastDayOfPreviousMonth = {
startDate: maxTimePeriod.startDate.plus({ day: -1 }),
endDate: maxTimePeriod.startDate.plus({ day: -1 }).endOf('days'),
}
const lastDayOfPreviousMonthQuery: QueryDefinition = this.buildMaxQuery(
timeStep,
lastDayOfPreviousMonth,
fluidType,
this._max_limit
)
const lastDayOfPreviousMonthResult = await this.fetchData(
lastDayOfPreviousMonthQuery
)
return Math.max(
lastDayOfPreviousMonthResult && lastDayOfPreviousMonthResult.data[0]
? lastDayOfPreviousMonthResult.data[0].load
: 0,
result && result.data[0] ? result.data[0].load : 0
)
}
if (result && result.data) {
const filteredResult = this.filterDataList(result, maxTimePeriod)
const mappedResult = this.mapDataList(filteredResult)
if (withDate) {
return mappedResult && mappedResult[0] && mappedResult[0]
}
return mappedResult && mappedResult[0] && mappedResult[0].value
}
return null
}
public async getFirstDateData(
fluidType: FluidType
): Promise<DateTime | null> {
const query: QueryDefinition = this.buildFirstDateQuery(fluidType, 1)
const result = await this.fetchData(query)
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,
result.data[0].hour ? result.data[0].hour : 0,
result.data[0].minute ? result.data[0].minute : 0
).setZone('utc', {
keepLocalTime: true,
})
}
return null
}
public async getLastDateData(fluidType: FluidType): Promise<DateTime | null> {
const query: QueryDefinition = this.buildLastDateQuery(fluidType, 1)
const result = await this.fetchData(query)
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,
result.data[0].hour ? result.data[0].hour : 0,
result.data[0].minute ? result.data[0].minute : 0
).setZone('utc', {
keepLocalTime: true,
})
}
return null
}
public async getEntries(fluidType: FluidType, timeStep: TimeStep) {
const doctype = this.getRelevantDoctype(fluidType, timeStep)
try {
const query = Q(doctype).where({})
const result = await this._client.query(query)
return result
} catch (error) {
return null
}
}