UNPKG

arlet-db

Version:

A simple database manager for Node.js

754 lines (718 loc) 35 kB
const fs = require('fs'); const path = require('path'); const { promisify } = require('util'); const readFile = promisify(fs.readFile); const writeFile = promisify(fs.writeFile); const { v4: uuidv4 } = require('uuid'); class ArletDb { constructor(pathDatabase, nameDatabase) { this.pathDatabase = path.resolve(pathDatabase, nameDatabase); if (!fs.existsSync(this.pathDatabase)) { fs.mkdirSync(this.pathDatabase, { recursive: true }); } } /** * Creates a new table in the database with the specified columns and optional auto-increment column. * * @param {string} tableName - The name of the table to create. * @param {Object} columns - An object where keys are column names and values are column types ('string' or 'number'). * @param {string} [autoIncrementColumn=null] - The name of the column to auto-increment. Must be of type 'number'. * @returns {Object} An object representing the created table structure, including columns, data, and auto-increment settings. * @throws {Error} Throws an error if the column type is not 'string' or 'number', if no columns are provided, or if the table already exists. */ async createTable(tableName, columns = {}, autoIncrementColumn = null) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); for (const key in columns) { if (columns[key] !== 'string' && columns[key] !== 'number') { throw new Error('Tipo de dato no permitido'); } } if (Object.keys(columns).length === 0) { throw new Error('No se puede crear una tabla sin columnas'); } if (fs.existsSync(tablePath)) { throw new Error('La tabla ya existe'); } columns['id_arlet'] = 'string'; const tableData = { columns, data: [], autoIncrement: {} }; if (autoIncrementColumn) { if (!columns[autoIncrementColumn] || columns[autoIncrementColumn] !== 'number') { throw new Error('La columna de auto-incremento debe ser de tipo número y debe existir en la tabla'); } tableData.autoIncrement[autoIncrementColumn] = 1; } await writeFile(tablePath, JSON.stringify(tableData, null, 2)); return tableData; } /** * Creates a new table in the database if it does not already exist. * If the table exists, returns the existing table structure without modifications. * * @param {string} tableName - The name of the table to create or check. * @param {Object} columns - An object where keys are column names and values are column types ('string' or 'number'). * @param {string} [autoIncrementColumn=null] - The name of the column to auto-increment. Must be of type 'number'. * @returns {Object} An object representing the created or existing table structure, including columns, data, and auto-increment settings. * @throws {Error} Throws an error if the column type is not 'string' or 'number', if no columns are provided, or if auto-increment column type or existence is invalid. */ async createTableIfNotExists(tableName, columns = {}, autoIncrementColumn = null) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); for (const key in columns) { if (columns[key] !== 'string' && columns[key] !== 'number') { throw new Error('Tipo de dato no permitido'); } } if (Object.keys(columns).length === 0) { throw new Error('No se puede crear una tabla sin columnas'); } columns['id_arlet'] = 'string'; const tableData = { columns, data: [], autoIncrement: {} }; if (autoIncrementColumn) { if (!columns[autoIncrementColumn] || columns[autoIncrementColumn] !== 'number') { throw new Error('La columna de auto-incremento debe ser de tipo número y debe existir en la tabla'); } tableData.autoIncrement[autoIncrementColumn] = 1; } if (fs.existsSync(tablePath)) { return tableData; } await writeFile(tablePath, JSON.stringify(tableData, null, 2)); console.log('Tabla creada'); return tableData; } /** * Updates the structure of an existing table in the database. * Modifies column definitions and optionally sets an auto-increment column. * * @param {string} tableName - The name of the table to update. * @param {Object} columns - An object where keys are column names and values are column types ('string' or 'number'). * @param {string} [autoIncrementColumn=null] - The name of the column to auto-increment. Must be of type 'number'. * @returns {Object} An object representing the updated table structure, including columns, data, and auto-increment settings. * @throws {Error} Throws an error if the table does not exist, if column types are invalid, if no columns are provided, or if auto-increment column type or existence is invalid. */ async updateTable(tableName, columns = {}, autoIncrementColumn = null) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); for (const key in columns) { if (columns[key] !== 'string' && columns[key] !== 'number') { throw new Error('Tipo de dato no permitido'); } } if (Object.keys(columns).length === 0) { throw new Error('No se puede crear una tabla sin columnas'); } if (autoIncrementColumn) { if (!columns[autoIncrementColumn] || columns[autoIncrementColumn] !== 'number') { throw new Error('La columna de auto-incremento debe ser de tipo número y debe existir en la tabla'); } tableData.autoIncrement[autoIncrementColumn] = 1; } tableData.columns = columns; await writeFile(tablePath, JSON.stringify(tableData, null, 2)); return tableData; } /** * Retrieves the schema (column definitions) of a specified table from the database. * * @param {string} tableName - The name of the table from which to retrieve the schema. * @returns {Object} An object representing the columns and their types for the specified table. * @throws {Error} Throws an error if the table does not exist. */ async getTableSchema(tableName) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return tableData.columns; } /** * Retrieves a list of table names from the database directory. * * @returns {Array} An array of strings representing the names of tables in the database. */ async getTables() { const files = fs.readdirSync(this.pathDatabase); return files.map(file => file.replace('.json', '')); } /** * Checks if a table exists in the database directory. * * @param {string} tableName - The name of the table to check. * @returns {boolean} True if the table exists, false otherwise. */ async tableExists(tableName) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); return fs.existsSync(tablePath); } /** * Clears all data from a table, optionally resetting auto-increment column. * * @param {string} tableName - The name of the table to clear. * @param {string} autoIncrementColumn - Optional. The auto-increment column name to reset. * @returns {Object} The updated table data object after clearing. * @throws {Error} Throws an error if the table does not exist. */ async clearTable(tableName, autoIncrementColumn) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); tableData.data = []; if (autoIncrementColumn && tableData.columns[autoIncrementColumn] === 'number') { tableData.autoIncrement[autoIncrementColumn] = 1; } await writeFile(tablePath, JSON.stringify(tableData, null, 2)); return tableData; } /** * Clears all data from a table without resetting auto-increment columns. * * @param {string} tableName - The name of the table to clear. * @returns {Object} The updated table data object after clearing. * @throws {Error} Throws an error if the table does not exist. */ async clearTableNoForce(tableName) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); tableData.data = []; await writeFile(tablePath, JSON.stringify(tableData, null, 2)); return tableData; } /** * Deletes a table and its associated file from the database. * * @param {string} tableName - The name of the table to delete. * @returns {boolean} True if the table was successfully deleted. * @throws {Error} Throws an error if the table does not exist or cannot be deleted. */ async deleteTable(tableName) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } fs.unlinkSync(tablePath); return true; } /** * Checks if a column exists in a specified table. * * @param {string} tableName - The name of the table to check. * @param {string} columnName - The name of the column to check for existence. * @returns {boolean} True if the column exists in the table, false otherwise. * @throws {Error} Throws an error if the table does not exist or cannot be read. */ async columnExists(tableName, columnName) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return tableData.columns.hasOwnProperty(columnName); } /** * Retrieves the list of column names from a specified table. * * @param {string} tableName - The name of the table from which to retrieve column names. * @returns {Array} An array of column names in the specified table. * @throws {Error} Throws an error if the table does not exist or cannot be read. */ async getColumns(tableName) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return Object.keys(tableData.columns); } /** * Retrieves the data type of each column in a specified table. * * @param {string} tableName - The name of the table from which to retrieve column types. * @returns {Object} An object where keys are column names and values are their respective data types. * @throws {Error} Throws an error if the table does not exist or cannot be read. */ async getColumnsType(tableName) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return tableData.columns; } /** * Retrieves the auto-increment column configuration from a specified table. * * @param {string} tableName - The name of the table from which to retrieve the auto-increment column configuration. * @returns {Object} An object containing the auto-increment column configuration. * @throws {Error} Throws an error if the table does not exist or cannot be read. */ async getAutoIncrementColumn(tableName) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return tableData.autoIncrement; } /** * Retrieves the current auto-increment value for a specified auto-increment column in a table. * * @param {string} tableName - The name of the table from which to retrieve the auto-increment value. * @param {string} autoIncrementColumn - The name of the auto-increment column for which to retrieve the value. * @returns {number} The current auto-increment value for the specified column. * @throws {Error} Throws an error if the table does not exist or cannot be read, or if the specified auto-increment column does not exist. */ async getAutoIncrementValue(tableName, autoIncrementColumn) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return tableData.autoIncrement[autoIncrementColumn]; } /** * Resets the auto-increment value for a specified auto-increment column in a table, * setting it to one greater than the current maximum value of that column in existing data. * * @param {string} tableName - The name of the table for which to reset the auto-increment value. * @param {string} autoIncrementColumn - The name of the auto-increment column to reset. * @returns {number} The new auto-increment value set after resetting. * @throws {Error} Throws an error if the table does not exist, cannot be read, or if the specified auto-increment column does not exist or is not of type 'number'. */ async resetAutoIncrement(tableName, autoIncrementColumn) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); const { columns, data, autoIncrement } = tableData; if (!columns[autoIncrementColumn] || columns[autoIncrementColumn] !== 'number') { throw new Error('La columna de auto-incremento debe ser de tipo número y debe existir en la tabla'); } let maxId = 0; if (data.length > 0) { maxId = Math.max(...data.map(item => item[autoIncrementColumn])); } autoIncrement[autoIncrementColumn] = maxId + 1; await writeFile(tablePath, JSON.stringify(tableData, null, 2)); return maxId + 1; } /** * Inserts a new row of data into the specified table. * * @param {string} tableName - The name of the table where the data will be inserted. * @param {Object} data - An object containing key-value pairs representing the data to insert. * @returns {boolean} Returns true if the insertion is successful. * @throws {Error} Throws an error if the table does not exist, or if there are issues with column validation or data types. */ async insert(tableName, data) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); const { columns, autoIncrement } = tableData; const columnNames = Object.keys(columns); for (const key in autoIncrement) { data[key] = autoIncrement[key]++; } data['id_arlet'] = uuidv4(); const dataKeys = Object.keys(data); if (columnNames.length !== dataKeys.length) { throw new Error('La cantidad de columnas no coincide'); } for (const key of dataKeys) { if (!columns[key] || typeof data[key] !== columns[key]) { throw new Error('Tipo de dato incorrecto o columna inexistente'); } } tableData.data.push(data); await writeFile(tablePath, JSON.stringify(tableData, null, 2)); return true; } /** * Inserts data into the specified table if a matching row does not already exist. * Checks based on the equality of key-value pairs provided in the data object. * * @param {string} tableName - The name of the table where the data will be inserted. * @param {Object} data - An object containing key-value pairs representing the data to insert. * @returns {boolean} Returns true if the insertion is successful and the data did not already exist. * @throws {Error} Throws an error if the table does not exist, or if there are issues with column validation or data types. */ async insertIfNotExists(tableName, data) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); const { columns, autoIncrement } = tableData; const exists = tableData.data.some(item => { return Object.keys(data).every(key => item[key] === data[key]); }); if (exists) { console.log('El dato ya existe, no se ha insertado'); return false; } for (const key in autoIncrement) { data[key] = autoIncrement[key]++; } data['id_arlet'] = uuidv4(); const columnNames = Object.keys(columns); const dataKeys = Object.keys(data); if (columnNames.length !== dataKeys.length) { throw new Error('La cantidad de columnas no coincide'); } for (const key of dataKeys) { if (!columns[key] || typeof data[key] !== columns[key]) { throw new Error('Tipo de dato incorrecto o columna inexistente'); } } tableData.data.push(data); await writeFile(tablePath, JSON.stringify(tableData, null, 2)); console.log('Dato insertado'); return true; } /** * Retrieves all data rows from the specified table. * * @param {string} tableName - The name of the table from which to retrieve data. * @returns {Array} An array containing all rows of data from the table. * @throws {Error} Throws an error if the table does not exist. */ async getAll(tableName) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return tableData.data; } /** * Queries data from the specified table based on given criteria and options. * * @param {string} tableName - The name of the table from which to query data. * @param {Object} criteria - An object containing key-value pairs to filter the data. Default is an empty object. * @param {Object} options - An object containing additional options for sorting and limiting the results. Default is an empty object. * @param {Array} options.sort - An array with two elements: the column to sort by and the order ('asc' or 'desc'). * @param {Number} options.limit - The maximum number of results to return. * @returns {Array} An array of objects representing rows that match the criteria, sorted and limited as specified. * @throws {Error} Throws an error if the table does not exist. */ async query(tableName, criteria = {}, options = {}) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); let result = tableData.data.filter(item => { return Object.keys(criteria).every(key => item[key] === criteria[key]); }); if (options.sort) { const [key, order] = options.sort; result.sort((a, b) => (a[key] > b[key] ? 1 : -1) * (order === 'desc' ? -1 : 1)); } if (options.limit) { result = result.slice(0, options.limit); } return result; } /** * Retrieves a specific row from the table based on the Arlet ID. * * @param {string} tableName - The name of the table from which to retrieve the row. * @param {string} arlet_id - The Arlet ID of the row to retrieve. * @returns {Object | undefined} The row object that matches the Arlet ID, or undefined if not found. * @throws {Error} Throws an error if the table does not exist. */ async getById(tableName, arlet_id) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return tableData.data.find(item => item.id_arlet === arlet_id); } /** * Counts the number of rows in the specified table. * * @param {string} tableName - The name of the table for which to count rows. * @returns {number} The number of rows in the table. * @throws {Error} Throws an error if the table does not exist. */ async count(tableName) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return tableData.data.length; } /** * Counts the number of rows in the specified table that match the given criteria. * * @param {string} tableName - The name of the table for which to count rows. * @param {Object} criteria - An object containing key-value pairs to filter the data. * @returns {number} The number of rows in the table that match the criteria. * @throws {Error} Throws an error if the table does not exist. */ async countWhere(tableName, criteria = {}) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return tableData.data.filter(item => { return Object.keys(criteria).every(key => item[key] === criteria[key]); }).length; } /** * Calculates the sum of values in the specified column of a table. * * @param {string} tableName - The name of the table from which to calculate the sum. * @param {string} column - The column name for which to calculate the sum. * @returns {number} The sum of values in the specified column. * @throws {Error} Throws an error if the table does not exist. */ async sum(tableName, column) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return tableData.data.reduce((acc, item) => acc + item[column], 0); } /** * Calculates the average (mean) of values in the specified column of a table. * * @param {string} tableName - The name of the table from which to calculate the average. * @param {string} column - The column name for which to calculate the average. * @returns {number} The average (mean) of values in the specified column. * @throws {Error} Throws an error if the table does not exist. */ async avg(tableName, column) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); return tableData.data.reduce((acc, item) => acc + item[column], 0) / tableData.data.length; } /** * Retrieves specific columns from multiple tables based on given criteria and options. * Allows for filtering, sorting, and limiting the joined results. * * @param {Array} tables - An array of table names from which to select data. * @param {Array} columns - An array of column names to be retrieved from the joined results. If empty, all columns are selected. * @param {Object} criteria - An object containing key-value pairs to filter the data. Default is an empty object. * @param {Object} options - An object containing additional options for sorting and limiting the joined results. Default is an empty object. * @param {Array} options.sort - An array with two elements: the column to sort by and the order ('asc' or 'desc'). * @param {Number} options.limit - The maximum number of results to return. * @returns {Array} An array of objects representing rows with the specified columns from the joined results. * @throws {Error} Throws an error if any of the tables do not exist. */ async selectJoin(tables, columns = [], criteria = {}, options = {}) { let joinedResults = []; for (const tableName of tables) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error(`La tabla ${tableName} no existe`); } const tableData = JSON.parse(await readFile(tablePath)); let tableResult = tableData.data.filter(item => { return Object.keys(criteria).every(key => item[key] === criteria[key]); }); if (joinedResults.length === 0) { joinedResults = tableResult; } else { joinedResults = joinedResults.flatMap(joinedItem => { return tableResult.map(item => ({ ...joinedItem, ...item })); }); } } if (options.sort) { const [key, order] = options.sort; joinedResults.sort((a, b) => (a[key] > b[key] ? 1 : -1) * (order === 'desc' ? -1 : 1)); } if (options.limit) { joinedResults = joinedResults.slice(0, options.limit); } if (columns.length > 0) { joinedResults = joinedResults.map(item => { const selectedItem = {}; columns.forEach(column => { if (item.hasOwnProperty(column)) { selectedItem[column] = item[column]; } }); return selectedItem; }); } return joinedResults; } /** * Retrieves specific columns from a table based on given criteria and options. * Allows for filtering, sorting, and limiting the results. * * @param {string} tableName - The name of the table from which to select data. * @param {Array} columns - An array of column names to be retrieved. If empty, all columns are selected. * @param {Object} criteria - An object containing key-value pairs to filter the data. Default is an empty object. * Each value can be a single value, an array of values (for multiple conditions), * or an object with comparison operators (like $eq, $ne, $lt, $lte, $gt, $gte, $in, $between). * @param {Object} options - An object containing additional options for sorting and limiting the results. Default is an empty object. * @param {Array} options.sort - An array with two elements: the column to sort by and the order ('asc' or 'desc'). * @param {Number} options.limit - The maximum number of results to return. * @returns {Array} An array of objects representing rows with the specified columns from the selected results. * @throws {Error} Throws an error if the table does not exist. */ async select(tableName, columns, criteria = {}, options = {}) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); let result = tableData.data.filter(item => { return Object.keys(criteria).every(key => { const conditions = criteria[key]; if (Array.isArray(conditions)) { return conditions.every(condition => this.evaluateCondition(item[key], condition)); } else if (typeof conditions === 'object' && conditions !== null) { const operator = Object.keys(conditions)[0]; const value = conditions[operator]; if (operator === '$like') { return this.evaluateLikeCondition(item[key], value); } else { return this.evaluateCondition(item[key], conditions); } } else { return this.evaluateCondition(item[key], conditions); } }); }); if (options.sort) { const [key, order] = options.sort; result.sort((a, b) => (a[key] > b[key] ? 1 : -1) * (order === 'desc' ? -1 : 1)); } if (options.limit) { result = result.slice(0, options.limit); } if (columns.length === 0) { return result; } result = result.map(item => { const selectedItem = {}; columns.forEach(column => { if (item.hasOwnProperty(column)) { selectedItem[column] = item[column]; } }); return selectedItem; }); return result; } evaluateCondition(value, condition) { const { operator, value: conditionValue, range } = condition; switch (operator) { case '=': return this.strictCompare(value, conditionValue); case '!=': return !this.strictCompare(value, conditionValue); case '<': return value < conditionValue; case '>': return value > conditionValue; case '<=': return value <= conditionValue; case '>=': return value >= conditionValue; case 'BETWEEN': return value >= range[0] && value <= range[1]; case '&&': return value && conditionValue; case '||': return value || conditionValue; default: return false; } } strictCompare(value, conditionValue) { return String(value) === String(conditionValue); } evaluateLikeCondition(value, pattern) { const regexPattern = '^' + pattern .replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') .replace(/%/g, '.*') + '$'; const regex = new RegExp(regexPattern, 'i'); // Case insensitive matching return regex.test(value); } /** * Updates rows in a table based on given criteria with new data. * * @param {string} tableName - The name of the table to update. * @param {Object} criteria - An object containing key-value pairs to filter the data to be updated. * Each value can be a single value, an array of values (for multiple conditions), * or an object with comparison operators (like $eq, $ne, $lt, $lte, $gt, $gte, $in, $between). * @param {Object} newData - An object containing key-value pairs of new data to update in matching rows. * @returns {boolean} Returns true if the update operation was successful. * @throws {Error} Throws an error if the table does not exist. */ async update(tableName, criteria, newData) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); for (let item of tableData.data) { if (Object.keys(criteria).every(key => item[key] === criteria[key])) { for (let key in newData) { if (item[key] !== undefined) { item[key] = newData[key]; } } } } await writeFile(tablePath, JSON.stringify(tableData, null, 2)); return true; } /** * Deletes rows from a table based on given criteria. * * @param {string} tableName - The name of the table from which to delete rows. * @param {Object} criteria - An object containing key-value pairs to filter the rows to be deleted. * Each value can be a single value, an array of values (for multiple conditions), * or an object with comparison operators (like $eq, $ne, $lt, $lte, $gt, $gte, $in, $between). * @returns {boolean} Returns true if the delete operation was successful. * @throws {Error} Throws an error if the table does not exist. */ async delete(tableName, criteria) { const tablePath = path.resolve(this.pathDatabase, `${tableName}.json`); if (!fs.existsSync(tablePath)) { throw new Error('La tabla no existe'); } const tableData = JSON.parse(await readFile(tablePath)); tableData.data = tableData.data.filter(item => { return !Object.keys(criteria).every(key => item[key] === criteria[key]); }); await writeFile(tablePath, JSON.stringify(tableData, null, 2)); return true; } } module.exports = ArletDb;