derzombiiie 25fc801fd3 node!
2021-08-05 20:13:12 +02:00

335 lines
12 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JsonDB = void 0;
const Utils_1 = require("./lib/Utils");
const FS = require("fs");
const path = require("path");
const mkdirp = require("mkdirp");
const Errors_1 = require("./lib/Errors");
const DBParentData_1 = require("./lib/DBParentData");
const ArrayInfo_1 = require("./lib/ArrayInfo");
const JsonDBConfig_1 = require("./lib/JsonDBConfig");
class JsonDB {
/**
* JSONDB Constructor
* @param filename where to save the "DB". Can also be used to give the whole configuration
* @param saveOnPush save the database at each push command into the json file
* @param humanReadable the JSON file will be readable easily by a human
* @param separator what to use as separator
*/
constructor(filename, saveOnPush = true, humanReadable = false, separator = '/') {
this.loaded = false;
this.data = {};
if (filename instanceof JsonDBConfig_1.Config) {
this.config = filename;
}
else {
this.config = new JsonDBConfig_1.Config(filename, saveOnPush, humanReadable, separator);
}
if (!FS.existsSync(this.config.filename)) {
const dirname = path.dirname(this.config.filename);
mkdirp.sync(dirname);
this.save(true);
this.loaded = true;
}
}
/**
* Process datapath into different parts
* @param dataPath
*/
processDataPath(dataPath) {
if (dataPath === undefined || !dataPath.trim()) {
throw new Errors_1.DataError("The Data Path can't be empty", 6);
}
if (dataPath == this.config.separator) {
return [];
}
dataPath = Utils_1.removeTrailingChar(dataPath, this.config.separator);
const path = dataPath.split(this.config.separator);
path.shift();
return path;
}
retrieveData(dataPath, create = false) {
this.load();
const thisDb = this;
const recursiveProcessDataPath = (data, index) => {
let property = dataPath[index];
/**
* Find the wanted Data or create it.
*/
function findData(isArray = false) {
if (data.hasOwnProperty(property)) {
data = data[property];
}
else if (create) {
if (isArray) {
data[property] = [];
}
else {
data[property] = {};
}
data = data[property];
}
else {
throw new Errors_1.DataError(`Can't find dataPath: ${thisDb.config.separator}${dataPath.join(thisDb.config.separator)}. Stopped at ${property}`, 5);
}
}
const arrayInfo = ArrayInfo_1.ArrayInfo.processArray(property);
if (arrayInfo) {
property = arrayInfo.property;
findData(true);
if (!Array.isArray(data)) {
throw new Errors_1.DataError(`DataPath: ${thisDb.config.separator}${dataPath.join(thisDb.config.separator)}. ${property} is not an array.`, 11);
}
const arrayIndex = arrayInfo.getIndex(data, true);
if (!arrayInfo.append && data.hasOwnProperty(arrayIndex)) {
data = data[arrayIndex];
}
else if (create) {
if (arrayInfo.append) {
data.push({});
data = data[data.length - 1];
}
else {
data[arrayIndex] = {};
data = data[arrayIndex];
}
}
else {
throw new Errors_1.DataError(`DataPath: ${thisDb.config.separator}${dataPath.join(thisDb.config.separator)}. . Can't find index ${arrayInfo.index} in array ${property}`, 10);
}
}
else {
findData();
}
if (dataPath.length == ++index) {
return data;
}
return recursiveProcessDataPath(data, index);
};
if (dataPath.length === 0) {
return this.data;
}
return recursiveProcessDataPath(this.data, 0);
}
getParentData(dataPath, create) {
const path = this.processDataPath(dataPath);
const last = path.pop();
return new DBParentData_1.DBParentData(this.retrieveData(path, create), this, dataPath, last);
}
/**
* Get the wanted data
* @param dataPath path of the data to retrieve
*/
getData(dataPath) {
const path = this.processDataPath(dataPath);
return this.retrieveData(path, false);
}
/**
* Same as getData only here it's directly typed to your object
* @param dataPath path of the data to retrieve
*/
getObject(dataPath) {
return this.getData(dataPath);
}
/**
* Check for existing datapath
* @param dataPath
*/
exists(dataPath) {
try {
this.getData(dataPath);
return true;
}
catch (e) {
if (e instanceof Errors_1.DataError) {
return false;
}
throw e;
}
}
/**
* Returns the number of element which constitutes the array
* @param dataPath
*/
count(dataPath) {
const result = this.getData(dataPath);
if (!Array.isArray(result)) {
throw new Errors_1.DataError(`DataPath: ${dataPath} is not an array.`, 11);
}
const path = this.processDataPath(dataPath);
const data = this.retrieveData(path, false);
return data.length;
}
/**
* Returns the index of the object that meets the criteria submitted.
* @param dataPath base dataPath from where to start searching
* @param searchValue value to look for in the dataPath
* @param propertyName name of the property to look for searchValue
*/
getIndex(dataPath, searchValue, propertyName = 'id') {
const result = this.getData(dataPath);
if (!Array.isArray(result)) {
throw new Errors_1.DataError(`DataPath: ${dataPath} is not an array.`, 11);
}
const path = this.processDataPath(dataPath);
const data = this.retrieveData(path, false);
return data.map(function (element) { return element[propertyName]; }).indexOf(searchValue);
}
/**
* Find all specific entry in an array/object
* @param rootPath base dataPath from where to start searching
* @param callback method to filter the result and find the wanted entry. Receive the entry and it's index.
*/
filter(rootPath, callback) {
const result = this.getData(rootPath);
if (Array.isArray(result)) {
return result.filter(callback);
}
if (result instanceof Object) {
const entries = Object.entries(result);
const found = entries.filter((entry) => {
return callback(entry[1], entry[0]);
});
if (!found || found.length < 1) {
return undefined;
}
return found.map((entry) => {
return entry[1];
});
}
throw new Errors_1.DataError("The entry at the path (" + rootPath + ") needs to be either an Object or an Array", 12);
}
/**
* Find a specific entry in an array/object
* @param rootPath base dataPath from where to start searching
* @param callback method to filter the result and find the wanted entry. Receive the entry and it's index.
*/
find(rootPath, callback) {
const result = this.getData(rootPath);
if (Array.isArray(result)) {
return result.find(callback);
}
if (result instanceof Object) {
const entries = Object.entries(result);
const found = entries.find((entry) => {
return callback(entry[1], entry[0]);
});
if (!found || found.length < 2) {
return undefined;
}
return found[1];
}
throw new Errors_1.DataError("The entry at the path (" + rootPath + ") needs to be either an Object or an Array", 12);
}
/**
* Pushing data into the database
* @param dataPath path leading to the data
* @param data data to push
* @param override overriding or not the data, if not, it will merge them
*/
push(dataPath, data, override = true) {
const dbData = this.getParentData(dataPath, true);
if (!dbData) {
throw new Error("Data not found");
}
let toSet = data;
if (!override) {
if (Array.isArray(data)) {
let storedData = dbData.getData();
if (storedData === undefined) {
storedData = [];
}
else if (!Array.isArray(storedData)) {
throw new Errors_1.DataError("Can't merge another type of data with an Array", 3);
}
toSet = storedData.concat(data);
}
else if (data === Object(data)) {
if (Array.isArray(dbData.getData())) {
throw new Errors_1.DataError("Can't merge an Array with an Object", 4);
}
toSet = Utils_1.merge(dbData.getData(), data);
}
}
dbData.setData(toSet);
if (this.config.saveOnPush) {
this.save();
}
}
/**
* Delete the data
* @param dataPath path leading to the data
*/
delete(dataPath) {
const dbData = this.getParentData(dataPath, true);
if (!dbData) {
return;
}
dbData.delete();
if (this.config.saveOnPush) {
this.save();
}
}
/**
* Only use this if you know what you're doing.
* It reset the full data of the database.
* @param data
*/
resetData(data) {
this.data = data;
}
/**
* Reload the database from the file
*/
reload() {
this.loaded = false;
this.load();
}
;
/**
* Manually load the database
* It is automatically called when the first getData is done
*/
load() {
if (this.loaded) {
return;
}
try {
const data = FS.readFileSync(this.config.filename, 'utf8');
this.data = JSON.parse(data);
this.loaded = true;
}
catch (err) {
const error = new Errors_1.DatabaseError("Can't Load Database", 1, err);
throw error;
}
}
/**
* Manually save the database
* By default you can't save the database if it's not loaded
* @param force force the save of the database
*/
save(force) {
force = force || false;
if (!force && !this.loaded) {
throw new Errors_1.DatabaseError("DataBase not loaded. Can't write", 7);
}
let data = "";
try {
if (this.config.humanReadable) {
data = JSON.stringify(this.data, null, 4);
}
else {
data = JSON.stringify(this.data);
}
FS.writeFileSync(this.config.filename, data, 'utf8');
}
catch (err) {
const error = new Errors_1.DatabaseError("Can't save the database", 2, err);
throw error;
}
}
}
exports.JsonDB = JsonDB;
//# sourceMappingURL=JsonDB.js.map