diff --git a/fxmanifest.lua b/fxmanifest.lua index fcd325c..52cfdd4 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -3,7 +3,7 @@ game 'common' name 'oxmysql' description 'Database wrapper for FiveM utilising node-mysql2 offering improved performance and security.' -version '1.3.5' +version '1.4.0' url 'https://github.com/overextended/oxmysql' author 'overextended' use_fxv2_oal 'yes' diff --git a/package.json b/package.json index d46518a..30f4b25 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oxmysql", - "version": "1.3.5", + "version": "1.4.0", "main": "oxmysql.js", "description": "FiveM MySQL wrapper using faster mysql2", "repository": "git@github.com:overextended/oxmysql.git", diff --git a/src/config.js b/src/config.js index 3b52212..5b6c8cf 100644 --- a/src/config.js +++ b/src/config.js @@ -15,23 +15,20 @@ if (Object.keys(config).length === 0) const slowQueryWarning = GetConvarInt('mysql_slow_query_warning', 100); const debug = GetConvar('mysql_debug', 'false') === 'true'; -let isolationLevel; -switch (GetConvarInt('mysql_transaction_isolation_level', 2)) { - case 1: - isolationLevel = 'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ'; - break; - case 2: - isolationLevel = 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED'; - break; - case 3: - isolationLevel = 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED'; - break; - case 4: - isolationLevel = 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE'; - break; - default: - break; -}; +const isolationLevel = (() => { + switch (GetConvarInt('mysql_transaction_isolation_level', 2)) { + case 1: + return 'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ'; + case 2: + return 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED'; + case 3: + return 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED'; + case 4: + return 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE'; + default: + return 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED'; + }; +})(); const resourceName = GetCurrentResourceName() || 'oxmysql'; diff --git a/src/index.js b/src/index.js index b3b0a26..c64d51d 100644 --- a/src/index.js +++ b/src/index.js @@ -51,9 +51,7 @@ global.exports('scalar', (query, parameters, cb, resource = GetInvokingResource( global.exports('transaction', (queries, parameters, cb, resource = GetInvokingResource()) => { transaction(queries, parameters, resource).then((result) => { - if (typeof parameters === 'function') - cb = parameters; - safeCallback(cb, result, resource, queries); + safeCallback(cb || parameters, result || false, resource, debug && JSON.stringify(queries)); }); }); diff --git a/src/parser.js b/src/parser.js index 9e1fc77..93d0915 100644 --- a/src/parser.js +++ b/src/parser.js @@ -28,7 +28,7 @@ const parseTypes = (field, next) => { const parseParameters = (query, parameters) => { if (query === undefined) throw new FormatError(`Undefined query passed`); - if(typeof parameters === 'function') return [query, []]; + if (typeof parameters === 'function') return [query, []]; if (query.includes('@') || query.includes(':')) return [query, parameters]; @@ -41,32 +41,31 @@ const parseParameters = (query, parameters) => { if (Array.isArray(parameters)) { if (parameters.length !== queryParams.length) - throw new Error(`Undefined array parameter #${parameters.length}`, query, parameters); + throw new Error(`Undefined array parameter #${parameters.length + 1}`, query, parameters); } else { queryParams.forEach((_, i) => { - if (parameters[`${i + 1}`] === undefined) throw new FormatError(`Undefined object parameter #${i + 1}`, query, parameters); + if (parameters[`${i + 1}`] === undefined) + throw new FormatError(`Undefined object parameter #${i + 1}`, query, parameters); }); } return [query, parameters]; }; -const parseParametersTransaction = (queries, parameters) => { +const parseTransaction = (queries, parameters) => { //https://github.com/GHMatti/ghmattimysql/blob/37f1d2ae5c53f91782d168fe81fba80512d3c46d/packages/ghmattimysql/src/server/utility/sanitizeTransactionInput.ts#L5 - - const cleanedTransactions = queries.map( (query) => { - let params; - if (typeof query === 'string') { - [query, params] = parseParameters(query, parameters || []); - return { query: query, params: params }; - } + if (!Array.isArray(queries)) throw new Error(`Transaction queries must be array type`); - [query, params] = parseParameters(query.query, query.parameters || query.values || []); - return { query: query, params: params }; + const parsedTransaction = queries.map((query) => { + const [parsedQuery, parsedParameters] = parseParameters( + typeof query === 'object' ? query.query : query, + (typeof query === 'object' && (query.parameters || query.values)) || parameters || [] + ); + return { query: parsedQuery, params: parsedParameters }; }); - return cleanedTransactions; + return parsedTransaction; }; -export { parseParameters, parseTypes, parseParametersTransaction }; +export { parseTypes, parseParameters, parseTransaction }; diff --git a/src/transaction.js b/src/transaction.js index a8383cd..561f2ad 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -1,21 +1,28 @@ import { pool } from './pool'; -import { parseParametersTransaction } from './parser'; +import { parseTransaction } from './parser'; import { slowQueryWarning, debug, resourceName } from './config'; +const transactionError = (queries, parameters) => + `${queries + .map((query) => + typeof query === 'string' ? query : `${query.query} ${JSON.stringify(query.values || query.parameters || [])}` + ) + .join('\n')}\n${JSON.stringify(parameters)}`; + const transaction = async (queries, parameters, resource) => { ScheduleResourceTick(resourceName); const connection = await pool.getConnection(); try { const time = debug ? process.hrtime.bigint() : Date.now(); - const fullQuery = parseParametersTransaction(queries, parameters); + const fullQuery = parseTransaction(queries, parameters); const transactionAmount = fullQuery.length; await connection.beginTransaction(); for (let i = 0; i < transactionAmount; i++) { await connection.query(fullQuery[i].query, fullQuery[i].params); - }; + } await connection.commit(); @@ -23,8 +30,9 @@ const transaction = async (queries, parameters, resource) => { if (executionTime >= slowQueryWarning * transactionAmount || debug) console.log( - `^3[${debug ? 'DEBUG' : 'WARNING'}] ${resource} took ${executionTime}ms to execute a transaction! - ${queries} ${JSON.stringify(parameters)}^0` + `^3[${ + debug ? 'DEBUG' : 'WARNING' + }] ${resource} took ${executionTime}ms to execute a transaction!\n${transactionError(queries, parameters)}^0` ); return true; @@ -33,12 +41,12 @@ const transaction = async (queries, parameters, resource) => { console.log( `^1[ERROR] ${resource} was unable to execute a transaction! ${error.message} - ${error.sql || `${queries} ${JSON.stringify(parameters)}`}^0` + ${error.sql || `${transactionError(queries, parameters)}`}^0` ); debug && console.trace(error); } finally { connection.release(); } -} +}; -export { transaction }; \ No newline at end of file +export { transaction };