UNPKG

@citrineos/data

Version:

The OCPP data module which includes all persistence layer implementation.

255 lines 11.1 kB
// SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project // // SPDX-License-Identifier: Apache-2.0 import { CrudRepository, OCPPVersion } from '@citrineos/base'; import { Op } from 'sequelize'; import { Sequelize } from 'sequelize-typescript'; import { Logger } from 'tslog'; import {} from '../../../index.js'; import { ChargingStation, Connector, Location, SequelizeRepository, StatusNotification, } from '../index.js'; import { Evse, LatestStatusNotification } from '../model/index.js'; export class SequelizeLocationRepository extends SequelizeRepository { chargingStation; statusNotification; latestStatusNotification; connector; constructor(config, logger, sequelizeInstance, chargingStation, statusNotification, latestStatusNotification, connector) { super(config, Location.MODEL_NAME, logger, sequelizeInstance); this.chargingStation = chargingStation ? chargingStation : new SequelizeRepository(config, ChargingStation.MODEL_NAME, logger, sequelizeInstance); this.statusNotification = statusNotification ? statusNotification : new SequelizeRepository(config, StatusNotification.MODEL_NAME, logger, sequelizeInstance); this.latestStatusNotification = latestStatusNotification ? latestStatusNotification : new SequelizeRepository(config, LatestStatusNotification.MODEL_NAME, logger, sequelizeInstance); this.connector = connector ? connector : new SequelizeRepository(config, Connector.MODEL_NAME, logger, sequelizeInstance); } async readLocationById(tenantId, id) { return await this.readOnlyOneByQuery(tenantId, { where: { id }, include: [ChargingStation], }); } async readChargingStationByStationId(tenantId, stationId) { return ((await ChargingStation.findOne({ where: { id: stationId, tenantId, }, include: [{ model: Evse, include: [Connector] }], })) ?? undefined); } async setChargingStationIsOnlineAndOCPPVersion(tenantId, stationId, isOnline, ocppVersion) { return await this.chargingStation.updateByKey(tenantId, { isOnline: isOnline, protocol: ocppVersion }, stationId); } async doesChargingStationExistByStationId(tenantId, stationId) { return await this.chargingStation.existsByKey(tenantId, stationId); } async addStatusNotificationToChargingStation(tenantId, stationId, statusNotification) { const savedStatusNotification = await this.statusNotification.create(tenantId, statusNotification); try { await this.updateLatestStatusNotification(tenantId, stationId, savedStatusNotification); } catch (e) { this.logger.error(`Failed to update latest status notification with error: ${e.message}`, e); } } async updateLatestStatusNotification(tenantId, stationId, statusNotification) { const evseId = statusNotification.evseId; const connectorId = statusNotification.connectorId; const statusNotificationId = statusNotification.id; // delete operation doesn't support "include" in query // so we need to find them at first and then delete const existingLatestStatusNotifications = await this.latestStatusNotification.readAllByQuery(tenantId, { where: { stationId, }, include: [ { model: StatusNotification, where: { evseId, connectorId, }, require: true, }, ], }); const idsToDelete = existingLatestStatusNotifications.map((l) => l.id); await this.latestStatusNotification.deleteAllByQuery(tenantId, { where: { stationId, id: { [Op.in]: idsToDelete, }, }, }); await this.latestStatusNotification.create(tenantId, LatestStatusNotification.build({ tenantId, stationId, statusNotificationId, })); } async getChargingStationsByIds(tenantId, stationIds) { const query = { where: { id: { [Op.in]: stationIds, }, }, }; return this.chargingStation.readAllByQuery(tenantId, query); } async createOrUpdateLocationWithChargingStations(tenantId, location) { location.tenantId = tenantId; let savedLocation; if (location.id) { const result = await this.readOrCreateByQuery(tenantId, { where: { tenantId, id: location.id, }, defaults: { name: location.name, address: location.address, city: location.city, postalCode: location.postalCode, state: location.state, country: location.country, coordinates: location.coordinates, }, }); savedLocation = result[0]; const locationCreated = result[1]; if (!locationCreated) { const values = {}; values.name = location.name ?? undefined; values.address = location.address ?? undefined; values.city = location.city ?? undefined; values.postalCode = location.postalCode ?? undefined; values.state = location.state ?? undefined; values.country = location.country ?? undefined; values.coordinates = location.coordinates ?? undefined; await this.updateByKey(tenantId, { ...values }, savedLocation.id); } } else { savedLocation = await this.create(tenantId, Location.build({ ...location })); } if (location.chargingPool && location.chargingPool.length > 0) { for (const chargingStation of location.chargingPool) { chargingStation.locationId = savedLocation.id; await this.createOrUpdateChargingStation(tenantId, chargingStation); } } return savedLocation.reload({ include: ChargingStation }); } async createOrUpdateChargingStation(tenantId, chargingStation) { chargingStation.tenantId = tenantId; if (chargingStation.id) { const [savedChargingStation, chargingStationCreated] = await this.chargingStation.readOrCreateByQuery(tenantId, { where: { tenantId, id: chargingStation.id, }, defaults: { locationId: chargingStation.locationId, chargePointVendor: chargingStation.chargePointVendor, chargePointModel: chargingStation.chargePointModel, chargePointSerialNumber: chargingStation.chargePointSerialNumber, chargeBoxSerialNumber: chargingStation.chargeBoxSerialNumber, firmwareVersion: chargingStation.firmwareVersion, iccid: chargingStation.iccid, imsi: chargingStation.imsi, meterType: chargingStation.meterType, meterSerialNumber: chargingStation.meterSerialNumber, }, }); if (!chargingStationCreated) { await this.chargingStation.updateByKey(tenantId, { locationId: chargingStation.locationId, chargePointVendor: chargingStation.chargePointVendor, chargePointModel: chargingStation.chargePointModel, chargePointSerialNumber: chargingStation.chargePointSerialNumber, chargeBoxSerialNumber: chargingStation.chargeBoxSerialNumber, firmwareVersion: chargingStation.firmwareVersion, iccid: chargingStation.iccid, imsi: chargingStation.imsi, meterType: chargingStation.meterType, meterSerialNumber: chargingStation.meterSerialNumber, }, savedChargingStation.id); } return savedChargingStation; } else { return await this.chargingStation.create(tenantId, ChargingStation.build({ ...chargingStation })); } } async createOrUpdateConnector(tenantId, connector) { let result; await this.s.transaction(async (sequelizeTransaction) => { const [savedConnector, connectorCreated] = await this.connector.readOrCreateByQuery(tenantId, { where: { tenantId, stationId: connector.stationId, connectorId: connector.connectorId, }, defaults: { ...connector, }, transaction: sequelizeTransaction, }); if (!connectorCreated) { const updatedConnectors = await this.connector.updateAllByQuery(tenantId, connector, { where: { id: savedConnector.id, }, transaction: sequelizeTransaction, }); result = updatedConnectors.length > 0 ? updatedConnectors[0] : undefined; } else { result = savedConnector; } }); return result; } async updateAllConnectorsByQuery(tenantId, value, query) { return await this.connector.updateAllByQuery(tenantId, value, query); } async readConnectorByStationIdAndOcpp16ConnectorId(tenantId, stationId, ocpp16ConnectorId) { return ((await Connector.findOne({ where: { tenantId, stationId, connectorId: ocpp16ConnectorId, }, include: [Evse], })) ?? undefined); } async readEvseByStationIdAndOcpp201EvseId(tenantId, stationId, ocpp201EvseId) { return ((await Evse.findOne({ where: { stationId, evseTypeId: ocpp201EvseId, tenantId, }, include: [Connector], })) ?? undefined); } async readConnectorByStationIdAndOcpp201EvseType(tenantId, stationId, ocpp201EvseType) { return ((await Connector.findOne({ where: { tenantId, stationId, evseTypeConnectorId: ocpp201EvseType.connectorId, }, include: [{ model: Evse, where: { evseTypeId: ocpp201EvseType.id }, required: true }], })) ?? undefined); } } //# sourceMappingURL=Location.js.map