UNPKG

oxzof-db

Version:

- It is a simple data processing module based on BSON.

372 lines (328 loc) 12.8 kB
const fs = require("fs"); const path = require("path"); const https = require("https"); const { BSON } = require("bson"); const { exec } = require("child_process"); const Table = require('cli-table3'); class Database { constructor(file = false, options = {}) { const { logMessages=false, autoUpdate=false } = options; this.logs = logMessages; this.autoUpdate = autoUpdate; const filePath = process.cwd(); this.packageName = "oxzof-db"; this.isVersionChecked = false; this.file = file ? path.join(filePath, file) : path.join(filePath, "./oxzof-db/database.bson"); this.isWriting = false; this.checkFile().catch((e) => this.messageLog(e.message)); } checkPackageVersion() { if (this.isVersionChecked) return Promise.resolve(); return new Promise((resolve) => { fs.promises .readFile(path.join(__dirname, "package.json"), "utf8") .then((localData) => { const localVersion = JSON.parse(localData).version; const registryUrl = `https://registry.npmjs.org/${this.packageName}`; https.get(registryUrl, (response) => { let data = ""; response.on("data", (chunk) => (data += chunk)); response.on("end", () => { try{ const latestVersion = JSON.parse(data)["dist-tags"].latest; if (localVersion !== latestVersion) { if (this.autoUpdate) { this.messageLog( "New update available, autoUpdate active. Updating...", "system" ); exec(`npm install ${this.packageName}@latest`, (error, stdout, stderr) => { if (error || stderr) { this.messageLog(error || stderr); resolve(); return; } this.messageLog( `Module update completed: ${stdout}`, "system" ); resolve(); }); } else { this.messageLog( `The current version is published as ${latestVersion}. Please update the package: npm i oxzof-db@latest`, "system" ); resolve(); } } else { resolve(); } }catch(err){ this.messageLog("NPM Error: "+err,"system") return; } }); }).on("error", (err) => { this.messageLog("Error in NPM version control: " + err.message,"system"); resolve(); }); this.isVersionChecked = true; }) .catch((e) => { this.messageLog("Error during version check: " + e.message,"system"); resolve(); }); }); } checkFile() { return new Promise((resolve, reject) => { const folderPath = path.dirname(this.file); fs.promises .mkdir(folderPath, { recursive: true }) .then(() => { if (!fs.existsSync(this.file)) { const emptyData = BSON.serialize({}); return fs.promises.writeFile(this.file, emptyData); } else { return fs.promises.readFile(this.file).then((fileData) => { if (fileData.length === 0) { const emptyData = BSON.serialize({}); return fs.promises.writeFile(this.file, emptyData); } }); } }) .then(() => { if (!this.file.endsWith(".bson")) { this.messageLog( "The file extension must be .bson: " + this.filePath,"system" ); resolve(false); } else { resolve(true); } }) .catch((e) => reject(e)); }); } writeFile(data) { return new Promise((resolve, reject) => { const bsonData = BSON.serialize(data); fs.promises .writeFile(this.file, bsonData) .then(() => resolve(true)) .catch((e) => { this.messageLog(e.message); resolve(false); }); }); } readFile() { return fs.promises .readFile(this.file) .then((data) => (data.length === 0 ? {} : BSON.deserialize(data))) .catch((e) => { this.messageLog(e.message); return false; }); } checkFileSync() { if (!fs.existsSync(this.file)) { fs.writeFileSync(this.file, BSON.serialize({})); } } readFileSync() { const fileContent = fs.readFileSync(this.file); return BSON.deserialize(fileContent); } writeFileSync(data) { const serializedData = BSON.serialize(data); fs.writeFileSync(this.file, serializedData); } messageLog(msg,type="error"){ const table = new Table({ head: ['[oxzof-db] Error Type', 'Message', 'Timestamp'], colWidths: [20, 50, 30], }); switch(type){ case "error": if(this.logs){ table.push( ['Error', msg, new Date().toISOString()] ); console.warn(table.toString()) } break; case "warning": if(this.logs){ table.push( ['Error', msg, new Date().toISOString()] ); console.warn(table.toString()) } break; case "success": if(this.logs){ console.warn(`\x1b[32m[oxzof-db] Success: ${msg} \x1b[0m`) } break; case "system": console.warn(`\x1b[33m[oxzof-db] System: ${msg} \x1b[0m`) break; default: console.warn(`\x1b[31m[oxzof-db] Info: ${msg} \x1b[0m`) break; } } set(key, value) { try { this.checkFileSync(); const data = this.readFileSync(); data[key] = isNaN(value)?value:Number(value); this.writeFileSync(data); return value; } catch (e) { this.messageLog(`Error during set(): ${e.message}`, "error"); return false; } } get(key = null) { try { this.checkFileSync(); const data = this.readFileSync(); return data[key] ? data[key] : false; } catch (e) { this.messageLog(`Error during get(): ${e.message}`, "error"); return false; } } all() { try { this.checkFileSync(); const data = this.readFileSync(); return Object.entries(data).map(([key, value]) => ({ [key]: value })); } catch (e) { this.messageLog(`Error during all(): ${e.message}`, "error"); return false; } } push(key, value) { try { this.checkFileSync(); const data = this.readFileSync(); if (!Array.isArray(data[key])) { data[key] = []; } if (Array.isArray(value)) { data[key].push(...value); } else { data[key].push(value); } this.writeFileSync(data); return data[key]; } catch (e) { this.messageLog(`Error during push(): ${e.message}`, "error"); return false; } } delete(key) { if (!key) { this.messageLog("A key is required for the delete() function!", "error"); return false; } try { this.checkFileSync(); const data = this.readFileSync(); if (data.hasOwnProperty(key)) { delete data[key]; this.writeFileSync(data); return true; } else { this.messageLog(`"${key}" is an invalid key.`, "warning"); return false; } } catch (e) { this.messageLog(`Error during delete(): ${e.message}`, "error"); return false; } } deleteAll() { try { this.checkFileSync(); const emptyData = BSON.serialize({}); fs.writeFileSync(this.file, emptyData); return true; } catch (e) { this.messageLog(`Error during deleteAll(): ${e.message}`, "error"); return false; } } unpush(key, element) { try { this.checkFileSync(); const data = this.readFileSync(); if (!data[key]) { this.messageLog(`Key "${key}" not found.`, "warning"); return undefined; } if (!Array.isArray(data[key])) { this.messageLog(`"${key}" is not an array: ${data[key]}`, "error"); return false; } if (Array.isArray(element)) { element.forEach(el => { data[key] = data[key].filter(item => item !== el); }); } else { data[key] = data[key].filter(item => item !== element); } this.writeFileSync(data); return data[key]; } catch (e) { this.messageLog(`Error during unpush(): ${e.message}`, "error"); return false; } } unpushByIndex(key, index) { try { this.checkFileSync(); const data = this.readFileSync(); if (!data[key]) { this.messageLog(`Key "${key}" not found.`, "warning"); return undefined; } if (!Array.isArray(data[key])) { this.messageLog(`"${key}" is not an array: ${data[key]}`, "error"); return false; } if (index < 0 || index >= data[key].length || isNaN(index)) { this.messageLog(`Invalid index number: ${index}`, "warning"); return false; } data[key].splice(index, 1); this.writeFileSync(data); return data[key]; } catch (e) { this.messageLog(`Error during unpushByIndex(): ${e.message}`, "error"); return false; } } } function createInstance(file, filePath) { const instance = new Database(file, filePath); instance.checkPackageVersion(); return { set: instance.set.bind(instance), delete: instance.delete.bind(instance), deleteAll: instance.deleteAll.bind(instance), get: instance.get.bind(instance), push: instance.push.bind(instance), unpush: instance.unpush.bind(instance), unpushByIndex: instance.unpushByIndex.bind(instance), all: instance.all.bind(instance) }; } module.exports = createInstance;