diff --git a/client.js b/client.js index b9e9df4..62c7dfa 100644 --- a/client.js +++ b/client.js @@ -61,7 +61,16 @@ async function testQuery(table, operation, params) { } ); // READ: See all rows in a table - await testQuery('Test', 'READ'); + await testQuery('Test', 'READ', { + Name: 'Tested item name', + }); + + // READ: See all rows in a table + await testQuery('Test', 'READ', { + partialMatch: true, + Name: 'Test', + }); + // DELETE: Ensure the ID is present await testQuery('Test', 'DELETE', { diff --git a/services/dbconnector/connectionManager.js b/services/dbconnector/connectionManager.js index b621f11..3d9d74d 100644 --- a/services/dbconnector/connectionManager.js +++ b/services/dbconnector/connectionManager.js @@ -47,7 +47,7 @@ function getDBConfig(dbType) { database: process.env.DB_DATABASE, options: { encrypt: true, // for secure connection - trustServerCertificate: process.env.DB_TRUST_CERT + trustServerCertificate: true } }; case 'ORACLE': diff --git a/services/dbconnector/paramLibrary.js b/services/dbconnector/paramLibrary.js index 947cb35..64bafd5 100644 --- a/services/dbconnector/paramLibrary.js +++ b/services/dbconnector/paramLibrary.js @@ -3,6 +3,14 @@ const sql = require('mssql'); const oracledb = require('oracledb'); +// Load paramsConfig.json once at the start +let paramsConfig; +try { + paramsConfig = require('./paramsConfig.json'); +} catch (error) { + console.error('Error reading JSON config:', error); +} + /** * Formats query parameters based on their keys and types, specific to each database type. * @@ -18,16 +26,16 @@ async function formatQueryParams(params) { switch (DB_TYPE.toUpperCase()) { case 'MSSQL': - formattedParams = formatMSSQLParams(params); + formattedParams = formatMSSQLParams(params, paramsConfig.mssql); break; case 'ORACLE': - formattedParams = formatOracleParams(params); + formattedParams = formatOracleParams(params, paramsConfig.oracle); break; case 'MARIADB': - formattedParams = formatMariaDBParams(params); + formattedParams = formatMariaDBParams(params, paramsConfig.mariaDB); break; case 'POSTGRES': - formattedParams = formatPostgresParams(params); + formattedParams = formatPostgresParams(params, paramsConfig.postgres); break; default: throw new Error('Unsupported database type'); @@ -41,66 +49,90 @@ async function formatQueryParams(params) { * Formats query parameters for MSSQL. * * @param {Object} params - An object containing the parameters to format. + * @param {Object} config - Database-specific configuration from JSON. * @returns {Object} Formatted parameters. */ -function formatMSSQLParams(params) { +function formatMSSQLParams(params, config) { 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] }; + if (!config[key]) { + console.warn(`Parameter '${key}' not defined in the configuration.`); + continue; } + + const paramConfig = config[key]; + let type; + + switch (paramConfig.type.toLowerCase()) { + case 'uniqueidentifier': + type = sql.UniqueIdentifier; + break; + case 'nvarchar': + if (!paramConfig.maxLength) { + throw new Error(`Parameter '${key}' is missing maxLength in configuration.`); + } + type = sql.NVarChar(paramConfig.maxLength); + break; + case 'text': + type = sql.Text; + break; + case 'int': + type = sql.Int; + break; + case 'bit': + type = sql.Bit; + break; + default: + throw new Error(`Unsupported parameter type: ${paramConfig.type} for parameter '${key}'`); + } + + formattedParams[key] = { type, value: params[key] }; } return formattedParams; } -// ... rest of the file ... - - /** * Formats query parameters for Oracle. * * @param {Object} params - An object containing the parameters to format. + * @param {Object} config - Database-specific configuration from JSON. * @returns {Object} Formatted parameters. */ -function formatOracleParams(params) { +function formatOracleParams(params, config) { 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] }; + if (!config[key]) { + console.warn(`Parameter '${key}' not defined in the configuration.`); + continue; } + + const paramConfig = config[key]; + let type; + + switch (paramConfig.type.toLowerCase()) { + case 'string': + type = oracledb.STRING; + break; + case 'varchar2': + if (!paramConfig.maxLength) { + throw new Error(`Parameter '${key}' is missing maxLength in configuration.`); + } + type = oracledb.VARCHAR2(paramConfig.maxLength); + break; + case 'clob': + type = oracledb.CLOB; + break; + case 'number': + type = oracledb.NUMBER; + break; + case 'boolean': + type = oracledb.BOOLEAN; + break; + default: + throw new Error(`Unsupported parameter type: ${paramConfig.type} for parameter '${key}'`); + } + + formattedParams[key] = { type, value: params[key] }; } return formattedParams; } @@ -109,30 +141,47 @@ function formatOracleParams(params) { * Formats query parameters for MariaDB. * * @param {Object} params - An object containing the parameters to format. + * @param {Object} config - Database-specific configuration from JSON. * @returns {Object} Formatted parameters. */ -function formatMariaDBParams(params) { +function formatMariaDBParams(params, config) { 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] }; + if (!config[key]) { + console.warn(`Parameter '${key}' not defined in the configuration.`); + continue; } + + const paramConfig = config[key]; + let type; + + switch (paramConfig.type.toLowerCase()) { + case 'char': + if (!paramConfig.length) { + throw new Error(`Parameter '${key}' is missing length in configuration.`); + } + type = { type: 'CHAR', length: paramConfig.length }; + break; + case 'uuid': + type = 'uuid'; + break; + case 'string': + type = 'string'; + break; + case 'text': + type = 'text'; + break; + case 'int': + type = 'int'; + break; + case 'boolean': + type = 'boolean'; + break; + default: + throw new Error(`Unsupported parameter type: ${paramConfig.type} for parameter '${key}'`); + } + + formattedParams[key] = { type, value: params[key] }; } return formattedParams; } @@ -141,32 +190,47 @@ function formatMariaDBParams(params) { * Formats query parameters for PostgreSQL. * * @param {Object} params - An object containing the parameters to format. + * @param {Object} config - Database-specific configuration from JSON. * @returns {Object} Formatted parameters. */ -function formatPostgresParams(params) { +function formatPostgresParams(params, config) { 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] }; + if (!config[key]) { + console.warn(`Parameter '${key}' not defined in the configuration.`); + continue; } + + const paramConfig = config[key]; + let type; + + switch (paramConfig.type.toLowerCase()) { + case 'uuid': + type = 'uuid'; + break; + case 'varchar': + if (!paramConfig.length) { + throw new Error(`Parameter '${key}' is missing length in configuration.`); + } + type = { type: 'VARCHAR', length: paramConfig.length }; + break; + case 'text': + type = 'text'; + break; + case 'int': + type = 'int'; + break; + case 'boolean': + type = 'boolean'; + break; + default: + throw new Error(`Unsupported parameter type: ${paramConfig.type} for parameter '${key}'`); + } + + formattedParams[key] = { type, value: params[key] }; } return formattedParams; } module.exports = { formatQueryParams }; + diff --git a/services/dbconnector/paramsConfig.json b/services/dbconnector/paramsConfig.json new file mode 100644 index 0000000..868862c --- /dev/null +++ b/services/dbconnector/paramsConfig.json @@ -0,0 +1,90 @@ +{ + "mssql": { + "ID": { "type": "uniqueidentifier" }, + "Name": { "type": "nvarchar", "maxLength": 255 }, + "Description": { "type": "nvarchar", "maxLength": 255 }, + "Building": { "type": "nvarchar", "maxLength": 255 }, + "Owner": { "type": "nvarchar", "maxLength": 255 }, + "Role": { "type": "nvarchar", "maxLength": 255 }, + "Location": { "type": "nvarchar", "maxLength": 255 }, + "Route": { "type": "nvarchar", "maxLength": 255 }, + "Email": { "type": "nvarchar", "maxLength": 255 }, + "DisplayName": { "type": "nvarchar", "maxLength": 255 }, + "Team": { "type": "nvarchar", "maxLength": 255 }, + "Username": { "type": "nvarchar", "maxLength": 50 }, + "AuthenticatedUsername": { "type": "nvarchar", "maxLength": 50 }, + "UITheme": { "type": "nvarchar", "maxLength": 50 }, + "Bio": { "type": "text" }, + "PasswordHash": { "type": "text" }, + "Image": { "type": "text" }, + "AvatarURL": { "type": "text" }, + "SQL_USER": { "type": "bit" }, + "Text": { "type": "nvarchar", "maxLength": 255 } + }, + "oracle": { + "ID": { "type": "string" }, + "Name": { "type": "varchar2", "maxLength": 255 }, + "Description": { "type": "varchar2", "maxLength": 255 }, + "Text": { "type": "varchar2", "maxLength": 255 }, + "Building": { "type": "varchar2", "maxLength": 255 }, + "Owner": { "type": "varchar2", "maxLength": 255 }, + "Role": { "type": "varchar2", "maxLength": 255 }, + "Location": { "type": "varchar2", "maxLength": 255 }, + "Route": { "type": "varchar2", "maxLength": 255 }, + "Email": { "type": "varchar2", "maxLength": 255 }, + "DisplayName": { "type": "varchar2", "maxLength": 255 }, + "Team": { "type": "varchar2", "maxLength": 255 }, + "Username": { "type": "varchar2", "maxLength": 50 }, + "AuthenticatedUsername": { "type": "varchar2", "maxLength": 50 }, + "UITheme": { "type": "varchar2", "maxLength": 50 }, + "Bio": { "type": "clob" }, + "PasswordHash": { "type": "clob" }, + "Image": { "type": "clob" }, + "AvatarURL": { "type": "clob" }, + "SQL_USER": { "type": "boolean" } + }, + "mariaDB": { + "ID": { "type": "uuid" }, + "Name": { "type": "string" }, + "Description": { "type": "string" }, + "Text": { "type": "string" }, + "Building": { "type": "string" }, + "Owner": { "type": "string" }, + "Role": { "type": "string" }, + "Location": { "type": "string" }, + "Route": { "type": "string" }, + "Email": { "type": "string" }, + "DisplayName": { "type": "string" }, + "Team": { "type": "string" }, + "Username": { "type": "string" }, + "AuthenticatedUsername": { "type": "string" }, + "UITheme": { "type": "string" }, + "Bio": { "type": "text" }, + "PasswordHash": { "type": "text" }, + "Image": { "type": "text" }, + "AvatarURL": { "type": "text" }, + "SQL_USER": { "type": "boolean" } + }, + "postgres": { + "ID": { "type": "uuid" }, + "Name": { "type": "varchar", "length": 255 }, + "Description": { "type": "varchar", "length": 255 }, + "Text": { "type": "varchar", "length": 255 }, + "Building": { "type": "varchar", "length": 255 }, + "Owner": { "type": "varchar", "length": 255 }, + "Role": { "type": "varchar", "length": 255 }, + "Location": { "type": "varchar", "length": 255 }, + "Route": { "type": "varchar", "length": 255 }, + "Email": { "type": "varchar", "length": 255 }, + "DisplayName": { "type": "varchar", "length": 255 }, + "Team": { "type": "varchar", "length": 255 }, + "Username": { "type": "varchar", "length": 50 }, + "AuthenticatedUsername": { "type": "varchar", "length": 50 }, + "UITheme": { "type": "varchar", "length": 50 }, + "Bio": { "type": "text" }, + "PasswordHash": { "type": "text" }, + "Image": { "type": "text" }, + "AvatarURL": { "type": "text" }, + "SQL_USER": { "type": "boolean" } + } +} diff --git a/services/dbconnector/queryConstructor.js b/services/dbconnector/queryConstructor.js index 0a6f636..6009c49 100644 --- a/services/dbconnector/queryConstructor.js +++ b/services/dbconnector/queryConstructor.js @@ -93,7 +93,7 @@ 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. @@ -144,22 +144,43 @@ function generateReadQuery(dbType, table, params) { // 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 + if (params[key]) { let condition; + if (key === 'partialMatch') continue; // Skip the partialSearch flag + switch (dbType.toUpperCase()) { case 'MSSQL': - condition = `${key} = @${key}`; + if (params.partialMatch) { + condition = `${key} LIKE '%' + @${key} + '%'`; + params[key] = `%${params[key]}%`; // Add % wildcard in params + } else { + condition = `${key} = @${key}`; + } + break; + case 'ORACLE': + if (params.partialMatch) { + condition = `${key} LIKE '%' || :${key} || '%'`; + params[key] = `%${params[key]}%`; // Add % wildcard in params + } else { + condition = `${key} = :${key}`; + } break; case 'POSTGRES': - condition = `${key} = $1`; + if (params.partialMatch) { + condition = `${key} LIKE $1`; + params[key] = `%${params[key]}%`; // Add % wildcard in params + } else { + condition = `${key} = $1`; + } break; case 'MARIADB': - condition = `${key} = ?`; + if (params.partialMatch) { + condition = `${key} LIKE ?`; + params[key] = `%${params[key]}%`; // Add % wildcard in params + } else { + condition = `${key} = ?`; + } break; default: throw new Error('Unsupported database type'); @@ -177,7 +198,6 @@ function generateReadQuery(dbType, table, params) { return query; } - /** * Generates a UPDATE SQL query string based on database type, table, and parameters. * @@ -221,8 +241,6 @@ async function generateUpdateQuery(dbType, table, params) { return `UPDATE ${table} SET ${updateClause} ${whereClause};`; } - - /** * Generates a DELETE SQL query string based on database type, table, and parameters. *