Initial upload with MSSQL and MariaDB implemented.

This commit is contained in:
2025-08-21 02:46:01 -04:00
commit 57430daf33
10 changed files with 3043 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules
.env

78
client.js Normal file
View File

@@ -0,0 +1,78 @@
// client.js
const axios = require('axios');
const generateUUID = require('uuid').v4;
async function testQuery(table, operation, params) {
try {
const response = await axios.post('http://localhost:3100/api/query', {
table,
operation,
params
});
console.log(response.data);
} catch (error) {
console.error('Error executing query:', error.response ? error.response.data : error.message);
}
}
// Example usage:
(async () => {
// CREATE: Ensure all required fields are present
const ID1 = generateUUID();
const ID2 = generateUUID();
const ID3 = generateUUID();
const ID4 = generateUUID();
await testQuery('Test', 'CREATE', {
Name: 'Test Item',
Text: 'A sample item created with ID: ' + ID1,
ID: ID1, // Assuming an ID is needed for identification or to prevent conflicts
// Add other necessary fields here based on your schema
});
await testQuery('Test', 'CREATE', {
Name: 'Test Item',
Text: 'A sample item created with ID: ' + ID2,
ID: ID2, // Assuming an ID is needed for identification or to prevent conflicts
// Add other necessary fields here based on your schema
});
await testQuery('Test', 'CREATE', {
Name: 'Test Item',
Text: 'A sample item created wth ID: ' + ID3,
ID: ID3, // Assuming an ID is needed for identification or to prevent conflicts
// Add other necessary fields here based on your schema
});
await testQuery('Test', 'CREATE', {
Name: 'Test Item',
Text: 'A sample item created with ID: ' + ID4,
ID: ID4, // Assuming an ID is needed for identification or to prevent conflicts
// Add other necessary fields here based on your schema
});
// UPDATE: Ensure both the ID and at least one field to update are present. ID must be the LAST field.
await testQuery('Test', 'UPDATE', {
Name: 'Tested item name',
Text: 'Updated item text successfully for item: ' + ID2,
ID: ID2
});
// READ: Ensure the ID is present
await testQuery('Test', 'READ', {
ID : ID1
} );
// READ: See all rows in a table
await testQuery('Test', 'READ');
// DELETE: Ensure the ID is present
await testQuery('Test', 'DELETE', {
ID: ID3
});
/*
// COMPARE: Ensure both compareTable and idField are present
const compareParams = {
compareTable: 'Test2',
idField: 'ID',
ID: '1'
};
await testQuery('Test', 'COMPARE', compareParams);*/
})();

2162
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

12
package.json Normal file
View File

@@ -0,0 +1,12 @@
{
"dependencies": {
"axios": "^1.11.0",
"cors": "^2.8.5",
"dotenv": "^17.2.1",
"express": "^5.1.0",
"mssql": "^11.0.1",
"mysql2": "^3.14.3",
"oracledb": "^6.9.0",
"pg": "^8.16.3"
}
}

68
readme.md Normal file
View File

