From fd778c63e7653a5b4b26422d4cef98d270be9626 Mon Sep 17 00:00:00 2001 From: ifsnow Date: Wed, 1 Feb 2017 23:59:51 +0900 Subject: [PATCH 1/3] Added an option to return resultsets as an array type. --- Readme.md | 1 + lib/ConnectionConfig.js | 2 ++ lib/protocol/Parser.js | 9 +++++++ lib/protocol/packets/RowDataPacket.js | 25 +++++++++++++++++- lib/protocol/sequences/Query.js | 9 +++++-- .../connection/test-query-rows-as-array.js | 26 +++++++++++++++++++ 6 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 test/integration/connection/test-query-rows-as-array.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..45488c2e7 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._globalRowsAsArray = options.config && options.config.rowsAsArray; } Parser.prototype.write = function write(chunk) { @@ -410,6 +411,14 @@ Parser.prototype.packetLength = function packetLength() { return this._packetHeader.length + this._longPacketBuffers.size; }; +Parser.prototype.setArrayRowMode = function(rowsAsArray) { + this._isArrayRowMode = typeof rowsAsArray === 'undefined' ? this._globalRowsAsArray : rowsAsArray; +}; + +Parser.prototype.isArrayRowMode = function() { + return this._isArrayRowMode; +}; + 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..50142dd0b 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.rowsAsArray = options.rowsAsArray; this._resultSet = null; this._results = []; @@ -138,12 +139,16 @@ Query.prototype._handleFinalResultPacket = function(packet) { }; Query.prototype['RowDataPacket'] = function(packet, parser, connection) { + parser.setArrayRowMode(this.rowsAsArray); + 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-query-rows-as-array.js b/test/integration/connection/test-query-rows-as-array.js new file mode 100644 index 000000000..e75f6bda0 --- /dev/null +++ b/test/integration/connection/test-query-rows-as-array.js @@ -0,0 +1,26 @@ +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.query({ + sql: 'SELECT ?', + rowsAsArray: false + }, [ 1 ], function (err, rows) { + assert.ifError(err); + assert.deepEqual(rows, [{1: 1}]); + }); + + connection.end(assert.ifError); +}); From 34698347ed697fe1f070cdfaec6b6986fd76d137 Mon Sep 17 00:00:00 2001 From: ifsnow Date: Sat, 4 Mar 2017 21:28:52 +0900 Subject: [PATCH 2/3] changes to apply feedback --- lib/protocol/packets/RowDataPacket.js | 12 ++---------- lib/protocol/sequences/Query.js | 8 ++++---- .../connection/test-query-rows-as-array.js | 5 +++++ 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/lib/protocol/packets/RowDataPacket.js b/lib/protocol/packets/RowDataPacket.js index 8226331e4..fd2c14ab8 100644 --- a/lib/protocol/packets/RowDataPacket.js +++ b/lib/protocol/packets/RowDataPacket.js @@ -13,19 +13,11 @@ Object.defineProperty(RowDataPacket.prototype, 'parse', { value : parse }); -Object.defineProperty(RowDataPacket.prototype, 'isArray', { +Object.defineProperty(RowDataPacket.prototype, '_getValue', { 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; + return this._row || this; } }); diff --git a/lib/protocol/sequences/Query.js b/lib/protocol/sequences/Query.js index 50142dd0b..53a3183d2 100644 --- a/lib/protocol/sequences/Query.js +++ b/lib/protocol/sequences/Query.js @@ -37,7 +37,9 @@ Query.prototype.determinePacket = function determinePacket(byte, parser) { switch (byte) { case 0x00: return Packets.OkPacket; case 0xff: return Packets.ErrorPacket; - default: return Packets.ResultSetHeaderPacket; + default: + parser.setArrayRowMode(this.rowsAsArray); + return Packets.ResultSetHeaderPacket; } } @@ -139,11 +141,9 @@ Query.prototype._handleFinalResultPacket = function(packet) { }; Query.prototype['RowDataPacket'] = function(packet, parser, connection) { - parser.setArrayRowMode(this.rowsAsArray); - packet.parse(parser, this._resultSet.fieldPackets, this.typeCast, this.nestTables, connection); - var row = packet.isArray() ? packet.getArrayValue() : packet; + var row = packet._getValue(); if (this._callback) { this._resultSet.rows.push(row); diff --git a/test/integration/connection/test-query-rows-as-array.js b/test/integration/connection/test-query-rows-as-array.js index e75f6bda0..c0f89cc70 100644 --- a/test/integration/connection/test-query-rows-as-array.js +++ b/test/integration/connection/test-query-rows-as-array.js @@ -22,5 +22,10 @@ common.getTestConnection({ rowsAsArray: true }, function (err, connection) { assert.deepEqual(rows, [{1: 1}]); }); + connection.query({ sql: 'SELECT ?' }, [ 1 ], function (err, rows) { + assert.ifError(err); + assert.deepEqual(rows, [[1]]); + }); + connection.end(assert.ifError); }); From 854a7fd5b8072a1b8756456b256c666e3cca054c Mon Sep 17 00:00:00 2001 From: ifsnow Date: Sat, 18 Mar 2017 22:55:43 +0900 Subject: [PATCH 3/3] fixed eslint errors. --- test/integration/connection/test-query-rows-as-array.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/connection/test-query-rows-as-array.js b/test/integration/connection/test-query-rows-as-array.js index c0f89cc70..ffdb943d1 100644 --- a/test/integration/connection/test-query-rows-as-array.js +++ b/test/integration/connection/test-query-rows-as-array.js @@ -15,8 +15,8 @@ common.getTestConnection({ rowsAsArray: true }, function (err, connection) { }); connection.query({ - sql: 'SELECT ?', - rowsAsArray: false + sql : 'SELECT ?', + rowsAsArray : false }, [ 1 ], function (err, rows) { assert.ifError(err); assert.deepEqual(rows, [{1: 1}]);