index.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. 'use strict';
  2. exports.__esModule = true;
  3. var _stringify = require('babel-runtime/core-js/json/stringify');
  4. var _stringify2 = _interopRequireDefault(_stringify);
  5. var _extend2 = require('lodash/extend');
  6. var _extend3 = _interopRequireDefault(_extend2);
  7. var _map2 = require('lodash/map');
  8. var _map3 = _interopRequireDefault(_map2);
  9. var _assign2 = require('lodash/assign');
  10. var _assign3 = _interopRequireDefault(_assign2);
  11. var _inherits = require('inherits');
  12. var _inherits2 = _interopRequireDefault(_inherits);
  13. var _client = require('../../client');
  14. var _client2 = _interopRequireDefault(_client);
  15. var _bluebird = require('bluebird');
  16. var _bluebird2 = _interopRequireDefault(_bluebird);
  17. var _compiler = require('./query/compiler');
  18. var _compiler2 = _interopRequireDefault(_compiler);
  19. var _columncompiler = require('./schema/columncompiler');
  20. var _columncompiler2 = _interopRequireDefault(_columncompiler);
  21. var _tablecompiler = require('./schema/tablecompiler');
  22. var _tablecompiler2 = _interopRequireDefault(_tablecompiler);
  23. var _compiler3 = require('./schema/compiler');
  24. var _compiler4 = _interopRequireDefault(_compiler3);
  25. var _string = require('../../query/string');
  26. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  27. // PostgreSQL
  28. // -------
  29. function Client_PG(config) {
  30. _client2.default.apply(this, arguments);
  31. if (config.returning) {
  32. this.defaultReturning = config.returning;
  33. }
  34. if (config.searchPath) {
  35. this.searchPath = config.searchPath;
  36. }
  37. }
  38. (0, _inherits2.default)(Client_PG, _client2.default);
  39. (0, _assign3.default)(Client_PG.prototype, {
  40. queryCompiler: function queryCompiler() {
  41. return new (Function.prototype.bind.apply(_compiler2.default, [null].concat([this], Array.prototype.slice.call(arguments))))();
  42. },
  43. columnCompiler: function columnCompiler() {
  44. return new (Function.prototype.bind.apply(_columncompiler2.default, [null].concat([this], Array.prototype.slice.call(arguments))))();
  45. },
  46. schemaCompiler: function schemaCompiler() {
  47. return new (Function.prototype.bind.apply(_compiler4.default, [null].concat([this], Array.prototype.slice.call(arguments))))();
  48. },
  49. tableCompiler: function tableCompiler() {
  50. return new (Function.prototype.bind.apply(_tablecompiler2.default, [null].concat([this], Array.prototype.slice.call(arguments))))();
  51. },
  52. dialect: 'postgresql',
  53. driverName: 'pg',
  54. _driver: function _driver() {
  55. return require('pg');
  56. },
  57. _escapeBinding: (0, _string.makeEscape)({
  58. escapeArray: function escapeArray(val, esc) {
  59. return esc(arrayString(val, esc));
  60. },
  61. escapeString: function escapeString(str) {
  62. var hasBackslash = false;
  63. var escaped = '\'';
  64. for (var i = 0; i < str.length; i++) {
  65. var c = str[i];
  66. if (c === '\'') {
  67. escaped += c + c;
  68. } else if (c === '\\') {
  69. escaped += c + c;
  70. hasBackslash = true;
  71. } else {
  72. escaped += c;
  73. }
  74. }
  75. escaped += '\'';
  76. if (hasBackslash === true) {
  77. escaped = 'E' + escaped;
  78. }
  79. return escaped;
  80. },
  81. escapeObject: function escapeObject(val, timezone, prepareValue) {
  82. var seen = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
  83. if (val && typeof val.toPostgres === 'function') {
  84. seen = seen || [];
  85. if (seen.indexOf(val) !== -1) {
  86. throw new Error('circular reference detected while preparing "' + val + '" for query');
  87. }
  88. seen.push(val);
  89. return prepareValue(val.toPostgres(prepareValue), seen);
  90. }
  91. return (0, _stringify2.default)(val);
  92. }
  93. }),
  94. wrapIdentifier: function wrapIdentifier(value) {
  95. if (value === '*') return value;
  96. var matched = value.match(/(.*?)(\[[0-9]\])/);
  97. if (matched) return this.wrapIdentifier(matched[1]) + matched[2];
  98. return '"' + value.replace(/"/g, '""') + '"';
  99. },
  100. // Get a raw connection, called by the `pool` whenever a new
  101. // connection needs to be added to the pool.
  102. acquireRawConnection: function acquireRawConnection() {
  103. var client = this;
  104. return new _bluebird2.default(function (resolver, rejecter) {
  105. var connection = new client.driver.Client(client.connectionSettings);
  106. connection.connect(function (err, connection) {
  107. if (err) {
  108. return rejecter(err);
  109. }
  110. connection.on('error', function (err) {
  111. connection.__knex__disposed = err;
  112. });
  113. if (!client.version) {
  114. return client.checkVersion(connection).then(function (version) {
  115. client.version = version;
  116. resolver(connection);
  117. });
  118. }
  119. resolver(connection);
  120. });
  121. }).tap(function setSearchPath(connection) {
  122. return client.setSchemaSearchPath(connection);
  123. });
  124. },
  125. // Used to explicitly close a connection, called internally by the pool
  126. // when a connection times out or the pool is shutdown.
  127. destroyRawConnection: function destroyRawConnection(connection) {
  128. connection.end();
  129. },
  130. // In PostgreSQL, we need to do a version check to do some feature
  131. // checking on the database.
  132. checkVersion: function checkVersion(connection) {
  133. return new _bluebird2.default(function (resolver, rejecter) {
  134. connection.query('select version();', function (err, resp) {
  135. if (err) return rejecter(err);
  136. resolver(/^PostgreSQL (.*?)( |$)/.exec(resp.rows[0].version)[1]);
  137. });
  138. });
  139. },
  140. // Position the bindings for the query. The escape sequence for question mark
  141. // is \? (e.g. knex.raw("\\?") since javascript requires '\' to be escaped too...)
  142. positionBindings: function positionBindings(sql) {
  143. var questionCount = 0;
  144. return sql.replace(/(\\*)(\?)/g, function (match, escapes) {
  145. if (escapes.length % 2) {
  146. return '?';
  147. } else {
  148. questionCount++;
  149. return '$' + questionCount;
  150. }
  151. });
  152. },
  153. setSchemaSearchPath: function setSchemaSearchPath(connection, searchPath) {
  154. var path = searchPath || this.searchPath;
  155. if (!path) return _bluebird2.default.resolve(true);
  156. return new _bluebird2.default(function (resolver, rejecter) {
  157. connection.query('set search_path to ' + path, function (err) {
  158. if (err) return rejecter(err);
  159. resolver(true);
  160. });
  161. });
  162. },
  163. _stream: function _stream(connection, obj, stream, options) {
  164. var PGQueryStream = process.browser ? undefined : require('pg-query-stream');
  165. var sql = obj.sql = this.positionBindings(obj.sql);
  166. return new _bluebird2.default(function (resolver, rejecter) {
  167. var queryStream = connection.query(new PGQueryStream(sql, obj.bindings, options));
  168. queryStream.on('error', rejecter);
  169. // 'error' is not propagated by .pipe, but it breaks the pipe
  170. stream.on('error', rejecter);
  171. // 'end' IS propagated by .pipe, by default
  172. stream.on('end', resolver);
  173. queryStream.pipe(stream);
  174. });
  175. },
  176. // Runs the query on the specified connection, providing the bindings
  177. // and any other necessary prep work.
  178. _query: function _query(connection, obj) {
  179. var sql = obj.sql = this.positionBindings(obj.sql);
  180. if (obj.options) sql = (0, _extend3.default)({ text: sql }, obj.options);
  181. return new _bluebird2.default(function (resolver, rejecter) {
  182. connection.query(sql, obj.bindings, function (err, response) {
  183. if (err) return rejecter(err);
  184. obj.response = response;
  185. resolver(obj);
  186. });
  187. });
  188. },
  189. // Ensures the response is returned in the same format as other clients.
  190. processResponse: function processResponse(obj, runner) {
  191. var resp = obj.response;
  192. if (obj.output) return obj.output.call(runner, resp);
  193. if (obj.method === 'raw') return resp;
  194. var returning = obj.returning;
  195. if (resp.command === 'SELECT') {
  196. if (obj.method === 'first') return resp.rows[0];
  197. if (obj.method === 'pluck') return (0, _map3.default)(resp.rows, obj.pluck);
  198. return resp.rows;
  199. }
  200. if (returning) {
  201. var returns = [];
  202. for (var i = 0, l = resp.rows.length; i < l; i++) {
  203. var row = resp.rows[i];
  204. if (returning === '*' || Array.isArray(returning)) {
  205. returns[i] = row;
  206. } else {
  207. returns[i] = row[returning];
  208. }
  209. }
  210. return returns;
  211. }
  212. if (resp.command === 'UPDATE' || resp.command === 'DELETE') {
  213. return resp.rowCount;
  214. }
  215. return resp;
  216. }
  217. });
  218. function arrayString(arr, esc) {
  219. var result = '{';
  220. for (var i = 0; i < arr.length; i++) {
  221. if (i > 0) result += ',';
  222. var val = arr[i];
  223. if (val === null || typeof val === 'undefined') {
  224. result += 'NULL';
  225. } else if (Array.isArray(val)) {
  226. result += arrayString(val, esc);
  227. } else if (typeof val === 'number') {
  228. result += val;
  229. } else {
  230. result += (0, _stringify2.default)(typeof val === 'string' ? val : esc(val));
  231. }
  232. }
  233. return result + '}';
  234. }
  235. exports.default = Client_PG;
  236. module.exports = exports['default'];