From 4015790b284f4333ce26c6943b761b0800154774 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Fri, 4 Nov 2016 21:23:32 +0000 Subject: [PATCH 1/7] tests: adds mysql.format() coverage --- test/integration/connection/test-format.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 test/integration/connection/test-format.js diff --git a/test/integration/connection/test-format.js b/test/integration/connection/test-format.js new file mode 100644 index 000000000..27ae171a7 --- /dev/null +++ b/test/integration/connection/test-format.js @@ -0,0 +1,14 @@ +var path = require('path'); +var assert = require('assert'); +var common = require('../../common'); +var lib = require(path.resolve(common.lib, '../index')); + +assert.equal( + lib.format('SELECT * FROM ?? WHERE ?? = ?', [ 'table', 'property', 123 ]), + 'SELECT * FROM `table` WHERE `property` = 123' +); + +assert.equal( + lib.format('INSERT INTO ?? SET ?', [ 'table', { property: 123 } ]), + 'INSERT INTO `table` SET `property` = 123' +); From dce49bdd92d3195e9da4c2369da60b562ac50c97 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Fri, 4 Nov 2016 21:31:52 +0000 Subject: [PATCH 2/7] tests: adds mysql.Types coverage --- test/integration/connection/test-types.js | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 test/integration/connection/test-types.js diff --git a/test/integration/connection/test-types.js b/test/integration/connection/test-types.js new file mode 100644 index 000000000..a9d97a7ab --- /dev/null +++ b/test/integration/connection/test-types.js @@ -0,0 +1,11 @@ +var path = require('path'); +var assert = require('assert'); +var common = require('../../common'); +var lib = require(path.resolve(common.lib, '../index')); +var types = require(path.resolve(common.lib, 'protocol/constants/types')); + +assert.equal(typeof lib.Types, "object"); + +for (var k in types) { + assert.equal(lib.Types[k], types[k]); +} From 77a23c1ed6c387d6a1ab68ca75854757c567876e Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Fri, 4 Nov 2016 22:10:36 +0000 Subject: [PATCH 3/7] tests: adds change user charset coverage --- .../connection/test-change-user-charset.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 test/integration/connection/test-change-user-charset.js diff --git a/test/integration/connection/test-change-user-charset.js b/test/integration/connection/test-change-user-charset.js new file mode 100644 index 000000000..9e3e0219f --- /dev/null +++ b/test/integration/connection/test-change-user-charset.js @@ -0,0 +1,18 @@ +var assert = require('assert'); +var common = require('../../common'); + +common.getTestConnection(function (err, connection) { + assert.ifError(err); + + // should change charset + connection.changeUser({charset:'KOI8R_GENERAL_CI'}, function (err) { + assert.ifError(err); + + connection.query('SHOW VARIABLES LIKE \'character_set_client\'', function (err, result) { + assert.ifError(err); + assert.strictEqual(result[0]['Value'], 'koi8r'); + + connection.destroy(); + }); + }); +}); From c97737ae478aec1f0cfcaf3b486a1d26805f3c23 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Fri, 4 Nov 2016 22:11:03 +0000 Subject: [PATCH 4/7] tests: adds another way of making a simple query with object params --- test/integration/connection/test-query.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/integration/connection/test-query.js b/test/integration/connection/test-query.js index 42ddba4d7..2d5aa4cd7 100644 --- a/test/integration/connection/test-query.js +++ b/test/integration/connection/test-query.js @@ -8,6 +8,13 @@ common.getTestConnection(function (err, connection) { assert.ifError(err); assert.deepEqual(rows, [{1: 1}]); assert.equal(fields[0].name, '1'); - connection.end(assert.ifError); + + // this is a coverage test, it shuold perform exactly as the previous one + connection.query({ sql: 'SELECT ?' }, [ 1 ], function (err, rows, fields) { + assert.ifError(err); + assert.deepEqual(rows, [{1: 1}]); + assert.equal(fields[0].name, '1'); + connection.end(assert.ifError); + }); }); }); From 7aa6da6f5928ebedb5a75c9c6c2ddd4ded2d00cd Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Fri, 4 Nov 2016 22:11:34 +0000 Subject: [PATCH 5/7] tests: updates change user test to cover calling without specifing new user --- test/unit/connection/test-change-user.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/unit/connection/test-change-user.js b/test/unit/connection/test-change-user.js index fb38fe8bc..dfe59c78a 100644 --- a/test/unit/connection/test-change-user.js +++ b/test/unit/connection/test-change-user.js @@ -21,8 +21,18 @@ server.listen(common.fakeServerPort, function(err) { assert.ifError(err); assert.strictEqual(result[0]['CURRENT_USER()'], 'user_2@localhost'); - connection.destroy(); - server.destroy(); + // should keep current user + connection.changeUser(function (err) { + assert.ifError(err); + + connection.query('SELECT CURRENT_USER()', function (err, result) { + assert.ifError(err); + assert.strictEqual(result[0]['CURRENT_USER()'], 'user_2@localhost'); + + connection.destroy(); + server.destroy(); + }); + }); }); }); }); From b7999b0d83c7bbd36d98e0a748da902a767b312b Mon Sep 17 00:00:00 2001 From: ifsnow Date: Sun, 29 Jan 2017 09:45:01 +0900 Subject: [PATCH 6/7] Added an option to return resultsets as an array type. --- Readme.md | 1 + lib/ConnectionConfig.js | 2 ++ lib/protocol/Parser.js | 5 ++++ lib/protocol/packets/RowDataPacket.js | 25 ++++++++++++++++++- lib/protocol/sequences/Query.js | 6 +++-- test/integration/connection/test-format.js | 14 ----------- .../connection/test-query-rows-as-array.js | 18 +++++++++++++ test/integration/connection/test-types.js | 11 -------- test/unit/connection/test-change-user.js | 14 ++--------- 9 files changed, 56 insertions(+), 40 deletions(-) delete mode 100644 test/integration/connection/test-format.js create mode 100644 test/integration/connection/test-query-rows-as-array.js delete mode 100644 test/integration/connection/test-types.js diff --git a/Readme.md b/Readme.md index 8454f1de3..9780bcbf3 100644 --- a/Readme.md +++ b/Readme.md @@ -224,6 +224,7 @@ issue [#501](https://github.com/mysqljs/mysql/issues/501). (Default: `false`) also possible to blacklist default ones. For more information, check [Connection Flags](#connection-flags). * `ssl`: object with ssl parameters or a string containing name of ssl profile. See [SSL options](#ssl-options). +* `rowsAsArray`: If `true`, resultsets return as an array type instead of an object. (Default: `false`) In addition to passing these options as an object, you can also use a url diff --git a/lib/ConnectionConfig.js b/lib/ConnectionConfig.js index 147aa0abb..792069340 100644 --- a/lib/ConnectionConfig.js +++ b/lib/ConnectionConfig.js @@ -58,6 +58,8 @@ function ConnectionConfig(options) { // Set the client flags var defaultFlags = ConnectionConfig.getDefaultFlags(options); this.clientFlags = ConnectionConfig.mergeFlags(defaultFlags, options.flags); + + this.rowsAsArray = options.rowsAsArray || false; } ConnectionConfig.mergeFlags = function mergeFlags(defaultFlags, userFlags) { diff --git a/lib/protocol/Parser.js b/lib/protocol/Parser.js index 38e004f23..84e0be288 100644 --- a/lib/protocol/Parser.js +++ b/lib/protocol/Parser.js @@ -21,6 +21,7 @@ function Parser(options) { this._nextPacketNumber = 0; this._encoding = 'utf-8'; this._paused = false; + this._rowsAsArray = options.config && options.config.rowsAsArray; } Parser.prototype.write = function write(chunk) { @@ -410,6 +411,10 @@ Parser.prototype.packetLength = function packetLength() { return this._packetHeader.length + this._longPacketBuffers.size; }; +Parser.prototype.isArrayRowMode = function() { + return this._rowsAsArray; +}; + Parser.prototype._combineNextBuffers = function _combineNextBuffers(bytes) { var length = this._buffer.length - this._offset; diff --git a/lib/protocol/packets/RowDataPacket.js b/lib/protocol/packets/RowDataPacket.js index 8313f87fb..8226331e4 100644 --- a/lib/protocol/packets/RowDataPacket.js +++ b/lib/protocol/packets/RowDataPacket.js @@ -13,6 +13,22 @@ Object.defineProperty(RowDataPacket.prototype, 'parse', { value : parse }); +Object.defineProperty(RowDataPacket.prototype, 'isArray', { + configurable : true, + enumerable : false, + value : function() { + return typeof this._row !== 'undefined'; + } +}); + +Object.defineProperty(RowDataPacket.prototype, 'getArrayValue', { + configurable : true, + enumerable : false, + value : function() { + return this._row; + } +}); + Object.defineProperty(RowDataPacket.prototype, '_typeCast', { configurable : true, enumerable : false, @@ -25,6 +41,11 @@ function parse(parser, fieldPackets, typeCast, nestTables, connection) { return self._typeCast(fieldPacket, parser, connection.config.timezone, connection.config.supportBigNumbers, connection.config.bigNumberStrings, connection.config.dateStrings); }; + var isArrayRowMode = parser.isArrayRowMode(); + if (isArrayRowMode) { + this._row = []; + } + for (var i = 0; i < fieldPackets.length; i++) { var fieldPacket = fieldPackets[i]; var value; @@ -39,7 +60,9 @@ function parse(parser, fieldPackets, typeCast, nestTables, connection) { : parser.parseLengthCodedString() ); } - if (typeof nestTables === 'string' && nestTables.length) { + if (isArrayRowMode) { + this._row.push(value); + } else if (typeof nestTables === 'string' && nestTables.length) { this[fieldPacket.table + nestTables + fieldPacket.name] = value; } else if (nestTables) { this[fieldPacket.table] = this[fieldPacket.table] || {}; diff --git a/lib/protocol/sequences/Query.js b/lib/protocol/sequences/Query.js index 12eb29860..aba9eb1af 100644 --- a/lib/protocol/sequences/Query.js +++ b/lib/protocol/sequences/Query.js @@ -140,10 +140,12 @@ Query.prototype._handleFinalResultPacket = function(packet) { Query.prototype['RowDataPacket'] = function(packet, parser, connection) { packet.parse(parser, this._resultSet.fieldPackets, this.typeCast, this.nestTables, connection); + var row = packet.isArray() ? packet.getArrayValue() : packet; + if (this._callback) { - this._resultSet.rows.push(packet); + this._resultSet.rows.push(row); } else { - this.emit('result', packet, this._index); + this.emit('result', row, this._index); } }; diff --git a/test/integration/connection/test-format.js b/test/integration/connection/test-format.js deleted file mode 100644 index 27ae171a7..000000000 --- a/test/integration/connection/test-format.js +++ /dev/null @@ -1,14 +0,0 @@ -var path = require('path'); -var assert = require('assert'); -var common = require('../../common'); -var lib = require(path.resolve(common.lib, '../index')); - -assert.equal( - lib.format('SELECT * FROM ?? WHERE ?? = ?', [ 'table', 'property', 123 ]), - 'SELECT * FROM `table` WHERE `property` = 123' -); - -assert.equal( - lib.format('INSERT INTO ?? SET ?', [ 'table', { property: 123 } ]), - 'INSERT INTO `table` SET `property` = 123' -); diff --git a/test/integration/connection/test-query-rows-as-array.js b/test/integration/connection/test-query-rows-as-array.js new file mode 100644 index 000000000..83696824e --- /dev/null +++ b/test/integration/connection/test-query-rows-as-array.js @@ -0,0 +1,18 @@ +var assert = require('assert'); +var common = require('../../common'); + +common.getTestConnection({ rowsAsArray: true }, function (err, connection) { + assert.ifError(err); + + connection.query('SELECT 1', function (err, rows) { + assert.ifError(err); + assert.deepEqual(rows, [[1]]); + }); + + connection.query({ sql: 'SELECT ?' }, [ 1 ], function (err, rows) { + assert.ifError(err); + assert.deepEqual(rows, [[1]]); + }); + + connection.end(assert.ifError); +}); diff --git a/test/integration/connection/test-types.js b/test/integration/connection/test-types.js deleted file mode 100644 index a9d97a7ab..000000000 --- a/test/integration/connection/test-types.js +++ /dev/null @@ -1,11 +0,0 @@ -var path = require('path'); -var assert = require('assert'); -var common = require('../../common'); -var lib = require(path.resolve(common.lib, '../index')); -var types = require(path.resolve(common.lib, 'protocol/constants/types')); - -assert.equal(typeof lib.Types, "object"); - -for (var k in types) { - assert.equal(lib.Types[k], types[k]); -} diff --git a/test/unit/connection/test-change-user.js b/test/unit/connection/test-change-user.js index 686ba7815..53ca0867a 100644 --- a/test/unit/connection/test-change-user.js +++ b/test/unit/connection/test-change-user.js @@ -21,18 +21,8 @@ server.listen(common.fakeServerPort, function(err) { assert.ifError(err); assert.strictEqual(result[0]['CURRENT_USER()'], 'user_2@localhost'); - // should keep current user - connection.changeUser(function (err) { - assert.ifError(err); - - connection.query('SELECT CURRENT_USER()', function (err, result) { - assert.ifError(err); - assert.strictEqual(result[0]['CURRENT_USER()'], 'user_2@localhost'); - - connection.destroy(); - server.destroy(); - }); - }); + connection.destroy(); + server.destroy(); }); }); }); From 4031e2dab764d7f0c2c5b629261ef8ab6793b3e0 Mon Sep 17 00:00:00 2001 From: ifsnow Date: Sun, 29 Jan 2017 11:11:25 +0900 Subject: [PATCH 7/7] Support for setting `rowsAsArray` per query. --- lib/protocol/Parser.js | 8 ++++++-- lib/protocol/sequences/Query.js | 3 +++ test/integration/connection/test-query-rows-as-array.js | 8 ++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/protocol/Parser.js b/lib/protocol/Parser.js index 84e0be288..fb5880fad 100644 --- a/lib/protocol/Parser.js +++ b/lib/protocol/Parser.js @@ -21,7 +21,7 @@ function Parser(options) { this._nextPacketNumber = 0; this._encoding = 'utf-8'; this._paused = false; - this._rowsAsArray = options.config && options.config.rowsAsArray; + this._rowsAsArray = options.config && options.config.rowsAsArray; } Parser.prototype.write = function write(chunk) { @@ -411,8 +411,12 @@ Parser.prototype.packetLength = function packetLength() { return this._packetHeader.length + this._longPacketBuffers.size; }; +Parser.prototype.setArrayRowMode = function(isArrayRowMode) { + this._isArrayRowMode = typeof isArrayRowMode === 'undefined' ? this._rowsAsArray : isArrayRowMode; +}; + Parser.prototype.isArrayRowMode = function() { - return this._rowsAsArray; + return this._isArrayRowMode; }; Parser.prototype._combineNextBuffers = function _combineNextBuffers(bytes) { diff --git a/lib/protocol/sequences/Query.js b/lib/protocol/sequences/Query.js index aba9eb1af..14820ff24 100644 --- a/lib/protocol/sequences/Query.js +++ b/lib/protocol/sequences/Query.js @@ -17,6 +17,7 @@ function Query(options, callback) { ? true : options.typeCast; this.nestTables = options.nestTables || false; + this.isArrayRowMode = options.rowsAsArray; this._resultSet = null; this._results = []; @@ -138,6 +139,8 @@ Query.prototype._handleFinalResultPacket = function(packet) { }; Query.prototype['RowDataPacket'] = function(packet, parser, connection) { + parser.setArrayRowMode(this.isArrayRowMode); + packet.parse(parser, this._resultSet.fieldPackets, this.typeCast, this.nestTables, connection); var row = packet.isArray() ? packet.getArrayValue() : packet; diff --git a/test/integration/connection/test-query-rows-as-array.js b/test/integration/connection/test-query-rows-as-array.js index 83696824e..e75f6bda0 100644 --- a/test/integration/connection/test-query-rows-as-array.js +++ b/test/integration/connection/test-query-rows-as-array.js @@ -14,5 +14,13 @@ common.getTestConnection({ rowsAsArray: true }, function (err, connection) { assert.deepEqual(rows, [[1]]); }); + connection.query({ + sql: 'SELECT ?', + rowsAsArray: false + }, [ 1 ], function (err, rows) { + assert.ifError(err); + assert.deepEqual(rows, [{1: 1}]); + }); + connection.end(assert.ifError); });