@citrineos/data
Version:
The OCPP data module which includes all persistence layer implementation.
135 lines • 5.48 kB
JavaScript
// SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache-2.0
import { CrudRepository } from '@citrineos/base';
import { QueryTypes } from 'sequelize';
import {} from 'sequelize-typescript';
import { Logger } from 'tslog';
import { DefaultSequelizeInstance } from '../util.js';
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 model = this.s.models[namespace];
const pk = model.primaryKeyAttribute;
const { tenantId: _ignored, ...safeValue } = value;
const where = {
[pk]: key,
tenantId,
};
const row = await model.findOne({ where });
if (!row)
return undefined;
await row.update(safeValue);
return row.reload();
}
async _updateAllByQuery(tenantId, value, query, namespace = this.namespace) {
const model = this.s.models[namespace];
const where = {
...query.where,
tenantId,
};
const rows = await model.findAll({
...query,
where,
});
if (rows.length === 0)
return [];
for (const row of rows) {
await row.update(value);
}
return Promise.all(rows.map((r) => r.reload()));
}
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