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..fd2c14ab8 100644 --- a/lib/protocol/packets/RowDataPacket.js +++ b/lib/protocol/packets/RowDataPacket.js @@ -13,6 +13,14 @@ Object.defineProperty(RowDataPacket.prototype, 'parse', { value : parse }); +Object.defineProperty(RowDataPacket.prototype, '_getValue', { + configurable : true, + enumerable : false, + value : function() { + return this._row || this; + } +}); + Object.defineProperty(RowDataPacket.prototype, '_typeCast', { configurable : true, enumerable : false, @@ -25,6 +33,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 +52,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..53a3183d2 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 = []; @@ -36,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; } } @@ -140,10 +143,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._getValue(); + 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..ffdb943d1 --- /dev/null +++ b/test/integration/connection/test-query-rows-as-array.js @@ -0,0 +1,31 @@ +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.query({ sql: 'SELECT ?' }, [ 1 ], function (err, rows) { + assert.ifError(err); + assert.deepEqual(rows, [[1]]); + }); + + connection.end(assert.ifError); +});