mssql 3.1.1 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/appveyor.yml CHANGED
@@ -5,6 +5,7 @@ environment:
5
5
  - nodejs_version: "0.10"
6
6
  - nodejs_version: "0.12"
7
7
  - nodejs_version: "4"
8
+ - nodejs_version: "5"
8
9
 
9
10
  install:
10
11
  - ps: Install-Product node $env:nodejs_version
@@ -186,7 +186,7 @@
186
186
  };
187
187
 
188
188
  resolveConnectionString = function(string) {
189
- var config, parsed, ref, ref1, ref10, ref11, ref12, ref13, ref14, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, server, user;
189
+ var config, parsed, ref, ref1, ref10, ref11, ref12, ref13, ref14, ref15, ref16, ref17, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, server, user;
190
190
  if (/^(mssql|tedious|msnodesql|tds)\:\/\//i.test(string)) {
191
191
  parsed = parseConnectionURI(string);
192
192
  } else {
@@ -211,13 +211,22 @@
211
211
  driver: parsed.driver,
212
212
  password: (ref6 = parsed.pwd) != null ? ref6 : parsed.password,
213
213
  database: (ref7 = parsed.database) != null ? ref7 : parsed['initial catalog'],
214
- connectionTimeout: (ref8 = (ref9 = parsed.timeout) != null ? ref9 : parsed['connect timeout']) != null ? ref8 : parsed['connection timeout'],
215
- requestTimeout: parsed['request timeout'],
216
- stream: (ref10 = (ref11 = parsed.stream) != null ? ref11.toLowerCase() : void 0) === 'true' || ref10 === 'yes' || ref10 === '1',
214
+ connectionTimeout: (ref8 = (ref9 = (ref10 = parsed.connectionTimeout) != null ? ref10 : parsed.timeout) != null ? ref9 : parsed['connect timeout']) != null ? ref8 : parsed['connection timeout'],
215
+ requestTimeout: (ref11 = parsed.requestTimeout) != null ? ref11 : parsed['request timeout'],
216
+ stream: (ref12 = (ref13 = parsed.stream) != null ? ref13.toLowerCase() : void 0) === 'true' || ref12 === 'yes' || ref12 === '1',
217
217
  options: {
218
- encrypt: (ref12 = (ref13 = parsed.encrypt) != null ? ref13.toLowerCase() : void 0) === 'true' || ref12 === 'yes' || ref12 === '1'
218
+ encrypt: (ref14 = (ref15 = parsed.encrypt) != null ? ref15.toLowerCase() : void 0) === 'true' || ref14 === 'yes' || ref14 === '1'
219
219
  }
220
220
  };
221
+ if (parsed.useUTC != null) {
222
+ config.options.useUTC = (ref16 = parsed.useUTC.toLowerCase()) === 'true' || ref16 === 'yes' || ref16 === '1';
223
+ }
224
+ if (config.connectionTimeout != null) {
225
+ config.connectionTimeout = parseInt(config.connectionTimeout);
226
+ }
227
+ if (config.requestTimeout != null) {
228
+ config.requestTimeout = parseInt(config.requestTimeout);
229
+ }
221
230
  if (/^(.*)\\(.*)$/.exec(user)) {
222
231
  config.domain = RegExp.$1;
223
232
  user = RegExp.$2;
@@ -238,7 +247,7 @@
238
247
  server = RegExp.$1.trim();
239
248
  config.port = parseInt(RegExp.$2.trim());
240
249
  }
241
- if ((ref14 = server.toLowerCase()) === '.' || ref14 === '(.)' || ref14 === '(localdb)' || ref14 === '(local)') {
250
+ if ((ref17 = server.toLowerCase()) === '.' || ref17 === '(.)' || ref17 === '(localdb)' || ref17 === '(local)') {
242
251
  server = 'localhost';
243
252
  }
244
253
  }
package/lib/main.js CHANGED
@@ -4,6 +4,7 @@
4
4
  extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
5
5
  hasProp = {}.hasOwnProperty,
6
6
  indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
7
+ slice = [].slice,
7
8
  bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
8
9
 
9
10
  EventEmitter = require('events').EventEmitter;
@@ -383,6 +384,36 @@
383
384
  return new Transaction(this);
384
385
  };
