Skip to content

Commit 24aafad

Browse files
authored
Merge pull request #29 from EVNotify/stations-association
✨ Stations association
2 parents db25ee1 + fc2388d commit 24aafad

4 files changed

Lines changed: 136 additions & 1 deletion

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { Injectable, Logger } from '@nestjs/common';
2+
import { OnEvent } from '@nestjs/event-emitter';
3+
import { LOG_FINISHED_EVENT } from '../entities/log.entity';
4+
import { Log } from '../schemas/log.schema';
5+
import { InjectModel } from '@nestjs/mongoose';
6+
import { Model, Types } from 'mongoose';
7+
import { LogsService } from '../logs.service';
8+
import { TYPE } from '../entities/type.entity';
9+
import { HISTORY_TYPE } from '../entities/history-type.entity';
10+
import { Station } from '../../stations/schemas/station.schema';
11+
import { MissingStation } from '../../stations/schemas/missing-station.schema';
12+
13+
@Injectable()
14+
export class StationAssociationHandler {
15+
constructor(
16+
private readonly logsService: LogsService,
17+
@InjectModel(Station.name) private readonly stationModel: Model<Station>,
18+
@InjectModel(MissingStation.name) private readonly missingStationModel: Model<MissingStation>,
19+
@InjectModel(Log.name) private readonly logModel: Model<Log>,
20+
) {}
21+
22+
@OnEvent(LOG_FINISHED_EVENT)
23+
async handleFinished(log: Log) {
24+
try {
25+
if (log.type !== TYPE.CHARGE) {
26+
return;
27+
}
28+
29+
const history = await this.logsService.findOneWithHistory(log.akey, log._id.toString(), HISTORY_TYPE.LOCATION_DATA);
30+
31+
const firstWithLocation = history.find((entry) => entry.latitude != null && entry.longitude != null);
32+
33+
if (!firstWithLocation) {
34+
return;
35+
}
36+
37+
const latitude = firstWithLocation.latitude;
38+
const longitude = firstWithLocation.longitude;
39+
40+
await this.stationModel.ensureIndexes();
41+
42+
const results = await this.stationModel.aggregate([
43+
{
44+
$geoNear: {
45+
near: { type: 'Point', coordinates: [longitude, latitude] },
46+
distanceField: 'distance',
47+
spherical: true,
48+
maxDistance: 200,
49+
key: 'location',
50+
},
51+
},
52+
{ $sort: { distance: 1 } },
53+
{ $limit: 1 },
54+
]);
55+
56+
if (results.length) {
57+
const stationDoc = results[0];
58+
59+
await this.logModel.updateOne({ _id: log._id, akey: log.akey }, { $set: { station: stationDoc._id } });
60+
} else {
61+
await this.missingStationModel.ensureIndexes();
62+
63+
const msResults = await this.missingStationModel.aggregate([
64+
{
65+
$geoNear: {
66+
near: { type: 'Point', coordinates: [longitude, latitude] },
67+
distanceField: 'distance',
68+
spherical: true,
69+
maxDistance: 200,
70+
key: 'location',
71+
},
72+
},
73+
{ $sort: { distance: 1 } },
74+
{ $limit: 1 },
75+
]);
76+
77+
if (!msResults.length) {
78+
await this.missingStationModel.create({
79+
akey: log.akey,
80+
logRef: log._id,
81+
location: { type: 'Point', coordinates: [longitude, latitude] },
82+
});
83+
}
84+
}
85+
} catch (error) {
86+
Logger.error('Error in StationAssociationHandler', error);
87+
}
88+
}
89+
}

src/logs/logs.module.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,23 @@ import { LastSyncHandler } from './handler/last-sync';
99
import { LastSync, LastSyncSchema } from './schemas/last-sync.schema';
1010
import { CronHandler } from './handler/cron';
1111
import { PremiumModule } from '../premium/premium.module';
12+
import { Station, StationSchema } from '../stations/schemas/station.schema';
13+
import { MissingStation, MissingStationSchema } from '../stations/schemas/missing-station.schema';
14+
import { StationAssociationHandler } from './handler/station-association.handler';
1215

1316
@Module({
1417
controllers: [LogsController],
15-
providers: [LogsService, MetadataHandler, LastSyncHandler, CronHandler],
1618
imports: [
1719
AccountModule,
1820
MongooseModule.forFeature([
1921
{ name: Log.name, schema: LogSchema },
2022
{ name: LastSync.name, schema: LastSyncSchema },
23+
{ name: Station.name, schema: StationSchema },
24+
{ name: MissingStation.name, schema: MissingStationSchema },
2125
]),
2226
PremiumModule,
2327
],
28+
providers: [LogsService, MetadataHandler, LastSyncHandler, CronHandler, StationAssociationHandler],
2429
exports: [LogsService],
2530
})
2631
export class LogsModule {}

src/logs/schemas/log.schema.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ export class Log {
124124

125125
@Prop()
126126
thresholdReached: Date;
127+
128+
@Prop({ type: Types.ObjectId, ref: 'Station' })
129+
station: Types.ObjectId;
127130
}
128131

129132
export const LogSchema = SchemaFactory.createForClass(Log);
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
2+
import { Document, Types } from 'mongoose';
3+
4+
export type MissingStationDocument = MissingStation & Document;
5+
6+
@Schema({ timestamps: true })
7+
export class MissingStation {
8+
_id: Types.ObjectId;
9+
10+
@Prop({ required: true })
11+
akey: string;
12+
13+
@Prop({ type: Types.ObjectId, ref: 'Log', required: true })
14+
logRef: Types.ObjectId;
15+
16+
@Prop({
17+
type: {
18+
type: String,
19+
enum: ['Point'],
20+
default: 'Point',
21+
},
22+
coordinates: {
23+
type: [Number],
24+
required: true,
25+
},
26+
})
27+
location: {
28+
type: 'Point';
29+
coordinates: [number, number];
30+
};
31+
32+
@Prop()
33+
note: string;
34+
}
35+
36+
export const MissingStationSchema = SchemaFactory.createForClass(MissingStation);
37+
38+
MissingStationSchema.index({ location: '2dsphere' });

0 commit comments

Comments
 (0)