Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@goodware/mysql

Package Overview
Dependencies
Maintainers
1
Versions
44
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@goodware/mysql - npm Package Compare versions

Comparing version 2.0.7 to 2.0.9

150

index.js
/* eslint-disable no-param-reassign */
/* eslint-disable no-await-in-loop */
const AWS = require('aws-sdk');
const RDS = require('aws-sdk/clients/rds');
const humanizeDuration = require('humanize-duration');
const Joi = require('joi');
const mysql2 = require('mysql2/promise');
const parseDuration = require('parse-duration');
/**
* Testing
/* Testing
*

@@ -15,17 +15,14 @@ * There are currently no unit tests. Instead, only whitebox testing is performed manually via uncommenting code. Search

*/
/**
* To Do
/* TODO: (#6)
* In order for decimals to be returned as numbers instead of strings, add an option and add this code conditionally.
* See https://github.com/sidorares/node-mysql2/issues/795 I tried this when creating a new connection but it didn't
* work:
*
* 1. In order for decimals to be returned as numbers instead of strings, add an option and add this code
* conditionally. See
* https://github.com/sidorares/node-mysql2/issues/795
* I tried this when creating a new connection and it didn't work:
* typeCast: (field, next) => {
* if (field.type === "DECIMAL") {
* const value = field.string();
* return (value === null) ? null : Number(value);
* }
* return next();
* }
* typeCast: (field, next) => {
* if (field.type === "DECIMAL") {
* const value = field.string();
* return (value === null) ? null : Number(value);
* }
* return next();
* }
*/

@@ -38,41 +35,42 @@

const optionsSchema = Joi.object({
// acquireTimeout:
// Joi.number().integer().min(0).default(10000).description('Not currently
// used'),
connectionLimit: Joi.number().integer().min(0).default(10).description('Only used when usePool is true'),
connectTimeout: Joi.number()
.integer()
.min(0)
connectionLimit: Joi.number().integer().min(0).default(10).description(`The maximum number of connections to keep \
in the connection pool when usePool is true`),
connectTimeout: Joi.alternatives(Joi.number().min(0), Joi.string())
.default(10000)
.description('Amount of time, in milliseconds, to wait for one database connection request'),
connectRetryTimeout: Joi.number()
.integer()
.min(0)
.description('The amount of time (converted to milliseconds), to wait for one database connection request'),
connectRetryTimeout: Joi.alternatives(Joi.number().min(0), Joi.string())
.default(5 * 60 * 1000)
.description('Amount of time, in milliseconds, to wait for a successful database connection (including retries)'),
database: Joi.string().default('mysql'),
enableKeepAlive: Joi.boolean(),
host: Joi.string().default('0.0.0.0'),
keepAliveInitialDelay: Joi.number().integer().min(0).default(10000),
logger: Joi.alternatives(Joi.object(), Joi.function()),
// eslint-disable-next-line quotes
maxConnectDelay: Joi.number()
.integer()
.min(0)
.default(100000)
// eslint-disable-next-line no-multi-str
.description(
`Maximum number of milliseconds to wait between connection attempts (starts at 10 ms and increases exponentially)`
// eslint-disable-next-line no-multi-str
'The amount of time (converted to milliseconds), to wait for a successful database connection \
(including retries)'
),
multipleStatements: Joi.boolean(),
password: Joi.string().allow(''),
port: Joi.number().integer().default(3306),
queueLimit: Joi.number().integer().min(0).default(0),
database: Joi.string().default('mysql').description('Which database (aka schema) to connect to'),
enableKeepAlive: Joi.boolean().description(`Used when usePool is true. When this value is true, pooled connections \
are periodically discarded if they are no longer alive, which also causes them to stay alive.`),
host: Joi.string().default('0.0.0.0').description('The database server host name'),
keepAliveInitialDelay: Joi.alternatives(Joi.number().min(0), Joi.string()).default(10000).description(`Used when \
enableKeepAlive is true and specifies how frequently (converted to milliseconds) connections are checked.`),
logger: Joi.alternatives(Joi.object(), Joi.function()).description('A logger object or function'),
// eslint-disable-next-line quotes
maxConnectDelay: Joi.alternatives(Joi.number().min(0), Joi.string()).default(100000).description(
`The maximum amount of time (converted to milliseconds) to wait between connection attempts. It starts at 10 ms \
and increases exponentially.`
),
multipleStatements: Joi.boolean().description(`true enables mysql2 connections to run multiple statements (separated \
by seicolons) via one call to query(), execute(), etc.`),
password: Joi.string().allow('').description(`The password for the database server user. Ignored when useIAM is
true.`),
port: Joi.number().integer().default(3306).description('The database server port number'),
queueLimit: Joi.number().integer().min(0).default(0).description(`The maximum command queue size for one mysql2 \
connection`),
region: Joi.when('useIAM', {
is: true,
then: Joi.string().required(),
}),
ssl: Joi.string().description('When useIAM is true, defaults to Amazon RDS'),
useIAM: Joi.boolean(),
user: Joi.string().default('root').allow(''),
usePool: Joi.boolean(),
}).description('Used when useIAM is true. The AWS region name.'),
ssl: Joi.string().description(`When useIAM is true, the value defaults to 'Amazon RDS'`),
useIAM: Joi.boolean().description('true to use AWS RDS IAM passwordless security'),
user: Joi.string().default('root').allow('').description('The database server user name'),
usePool: Joi.boolean().description('true enables connection pooling'),
});

