arlet-db
Version:
A simple database manager for Node.js
754 lines (718 loc) • 35 kB
JavaScript
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;