mirror of
https://github.com/Ride-The-Lightning/RTL
synced 2024-10-31 09:20:27 +00:00
bea5980c6f
Release 0.12.0
210 lines
9.1 KiB
JavaScript
210 lines
9.1 KiB
JavaScript
import * as fs from 'fs';
|
|
import { join, dirname, sep } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import { Common } from '../utils/common.js';
|
|
import { Logger } from '../utils/logger.js';
|
|
import { CollectionsEnum, validateOffer } from '../models/database.model.js';
|
|
export class DatabaseService {
|
|
constructor() {
|
|
this.common = Common;
|
|
this.logger = Logger;
|
|
this.dbDirectory = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'database');
|
|
this.nodeDatabase = {};
|
|
}
|
|
loadDatabase(selectedNode) {
|
|
try {
|
|
if (!this.nodeDatabase[selectedNode.index]) {
|
|
this.nodeDatabase[selectedNode.index] = { adapter: null, data: null };
|
|
}
|
|
this.nodeDatabase[selectedNode.index].adapter = new DatabaseAdapter(this.dbDirectory, 'rtldb', selectedNode);
|
|
this.nodeDatabase[selectedNode.index].data = this.nodeDatabase[selectedNode.index].adapter.fetchData();
|
|
}
|
|
catch (err) {
|
|
this.logger.log({ selectedNode: selectedNode, level: 'ERROR', fileName: 'Database', msg: 'Database Load Error', error: err });
|
|
}
|
|
}
|
|
create(selectedNode, collectionName, newDocument) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
if (!selectedNode || !selectedNode.index) {
|
|
reject(new Error('Selected Node Config Not Found.'));
|
|
}
|
|
const validationRes = this.validateDocument(CollectionsEnum.OFFERS, newDocument);
|
|
if (!validationRes.isValid) {
|
|
reject(validationRes.error);
|
|
}
|
|
else {
|
|
this.nodeDatabase[selectedNode.index].data[collectionName].push(newDocument);
|
|
this.saveDatabase(+selectedNode.index);
|
|
resolve(newDocument);
|
|
}
|
|
}
|
|
catch (errRes) {
|
|
reject(errRes);
|
|
}
|
|
});
|
|
}
|
|
update(selectedNode, collectionName, updatedDocument, documentFieldName, documentFieldValue) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
if (!selectedNode || !selectedNode.index) {
|
|
reject(new Error('Selected Node Config Not Found.'));
|
|
}
|
|
let foundDocIdx = -1;
|
|
let foundDoc = null;
|
|
if (this.nodeDatabase[selectedNode.index].data[collectionName]) {
|
|
foundDocIdx = this.nodeDatabase[selectedNode.index].data[collectionName].findIndex((document) => document[documentFieldName] === documentFieldValue);
|
|
foundDoc = foundDocIdx > -1 ? JSON.parse(JSON.stringify(this.nodeDatabase[selectedNode.index].data[collectionName][foundDocIdx])) : null;
|
|
}
|
|
if (foundDocIdx > -1 && foundDoc) {
|
|
for (const docKey in updatedDocument) {
|
|
if (Object.prototype.hasOwnProperty.call(updatedDocument, docKey)) {
|
|
foundDoc[docKey] = updatedDocument[docKey];
|
|
}
|
|
}
|
|
updatedDocument = foundDoc;
|
|
}
|
|
const validationRes = this.validateDocument(CollectionsEnum.OFFERS, updatedDocument);
|
|
if (!validationRes.isValid) {
|
|
reject(validationRes.error);
|
|
}
|
|
else {
|
|
if (foundDocIdx > -1) {
|
|
this.nodeDatabase[selectedNode.index].data[collectionName].splice(foundDocIdx, 1, updatedDocument);
|
|
}
|
|
else {
|
|
if (!this.nodeDatabase[selectedNode.index].data[collectionName]) {
|
|
this.nodeDatabase[selectedNode.index].data[collectionName] = [];
|
|
}
|
|
this.nodeDatabase[selectedNode.index].data[collectionName].push(updatedDocument);
|
|
}
|
|
this.saveDatabase(+selectedNode.index);
|
|
resolve(updatedDocument);
|
|
}
|
|
}
|
|
catch (errRes) {
|
|
reject(errRes);
|
|
}
|
|
});
|
|
}
|
|
find(selectedNode, collectionName, documentFieldName, documentFieldValue) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
if (!selectedNode || !selectedNode.index) {
|
|
reject(new Error('Selected Node Config Not Found.'));
|
|
}
|
|
if (documentFieldName && documentFieldValue) {
|
|
resolve(this.nodeDatabase[selectedNode.index].data[collectionName].find((document) => document[documentFieldName] === documentFieldValue));
|
|
}
|
|
else {
|
|
resolve(this.nodeDatabase[selectedNode.index].data[collectionName]);
|
|
}
|
|
}
|
|
catch (errRes) {
|
|
reject(errRes);
|
|
}
|
|
});
|
|
}
|
|
destroy(selectedNode, collectionName, documentFieldName, documentFieldValue) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
if (!selectedNode || !selectedNode.index) {
|
|
reject(new Error('Selected Node Config Not Found.'));
|
|
}
|
|
const removeDocIdx = this.nodeDatabase[selectedNode.index].data[collectionName].findIndex((document) => document[documentFieldName] === documentFieldValue);
|
|
if (removeDocIdx > -1) {
|
|
this.nodeDatabase[selectedNode.index].data[collectionName].splice(removeDocIdx, 1);
|
|
}
|
|
else {
|
|
reject(new Error('Unable to delete, document not found.'));
|
|
}
|
|
this.saveDatabase(+selectedNode.index);
|
|
resolve(documentFieldValue);
|
|
}
|
|
catch (errRes) {
|
|
reject(errRes);
|
|
}
|
|
});
|
|
}
|
|
validateDocument(collectionName, documentToValidate) {
|
|
switch (collectionName) {
|
|
case CollectionsEnum.OFFERS:
|
|
return validateOffer(documentToValidate);
|
|
default:
|
|
return ({ isValid: false, error: 'Collection does not exist' });
|
|
}
|
|
}
|
|
saveDatabase(nodeIndex) {
|
|
try {
|
|
const selNode = this.nodeDatabase[nodeIndex] && this.nodeDatabase[nodeIndex].adapter && this.nodeDatabase[nodeIndex].adapter.selNode ? this.nodeDatabase[nodeIndex].adapter.selNode : null;
|
|
if (!this.nodeDatabase[nodeIndex]) {
|
|
this.logger.log({ selectedNode: selNode, level: 'ERROR', fileName: 'Database', msg: 'Database Save Error: Selected Node Setup Not Found.' });
|
|
throw new Error('Database Save Error: Selected Node Setup Not Found.');
|
|
}
|
|
this.nodeDatabase[nodeIndex].adapter.saveData(this.nodeDatabase[nodeIndex].data);
|
|
this.logger.log({ selectedNode: this.nodeDatabase[nodeIndex].adapter.selNode, level: 'INFO', fileName: 'Database', msg: 'Database Saved' });
|
|
return true;
|
|
}
|
|
catch (err) {
|
|
const selNode = this.nodeDatabase[nodeIndex] && this.nodeDatabase[nodeIndex].adapter && this.nodeDatabase[nodeIndex].adapter.selNode ? this.nodeDatabase[nodeIndex].adapter.selNode : null;
|
|
this.logger.log({ selectedNode: selNode, level: 'ERROR', fileName: 'Database', msg: 'Database Save Error', error: err });
|
|
return new Error(err);
|
|
}
|
|
}
|
|
unloadDatabase(nodeIndex) {
|
|
this.saveDatabase(nodeIndex);
|
|
this.nodeDatabase[nodeIndex] = null;
|
|
}
|
|
}
|
|
export class DatabaseAdapter {
|
|
constructor(dbDirectoryPath, fileName, selNode = null) {
|
|
this.dbDirectoryPath = dbDirectoryPath;
|
|
this.fileName = fileName;
|
|
this.selNode = selNode;
|
|
this.dbFile = '';
|
|
this.dbFile = dbDirectoryPath + sep + fileName + '-node-' + selNode.index + '.json';
|
|
}
|
|
fetchData() {
|
|
try {
|
|
if (!fs.existsSync(this.dbDirectoryPath)) {
|
|
fs.mkdirSync(this.dbDirectoryPath);
|
|
}
|
|
}
|
|
catch (err) {
|
|
return new Error('Unable to Create Directory Error ' + JSON.stringify(err));
|
|
}
|
|
try {
|
|
if (!fs.existsSync(this.dbFile)) {
|
|
fs.writeFileSync(this.dbFile, '{}');
|
|
}
|
|
}
|
|
catch (err) {
|
|
return new Error('Unable to Create Database File Error ' + JSON.stringify(err));
|
|
}
|
|
try {
|
|
const dataFromFile = fs.readFileSync(this.dbFile, 'utf-8');
|
|
return !dataFromFile ? null : JSON.parse(dataFromFile);
|
|
}
|
|
catch (err) {
|
|
return new Error('Database Read Error ' + JSON.stringify(err));
|
|
}
|
|
}
|
|
getSelNode() {
|
|
return this.selNode;
|
|
}
|
|
saveData(data) {
|
|
try {
|
|
if (data) {
|
|
const tempFile = this.dbFile + '.tmp';
|
|
fs.writeFileSync(tempFile, JSON.stringify(data, null, 2));
|
|
fs.renameSync(tempFile, this.dbFile);
|
|
}
|
|
return true;
|
|
}
|
|
catch (err) {
|
|
return new Error('Database Write Error ' + JSON.stringify(err));
|
|
}
|
|
}
|
|
}
|
|
export const Database = new DatabaseService();
|