UNPKG

json-as-sql

Version:

Use JSON files like an SQL database with full CRUD, filters, sorting, and more.

189 lines (163 loc) 4.88 kB
// JSON-based version of the same DB utility const fs = require('fs'); const path = require('path'); class JsonDB { constructor(filePath) { this.filePath = path.resolve(filePath); if (!fs.existsSync(this.filePath)) { fs.writeFileSync(this.filePath, JSON.stringify([])); } } _readData() { const content = fs.readFileSync(this.filePath, 'utf-8'); const data = JSON.parse(content); return Array.isArray(data) ? data : []; } _writeData(data) { fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2)); } _parseValue(value, isDate) { if (isDate) return new Date(value).getTime(); if (!isNaN(value)) return parseFloat(value); return value.toString().toLowerCase(); } _applyFilter(data, where) { return data.filter(row => { return Object.entries(where).every(([key, condition]) => { const rowVal = row[key] || ''; const isDate = key.toLowerCase().includes('date'); if (typeof condition === 'object' && condition !== null) { const { op, value } = condition; const a = this._parseValue(rowVal, isDate); const b = this._parseValue(value, isDate); switch (op) { case '>': return a > b; case '<': return a < b; case '>=': return a >= b; case '<=': return a <= b; case '!=': return a != b; case '=': return a == b; case 'contains': return rowVal.toLowerCase().includes(String(value).toLowerCase()); default: return false; } } else { return rowVal == condition; } }); }); } _applySorting(data, orderBy = []) { return data.sort((a, b) => { for (let { column, direction } of orderBy) { const isDate = column.toLowerCase().includes('date'); const valA = this._parseValue(a[column], isDate); const valB = this._parseValue(b[column], isDate); if (valA < valB) return direction === 'desc' ? 1 : -1; if (valA > valB) return direction === 'desc' ? -1 : 1; } return 0; }); } _applySelectFields(data, fields) { return data.map(row => { const newObj = {}; fields.forEach(f => newObj[f] = row[f]); return newObj; }); } async createTable(columns = []) { if (!columns || !Array.isArray(columns) || columns.length === 0) { throw new Error('You must pass an array of column names'); } this._writeData([]); return { success: true, message: 'Table created (JSON file initialized)', columns }; } async select(where = {}, options = {}) { let data = this._readData(); data = this._applyFilter(data, where); if (options.orderBy) data = this._applySorting(data, options.orderBy); if (options.offset) data = data.slice(options.offset); if (options.limit) data = data.slice(0, options.limit); if (options.selectFields) data = this._applySelectFields(data, options.selectFields); return data; } async insertOne(rowObj) { const data = this._readData(); data.push(rowObj); this._writeData(data); return { success: true, insertedData: rowObj }; } async insertMany(rows) { const data = this._readData(); const insertRows = Array.isArray(rows) ? rows : [rows]; const updated = [...data, ...insertRows]; this._writeData(updated); return { success: true, insertedCount: insertRows.length }; } async update(where, newData) { const data = this._readData(); const updated = []; const result = data.map(row => { if (this._applyFilter([row], where).length > 0) { const updatedRow = { ...row, ...newData }; updated.push(updatedRow); return updatedRow; } return row; }); this._writeData(result); return { success: true, updatedCount: updated.length, updatedRows: updated }; } async delete(where) { const data = this._readData(); const filtered = []; const deleted = []; for (const row of data) { if (this._applyFilter([row], where).length > 0) { deleted.push(row); } else { filtered.push(row); } } this._writeData(filtered); return { success: true, deletedCount: deleted.length }; } async dropTable() { fs.unlinkSync(this.filePath); return { success: true, message: 'JSON table deleted' }; } async truncateTable() { this._writeData([]); return { success: true, message: 'JSON table truncated (all data cleared)' }; } async showTableDetail() { const data = this._readData(); const first = data[0] || {}; return { success: true, columns: Object.keys(first), path: this.filePath }; } } module.exports = JsonDB;