Skip to content

Commit

Permalink
feat: Add an export to call prepared statements (#54)
Browse files Browse the repository at this point in the history
* feat: Add an export to call prepared queries

- Utilises pool.execute (rather than query) to actually prepare parameters through mysql.

This is intended for appropriately built queries utilising  placeholders and parameters, and should only be used on frequently repeated queries.

* refactor(prepare): Clean up results and add total execution time

* feat(prepare): Send scalar response for a single value

* fix(prepare): Check if result exists before getting keys
  • Loading branch information
thelindat authored Oct 22, 2021
1 parent 1d0a5bc commit 2a8f4b1
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 28 deletions.
74 changes: 69 additions & 5 deletions src/execute.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { pool } from './pool';
import { parseParameters } from './parser';
import { slowQueryWarning, debug, resourceName } from './config';
import { FormatError } from './errors';

const execute = async (query, parameters, resource) => {
ScheduleResourceTick(resourceName);
try {

[query, parameters] = parseParameters(query, parameters);

const [rows, _, executionTime] = await pool.query(query, parameters);
ScheduleResourceTick(resourceName);
const [executionTime, rows] = await pool.query(query, parameters);

if (executionTime >= slowQueryWarning || debug)
console.log(
Expand All @@ -27,4 +26,69 @@ const execute = async (query, parameters, resource) => {
}
};

export { execute };
const queryType = (query) => {
switch (query.replace(/\s.*/, '')) {
case 'SELECT':
return 1;
case 'INSERT':
return 2;
case 'UPDATE':
return 3;
case 'DELETE':
return 3;
default:
return false;
}
};

const preparedStatement = async (query, parameters, resource) => {
try {
if (!Array.isArray(parameters))
throw new FormatError(`Placeholders were defined, but query received no parameters!`, query);

if (typeof query !== 'string') throw new FormatError(`Prepared statements must utilise a single query`);

const type = queryType(query);
if (!type) throw new FormatError(`Prepared statements only accept SELECT, INSERT, UPDATE, and DELETE methods!`);

ScheduleResourceTick(resourceName);
const results = [];
let totalTime = 0;
let queryCount = parameters.length;

for (let i = 0; i < queryCount; i++) {
const [executionTime, rows] = await pool.execute(query, parameters[i]);
totalTime + executionTime;
results[i] = rows && (type === 3 ? rows.affectedRows : type === 2 ? rows.insertId : rows);
}

totalTime = totalTime / queryCount;
if (totalTime >= slowQueryWarning || debug)
console.log(
`^3[${debug ? 'DEBUG' : 'WARNING'}] ${resource} took ${totalTime}ms to execute ${
queryCount > 1 ? queryCount + ' queries' : 'a query'
}!
${query} ${JSON.stringify(parameters)}^0`
);

if (results.length === 1) {
if (type === 1) {
if (results[0][0] && Object.keys(results[0][0]).length === 1) {
return Object.values(results[0][0])[0];
}
return results[0][0];
}
return results[0];
}
return results;
} catch (error) {
console.log(
`^1[ERROR] ${resource} was unable to execute a query!
${error.message}
${error.sql || `${query} ${JSON.stringify(parameters)}`}^0`
);
debug && console.trace(error);
}
};

export { execute, preparedStatement };
12 changes: 11 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { pool } from './pool';
import { execute } from './execute';
import { execute, preparedStatement } from './execute';
import { transaction } from './transaction';
import { debug, isolationLevel } from './config';

Expand Down Expand Up @@ -55,7 +55,17 @@ global.exports('transaction', (queries, parameters, cb, resource = GetInvokingRe
});
});

global.exports('prepared', (query, parameters, cb, resource = GetInvokingResource()) => {
preparedStatement(query, parameters, resource).then((result) =>
safeCallback(cb || parameters, result, resource, query))
});

if (!GetResourceMetadata(GetCurrentResourceName(), 'server_script', 1)) {
global.exports('preparedSync', async (query, parameters) => {
const result = await preparedStatement(query, parameters, GetInvokingResource());
return result;
});

global.exports('executeSync', async (query, parameters) => {
const result = await execute(query, parameters, GetInvokingResource());
return result;
Expand Down
44 changes: 22 additions & 22 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@
"@types/estree" "*"

"@types/eslint@*":
version "7.28.1"
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.28.1.tgz#50b07747f1f84c2ba8cd394cf0fe0ba07afce320"
integrity sha512-XhZKznR3i/W5dXqUhgU9fFdJekufbeBd5DALmkuXoeFcjbQcPk+2cL+WLHf6Q81HWAnM2vrslIHpGVyCAviRwg==
version "7.28.2"
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.28.2.tgz#0ff2947cdd305897c52d5372294e8c76f351db68"
integrity sha512-KubbADPkfoU75KgKeKLsFHXnU4ipH7wYg0TRT33NK3N3yiu7jlFAAoygIWBV+KbuHx/G+AvuGX6DllnK35gfJA==
dependencies:
"@types/estree" "*"
"@types/json-schema" "*"
Expand All @@ -60,9 +60,9 @@
integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==

"@types/node@*":
version "16.11.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.1.tgz#2e50a649a50fc403433a14f829eface1a3443e97"
integrity sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA==
version "16.11.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.2.tgz#31c249c136c3f9b35d4b60fb8e50e01a1f0cc9a5"
integrity sha512-w34LtBB0OkDTs19FQHXy4Ig/TOXI4zqvXS2Kk1PAsRKZ0I+nik7LlMYxckW0tSNGtvWmzB+mrCTbuEjuB9DVsw==

"@webassemblyjs/[email protected]":
version "1.11.1"
Expand Down Expand Up @@ -291,9 +291,9 @@ buffer-from@^1.0.0:
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==

caniuse-lite@^1.0.30001265:
version "1.0.30001269"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001269.tgz#3a71bee03df627364418f9fd31adfc7aa1cc2d56"
integrity sha512-UOy8okEVs48MyHYgV+RdW1Oiudl1H6KolybD6ZquD0VcrPSgj25omXO1S7rDydjpqaISCwA8Pyx+jUQKZwWO5w==
version "1.0.30001270"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001270.tgz#cc9c37a4ec5c1a8d616fc7bace902bb053b0cdea"
integrity sha512-TcIC7AyNWXhcOmv2KftOl1ShFAaHQYcB/EPL/hEyMrcS7ZX0/DvV1aoy6BzV0+16wTpoAyTMGDNAJfSqS/rz7A==

chalk@^2.4.2:
version "2.4.2"
Expand Down Expand Up @@ -408,9 +408,9 @@ dir-glob@^3.0.1:
path-type "^4.0.0"

electron-to-chromium@^1.3.867:
version "1.3.871"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.871.tgz#6e87365fd72037a6c898fb46050ad4be3ac9ef62"
integrity sha512-qcLvDUPf8DSIMWarHT2ptgcqrYg62n3vPA7vhrOF24d8UNzbUBaHu2CySiENR3nEDzYgaN60071t0F6KLYMQ7Q==
version "1.3.877"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.877.tgz#956870eea7c9d8cf43cc54ea40687fee4dc0c12a"
integrity sha512-fT5mW5Giw5iyVukeHb2XvB4joBKvzHtl8Vs3QzE7APATpFMt/T7RWyUcIKSZzYkKQgpMbu+vDBTCHfQZvh8klA==

enhanced-resolve@^5.8.3:
version "5.8.3"
Expand Down Expand Up @@ -763,9 +763,9 @@ isobject@^3.0.1:
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=

jest-worker@^27.0.6:
version "27.3.0"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.3.0.tgz#6b636b63b6672208b91b92d8dcde112d1d4dba2d"
integrity sha512-xTTvvJqOjKBqE1AmwDHiQN8qzp9VoT981LtfXA+XiJVxHn4435vpnrzVcJ6v/ESiuB+IXPjZakn/ppT00xBCWA==
version "27.3.1"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.3.1.tgz#0def7feae5b8042be38479799aeb7b5facac24b2"
integrity sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==
dependencies:
"@types/node" "*"
merge-stream "^2.0.0"
Expand Down Expand Up @@ -881,7 +881,7 @@ minimist@^1.2.0:

"mysql2@https://github.com/overextended/node-mysql2.git":
version "2.3.2"
resolved "https://github.com/overextended/node-mysql2.git#b50b58cefc23c6eee1811a2769395904666b8899"
resolved "https://github.com/overextended/node-mysql2.git#0621bdc95f3bc6db1e5cd06efd52663ea9410c9a"
dependencies:
denque "^2.0.1"
generate-function "^2.3.1"
Expand Down Expand Up @@ -910,9 +910,9 @@ nice-try@^1.0.4:
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==

node-releases@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.0.tgz#67dc74903100a7deb044037b8a2e5f453bb05400"
integrity sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==
version "2.0.1"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5"
integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==

normalize-path@^3.0.0:
version "3.0.0"
Expand Down Expand Up @@ -1344,9 +1344,9 @@ webpack-sources@^3.2.0:
integrity sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==

webpack@^5.52.1:
version "5.58.2"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.58.2.tgz#6b4af12fc9bd5cbedc00dc0a2fc2b9592db16b44"
integrity sha512-3S6e9Vo1W2ijk4F4PPWRIu6D/uGgqaPmqw+av3W3jLDujuNkdxX5h5c+RQ6GkjVR+WwIPOfgY8av+j5j4tMqJw==
version "5.59.1"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.59.1.tgz#60c77e9aad796252153d4d7ab6b2d4c11f0e548c"
integrity sha512-I01IQV9K96FlpXX3V0L4nvd7gb0r7thfuu1IfT2P4uOHOA77nKARAKDYGe/tScSHKnffNIyQhLC8kRXzY4KEHQ==
dependencies:
"@types/eslint-scope" "^3.7.0"
"@types/estree" "^0.0.50"
Expand Down

0 comments on commit 2a8f4b1

Please sign in to comment.