UNPKG

nixabase

Version:

A lightweight and flexible database for JSON and TXT with memory caching and image compression

212 lines (196 loc) 7.22 kB
const fs = require('fs').promises; const path = require('path'); const sharp = require('sharp'); /** * Nixabase - A lightweight database management system with file storage and caching capabilities. */ class Nixabase { /** * Creates a new Nixabase instance. * @param {string} filePath - The path to the database file. * @param {Object} [options={}] - Configuration options for the database. * @param {string} [options.format='json'] - The format of the database file ('json' or 'txt'). * @param {Object} [options.performance={}] - Performance-related options. */ constructor(filePath, options = {}) { this.filePath = filePath; this.format = options.format || 'json'; this.performance = options.performance || {}; this.initialized = false; this.memoryCache = new Map(); } /** * Initializes the database, creating the file if it doesn't exist. * @returns {Promise<void>} */ async initialize() { try { await fs.access(this.filePath); } catch (error) { if (error.code === 'ENOENT') { await this.writeData({}); } else { throw error; } } this.initialized = true; } /** * Ensures the database is initialized before performing operations. * @returns {Promise<void>} */ async ensureInitialized() { if (!this.initialized) { await this.initialize(); } } /** * Reads the entire database content. * @returns {Promise<Object>} The parsed database content. */ async read() { await this.ensureInitialized(); const data = await fs.readFile(this.filePath, 'utf8'); return this.format === 'json' ? JSON.parse(data) : this.parseTxtData(data); } /** * Saves a key-value pair to the database. * @param {string} key - The key to save. * @param {*} value - The value to save. * @returns {Promise<void>} */ async save(key, value) { await this.ensureInitialized(); const data = await this.read(); data[key] = value; await this.writeData(data); if (this.performance.memory && this.performance.memory.enabled) { this.memoryCache.set(key, value); if (this.memoryCache.size > this.performance.memory.maxItemCount) { const oldestKey = this.memoryCache.keys().next().value; this.memoryCache.delete(oldestKey); } } } /** * Retrieves a value from the database by its key. * @param {string} key - The key to retrieve. * @returns {Promise<*>} The value associated with the key. */ async get(key) { if (this.performance.memory && this.performance.memory.enabled && this.memoryCache.has(key)) { return this.memoryCache.get(key); } const data = await this.read(); return data[key]; } /** * Updates an existing key-value pair in the database. * @param {string} key - The key to update. * @param {*} value - The new value. * @returns {Promise<void>} * @throws {Error} If the key doesn't exist in the database. */ async update(key, value) { await this.ensureInitialized(); const data = await this.read(); if (key in data) { data[key] = value; await this.writeData(data); if (this.performance.memory && this.performance.memory.enabled) { this.memoryCache.set(key, value); } } else { throw new Error(`Key "${key}" not found in the database.`); } } /** * Deletes a key-value pair from the database. * @param {string} key - The key to delete. * @returns {Promise<void>} */ async delete(key) { await this.ensureInitialized(); const data = await this.read(); if (key in data) { delete data[key]; await this.writeData(data); if (this.performance.memory && this.performance.memory.enabled) { this.memoryCache.delete(key); } } } /** * Writes data to the database file. * @param {Object} data - The data to write. * @returns {Promise<void>} */ async writeData(data) { if (this.format === 'json') { await fs.writeFile(this.filePath, JSON.stringify(data, null, 2)); } else { const txtData = Object.entries(data) .map(([key, value]) => `${key}=${this.stringifyValue(value)}`) .join('\n'); await fs.writeFile(this.filePath, txtData); } } /** * Converts a value to a string representation. * @param {*} value - The value to stringify. * @returns {string} The stringified value. */ stringifyValue(value) { if (typeof value === 'object' && value !== null) { return JSON.stringify(value); } return String(value); } /** * Parses text data into an object. * @param {string} data - The text data to parse. * @returns {Object} The parsed object. */ parseTxtData(data) { return data.split('\n').reduce((acc, line) => { const [key, value] = line.split('=').map(item => item.trim()); if (key && value) { try { acc[key] = JSON.parse(value); } catch (e) { acc[key] = value; } } return acc; }, {}); } /** * Uploads a file to the database with optional image compression. * @param {string} sourcePath - The path to the source file. * @param {string} destinationKey - The key to store the file under in the database. * @returns {Promise<void>} */ async uploadFile(sourcePath, destinationKey) { await this.ensureInitialized(); let fileBuffer = await fs.readFile(sourcePath); if (this.performance.imageCompression && this.performance.imageCompression.enabled) { const { level, resize, quality } = this.performance.imageCompression; fileBuffer = await sharp(fileBuffer) .resize(resize) .jpeg({ quality, progressive: true, force: false }) .png({ compressionLevel: level, progressive: true, force: false }) .toBuffer(); } await this.save(destinationKey, fileBuffer.toString('base64')); } /** * Retrieves a file from the database. * @param {string} key - The key of the file in the database. * @returns {Promise<Buffer|null>} The file buffer or null if not found. */ async getFile(key) { const base64Data = await this.get(key); return base64Data ? Buffer.from(base64Data, 'base64') : null; } } module.exports = Nixabase;