diff --git a/src/logs/entities/history-type.entity.ts b/src/logs/entities/history-type.entity.ts new file mode 100644 index 0000000..b463c7c --- /dev/null +++ b/src/logs/entities/history-type.entity.ts @@ -0,0 +1,5 @@ +export enum HISTORY_TYPE { + ALL = 'all', + LOCATION_DATA = 'location', + BATTERY_DATA = 'battery', +} diff --git a/src/logs/logs.controller.spec.ts b/src/logs/logs.controller.spec.ts index cd92f60..595f5f2 100644 --- a/src/logs/logs.controller.spec.ts +++ b/src/logs/logs.controller.spec.ts @@ -15,6 +15,7 @@ import { UpdateLogDto } from './dto/update-log.dto'; import { STATUS } from './entities/status.entity'; import { LastSyncDto } from './dto/last-sync.dto'; import { TYPE } from './entities/type.entity'; +import { HISTORY_TYPE } from './entities/history-type.entity'; describe('LogsController', () => { let accountService: AccountService; @@ -161,7 +162,8 @@ describe('LogsController', () => { it('should be able to sync data with a timestamp', async () => { const dto = new SyncDto(); - dto.socDisplay = 80; + dto.latitude = 32.123; + dto.longitude = 34.111; dto.timestamp = '2022-11-06T22:15:58.238Z'; const response = await controller.syncData(testAccount.akey, dto); @@ -176,13 +178,51 @@ describe('LogsController', () => { ); expect(response).toHaveLength(2); - expect(response.at(1)).toHaveProperty('socDisplay', 80); + expect(response.at(1)).toHaveProperty('latitude', 32.123); + expect(response.at(1)).toHaveProperty('longitude', 34.111); expect(response.at(1)).toHaveProperty( 'timestamp', '2022-11-06T22:15:58.238Z', ); }); + it('should be able to retrieve location log history', async () => { + const response = await controller.findOneWithHistory( + testAccount.akey, + logId, + HISTORY_TYPE.LOCATION_DATA + ); + + expect(response).toHaveLength(1); + expect(response.at(0)).toHaveProperty('latitude', 32.123); + expect(response.at(0)).toHaveProperty('longitude', 34.111); + expect(response.at(0)).toHaveProperty( + 'timestamp', + '2022-11-06T22:15:58.238Z', + ); + }); + + it('should be able to retrieve battery log history', async () => { + const response = await controller.findOneWithHistory( + testAccount.akey, + logId, + HISTORY_TYPE.BATTERY_DATA + ); + + expect(response).toHaveLength(1); + expect(response.at(0)).toHaveProperty('socDisplay', 80); + }); + + it('should be able to retrieve all log history', async () => { + const response = await controller.findOneWithHistory( + testAccount.akey, + logId, + HISTORY_TYPE.ALL + ); + + expect(response).toHaveLength(2); + }); + it('should be able to update log', async () => { const dto = new UpdateLogDto(); diff --git a/src/logs/logs.controller.ts b/src/logs/logs.controller.ts index 50b7505..528e096 100644 --- a/src/logs/logs.controller.ts +++ b/src/logs/logs.controller.ts @@ -24,6 +24,7 @@ import { LogNotExistsException } from './exceptions/log-not-exists.exception'; import { LogMissingSyncDataException } from './exceptions/log-missing-sync-data.exception'; import { TYPE } from './entities/type.entity'; import { LogNotRunningException } from './exceptions/log-not-running.exception'; +import { HISTORY_TYPE } from './entities/history-type.entity'; @Controller('logs') @UseGuards(AuthGuard) @@ -75,9 +76,10 @@ export class LogsController { async findOneWithHistory( @Param('akey') akey: string, @Param('id') id: string, + @Query('type') type?: HISTORY_TYPE, ) { try { - return await this.logsService.findOneWithHistory(akey, id); + return await this.logsService.findOneWithHistory(akey, id, type); } catch (error) { if (error instanceof LogNotExistsException) { throw new NotFoundException(error.message); diff --git a/src/logs/logs.service.ts b/src/logs/logs.service.ts index 4a999ee..f69cfe9 100644 --- a/src/logs/logs.service.ts +++ b/src/logs/logs.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { InjectModel } from '@nestjs/mongoose'; -import { Model } from 'mongoose'; +import { Model, Types } from 'mongoose'; import { LastSyncDto } from './dto/last-sync.dto'; import { LogDto } from './dto/log.dto'; import { SyncDto } from './dto/sync.dto'; @@ -19,6 +19,7 @@ import { Log } from './schemas/log.schema'; import { Sync } from './schemas/sync.schema'; import { TYPE } from './entities/type.entity'; import { LogNotRunningException } from './exceptions/log-not-running.exception'; +import { HISTORY_TYPE } from './entities/history-type.entity'; @Injectable() export class LogsService { @@ -114,16 +115,79 @@ export class LogsService { return Promise.resolve(new LogDto(log)); } - async findOneWithHistory(akey: string, id: string) { - const log = await this.logModel - .findOne({ akey, _id: id }) - .select('history'); - - if (!log) { - throw new LogNotExistsException(); + async findOneWithHistory(akey: string, id: string, type: HISTORY_TYPE = HISTORY_TYPE.ALL): Promise { + let history = []; + + switch (type) { + case HISTORY_TYPE.ALL: + const logWithAllHistory = await this.logModel + .findOne({ akey, _id: id }) + .select('history'); + + if (!logWithAllHistory) { + throw new LogNotExistsException(); + } + + history = logWithAllHistory.history; + break; + case HISTORY_TYPE.LOCATION_DATA: + const logWithLocationHistory = await this.logModel.aggregate([ + { + $match: { akey, _id: new Types.ObjectId(id) } + }, + { + $project: { + _id: 0, + history: { + $filter: { + input: '$history', + as: 'entry', + cond: { + $and: [ + { $in: [{ $type: '$$entry.latitude' }, ['double', 'int', 'long']] }, + { $in: [{ $type: '$$entry.longitude' }, ['double', 'int', 'long']] }, + ], + }, + }, + }, + } + } + ]); + + history = logWithLocationHistory.map((entry) => entry.history)[0]; + break; + case HISTORY_TYPE.BATTERY_DATA: + const logWithBatteryHistory = await this.logModel.aggregate([ + { + $match: { akey, _id: new Types.ObjectId(id) } + }, + { + $project: { + _id: 0, + history: { + $filter: { + input: '$history', + as: 'entry', + cond: { + $or: [ + { $in: [{ $type: '$$entry.socDisplay' }, ['double', 'int', 'long']] }, + { $in: [{ $type: '$$entry.socBMS' }, ['double', 'int', 'long']] }, + { $in: [{ $type: '$$entry.dcBatteryPower' }, ['double', 'int', 'long']] }, + ], + }, + }, + }, + } + } + ]); + + history = logWithBatteryHistory.map((entry) => entry.history)[0]; + break; + default: + break; } - return log.history; + return history; } async update(