@@ -0,0 +1,68 @@
## JS DB Connector Service Guide
This set of modules is intended to serve as a general purpose toolkit for building Node.js applications with a database-type agnostic SQL backend. The audience at creation is myself, as I wanted a reusable module for communicating with my SQL backends in Node.js projects.
## Features
At the moment, CRUD operations against Microsoft SQL Server and MariaDB servers are supported. I plan to implement support for interoperability with Postgres, Oracle, and MongoDB as well to provide the most possible utility in this package. An example implementation is available in the included server.js:
```javascript
// server.js
require('dotenv').config();
const express = require('express');
const app = express();
const queryExecutor = require('./services/dbconnector/queryExecutor');
const cors = require('cors');
app.use(express.json());
app.use(cors());
/**
* Example route to demonstrate CRUD operations.
*/
app.post('/api/query', async (req, res) => {
try {
const { table, operation, params } = req.body;
const result = await queryExecutor.executeQuery(table, operation, params);
res.status(200).json(result);
} catch (err) {
console.error('Error executing query:', err);
res.status(500).json({ error: err.message });
}
});
const PORT = process.env.PORT || 3100;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
```
Additionally, the script `client.js` which runs simulated interactions with the server.js contains the following example for a request to the sample API route:
```javascript
async function testQuery(table, operation, params) {
try {
const response = await axios.post('http://localhost:3100/api/query', {
table,
operation,
params
});
console.log(response.data);
} catch (error) {
console.error('Error executing query:', error.response ? error.response.data : error.message);
}
}
```
The following environment variables are used to control the operation of the DB connector:
```
DB_USER= # A user with permissions to manage the database
DB_PASSWORD= # Password for DB_USER
DB_SERVER= # Hostname or IP of the database server
DB_PORT= # Port if not using default for the database type
DB_DATABASE= # Database to be used. As written, only a single database is supported
DB_TYPE= # MSSQL and MARIADB are implemented. ORACLEDB and POSTGRES are planned.
DB_TRUST_CERT= # Trust the local system SSL certificate, useful for developing against MSSQL server.
```
## Testing
To test the function of these modules, run "node server.js" in the project root, and post to http://localhost:3100/api/query. You can instead run client.js to automatically attempt each query type against the default server URL.

28
server.js Normal file
View File

@@ -0,0 +1,28 @@
// server.js
require('dotenv').config();
const express = require('express');
const app = express();
const queryExecutor = require('./services/dbconnector/queryExecutor');
const cors = require('cors');
app.use(express.json());
app.use(cors());
/**
* Example route to demonstrate CRUD operations.
*/
app.post('/api/query', async (req, res) => {
try {
const { table, operation, params } = req.body;
const result = await queryExecutor.executeQuery(table, operation, params);
res.status(200).json(result);
} catch (err) {
console.error('Error executing query:', err);
res.status(500).json({ error: err.message });
}
});
const PORT = process.env.PORT || 3100;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});

View File

@@ -0,0 +1,81 @@
// /services/dbconnector/connectionManager.js
require('dotenv').config();
const sql = require('mssql');
const oracledb = require('oracledb');
const mysql = require('mysql2/promise');
const { Client } = require('pg');
/**
* Gets a connection based on the configured database type.
*
* @returns {Promise<Object>} A promise that resolves with the database connection.
*/
async function getConnection() {
const dbType = process.env.DB_TYPE;
const config = getDBConfig(dbType);
switch (dbType) {
case 'MSSQL':
return await sql.connect(config);
case 'ORACLE':
return await oracledb.getConnection(config);
case 'MARIADB':
return await mysql.createConnection(config);
case 'POSTGRES':
const client = new Client(config);
await client.connect();
return client;
default:
throw new Error('Unsupported database type');
}
}
/**
* Fetches the configuration for a specified database type from environment variables.
*
* @param {string} dbType - Type of database (e.g., 'MSSQL', 'ORACLE').
* @returns {Object} The database configuration object.
*/
function getDBConfig(dbType) {
switch (dbType) {
case 'MSSQL':
return {
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
server: process.env.DB_SERVER,
database: process.env.DB_DATABASE,
options: {
encrypt: true, // for secure connection
trustServerCertificate: process.env.DB_TRUST_CERT
}
};
case 'ORACLE':
return {
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
connectString: process.env.ORACLE_CONNECTION_STRING
};
case 'MARIADB':
return {
host: process.env.DB_SERVER,
port: parseInt(process.env.DB_PORT, 10) || 3006,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
namedPlaceholders: true
};
case 'POSTGRES':
return {
host: process.env.DB_SERVER,
port: parseInt(process.env.DB_PORT, 10) || 5432,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE
};
default:
throw new Error('Unsupported database type');
}
}
module.exports = { getConnection };

View File

