@citrineos/data
Version:
The OCPP data module which includes all persistence layer implementation.
116 lines • 5.18 kB
JavaScript
// SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache-2.0
import { CrudRepository } from '@citrineos/base';
import {} from 'sequelize-typescript';
import { DefaultSequelizeInstance } from '../util.js';
import { Logger } from 'tslog';
import { QueryTypes } from 'sequelize';
export class SequelizeRepository extends CrudRepository {
s;
namespace;
logger;
constructor(config, namespace, logger, sequelizeInstance) {
super();
this.s = sequelizeInstance ?? DefaultSequelizeInstance.getInstance(config, logger);
this.namespace = namespace;
this.logger = logger
? logger.getSubLogger({ name: this.constructor.name })
: new Logger({ name: this.constructor.name });
}
async readByKey(tenantId, key, namespace = this.namespace) {
return await this.s.models[namespace].findByPk(key).then((row) => row);
}
async readAllByQuery(tenantId, query, namespace = this.namespace) {
return await this.s.models[namespace]
.findAll(query)
.then((row) => row);
}
async readAllBySqlString(tenantId, sqlString, _namespace = this.namespace) {
return await this.s.query(`${sqlString}`, { type: QueryTypes.SELECT });
}
async readNextValue(tenantId, columnName, query, startValue, namespace = this.namespace) {
const options = query ? query : undefined;
const maxValue = await this.s.models[namespace].max(columnName, options);
if (maxValue === null || maxValue === undefined) {
// maxValue can be 0, so we need to specifically check for null or undefined
return startValue ?? 1;
}
if (typeof maxValue !== 'number' || isNaN(maxValue)) {
throw new Error(`Max value ${maxValue} on ${columnName} is invalid.`);
}
return maxValue + 1;
}
async existsByKey(tenantId, key, namespace = this.namespace) {
return await this.s.models[namespace].findByPk(key).then((row) => row !== null);
}
async existByQuery(tenantId, query, namespace = this.namespace) {
return await this.s.models[namespace].findAll(query).then((row) => row.length);
}
async findAndCount(tenantId, options, namespace = this.namespace) {
return this.s.models[namespace].findAndCountAll(options);
}
async _create(tenantId, value, _namespace = this.namespace) {
return await value.save();
}
async _bulkCreate(tenantId, values, namespace = this.namespace) {
return await this.s.models[namespace].bulkCreate(values);
}
async _createByKey(tenantId, value, key, namespace = this.namespace) {
const primaryKey = this.s.models[namespace].primaryKeyAttribute;
value.setDataValue(primaryKey, key);
return (await this.s.models[namespace].create(value.toJSON()));
}
async _readOrCreateByQuery(tenantId, query, namespace = this.namespace) {
return await this.s.models[namespace]
.findOrCreate(query)
.then((result) => [result[0], result[1]]);
}
async _updateByKey(tenantId, value, key, namespace = this.namespace) {
const primaryKey = this.s.models[namespace].primaryKeyAttribute;
return await this._updateAllByQuery(tenantId, value, { where: { [primaryKey]: key } }, namespace).then((rows) => (rows && rows.length === 1 ? rows[0] : undefined));
}
async _updateAllByQuery(tenantId, value, query, namespace = this.namespace) {
const updateOptions = query;
updateOptions.returning = true;
// Lengthy type conversion to satisfy sequelize-typescript
return await this.s.models[namespace]
.update(value, updateOptions)
.then((result) => result[1]);
}
async _deleteByKey(tenantId, key, namespace = this.namespace) {
return this.s.transaction(async (transaction) => {
const entryToDelete = await this.s.models[namespace]
.findByPk(key, { transaction })
.then((row) => row);
if (entryToDelete) {
await this.s.models[namespace].destroy({
where: { [this.s.models[namespace].primaryKeyAttribute]: key },
transaction,
});
return entryToDelete;
}
else {
return undefined;
}
});
}
async _deleteAllByQuery(tenantId, query, namespace = this.namespace) {
return this.s.transaction(async (transaction) => {
const entriesToDelete = await this.s.models[namespace]
.findAll({
...query,
transaction,
})
.then((rows) => rows);
const deletedCount = await this.s.models[namespace].destroy({ ...query, transaction });
if (entriesToDelete.length === deletedCount) {
return entriesToDelete;
}
else {
throw new Error(`Deleted ${deletedCount} entries, expected ${entriesToDelete.length}`);
}
});
}
}
//# sourceMappingURL=Base.js.map