Newer
Older
import { Client, Q, QueryDefinition } from 'cozy-client'
EGL_DAY_DOCTYPE,
EGL_MONTH_DOCTYPE,
EGL_YEAR_DOCTYPE,
ENEDIS_MONTH_DOCTYPE,
ENEDIS_YEAR_DOCTYPE,
GRDF_DAY_DOCTYPE,
GRDF_MONTH_DOCTYPE,
GRDF_YEAR_DOCTYPE,
} from 'doctypes'
/* eslint-disable camelcase */
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,
/* eslint-enable camelcase */
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,
timeStep?: TimeStep
) {
const doctype = this.getRelevantDoctype(fluidType, timeStep || TimeStep.DAY)
.where({ year: { $ne: null }, month: { $ne: null }, day: { $ne: null } })
.indexFields(['year', 'month', 'day'])
.sortBy([{ year: 'asc' }, { month: 'asc' }, { day: 'asc' }])
.limitBy(limit)
}
private buildLastDateQuery(
fluidType: FluidType,
limit: number,
timeStep?: TimeStep
) {
const doctype = this.getRelevantDoctype(fluidType, timeStep || TimeStep.DAY)
.where({ year: { $ne: null }, month: { $ne: null }, day: { $ne: null } })
.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')
private filterDataList(
data: any,
timePeriod: TimePeriod,
timeStep: TimeStep
) {
// increase timeperiod range because the last data for a day is actually stored the next day at 00:00
timePeriod.startDate = timePeriod.startDate.plus({ minutes: 30 })
timePeriod.endDate = timePeriod.endDate.plus({ minutes: 30 })
}
const filteredResult = data.data.filter((entry: any) =>
this.withinDateBoundaries(
DateTime.local(
entry.year,
entry.month || 1,
entry.day || 1,
entry.hour,
entry.minute
).setZone('utc', {
keepLocalTime: true,
}),
private mapDataList(data: any, timeStep?: TimeStep): Dataload[] {
// set back every half hour data at -30 minutes so it is displayed as 23:30 instead of 00:00 etc..
const minusValue = timeStep === TimeStep.HALF_AN_HOUR ? 30 : 0
const mappedResult = data.map((entry: any) => ({
entry.month || 1,
entry.day || 1,
)
.setZone('utc', {
keepLocalTime: true,
})
.minus({ minutes: minusValue }),
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: {
$in: [timePeriod.startDate.day, timePeriod.startDate.day + 1],
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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
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?.data) {
const filteredResult = this.filterDataList(result, timePeriod, timeStep)
const mappedResult: Dataload[] = this.mapDataList(
filteredResult,
timeStep
)
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> {
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('day'),
}
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?.data) {
const filteredResult = this.filterDataList(
result,
maxTimePeriod,
timeStep
)
const mappedResult = this.mapDataList(filteredResult, timeStep)
if (withDate) {
return mappedResult && mappedResult[0] && mappedResult[0]
}
return mappedResult && mappedResult[0] && mappedResult[0].value
}
return null
}
public async getFirstDateData(
): Promise<DateTime | null> {
const query: QueryDefinition = this.buildFirstDateQuery(
fluidType,
1,
timeStep
)
const result = await this.fetchData(query)
if (
result?.data[0]?.year &&
result?.data[0]?.month &&
) {
return DateTime.local(
result.data[0].year,
result.data[0].month,
result.data[0].day || 1,
result.data[0].hour || 0,
result.data[0].minute || 0
).setZone('utc', {
keepLocalTime: true,
})
}
return null
}
public async getLastDateData(
fluidType: FluidType,
timeStep?: TimeStep
): Promise<DateTime | null> {
const query: QueryDefinition = this.buildLastDateQuery(
fluidType,
1,
timeStep
)
const result = await this.fetchData(query)
if (
result?.data[0]?.year &&
result?.data[0]?.month &&
) {
return DateTime.local(
result.data[0].year,
result.data[0].month,
result.data[0].day || 1,
result.data[0].hour || 0,
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({}).limitBy(1)
const result = await this._client.query(query)
return result
} catch (error) {
return null
}
}