@@ -0,0 +1,172 @@
// /services/dbconnector/paramLibrary.js
const sql = require('mssql');
const oracledb = require('oracledb');
/**
* Formats query parameters based on their keys and types, specific to each database type.
*
* @param {Object} params - An object containing the parameters to format.
* @returns {Promise<Object>} A promise that resolves with formatted parameters.
*/
async function formatQueryParams(params) {
const { DB_TYPE } = process.env;
let formattedParams = {};
console.log(`Formatting query parameters for ${DB_TYPE.toUpperCase()}...`); // Debugging log
console.log('Raw params:', params); // Log the raw parameters received
switch (DB_TYPE.toUpperCase()) {
case 'MSSQL':
formattedParams = formatMSSQLParams(params);
break;
case 'ORACLE':
formattedParams = formatOracleParams(params);
break;
case 'MARIADB':
formattedParams = formatMariaDBParams(params);
break;
case 'POSTGRES':
formattedParams = formatPostgresParams(params);
break;
default:
throw new Error('Unsupported database type');
}
console.log('Formatted params:', formattedParams); // Log the formatted parameters
return formattedParams;
}
/**
* Formats query parameters for MSSQL.
*
* @param {Object} params - An object containing the parameters to format.
* @returns {Object} Formatted parameters.
*/
function formatMSSQLParams(params) {
const formattedParams = {};
for (const key in params) {
if (key === 'ID') {
console.log(`Formatting ID: ${params[key]}`); // Debugging log
formattedParams[key] = { type: sql.UniqueIdentifier, value: params[key] };
} else if (
['Name', 'Description', 'Building', 'Owner', 'Role', 'Location', 'Route', 'Email', 'DisplayName', 'Team'].includes(key)
) {
formattedParams[key] = { type: sql.NVarChar(255), value: params[key] };
} else if (key === 'Username' || key === 'AuthenticatedUsername') {
formattedParams[key] = { type: sql.NVarChar(50), value: params[key].toLowerCase() }; // Normalize to lowercase
} else if (key === 'UITheme' || key === 'UITHeme') {
formattedParams[key] = { type: sql.NVarChar(50), value: params[key] };
} else if (['Bio', 'PasswordHash', 'Image', 'AvatarURL'].includes(key)) {
formattedParams[key] = { type: sql.Text, value: params[key] };
} else if (key === 'SQL_USER') {
formattedParams[key] = { type: sql.Bit, value: params[key] }; // Support for bit data type
} else if (typeof params[key] === 'string') {
formattedParams[key] = { type: sql.NVarChar(255), value: params[key] };
} else if (typeof params[key] === 'number') {
formattedParams[key] = { type: sql.Int, value: params[key] };
}
}
return formattedParams;
}
// ... rest of the file ...
/**
* Formats query parameters for Oracle.
*
* @param {Object} params - An object containing the parameters to format.
* @returns {Object} Formatted parameters.
*/
function formatOracleParams(params) {
const formattedParams = {};
for (const key in params) {
if (key === 'ID') {
formattedParams[key] = { type: oracledb.STRING, value: params[key] }; // UUID can be handled as a string
} else if (
['Name', 'Description', 'Building', 'Owner', 'Role', 'Location', 'Route', 'Email', 'DisplayName', 'Team'].includes(key)
) {
formattedParams[key] = { type: oracledb.STRING, value: params[key] };
} else if (key === 'Username' || key === 'AuthenticatedUsername') {
formattedParams[key] = { type: oracledb.STRING, value: params[key].toLowerCase() }; // Normalize to lowercase
} else if (key === 'UITheme' || key === 'UITHeme') {
formattedParams[key] = { type: oracledb.STRING, value: params[key] };
} else if (['Bio', 'PasswordHash', 'Image', 'AvatarURL'].includes(key)) {
formattedParams[key] = { type: oracledb.CLOB, value: params[key] };
} else if (key === 'SQL_USER') {
formattedParams[key] = { type: oracledb.BOOLEAN, value: params[key] }; // Support for bit data type
} else if (typeof params[key] === 'string') {
formattedParams[key] = { type: oracledb.STRING, value: params[key] };
} else if (typeof params[key] === 'number') {
formattedParams[key] = { type: oracledb.NUMBER, value: params[key] };
}
}
return formattedParams;
}
/**
* Formats query parameters for MariaDB.
*
* @param {Object} params - An object containing the parameters to format.
* @returns {Object} Formatted parameters.
*/
function formatMariaDBParams(params) {
const formattedParams = {};
for (const key in params) {
if (key === 'ID') {
formattedParams[key] = { type: 'char', value: params[key] }; // UUID can be handled as a string
} else if (
['Name', 'Description', 'Building', 'Owner', 'Role', 'Location', 'Route', 'Email', 'DisplayName', 'Team'].includes(key)
) {
formattedParams[key] = { type: 'string', value: params[key] };
} else if (key === 'Username' || key === 'AuthenticatedUsername') {
formattedParams[key] = { type: 'string', value: params[key].toLowerCase() }; // Normalize to lowercase
} else if (key === 'UITheme' || key === 'UITHeme') {
formattedParams[key] = { type: 'string', value: params[key] };
} else if (['Bio', 'PasswordHash', 'Image', 'AvatarURL'].includes(key)) {
formattedParams[key] = { type: 'text', value: params[key] };
} else if (key === 'SQL_USER') {
formattedParams[key] = { type: 'boolean', value: params[key] }; // Support for bit data type
} else if (typeof params[key] === 'string') {
formattedParams[key] = { type: 'string', value: params[key] };
} else if (typeof params[key] === 'number') {
formattedParams[key] = { type: 'int', value: params[key] };
}
}
return formattedParams;
}
/**
* Formats query parameters for PostgreSQL.
*
* @param {Object} params - An object containing the parameters to format.
* @returns {Object} Formatted parameters.
*/
function formatPostgresParams(params) {
const formattedParams = {};
for (const key in params) {
if (key === 'ID') {
formattedParams[key] = { type: 'uuid', value: params[key] };
} else if (
['Name', 'Description', 'Building', 'Owner', 'Role', 'Location', 'Route', 'Email', 'DisplayName', 'Team'].includes(key)
) {
formattedParams[key] = { type: 'varchar', value: params[key] };
} else if (key === 'Username' || key === 'AuthenticatedUsername') {
formattedParams[key] = { type: 'varchar', value: params[key].toLowerCase() }; // Normalize to lowercase
} else if (key === 'UITheme' || key === 'UITHeme') {
formattedParams[key] = { type: 'varchar', value: params[key] };
} else if (['Bio', 'PasswordHash', 'Image', 'AvatarURL'].includes(key)) {
formattedParams[key] = { type: 'text', value: params[key] };
} else if (key === 'SQL_USER') {
formattedParams[key] = { type: 'boolean', value: params[key] }; // Support for bit data type
} else if (typeof params[key] === 'string') {
formattedParams[key] = { type: 'varchar', value: params[key] };
} else if (typeof params[key] === 'number') {
formattedParams[key] = { type: 'int', value: params[key] };
}
}
return formattedParams;
}
module.exports = { formatQueryParams };

View File

@@ -0,0 +1,294 @@
// /services/dbconnector/queryConstructor.js
/**
* Generates a SQL query string based on table, operation, and parameters.
*
* @param {string} table - The name of the database table.
* @param {string} operation - CRUD operation (e.g., 'CREATE', 'READ').
* @param {Object} params - Parameters for the SQL query.
* @returns {Promise<string>} A promise that resolves with the constructed SQL query string.
*/
async function generateQuery(table, operation, params) {
const { DB_TYPE } = process.env;
let query = '';
switch (operation.toUpperCase()) {
case 'CREATE':
validateCreateParams(params);
query = generateCreateQuery(DB_TYPE, table, params);
break;
case 'READ':
validateReadParams(params);
query = generateReadQuery(DB_TYPE, table, params);
break;
case 'UPDATE':
validateUpdateParams(params);
query = generateUpdateQuery(DB_TYPE, table, params);
break;
case 'DELETE':
validateDeleteParams(params);
query = generateDeleteQuery(DB_TYPE, table, params);
break;
/* case 'COMPARE':
validateCompareParams(params);
query = generateCompareQuery(DB_TYPE, table, params);
break; */
default:
throw new Error('Unsupported operation');
}
return query;
}
/*
/**
* Validates parameters for CREATE operation.
*
* @param {Object} params - Parameters for the SQL query.
*/
function validateCreateParams(params) {
if (!params || typeof params !== 'object' || Object.keys(params).length === 0) {
throw new Error('Missing or invalid parameters for CREATE operation. Please provide a non-empty object with necessary fields.');
}
}
/**
* Validates parameters for READ operation.
*
* @param {Object} params - Parameters for the SQL query.
*/
function validateReadParams(params) {
if (params && typeof params !== 'object') {
throw new Error('Missing or invalid parameters for READ operation. Please provide an object with "ID" field.');
}
}
/**
* Validates parameters for UPDATE operation.
*
* @param {Object} params - Parameters for the SQL query.
*/
function validateUpdateParams(params) {
if (!params || typeof params !== 'object' || !params.ID || Object.keys(params).length <= 1) {
throw new Error('Missing or invalid parameters for UPDATE operation. Please provide an object with "ID" field and at least one other field to update.');
}
}
/**
* Validates parameters for DELETE operation.
*
* @param {Object} params - Parameters for the SQL query.
*/
function validateDeleteParams(params) {
if (!params || typeof params !== 'object' || !params.ID) {
throw new Error('Missing or invalid parameters for DELETE operation. Please provide an object with "ID" field.');
}
}
/**
* Validates parameters for COMPARE operation.
*
* @param {Object} params - Parameters for the SQL query.
*
function validateCompareParams(params) {
if (!params || typeof params !== 'object' || !params.compareTable || !params.idField) {
throw new Error('Missing or invalid parameters for COMPARE operation. Please provide an object with "compareTable" and "idField" fields.');
}
}*/
/**
* Generates a CREATE SQL query string based on database type, table, and parameters.
*
* @param {string} dbType - Type of database (e.g., 'MSSQL', 'ORACLE').
* @param {string} table - The name of the database table.
* @param {Object} params - Parameters for the SQL query.
* @returns {string} The constructed CREATE SQL query string.
*/
function generateCreateQuery(dbType, table, params) {
const columns = Object.keys(params).join(', ');
// Generate placeholders based on dbType
let placeholders;
switch (dbType.toUpperCase()) {
case 'MSSQL':
placeholders = Object.keys(params)
.map(key => `@${key}`)
.join(', ');
break;
case 'POSTGRES':
placeholders = Object.keys(params).map(() => '?').join(', '); // Use ? for PostgreSQL
break;
case 'MARIADB':
placeholders = Object.keys(params).map(() => `?`).join(', '); // Use ? for MariaDB
break;
case 'ORACLE':
throw new Error('CREATE operation is not supported for ORACLE in this implementation.');
default:
throw new Error('Unsupported database type for this operation!');
}
return `INSERT INTO ${table} (${columns}) VALUES (${placeholders});`;
}
/**
* Generates a READ SQL query string based on database type, table, and parameters.
*
* @param {string} dbType - Type of database (e.g., 'MSSQL', 'ORACLE').
* @param {string} table - The name of the database table.
* @param {Object} params - Parameters for the SQL query.
* @returns {string} The constructed READ SQL query string.
*/
function generateReadQuery(dbType, table, params) {
// Start with the basic SELECT statement
let query = `SELECT * FROM ${table}`;
// Prepare an array to hold WHERE conditions
const whereConditions = [];
// Iterate over each parameter in params
for (const key in params) {
if (params.hasOwnProperty(key)) {
const value = params[key];
// Construct the condition based on dbType
let condition;
switch (dbType.toUpperCase()) {
case 'MSSQL':
condition = `${key} = @${key}`;
break;
case 'POSTGRES':
condition = `${key} = $1`;
break;
case 'MARIADB':
condition = `${key} = ?`;
break;
default:
throw new Error('Unsupported database type');
}
whereConditions.push(condition);
}
}
// If there are any WHERE conditions, append them to the query
if (whereConditions.length > 0) {
query += ` WHERE ${whereConditions.join(' AND ')}`;
}
return query;
}
/**
* Generates a UPDATE SQL query string based on database type, table, and parameters.
*
* @param {string} dbType - Type of database (e.g., 'MSSQL', 'ORACLE').
* @param {string} table - The name of the database table.
* @param {Object} params - Parameters for the SQL query.
* @returns {Promise<string>} The constructed UPDATE SQL query string.
*/
async function generateUpdateQuery(dbType, table, params) {
const updateClause = Object.keys(params)
.filter(key => key !== 'ID') // Exclude ID from update clause
.map(key => {
switch (dbType.toUpperCase()) {
case 'MSSQL':
return `${key} = @${key}`;
case 'POSTGRES':
return `${key} = $1`;
case 'MARIADB':
return `${key} = ?`;
default:
throw new Error('Unsupported database type');
}
})
.join(', ');
let whereClause;
switch (dbType.toUpperCase()) {
case 'MSSQL':
whereClause = `WHERE ID = @ID`;
break;
case 'POSTGRES':
whereClause = `WHERE ID = $2`;
break;
case 'MARIADB':
whereClause = `WHERE ID = ?`;
break;
default:
throw new Error('Unsupported database type');
}
return `UPDATE ${table} SET ${updateClause} ${whereClause};`;
}
/**
* Generates a DELETE SQL query string based on database type, table, and parameters.
*
* @param {string} dbType - Type of database (e.g., 'MSSQL', 'ORACLE').
* @param {string} table - The name of the database table.
* @param {Object} params - Parameters for the SQL query.
* @returns {Promise<string>} The constructed DELETE SQL query string.
*/
async function generateDeleteQuery(dbType, table, params) {
let idParam = params.ID || 'ID';
switch (dbType.toUpperCase()) {
case 'MSSQL':
return `DELETE FROM ${table} WHERE ID = @ID;`;
case 'POSTGRES':
return `DELETE FROM ${table} WHERE ID = $1;`; // Use $1 for PostgreSQL
case 'MARIADB':
return `DELETE FROM ${table} WHERE ID = ?;`;
case 'ORACLE':
throw new Error('DELETE operation is not supported for ORACLE in this implementation.');
default:
throw new Error('Unsupported database type!');
}
}
/*
*
* I intend to implement "compare" functionality but haven't yet decided how to do so. This is some spitballed code that I came up with for this exercise, and I hope to complete work on it in the future.
/**
* Generates a COMPARE SQL query string based on database type, table, and parameters.
*
* @param {string} dbType - Type of database (e.g., 'MSSQL', 'ORACLE').
* @param {Object} params - Parameters for the SQL query.
* @returns {string} The constructed COMPARE SQL query string.
*
function generateCompareQuery(dbType, table, params) {
const { compareTable, idField } = params;
switch (dbType.toUpperCase()) {
case 'MSSQL':
return `
SELECT a.*
FROM ${table} a
JOIN ${compareTable} b ON a.${idField} = b.${idField}
`;
case 'ORACLE':
return `
SELECT a.*
FROM ${table} a
JOIN ${compareTable} b ON a.${idField} = b.${idField}
`;
case 'POSTGRES':
return `
SELECT a.*
FROM ${table} a
JOIN ${compareTable} b ON a.${idField} = b.${idField}
`;
case 'MARIADB':
return `
SELECT a.*
FROM ${table} a
JOIN ${compareTable} b ON a.${idField} = b.${idField}
`;
default:
throw new Error('Unsupported database type');
}
}*/
module.exports = { generateQuery };