385
386
 
387
+
388
+ /*
389
+ Creates a new query using this connection from a tagged template string.
390
+
391
+ @param {Array} strings Array of string literals.
392
+ @param {...*} keys Values.
393
+ @returns {Request}
394
+ */
395
+
396
+ Connection.prototype.query = function() {
397
+ var strings, values;
398
+ strings = arguments[0], values = 2 <= arguments.length ? slice.call(arguments, 1) : [];
399
+ return new Request(this)._template('query', strings, values);
400
+ };
401
+
402
+
403
+ /*
404
+ Creates a new batch using this connection from a tagged template string.
405
+
406
+ @param {Array} strings Array of string literals.
407
+ @param {...*} keys Values.
408
+ @returns {Request}
409
+ */
410
+
411
+ Connection.prototype.batch = function() {
412
+ var strings, values;
413
+ strings = arguments[0], values = 2 <= arguments.length ? slice.call(arguments, 1) : [];
414
+ return new Request(this)._template('batch', strings, values);
415
+ };
416
+
386
417
  return Connection;
387
418
 
388
419
  })(EventEmitter);
@@ -396,6 +427,7 @@
396
427
  @property {Connection} connection Reference to used connection.
397
428
  @property {Boolean} multiple If `true`, `execute` will handle multiple recordsets.
398
429
  @property {String} statement Prepared SQL statement.
430
+ @property {Request} lastRequest References instance of most recent Request created by executing a statement.
399
431
  */
400
432
 
401
433
  PreparedStatement = (function(superClass) {
@@ -423,6 +455,8 @@
423
455
 
424
456
  PreparedStatement.prototype.stream = null;
425
457
 
458
+ PreparedStatement.prototype.lastRequest = null;
459
+
426
460
 
427
461
  /*
428
462
  Create new Prepared Statement.
@@ -678,7 +712,7 @@
678
712
 
679
713
  PreparedStatement.prototype._execute = function(values, callback) {
680
714
  var name, param, ref1, req;
681
- req = new Request(this);
715
+ req = this.lastRequest = new Request(this);
682
716
  if (this.stream != null) {
683
717
  req.stream = this.stream;
684
718
  }
@@ -1119,6 +1153,22 @@
1119
1153
  };
1120
1154
 
1121
1155
 
1156
+ /*
1157
+ Fetch request from tagged template string.
1158
+ */
1159
+
1160
+ Request.prototype._template = function(method, strings, values) {
1161
+ var command, i, index, len, value;
1162
+ command = [strings[0]];
1163
+ for (index = i = 0, len = values.length; i < len; index = ++i) {
1164
+ value = values[index];
1165
+ this.input("param" + (index + 1), value);
1166
+ command.push("@param" + (index + 1), strings[index + 1]);
1167
+ }
1168
+ return this[method](command.join(''));
1169
+ };
1170
+
1171
+
1122
1172
  /*
1123
1173
  Acquire connection for this request from connection.
1124
1174
  */
@@ -1810,10 +1860,49 @@
1810
1860
  return global_connection != null ? global_connection.close(callback) : void 0;
1811
1861
  };
1812
1862
 
1863
+
1864
+ /*
1865
+ Attach evnet handler to global connection.
1866
+
1867
+ @param {String} event Event name.
1868
+ @param {Function} handler Event handler.
1869
+ @returns {Connection}
1870
+ */
1871
+
1813
1872
  module.exports.on = function(event, handler) {
1814
1873
  return global_connection != null ? global_connection.on(event, handler) : void 0;
1815
1874
  };
1816
1875
 
1876
+
1877
+ /*
1878
+ Creates a new query using global connection from a tagged template string.
1879
+
1880
+ @param {Array} strings Array of string literals.
1881
+ @param {...*} keys Values.
1882
+ @returns {Request}
1883
+ */
1884
+
1885
+ module.exports.query = function() {
1886
+ var strings, values;
1887
+ strings = arguments[0], values = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1888
+ return new Request()._template('query', strings, values);
1889
+ };
1890
+
1891
+
1892
+ /*
1893
+ Creates a new batch using global connection from a tagged template string.
1894
+
1895
+ @param {Array} strings Array of string literals.
1896
+ @param {...*} keys Values.
1897
+ @returns {Request}
1898
+ */
1899
+
1900
+ module.exports.batch = function() {
1901
+ var strings, values;
1902
+ strings = arguments[0], values = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1903
+ return new Request()._template('batch', strings, values);
1904
+ };
1905
+
1817
1906
  module.exports.Connection = Connection;
1818
1907
 
1819
1908
  module.exports.Transaction = Transaction;
package/lib/msnodesql.js CHANGED
@@ -429,10 +429,28 @@
429
429
  _this._log("---------- response -----------");
430
430
  }
