fasturl.db
Version:
A simple JSON database for javacsript node.js
196 lines (166 loc) • 8.29 kB
JavaScript
const path = require("path");
const fs = require("fs");
const Lodash = require("lodash");
// variables temporary storage
const Variables = new Map();
class FasturlDB {
constructor(options){
const defaultOptions = {
directory: options.directory || "./database",
tables: { "main": "/main/database.json" },
showLogs: options.showLogs || false
};
this.options = {
...options,
...defaultOptions,
tables: Lodash.merge(defaultOptions.tables, options.tables)
};
this.tables = this.options.tables;
this.Variables = Variables;
if(this.options.directory && !fs.existsSync(this.options.directory)) {
// create database directory
fs.mkdir(this.options.directory, {
recursive: true
}, (err) => {
if(err) throw new Error();
this.sendLogs(`Success create "${this.options.directory}" directory`);
});
}
// create database files
const tables = this.tables;
for(let table in tables) {
const filePath = path.join(this.options.directory, tables[table]);
const isCreated = fs.existsSync(filePath);
if(!isCreated) {
if(!filePath.endsWith(".json")) throw new Error(`Invalid database file at ${table} ${tables[table]}`);
const fileDirectorPath = filePath.split("/").slice(0, -1).join("/");
fs.mkdirSync(fileDirectorPath, { recursive: true });
fs.writeFileSync(filePath, "{}", { recursive: true });
this.sendLogs(`Success create "${table}" table on path: ${filePath}`);
}
}
}
isEmpty(value) {
if (value === null) return false;
if (typeof value === 'boolean') return false;
if (typeof value === 'number') return false;
if (typeof value === 'string') return false;
if (Array.isArray(value)) return false;
if (typeof value === 'object') return false;
if (typeof value === 'symbol') return false;
if (typeof value === 'function') return false;
return !value;
}
async isExists(table) {
if(!table) throw new Error(`Failed check the table, table name is not defined!`);
return await fs.existsSync(path.join(this.options.directory, `${this.tables[table]}`));
}
variables(data, table = "main") {
if(!this.tables[table]) throw new Error(`Invalid table, table with name "${table}" is not found!`);
const currentData = this.Variables.get(table);
this.Variables.set(table, Lodash.merge(currentData, data));
}
async setKey(oldKey, newKey, table = "main") {
if(!this.tables[table]) throw new Error(`Invalid table, table with name "${table}" is not found!`);
const filePath = path.join(this.options.directory, this.tables[table]);
// checking params
if(this.isEmpty(oldKey)) throw new Error(`oldKey parameter value is undefined!`)
if(this.isEmpty(newKey)) throw new Error(`newKey parameter value is undefined!`)
if(!this.isExists(table)) throw new Error(`Table with name "${table}" at ${this.tables[table]} is not exists!`);
if(!await this.has(oldKey)) return false;
let content = await this.getContent(filePath);
content = Lodash.set(content, newKey, Lodash.get(content, oldKey));
Lodash.unset(content, oldKey);
await this.setContent(filePath, content)
return true;
}
async set(key, value, table = "main") {
if(!this.tables[table]) throw new Error(`Invalid table, table with name "${table}" is not found!`);
const filePath = path.join(this.options.directory, this.tables[table]);
if(this.isEmpty(key)) throw new Error(`Key parameter value is undefined`)
if(this.isEmpty(value)) throw new Error(`Value parameter value is undefined`)
if(!this.isExists(table)) throw new Error(`Table with name "${table}" at ${this.tables[table]} is not exists!`);
let content = await this.getContent(filePath);
content = Lodash.set(content, key, value);
await this.setContent(filePath, content)
return Lodash.get(content, key);
}
async get(key, table = "main") {
if(!this.tables[table]) throw new Error(`Invalid table, table with name "${table}" is not found!`);
const filePath = path.join(this.options.directory, this.tables[table]);
if(this.isEmpty(key)) throw new Error(`Key parameter value is undefined`)
if(!this.isExists(table)) throw new Error(`Table with name "${table}" at ${this.tables[table]} is not exists!`);
let content = await this.getContent(filePath);
let data = Lodash.get(content, key);
return data || JSON.stringify(this.Variables.get(table)[key.split(".").slice(-1)[0]]);
}
async delete(key, table = "main") {
if(!this.tables[table]) throw new Error(`Invalid table, table with name "${table}" is not found!`);
const filePath = path.join(this.options.directory, this.tables[table]);
if(this.isEmpty(key)) throw new Error(`Key parameter value is undefined`)
if(!this.isExists(table)) throw new Error(`Table with name "${table}" at ${this.tables[table]} is not exists!`);
let content = await this.getContent(filePath);
Lodash.unset(content, key);
await this.setContent(filePath, content)
return true
}
async has(key, table = "main") {
if(!this.tables[table]) throw new Error(`Invalid table, table with name "${table}" is not found!`);
const filePath = path.join(this.options.directory, this.tables[table]);
if(this.isEmpty(key)) throw new Error(`Key parameter value is undefined`)
if(!this.isExists(table)) throw new Error(`Table with name "${table}" at ${this.tables[table]} is not exists!`);
let content = await this.getContent(filePath);
let data = Lodash.get(content, key);
if(!data) return false;
return true;
}
async all(table = "main") {
if(!this.tables[table]) throw new Error(`Invalid table, table with name "${table}" is not found!`);
const filePath = path.join(this.options.directory, this.tables[table]);
return await this.getContent(filePath);
}
abbreviate(number, format = "0.00a") {
const SI_SYMBOL = ["", "K", "M", "B", "T", "Qa", "Qi", "Sx", "Sp", "O", "N", "D", "UD", "UD", "DD", "TD", "QaD", "QiD", "SxD", "SpD", "OD", "ND", "V", "UV", "DV", "TV", "QaV", "QiV", "SxV", "SpV", "OV", "NV", "DT", "UDT", "DDT", "TDT", "QaDT", "QiDT", "SxDT", "SpDT", "ODT", "NDT", "DQa", "UDQa", "DDQa", "TDQa", "QaDQa", "QiDQa", "SxDQa", "SpDQa", "ODQa", "NDQa", "DQi", "UDQi", "DDQi", "TDQi", "QaDQi", "QiDQi", "SxDQi", "SpDQi", "ODQi", "NDQi", "DSx", "UDSx", "DDSx", "TDSx", "QaDSx", "QiDSx", "SxDSx", "SpDSx", "ODSx", "NDSx", "DSp", "UDSp", "DDSp", "TDSp", "QaDSp", "QiDSp", "SxDSp", "SpDSp", "ODSp", "NDSp", "DO", "UDO", "DDO", "TDO", "QaDO", "QiDO", "SxDO", "SpDO", "ODO", "NDO", "DN", "UDN", "DDN", "TDN", "QaDN", "QiDN", "SxDN", "SpDN", "ODN", "NDN", "C"];
if (!isNaN(number)) {
if (number < 1000) {
return number;
}
const exponent = Math.floor(Math.log10(number) / 3);
const exponentCheck = Math.log10(number);
const suffix = SI_SYMBOL[exponent];
const cvtdNum = number / Math.pow(10, exponent * 3);
let dec = 0;
if (format.startsWith("0.")) {
dec = format.slice(3).length;
}
const roundNum = cvtdNum.toFixed(dec);
const decSep = format.includes(",") ? "," : ".";
if (exponentCheck > 306) {
const result = roundNum.replace(".", decSep) + suffix;
return result;
} else {
const result = roundNum.replace(".", decSep) + suffix;
return result;
}
} else {
throw new Error(`FasturlDB: invalid number on abbreviate() function at "number" parameter.`);
return undefined;
}
}
// write file
async getContent(filePath) {
if(!this.isExists(filePath)) throw new Error(`Database file at path "${filePath}" is not exists!`);
return JSON.parse(fs.readFileSync(filePath, "utf8"));
}
// read file
async setContent(filePath, content) {
if(!this.isExists(filePath)) throw new Error(`Database file at path "${filePath}" is not exists!`);
fs.writeFileSync(filePath, JSON.stringify(content, null, 2));
return JSON.stringify(content, null, 2);
}
sendLogs(text) {
// send logs
this.options.showLogs ? console.log("FasturlDB:", text) : null;
}
}
module.exports = { FasturlDB };