View File

@@ -0,0 +1,146 @@
// /services/dbconnector/queryExecutor.js
require('dotenv').config();
const connectionManager = require('./connectionManager');
const queryConstructor = require('./queryConstructor');
const paramLibrary = require('./paramLibrary');
/**
* Executes a query against the configured database type.
*
* @param {string} table - The name of the database table.
* @param {string} operation - CRUD operation (e.g., 'CREATE', 'READ').
* @param {Object} config - Database configuration object.
* @param {Object} params - Parameters for the SQL query.
* @returns {Promise<Object>} A promise that resolves with the result of the query execution.
*/
async function executeQuery(table, operation, params) {
console.log(`Executing query for ${operation.toUpperCase()} on table ${table}...`); // Debugging log
console.log('Raw parameters:', params); // Log the raw parameters received
const query = await queryConstructor.generateQuery(table, operation, params);
let result;
try {
const formattedParams = await paramLibrary.formatQueryParams(params);
const connection = await connectionManager.getConnection();
switch (process.env.DB_TYPE.toUpperCase()) {
case 'MSSQL':
console.log('Executing MSSQL query:', query); // Debugging log
console.log('Formatted parameters for MSSQL:', formattedParams); // Log the formatted parameters
result = await executeMSSQLQuery(connection, query, formattedParams);
break;
case 'ORACLE':
console.log('Executing Oracle query:', query); // Debugging log
console.log('Formatted parameters for Oracle:', formattedParams); // Log the formatted parameters
result = await executeOracleQuery(connection, query, formattedParams);
break;
case 'MARIADB':
console.log('Executing MariaDB query:', query); // Debugging log
console.log('Formatted parameters for MariaDB:', formattedParams); // Log the formatted parameters
result = await executeMariaDBQuery(connection, query, formattedParams);
break;
case 'POSTGRES':
console.log('Executing PostgreSQL query:', query); // Debugging log
console.log('Formatted parameters for PostgreSQL:', formattedParams); // Log the formatted parameters
result = await executePostgresQuery(connection, query, formattedParams);
break;
default:
throw new Error('Unsupported database type');
}
} catch (err) {
console.error('Error executing query:', err.message);
throw err;
}
switch (operation.toUpperCase()) {
case 'READ':
return result.recordset || [];
case 'UPDATE':
case 'DELETE':
return { success: true, affectedRows: result.affectedRows };
case 'CREATE':
return { success: true };
}
return result;
}
async function executeMSSQLQuery(connection, query, params) {
console.log('Binding parameters for MSSQL:', params); // Debugging log
const request = connection.request();
// Bind each parameter with its name and value
for (const key in params) {
if (params[key]) {
request.input(key, params[key].type, params[key].value);
}
}
try {
console.log('Executing MSSQL query:', query); // Debugging log
const result = await request.query(query);
return { recordset: result.recordset, affectedRows: result.rowsAffected };
} catch (error) {
console.error('Error executing MSSQL query:', error.message);
throw error;
}
}
async function executeOracleQuery(connection, query, params) {
const binds = {};
// Bind each parameter with its name and value
Object.keys(params).forEach((key, index) => {
binds[`param${index + 1}`] = { type: params[key].type, val: params[key].value };
});
const options = {
outFormat: require('oracledb').OUT_FORMAT_OBJECT
};
try {
console.log('Executing Oracle query:', query); // Debugging log
console.log('Binding parameters for Oracle:', binds); // Debugging log
const result = await connection.execute(query, binds, options);
return { recordset: result.rows, affectedRows: result.rowsAffected };
} catch (error) {
console.error('Error executing Oracle query:', error.message);
throw error;
}
}
async function executeMariaDBQuery(connection, query, params) {
try {
// Extract parameter values in order
const paramValues = Object.keys(params).map(key => params[key].value);
console.log('Executing MariaDB query:', query); // Debugging log
console.log('Binding parameters for MariaDB:', paramValues); // Debugging log
const [result] = await connection.execute(query, paramValues);
return { recordset: result };
} finally {
await connection.end();
}
}
async function executePostgresQuery(connection, query, params) {
try {
// Extract parameter values in order
const paramValues = Object.keys(params).map(key => params[key].value);
console.log('Executing PostgreSQL query:', query); // Debugging log
console.log('Binding parameters for PostgreSQL:', paramValues); // Debugging log
const result = await connection.query(query, paramValues);
return { recordset: result.rows };
} catch (error) {
console.error('Error executing PostgreSQL query:', error.message);
throw error;
}
}
module.exports = { executeQuery };