431
431
  req.on('meta', function(metadata) {
432
- var ref1;
432
+ var error, ex, ref1;
433
433
  if (row) {
434
434
  if (isChunkedRecordset) {
435
- row[columns[0].name] = chunksBuffer.join('');
435
+ if (columns[0].name === JSON_COLUMN_ID && _this.connection.config.parseJSON === true) {
436
+ try {
437
+ row = JSON.parse(chunksBuffer.join(''));
438
+ if (!_this.stream) {
439
+ recordsets[recordsets.length - 1][0] = row;
440
+ }
441
+ } catch (error) {
442
+ ex = error;
443
+ row = null;
444
+ ex = RequestError(new Error("Failed to parse incoming JSON. " + ex.message), 'EJSON');
445
+ if (_this.stream) {
446
+ _this.emit('error', ex);
447
+ } else {
448
+ console.error(ex);
449
+ }
450
+ }
451
+ } else {
452
+ row[columns[0].name] = chunksBuffer.join('');
453
+ }
436
454
  chunksBuffer = null;
437
455
  }
438
456
  if (_this.verbose) {
@@ -528,11 +546,29 @@
528
546
  return typeof callback === "function" ? callback(e) : void 0;
529
547
  });
530
548
  return req.once('done', function() {
531
- var elapsed, last, ref1, ref2;
549
+ var elapsed, error, ex, last, ref1, ref2;
532
550
  if (!_this.nested) {
533
551
  if (row) {
534
552
  if (isChunkedRecordset) {
535
- row[columns[0].name] = chunksBuffer.join('');
553
+ if (columns[0].name === JSON_COLUMN_ID && _this.connection.config.parseJSON === true) {
554
+ try {
555
+ row = JSON.parse(chunksBuffer.join(''));
556
+ if (!_this.stream) {
557
+ recordsets[recordsets.length - 1][0] = row;
558
+ }
559
+ } catch (error) {
560
+ ex = error;
561
+ row = null;
562
+ ex = RequestError(new Error("Failed to parse incoming JSON. " + ex.message), 'EJSON');
563
+ if (_this.stream) {
564
+ _this.emit('error', ex);
565
+ } else {
566
+ console.error(ex);
567
+ }
568
+ }
569
+ } else {
570
+ row[columns[0].name] = chunksBuffer.join('');
571
+ }
536
572
  chunksBuffer = null;
537
573
  }
538
574
  if (_this.verbose) {
@@ -519,10 +519,28 @@
519
519
  _this._log("---------- response -----------");
520
520
  }
521
521
  req.on('meta', function(metadata) {
522
- var ref1;
522
+ var error, ex, ref1;
523
523
  if (row) {
524
524
  if (isChunkedRecordset) {
525
- row[columns[0].name] = chunksBuffer.join('');
525
+ if (columns[0].name === JSON_COLUMN_ID && _this.connection.config.parseJSON === true) {
526
+ try {
527
+ row = JSON.parse(chunksBuffer.join(''));
528
+ if (!_this.stream) {
529
+ recordsets[recordsets.length - 1][0] = row;
530
+ }
531
+ } catch (error) {
532
+ ex = error;
533
+ row = null;
534
+ ex = RequestError(new Error("Failed to parse incoming JSON. " + ex.message), 'EJSON');
535
+ if (_this.stream) {
536
+ _this.emit('error', ex);
537
+ } else {
538
+ console.error(ex);
539
+ }
540
+ }
541
+ } else {
542
+ row[columns[0].name] = chunksBuffer.join('');
543
+ }
526
544
  chunksBuffer = null;
527
545
  }
528
546
  if (_this.verbose) {
@@ -618,11 +636,29 @@
618
636
  return typeof callback === "function" ? callback(e) : void 0;
619
637
  });
620
638
  return req.once('done', function() {
621
- var elapsed, last, ref1, ref2;
639
+ var elapsed, error, ex, last, ref1, ref2;
622
640
  if (!_this.nested) {
623
641
  if (row) {
624
642
  if (isChunkedRecordset) {
625
- row[columns[0].name] = chunksBuffer.join('');
643
+ if (columns[0].name === JSON_COLUMN_ID && _this.connection.config.parseJSON === true) {
644
+ try {
645
+ row = JSON.parse(chunksBuffer.join(''));
646
+ if (!_this.stream) {
647
+ recordsets[recordsets.length - 1][0] = row;
648
+ }
649
+ } catch (error) {
650
+ ex = error;
651
+ row = null;
652
+ ex = RequestError(new Error("Failed to parse incoming JSON. " + ex.message), 'EJSON');
653
+ if (_this.stream) {
654
+ _this.emit('error', ex);
655
+ } else {
656
+ console.error(ex);
657
+ }
658
+ }
659
+ } else {
660
+ row[columns[0].name] = chunksBuffer.join('');
661
+ }
626
662
  chunksBuffer = null;
627
663
  }
628
664
  if (_this.verbose) {
package/lib/tds.js CHANGED
@@ -551,6 +551,17 @@
551
551
  return typeof callback === "function" ? callback(error, _this.multiple || _this.nested ? recordsets : recordsets[0]) : void 0;
552
552
  }
553
553
  });
554
+ req.on('message', function(msg) {
555
+ return _this.emit('info', {
556
+ message: msg.text,
557
+ number: msg.number,
558
+ state: msg.state,
559
+ "class": msg.severity,
560
+ lineNumber: msg.lineNumber,
561
+ serverName: msg.serverName,
562
+ procName: msg.procName
563
+ });
564
+ });
554
565
  req.on('error', function(err) {
555
566
  var e;
556
567
  e = RequestError(err, 'EREQUEST');
package/lib/tedious.js CHANGED
@@ -461,9 +461,15 @@
461
461
  }
462
462
 
463
463
  TediousTransaction.prototype._abort = function() {
464
+ var pc;
464
465
  if (!this._rollbackRequested) {
466
+ pc = this._pooledConnection;
467
+ setImmediate((function(_this) {
468
+ return function() {
469
+ return _this.connection.pool.release(pc);
470
+ };
471
+ })(this));
465
472
  this._pooledConnection.removeListener('rollbackTransaction', this._abort);
466
- this.connection.pool.release(this._pooledConnection);
467
473
  this._pooledConnection = null;
468
474
  this._aborted = true;
469
475
  return this.emit('rollback', true);
@@ -545,7 +551,7 @@
545
551
  */
546
552
 
547
553
  TediousRequest.prototype.bulk = function(table, callback) {
548
- var errorHandlers, errors, handleError, hasReturned, started;
554
+ var errorHandlers, errors, handleError, handleInfo, hasReturned, started;
549
555
  table._makeBulk();
550
556
  if (!table.name) {
551
557
  process.nextTick(function() {
@@ -587,6 +593,19 @@
587
593
  return errors.push(e);
588
594
  };
589
595
  })(this);
596
+ handleInfo = (function(_this) {
597
+ return function(msg) {
598
+ return _this.emit('info', {
599
+ message: msg.message,
600
+ number: msg.number,
601
+ state: msg.state,
602
+ "class": msg["class"],
603
+ lineNumber: msg.lineNumber,
604
+ serverName: msg.serverName,
605
+ procName: msg.procName
606
+ });
607
+ };
608
+ })(this);
590
609
  return this._acquire((function(_this) {
591
610
  return function(err, connection) {
592
611
  var bulk, col, done, i, j, len, len1, objectid, ref1, ref2, req, row;
@@ -607,8 +626,10 @@
607
626
  }
608
627
  return connection.cancel();
609
628
  };
629
+ errorHandlers['infoMessage'] = handleInfo;
610
630
  errorHandlers['errorMessage'] = handleError.bind(void 0, false, connection);
611
631
  errorHandlers['error'] = handleError.bind(void 0, true, connection);
632
+ connection.on('infoMessage', errorHandlers['infoMessage']);
612
633
  connection.on('errorMessage', errorHandlers['errorMessage']);
613
634
  connection.on('error', errorHandlers['error']);
614
635
  done = bindDomain(function(err, rowCount) {
@@ -696,7 +717,7 @@
696
717
  */
697
718
 
698
719
  TediousRequest.prototype.query = function(command, callback) {
699
- var batchHasOutput, batchLastRow, chunksBuffer, columns, errorHandlers, errors, handleError, hasReturned, isChunkedRecordset, isJSONRecordset, recordset, recordsets, started, xmlBuffer;
720
+ var batchHasOutput, batchLastRow, chunksBuffer, columns, errorHandlers, errors, handleError, handleInfo, hasReturned, isChunkedRecordset, isJSONRecordset, recordset, recordsets, started, xmlBuffer;
700
721
  columns = {};
701
722
  recordset = [];
702
723
  recordsets = [];
@@ -736,6 +757,19 @@
736
757
  return errors.push(e);
737
758
  };
738
759
  })(this);
760
+ handleInfo = (function(_this) {
761
+ return function(msg) {
762
+ return _this.emit('info', {
763
+ message: msg.message,
764
+ number: msg.number,
765
+ state: msg.state,
766
+ "class": msg["class"],
767
+ lineNumber: msg.lineNumber,
768
+ serverName: msg.serverName,
769
+ procName: msg.procName
770
+ });
771
+ };
772
+ })(this);
739
773
  return this._acquire((function(_this) {
740
774
  return function(err, connection) {
741
775
  var assigns, declarations, doneHandler, name, param, ref1, ref2, req, selects, value;
@@ -756,8 +790,10 @@
756
790
  }
757
791
  return connection.cancel();
758
792
  };
793
+ errorHandlers['infoMessage'] = handleInfo;
759
794
  errorHandlers['errorMessage'] = handleError.bind(void 0, false, connection);
760
795
  errorHandlers['error'] = handleError.bind(void 0, true, connection);
796
+ connection.on('infoMessage', errorHandlers['infoMessage']);
761
797
  connection.on('errorMessage', errorHandlers['errorMessage']);
762
798
  connection.on('error', errorHandlers['error']);
763
799
  req = new tds.Request(command, bindDomain(function(err) {
package/package.json CHANGED
@@ -4,11 +4,12 @@
4
4
  "url": "https://patriksimek.cz"
5
5
  },
6
6
  "name": "mssql",
7
- "description": "An easy-to-use MSSQL database connector for Node.js.",
7
+ "description": "Microsoft SQL Server client for Node.js.",
8
8
  "keywords": [
9
9
  "database",
10
10
  "mssql",
11
11
  "sql",
12
+ "server",
12
13
  "msnodesql",
13
14
  "sqlserver",
14
15
  "tds",
@@ -20,7 +21,7 @@
20
21
  "azure",
21
22
  "node-mssql"
22
23
  ],
23
- "version": "3.1.1",
24
+ "version": "3.3.0",
24
25
  "main": "index.js",
25
26
  "repository": {
26
27
  "type": "git",
@@ -28,7 +29,7 @@
28
29
  },
29
30
  "license": "MIT",
30
31
  "dependencies": {
31
- "tedious": "~1.13.1",
32
+ "tedious": "~1.14.0",
32
33
  "generic-pool": "^2.2.0",
33
34
  "promise": "^7.0.1"
34
35
  },
@@ -45,6 +46,7 @@
45
46
  "test": "node_modules/.bin/mocha test/unit",
46
47
  "test-tedious": "node_modules/.bin/mocha test/integration -g tedious",
47
48
  "test-msnodesql": "node_modules/.bin/mocha test/integration -g msnodesql",
49
+ "test-msnodesqlv8": "node_modules/.bin/mocha test/integration -g msnodesqlv8",
48
50
  "test-tds": "node_modules/.bin/mocha test/integration -g tds",
49
51
  "test-cli": "node_modules/.bin/mocha test/integration -g cli"
50
52
  },
@@ -159,7 +159,7 @@ resolveConnectionString = (string) ->
159
159
  parsed = parseConnectionURI string
160
160
  else
161
161
  parsed = parseConnectionString string
162
-
162
+
163
163
  if parsed.driver is 'msnodesql'
164
164
  parsed.driver = 'SQL Server Native Client 11.0'
165
165
  parsed.__original__?.driver = name: 'Driver', escape: ['{', '}']
@@ -172,11 +172,15 @@ resolveConnectionString = (string) ->
172
172
  driver: parsed.driver
173
173
  password: parsed.pwd ? parsed.password
174
174
  database: parsed.database ? parsed['initial catalog']
175
- connectionTimeout: parsed.timeout ? parsed['connect timeout'] ? parsed['connection timeout']
176
- requestTimeout: parsed['request timeout']
175
+ connectionTimeout: parsed.connectionTimeout ? parsed.timeout ? parsed['connect timeout'] ? parsed['connection timeout']
176
+ requestTimeout: parsed.requestTimeout ? parsed['request timeout']
177
177
  stream: parsed.stream?.toLowerCase() in ['true', 'yes', '1']
178
178
  options:
179
179
  encrypt: parsed.encrypt?.toLowerCase() in ['true', 'yes', '1']
180
+
181
+ if parsed.useUTC? then config.options.useUTC = parsed.useUTC.toLowerCase() in ['true', 'yes', '1']
182
+ if config.connectionTimeout? then config.connectionTimeout = parseInt config.connectionTimeout
183
+ if config.requestTimeout? then config.requestTimeout = parseInt config.requestTimeout
180
184
 
181
185
  if (/^(.*)\\(.*)$/).exec user
182
186
  config.domain = RegExp.$1
package/src/main.coffee CHANGED
@@ -293,6 +293,28 @@ class Connection extends EventEmitter
293
293
 
294
294
  transaction: ->
295
295
  new Transaction @
296
+
297
+ ###
298
+ Creates a new query using this connection from a tagged template string.
299
+
300
+ @param {Array} strings Array of string literals.
301
+ @param {...*} keys Values.
302
+ @returns {Request}
303
+ ###
304
+
305
+ query: (strings, values...) ->
306
+ new Request(@)._template 'query', strings, values
307
+
308
+ ###
309
+ Creates a new batch using this connection from a tagged template string.
310
+
311
+ @param {Array} strings Array of string literals.
312
+ @param {...*} keys Values.
313
+ @returns {Request}
314
+ ###
315
+
316
+ batch: (strings, values...) ->
317
+ new Request(@)._template 'batch', strings, values
296
318
 
297
319
  ###
298
320
  Class PreparedStatement.
@@ -302,6 +324,7 @@ IMPORTANT: Rememeber that each prepared statement means one reserved connection
302
324
  @property {Connection} connection Reference to used connection.
303
325
  @property {Boolean} multiple If `true`, `execute` will handle multiple recordsets.
304
326
  @property {String} statement Prepared SQL statement.
327
+ @property {Request} lastRequest References instance of most recent Request created by executing a statement.
305
328
  ###
306
329
 
307
330
  class PreparedStatement extends EventEmitter
@@ -317,6 +340,7 @@ class PreparedStatement extends EventEmitter
317
340
  parameters: null
318
341
  multiple: false
319
342
  stream: null
343
+ lastRequest: null
320
344
 
321
345
  ###
322
346
  Create new Prepared Statement.
@@ -534,7 +558,7 @@ class PreparedStatement extends EventEmitter
534
558
  resolve recordset
535
559
 
536
560
  _execute: (values, callback) ->
537
- req = new Request @
561
+ req = @lastRequest = new Request @
538
562
  req.stream = @stream if @stream?
539
563
  req.input 'handle', TYPES.Int, @_handle
540
564
 
@@ -866,6 +890,19 @@ class Request extends EventEmitter
866
890
  _log: (out) ->
867
891
  if typeof @logger is "function" then @logger out else console.log out
868
892
 
893
+ ###
894
+ Fetch request from tagged template string.
895
+ ###
896
+
897
+ _template: (method, strings, values) ->
898
+ command = [strings[0]]
899
+
900
+ for value, index in values
901
+ @input "param#{index + 1}", value
902
+ command.push "@param#{index + 1}", strings[index + 1]
903
+
904
+ @[method] command.join ''
905
+
869
906
  ###
870
907
  Acquire connection for this request from connection.
871
908
  ###
@@ -1412,9 +1449,39 @@ Close global connection.
1412
1449
  module.exports.close = (callback) ->
1413
1450
  global_connection?.close callback
1414
1451
 
1452
+ ###
1453
+ Attach evnet handler to global connection.
1454
+
1455
+ @param {String} event Event name.
1456
+ @param {Function} handler Event handler.
1457
+ @returns {Connection}
1458
+ ###
1459
+
1415
1460
  module.exports.on = (event, handler) ->
1416
1461
  global_connection?.on event, handler
1417
1462
 
1463
+ ###
1464
+ Creates a new query using global connection from a tagged template string.
1465
+
1466
+ @param {Array} strings Array of string literals.
1467
+ @param {...*} keys Values.
1468
+ @returns {Request}
1469
+ ###
1470
+
1471
+ module.exports.query = (strings, values...) ->
1472
+ new Request()._template 'query', strings, values
1473
+
1474
+ ###
1475
+ Creates a new batch using global connection from a tagged template string.
1476
+
1477
+ @param {Array} strings Array of string literals.
1478
+ @param {...*} keys Values.
1479
+ @returns {Request}
1480
+ ###
1481
+
1482
+ module.exports.batch = (strings, values...) ->
1483
+ new Request()._template 'batch', strings, values
1484
+
1418
1485
  module.exports.Connection = Connection
1419
1486
  module.exports.Transaction = Transaction
1420
1487
  module.exports.Request = Request
@@ -1439,7 +1506,7 @@ module.exports.Promise = global.Promise ? require('promise')
1439
1506
  for key, value of TYPES
1440
1507
  module.exports[key] = value
1441
1508
  module.exports[key.toUpperCase()] = value
1442
-
1509
+
1443
1510
  # --- DEPRECATED IN 0.3.0 ------------------------------------------
1444
1511
 
1445
1512
  module.exports.pool =
@@ -249,7 +249,23 @@ module.exports = (Connection, Transaction, Request, ConnectionError, Transaction
249
249
  req.on 'meta', (metadata) =>
250
250
  if row
251
251
  if isChunkedRecordset
252
- row[columns[0].name] = chunksBuffer.join ''
252
+ if columns[0].name is JSON_COLUMN_ID and @connection.config.parseJSON is true
253
+ try
254
+ row = JSON.parse chunksBuffer.join('')
255
+ if not @stream then recordsets[recordsets.length - 1][0] = row
256
+ catch ex
257
+ row = null
258
+ ex = RequestError new Error("Failed to parse incoming JSON. #{ex.message}"), 'EJSON'
259
+
260
+ if @stream
261
+ @emit 'error', ex
262
+
263
+ else
264
+ console.error ex
265
+
266
+ else
267
+ row[columns[0].name] = chunksBuffer.join ''
268
+
253
269
  chunksBuffer = null
254
270
 
255
271
  if @verbose
@@ -341,7 +357,23 @@ module.exports = (Connection, Transaction, Request, ConnectionError, Transaction
341
357
  unless @nested
342
358
  if row
343
359
  if isChunkedRecordset
344
- row[columns[0].name] = chunksBuffer.join ''
360
+ if columns[0].name is JSON_COLUMN_ID and @connection.config.parseJSON is true
361
+ try
362
+ row = JSON.parse chunksBuffer.join('')
363
+ if not @stream then recordsets[recordsets.length - 1][0] = row
364
+ catch ex
365
+ row = null
366
+ ex = RequestError new Error("Failed to parse incoming JSON. #{ex.message}"), 'EJSON'
367
+
368
+ if @stream
369
+ @emit 'error', ex
370
+
371
+ else
372
+ console.error ex
373
+
374
+ else
375
+ row[columns[0].name] = chunksBuffer.join ''
376
+
345
377
  chunksBuffer = null
346
378
 
347
379
  if @verbose