├── .gitignore ├── .eslintrc ├── test ├── fixtures │ └── db.sql └── index.test.js ├── .travis.yml ├── package.json ├── CHANGELOG.md ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .DS_Store 3 | node_modules/ 4 | coverage 5 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@aptoma/eslint-config/lib/es5", 3 | "env": { 4 | "node": true, 5 | "mocha": true, 6 | "es6": false 7 | }, 8 | "rules": { 9 | "object-curly-spacing": [2, "always"] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/db.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `test`; 2 | 3 | CREATE TABLE `test` ( 4 | `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 5 | `foobar` varchar(128) NOT NULL, 6 | PRIMARY KEY (`id`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 6 5 | - 8 6 | - 10 7 | 8 | script: 9 | - npm test 10 | 11 | before_install: 12 | - npm -g install npm@latest-2 13 | 14 | before_script: 15 | - mysql -e 'create database mysqlpromise;' 16 | - mysql -u travis mysqlpromise < test/fixtures/db.sql 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mysql-promise", 3 | "version": "5.0.0", 4 | "description": "Small wrapper for mysql that use promises.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "NODE_ENV=test npm run lint && istanbul cover -i 'index.js' _mocha -- -u exports --exit -R spec 'test/**/*.test.js'", 8 | "lint": "eslint --ext '.js' test index.js", 9 | "release": "npm test && release-it -n -i patch", 10 | "release:minor": "npm test && release-it -n -i minor", 11 | "release:major": "npm test && release-it -n -i major" 12 | }, 13 | "engines": { 14 | "node": ">=6.0.0" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/martinj/node-mysql-promise" 19 | }, 20 | "keywords": [ 21 | "mysql", 22 | "promise" 23 | ], 24 | "author": "Martin Jonsson ", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/martinj/node-mysql-promise/issues" 28 | }, 29 | "dependencies": { 30 | "bluebird": "^3.5.2", 31 | "mysql": "^2.16.0" 32 | }, 33 | "devDependencies": { 34 | "@aptoma/eslint-config": "^5.0.1", 35 | "eslint": "^5.6.0", 36 | "istanbul": "^0.4.5", 37 | "mocha": "^5.2.0", 38 | "mysql2": "^1.6.1", 39 | "release-it": "^2.5.1", 40 | "should": "^13.2.3", 41 | "sinon": "^6.3.4" 42 | }, 43 | "greenkeeper": { 44 | "ignore": [ 45 | "eslint" 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 5.0.0 4 | 5 | * [[51c64cc](../../commit/51c64cc)] Drop support for node < 6 6 | * [[518eaf1](../../commit/518eaf1)] Update dependencies: bluebird@3.5.2, mysql@2.16.0 7 | 8 | ## 4.1.0 9 | 10 | * [[b98ec1e](../../commit/b98ec1e)] Add option for using different promise implementation 11 | 12 | ## 4.0.0 13 | 14 | * [[838c1f4](../../commit/838c1f4)] Update dependency mysql@2.12.0 15 | * [[5d47901](../../commit/5d47901)] add `getConnection()` for getting a connection from the pool. 16 | * [[7472b3e](../../commit/7472b3e)] Stop support for node v0.10.x Run test again node v6.x.x Greenkeeper ignore eslint. 17 | 18 | ## 3.1.0 19 | 20 | * [[a8b693f](../../commit/a8b693f)] Update deps: mysql@2.11.1 21 | * [[b08d495](../../commit/b08d495)] chore(package): update bluebird to version 3.4.1 22 | 23 | ## 3.0.0 24 | 25 | * [[ecd493a](../../commit/ecd493a)] Change mysql implementation selection to be passed as parameter to .configure() instead of the constructor. 26 | * [[3ae597a](../../commit/3ae597a)] Update bluebird@3.4.0 and dev dependencies. 27 | 28 | ## 2.1.0 29 | 30 | * [[e62613e](../../commit/e62613e)] Add support for selecting mysql driver e.g mysql2. 31 | 32 | ## 2.0.0 33 | 34 | Now uses bluebird@3.x which may contain breaking changes. 35 | 36 | * [ebcb0aa](../../commit/ebcb0aa) - Remove deprecated bluebird functions. Added more tests. 37 | * [6ec64e2](../../commit/6ec64e2) - Change linting. 38 | * [7ca2cd4](../../commit/7ca2cd4) - chore(package): update dependencies 39 | 40 | ## 1.5.0 41 | 42 | - *Changed* dependencies bluebird@2.10.2, mysql@2.10.2 43 | - *Added* isConfigured() on the DB instance to check if a pool has been configured. 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mysql-promise 2 | 3 | Small wrapper for [mysql](https://www.npmjs.com/package/mysql) and [mysql2](https://github.com/sidorares/node-mysql2) that use promises. 4 | 5 | [![Build Status](https://travis-ci.org/martinj/node-mysql-promise.svg?branch=master)](https://travis-ci.org/martinj/node-mysql-promise) 6 | 7 | ## Installation 8 | 9 | This module is installed via npm: 10 | 11 | ``` bash 12 | $ npm install mysql-promise 13 | ``` 14 | 15 | ## Example Usage 16 | 17 | var db = require('mysql-promise')(); 18 | 19 | db.configure({ 20 | "host": "localhost", 21 | "user": "foo", 22 | "password": "bar", 23 | "database": "db" 24 | }); 25 | 26 | db.query('UPDATE foo SET key = ?', ['value']).then(function () { 27 | return db.query('SELECT * FROM foo'); 28 | }).spread(function (rows) { 29 | console.log('Loook at all the foo', rows); 30 | }); 31 | 32 | //using multiple databases, giving it a name 'second-db' so it can be retrieved inside other modules/files. 33 | var db2 = require('mysql-promise')('second-db'); 34 | 35 | //check if has already been configured 36 | if (!db2.isConfigured()) { 37 | db2.configure({ 38 | "host": "localhost", 39 | "user": "foo", 40 | "password": "bar", 41 | "database": "another-db" 42 | }); 43 | } 44 | 45 | db2.query('SELECT * FROM users').spread(function (users) { 46 | console.log('Hello users', users); 47 | }); 48 | 49 | 50 | Using [mysql2](https://github.com/sidorares/node-mysql2) 51 | 52 | var mysql2 = require('mysql2'); 53 | var db = require('mysql-promise')(); 54 | var opts = { 55 | "host": "localhost", 56 | "user": "foo", 57 | "password": "bar", 58 | "database": "db" 59 | }; 60 | 61 | db.configure(opts, require('mysql2')); 62 | 63 | 64 | Use different promise implementation 65 | 66 | var db = require('mysql-promise')(); 67 | 68 | db.configure(dbOpts, null, PromiseImpl); 69 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BlueBird = require('bluebird'); 4 | var instances = {}; 5 | var defaultMysqlDriver; 6 | 7 | /** 8 | * Constructor 9 | */ 10 | function DB() { 11 | this.pool = null; 12 | this.PromiseImpl = BlueBird; 13 | } 14 | 15 | /** 16 | * Setup the Database connection pool for this instance 17 | * @param {Object} config 18 | * @param {Object} [mysql] mysql driver 19 | * @param {Object} [PromiseImpl] PromiseImpl promise implementation to use 20 | */ 21 | DB.prototype.configure = function (config, mysql, PromiseImpl) { 22 | if (!mysql) { 23 | if (!defaultMysqlDriver) { 24 | defaultMysqlDriver = require('mysql'); 25 | } 26 | mysql = defaultMysqlDriver; 27 | } 28 | 29 | if (PromiseImpl) { 30 | this.PromiseImpl = PromiseImpl; 31 | } 32 | this.pool = mysql.createPool(config); 33 | }; 34 | 35 | /** 36 | * Check if a pool has been configured for this instance. 37 | * @return {Boolean} 38 | */ 39 | DB.prototype.isConfigured = function () { 40 | return Boolean(this.pool); 41 | }; 42 | 43 | /** 44 | * Get a connection from the pool 45 | * @return {Promise} resolves with the connection 46 | */ 47 | DB.prototype.getConnection = function () { 48 | var self = this; 49 | 50 | return new self.PromiseImpl(function (resolve, reject) { 51 | self.pool.getConnection(function (err, con) { 52 | if (err) { 53 | if (con) { 54 | con.release(); 55 | } 56 | return reject(err); 57 | } 58 | 59 | return resolve(con); 60 | }); 61 | }); 62 | }; 63 | 64 | /** 65 | * Run DB query 66 | * @param {String} query 67 | * @param {Object} [params] 68 | * @return {Promise} 69 | */ 70 | DB.prototype.query = function (query, params) { 71 | var self = this; 72 | params = params || {}; 73 | 74 | return this 75 | .getConnection() 76 | .then(function (con) { 77 | return new self.PromiseImpl(function (resolve, reject) { 78 | con.query(query, params, function (err) { 79 | if (err) { 80 | if (con) { 81 | con.release(); 82 | } 83 | return reject(err); 84 | } 85 | 86 | con.release(); 87 | resolve([].splice.call(arguments, 1)); 88 | }); 89 | }); 90 | }); 91 | }; 92 | 93 | /** 94 | * End DB pool connections 95 | * @return {Promise} 96 | */ 97 | DB.prototype.end = function () { 98 | var self = this; 99 | 100 | return new self.PromiseImpl(function (resolve, reject) { 101 | self.pool.end(function (err) { 102 | if (err) { 103 | return reject(err); 104 | } 105 | 106 | resolve(); 107 | }); 108 | }); 109 | }; 110 | 111 | module.exports = function (name) { 112 | name = name || '_default_'; 113 | if (!instances[name]) { 114 | instances[name] = new DB(); 115 | } 116 | return instances[name]; 117 | }; 118 | 119 | /** 120 | * Get all instances 121 | * @return {Object} 122 | */ 123 | module.exports.getInstances = function () { 124 | return instances; 125 | }; 126 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var mysql = require('../'); 3 | var mysql2 = require('mysql2'); 4 | var sinon = require('sinon'); 5 | 6 | var dbConfig = { 7 | host: 'localhost', 8 | user: 'travis', 9 | database: 'mysqlpromise' 10 | }; 11 | 12 | var should = require('should'); 13 | 14 | describe('mysql-promise', function () { 15 | it('should return correct instance', function () { 16 | var db = mysql(); 17 | var namedDb = mysql('foo'); 18 | namedDb.should.equal(mysql('foo')); 19 | db.should.equal(mysql()); 20 | db.should.not.equal(namedDb); 21 | }); 22 | 23 | describe('isConfigured()', function () { 24 | 25 | it('should return false if it has no pool configured', function () { 26 | var db = mysql(); 27 | db.isConfigured().should.be.false; 28 | }); 29 | 30 | it('should return false if it has no pool configured', function () { 31 | var db = mysql(); 32 | db.configure({ 33 | host: 'localhost', 34 | user: 'foo', 35 | password: 'bar', 36 | database: 'db' 37 | }); 38 | db.isConfigured().should.be.true; 39 | }); 40 | 41 | }); 42 | 43 | describe('Configureable Promise Implementation', function () { 44 | 45 | it('should use bundled bluebird promise by default', function () { 46 | var db = mysql('promise-by-default'); 47 | db.configure(dbConfig); 48 | 49 | db.PromiseImpl.should.equal(require('bluebird')); 50 | var promise = db.getConnection(); 51 | promise.spread.should.be.a.Function; 52 | }); 53 | 54 | it('should use configured promise implementation', function () { 55 | var db = mysql('native-promise'); 56 | db.configure(dbConfig, null, Promise); // eslint-disable-line 57 | 58 | db.PromiseImpl.should.equal(Promise); // eslint-disable-line 59 | 60 | var promise = db.getConnection(); 61 | should.not.exist(promise.spread); 62 | promise.then.should.be.a.Function; 63 | }); 64 | 65 | }); 66 | 67 | describe('getConnection()', function () { 68 | 69 | it('should return a connection', function (done) { 70 | var db = mysql('connection'); 71 | db.configure(dbConfig); 72 | db.getConnection() 73 | .then(function (con) { 74 | should(con).exist; 75 | con.release(); 76 | done(); 77 | }) 78 | .catch(done); 79 | }); 80 | 81 | it('should reject if it fails to open a connection', function (done) { 82 | var db = mysql('connectFail'); 83 | db.configure({ 84 | host: 'localhost', 85 | port: 1123, 86 | user: 'foo', 87 | password: 'bar', 88 | database: 'db', 89 | connectTimeout: 5 90 | }); 91 | 92 | db.getConnection() 93 | .catch({ code: 'ECONNREFUSED' }, done.bind(null, null)) 94 | .catch(done); 95 | }); 96 | 97 | }); 98 | describe('query()', function () { 99 | 100 | beforeEach(function (done) { 101 | var db = mysql('query'); 102 | db.configure(dbConfig); 103 | 104 | db.query('DELETE FROM test') 105 | .then(done.bind(null, null)) 106 | .catch(done); 107 | }); 108 | 109 | it('should return results', function (done) { 110 | var db = mysql('query'); 111 | 112 | db.query('INSERT INTO test SET ?', { id: 1, foobar: 'monkey' }) 113 | .spread(function (res) { 114 | res.affectedRows.should.equal(1); 115 | return db.query('SELECT * FROM test'); 116 | }) 117 | .spread(function (rows) { 118 | rows.should.have.a.lengthOf(1); 119 | rows[0].id.should.equal(1); 120 | rows[0].foobar.should.equal('monkey'); 121 | done(); 122 | }) 123 | .catch(done); 124 | }); 125 | 126 | it('should reject on error', function (done) { 127 | var db = mysql('query'); 128 | 129 | db.query('SELECT * FROM non_existing_table') 130 | .catch({ code: 'ER_NO_SUCH_TABLE' }, function (err) { 131 | err.should.exist; 132 | done(); 133 | }) 134 | .catch(done); 135 | 136 | }); 137 | }); 138 | 139 | describe('end()', function () { 140 | 141 | it('should close all connections in the pool', function (done) { 142 | var db = mysql('end'); 143 | db.configure(dbConfig); 144 | db.query('SELECT * FROM test') 145 | .then(function () { 146 | db.pool._allConnections.should.have.a.lengthOf(1); 147 | return db.end(); 148 | }) 149 | .then(function () { 150 | db.pool._allConnections.should.have.a.lengthOf(0); 151 | done(); 152 | }) 153 | .catch(done); 154 | }); 155 | 156 | }); 157 | 158 | describe('Specifying mysql driver', function () { 159 | 160 | beforeEach(function () { 161 | sinon.spy(mysql2, 'createPool'); 162 | }); 163 | 164 | afterEach(function () { 165 | mysql2.createPool.restore(); 166 | }); 167 | 168 | it('should use mysql2', function (done) { 169 | var db = mysql('mysql2'); 170 | db.configure(dbConfig, mysql2); 171 | mysql2.createPool.calledOnce.should.be.true(); 172 | 173 | db.query('SELECT * FROM non_existing_table') 174 | .catch({ code: 'ER_NO_SUCH_TABLE' }, function (err) { 175 | err.should.exist; 176 | done(); 177 | }) 178 | .catch(done); 179 | }); 180 | }); 181 | }); 182 | --------------------------------------------------------------------------------