@@ -82,2 +80,3 @@

* @private
* @ignore
* @description This tag is always logged

@@ -89,2 +88,3 @@ */

* @private
* @ignore
* @description Logs a message

@@ -104,5 +104,7 @@ * @param {Object | Function} logger

/**
* @description Creates mysql2-promise Connections, optionally from a pool. If a database connection can not be acquired
* due to a timeout specified via the 'connectTimeout' options setting, the methods try again using exponential backoff
* with jitter until the 'connectRetryTimeout' options setting is exceeded.
* @description Creates mysql2-promise Connection objects, optionally from a pool. If a database connection can not be
* acquired due to a timeout specified via the 'connectTimeout' options setting, the methods try again using exponential
* backoff with jitter until the 'connectRetryTimeout' options setting is exceeded. All duration-related options values
* can be provided as either numbers (milliseconds, including fractions) or as string values that are supported by
* [parse-duration](https://www.npmjs.com/package/parse-duration).
*/

@@ -122,7 +124,32 @@ class MySqlConnector {

* @constructor
* @description Optionally call connect() afterward to check the connection
* @param {Object} options Database connection options
* @param {Object} [logger]
* @description Optionally call connect() afterward to check whether a connection can be acquired
* @param {Object} [options] Constructor options. Defaults are used if the provided value is falsy.
* @param {Integer} [options.connectionLimit] The maximum number of connections to keep in the connection pool when
* usePool is true. Defaults to 10 connections.
* @param {Number|String} [options.connectTimeout] The amount of time (converted to milliseconds), to wait for one
* database connection request
* @param {Number|String} [options.connectRetryTimeout] The amount of time (converted to milliseconds), to wait for a
* successful database connection (including retries). Defaults to 5 minutes.
* @param {String} [options.database] Which database (aka schema) to connect to. Defaults to mysql.
* @param {Boolean} [options.enableKeepAlive] Used when usePool is true. When this value is true, pooled connections
* are periodically discarded if they are no longer alive, which also causes them to stay alive.
* @param {String} [options.host] The database server host name. Defaults to 0.0.0.0.
* @param {Number|String} [options.keepAliveInitialDelay] Used when enableKeepAlive is true and specifies how
* frequently (converted to milliseconds) connections are checked. Defaults to 10 seconds.
* @param {Object|Function} [options.logger] A logger object or function
* @param {Number|String} [options.maxConnectDelay] The maximum amount of time (converted to milliseconds) to wait
* between connection attempts. It starts at 10 ms and increases exponentially. Defaults to 100 seconds.
* @param {Boolean} [options.multipleStatements] true enables mysql2 connections to run multiple statements (separated
* by seicolons) via one call to query(), execute(), etc.
* @param {String} [options.password] The password for the Database server user. Ignored when useIAM is tue.
* @param {String} [options.port] The database server port number. Defaults to 3306.
* @param {Integer} [options.queueLimit] The maximum command queue size for one mysql2 connection
* @param {String} [options.region] Used when useIAM is true. The AWS region name.
* @param {String} [options.ssl] When useIAM is true, this value defaults to 'Amazon RDS'
* @param {Boolean} [options.useIAM] true to use AWS RDS IAM passwordless security
* @param {String} [options.user] The database server user name. Defaults to root.
* @param {Boolean} [options.usePool] true enables connection pooling
*/
constructor(options, logger) {
if (!options) options = {};
if (logger && !options.logger) options = { ...options, logger };

@@ -133,2 +160,10 @@ const validation = optionsSchema.validate(options);

['connectTimeout', 'connectRetryTimeout', 'keepAliveInitialDelay', 'maxConnectDelay'].forEach((key) => {
const value = options[key];
if (typeof value === 'number') return;
const newValue = parseDuration(value);
if (newValue === null || newValue < 0) throw new Error(`Invalid duration for '${key}': ${value}`);
options[key] = newValue;
});
if (options.useIAM && !options.ssl) options.ssl = 'Amazon RDS';

@@ -160,3 +195,3 @@

// https://stackoverflow.com/questions/58067254/node-mysql2-aws-rds-signer-connection-pooling/60013378#60013378
const signer = new AWS.RDS.Signer();
const signer = new RDS.Signer();
// eslint-disable-next-line require-jsdoc

@@ -205,3 +240,3 @@ const iamTokenPlugin = () => () =>

/**
* @description Runs a bogus SQL statement to check the database connection
* @description Checks the database connection
* @param {Object} [logger]

@@ -252,2 +287,3 @@ * @return {Promise} Resolves to true or rejects in case of connection failure

* @private
* @ignore
* @description Acquires a database connection and invokes a function

@@ -254,0 +290,0 @@ * @param {Function} task A function that accepts a mysql2 connection object as the first parameter

{
"name": "@goodware/mysql",
"version": "2.0.7",
"version": "2.0.9",
"description": "A mysql2-based connection helper",

@@ -26,3 +26,4 @@ "keywords": [

"joi": "^17.0.0",
"mysql2": "^2.0.0"
"mysql2": "^2.0.0",
"parse-duration": "^0.0.0"
},

@@ -29,0 +30,0 @@ "devDependencies": {

@@ -13,4 +13,12 @@ # @goodware/mysql: A mysql2-based connection helper

ES 2017
- ES5+ (lts/dubnium or later is recommended)
# Features
- Creates database connections via mysql2-promise, optionally from a pool, with exponential backoff retry
- Handles AWS RDS passwordless IAM connections
- Optionally manages database transactions by wrapping begin end transaction comments around a function invocation
- Same API whether using connection pooling or individual connections
- Same API whether using explicit or implicit transactions
# Installation

@@ -28,3 +36,3 @@

npm i --save @goodware/mysql@2
`npm i --save @goodware/mysql@2`

@@ -36,32 +44,18 @@ Or, in package.json dependencies:

2. Add the missing dependencies to your package.json
3. upgrade to npm version 7
3. Upgrade to npm version 7
```shell
npm i -g npm@7
```
`npm i -g npm@7`
# Features
- Creates database connections via mysql2-promise, optionally from a pool, with exponential backoff retry
- Handles AWS RDS passwordless IAM connections
- Manages database transactions by wrapping begin/end around a function invocation
# Notes
- mysql2 Connection objects are from mysql2-promise, so their methods execute(), query() etc. return Promises.
- If usePool is true, "await stop()" must be called on the MySqlConnector object if you wish to release the connections
in the pool. **Letting these objects go out of scope without stopping them will not close the connections.**
# Usage
1. Create an instance of the class that is exported by this module
2. Call exectue() or transaction(). These accept a function that accepts a mysql2 connection object. The provided functions usually call query() on the connection object.
3. If you're using connection pooling, call stop() to close all connections. This is necessary if:
1. Create an instance of the MySqlConnection class (it is the default export)
2. Call execute() or transaction(). These accept a function that accepts a mysql2-promise connection object. The provided functions usually call query() on the connection object.
3. If you're using connection pooling, call stop() to close the connections in the pool. This is necessary if:
- The app instantiates multiple instances to access the same database server. It is recommended to use a single global instance to avoid this issue.
- The app hangs when exiting
- The app instantiates multiple instances to access the same database server. It is recommended to use a single global instance to avoid this issue.
- The app hangs instead of terminating
# Logger
The options provided by the constructor and all other methods accept an optional 'logger' function or object. If an object is provided, it must have the method log():
The options provided by the constructor and all other methods accept an optional 'logger' function or object. If an object is provided, it must have the method log().

@@ -78,3 +72,3 @@ ```js

# Usage
# Example

@@ -85,3 +79,2 @@ The following program outputs 'success' to the console.

const mysql = require('@goodware/mysql');
const pack = require('../package.json');

@@ -92,16 +85,21 @@ const config = {

// user: 'root', // This is the default
// database: 'mysql', This is the default
password: '',
// database: 'mysql', // This is the default
password: 'password',
usePool: true, // Defaults to 10 connections (see connectionLimit in constructor options)
};
const connector = new mysql(config, console.log); // The second parameter is a logger function
async () => {
const connector = new mysql(config, console.log); // The second parameter is a logger function
// Acquire a database connection
const result = await connector.execute( async (connection) => {
// Perform database operations
const [results] = await connection.query(`select 'success' AS status`);
// The Promise resolves to 'success'
return results[0].status;
});
console.log(result);
// Close all database connections in the pool
await connector.stop();
// The Promise resolves to 'success'
return result;
}().then(console.info, console.error);
```

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc