UNPKG

13.1 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.enable = exports.postgres = exports.postgres6 = void 0;
4// Copyright (c) Microsoft Corporation. All rights reserved.
5// Licensed under the MIT license. See LICENSE file in the project root for details.
6var diagnostic_channel_1 = require("diagnostic-channel");
7var events_1 = require("events");
8var publisherName = "postgres";
9function postgres6PatchFunction(originalPg, originalPgPath) {
10 var originalClientQuery = originalPg.Client.prototype.query;
11 var diagnosticOriginalFunc = "__diagnosticOriginalFunc";
12 // wherever the callback is passed, find it, save it, and remove it from the call
13 // to the the original .query() function
14 originalPg.Client.prototype.query = function query(config, values, callback) {
15 var data = {
16 query: {},
17 database: {
18 host: this.connectionParameters.host,
19 port: this.connectionParameters.port
20 },
21 result: null,
22 error: null,
23 duration: 0,
24 time: new Date()
25 };
26 var start = process.hrtime();
27 var queryResult;
28 function patchCallback(cb) {
29 if (cb && cb[diagnosticOriginalFunc]) {
30 cb = cb[diagnosticOriginalFunc];
31 }
32 var trackingCallback = diagnostic_channel_1.channel.bindToContext(function (err, res) {
33 var end = process.hrtime(start);
34 data.result = res && { rowCount: res.rowCount, command: res.command };
35 data.error = err;
36 data.duration = Math.ceil((end[0] * 1e3) + (end[1] / 1e6));
37 diagnostic_channel_1.channel.publish(publisherName, data);
38 // emulate weird internal behavior in pg@6
39 // on success, the callback is called *before* query events are emitted
40 // on failure, the callback is called *instead of* the query emitting events
41 // with no events, that means no promises (since the promise is resolved/rejected in an event handler)
42 // since we are always inserting ourselves as a callback, we have to restore the original
43 // behavior if the user didn't provide one themselves
44 if (err) {
45 if (cb) {
46 return cb.apply(this, arguments);
47 }
48 else if (queryResult && queryResult instanceof events_1.EventEmitter) {
49 queryResult.emit("error", err);
50 }
51 }
52 else if (cb) {
53 cb.apply(this, arguments);
54 }
55 });
56 try {
57 Object.defineProperty(trackingCallback, diagnosticOriginalFunc, { value: cb });
58 return trackingCallback;
59 }
60 catch (e) {
61 // this should never happen, but bailout in case it does
62 return cb;
63 }
64 }
65 // this function takes too many variations of arguments.
66 // this patches any provided callback or creates a new callback if one wasn't provided.
67 // since the callback is always called (if provided) in addition to always having a Promisified
68 // EventEmitter returned (well, sometimes -- see above), its safe to insert a callback if none was given
69 try {
70 if (typeof config === "string") {
71 if (values instanceof Array) {
72 data.query.preparable = {
73 text: config,
74 args: values
75 };
76 callback = patchCallback(callback);
77 }
78 else {
79 data.query.text = config;
80 // pg v6 will, for some reason, accept both
81 // client.query("...", undefined, () => {...})
82 // **and**
83 // client.query("...", () => {...});
84 // Internally, precedence is given to the callback argument
85 if (callback) {
86 callback = patchCallback(callback);
87 }
88 else {
89 values = patchCallback(values);
90 }
91 }
92 }
93 else {
94 if (typeof config.name === "string") {
95 data.query.plan = config.name;
96 }
97 else if (config.values instanceof Array) {
98 data.query.preparable = {
99 text: config.text,
100 args: config.values
101 };
102 }
103 else {
104 data.query.text = config.text;
105 }
106 if (callback) {
107 callback = patchCallback(callback);
108 }
109 else if (values) {
110 values = patchCallback(values);
111 }
112 else {
113 config.callback = patchCallback(config.callback);
114 }
115 }
116 }
117 catch (e) {
118 // if our logic here throws, bail out and just let pg do its thing
119 return originalClientQuery.apply(this, arguments);
120 }
121 arguments[0] = config;
122 arguments[1] = values;
123 arguments[2] = callback;
124 arguments.length = (arguments.length > 3) ? arguments.length : 3;
125 queryResult = originalClientQuery.apply(this, arguments);
126 return queryResult;
127 };
128 return originalPg;
129}
130function postgresLatestPatchFunction(originalPg, originalPgPath) {
131 var originalClientQuery = originalPg.Client.prototype.query;
132 var diagnosticOriginalFunc = "__diagnosticOriginalFunc";
133 // wherever the callback is passed, find it, save it, and remove it from the call
134 // to the the original .query() function
135 originalPg.Client.prototype.query = function query(config, values, callback) {
136 var _this = this;
137 var _a, _b;
138 var callbackProvided = !!callback; // Starting in pg@7.x+, Promise is returned only if !callbackProvided
139 var data = {
140 query: {},
141 database: {
142 host: this.connectionParameters.host,
143 port: this.connectionParameters.port
144 },
145 result: null,
146 error: null,
147 duration: 0,
148 time: new Date()
149 };
150 var queryResult;
151 var start = process.hrtime();
152 function patchCallback(cb) {
153 if (cb && cb[diagnosticOriginalFunc]) {
154 cb = cb[diagnosticOriginalFunc];
155 }
156 var trackingCallback = diagnostic_channel_1.channel.bindToContext(function (err, res) {
157 var end = process.hrtime(start);
158 data.result = res && { rowCount: res.rowCount, command: res.command };
159 data.error = err;
160 data.duration = Math.ceil((end[0] * 1e3) + (end[1] / 1e6));
161 diagnostic_channel_1.channel.publish(publisherName, data);
162 if (err) {
163 if (cb) {
164 return cb.apply(this, arguments);
165 }
166 else if (queryResult && queryResult instanceof events_1.EventEmitter) {
167 queryResult.emit("error", err);
168 }
169 }
170 else if (cb) {
171 cb.apply(this, arguments);
172 }
173 });
174 try {
175 Object.defineProperty(trackingCallback, diagnosticOriginalFunc, { value: cb });
176 return trackingCallback;
177 }
178 catch (e) {
179 // this should never happen, but bailout in case it does
180 return cb;
181 }
182 }
183 // Only try to wrap the callback if it is a function. We want to keep the same
184 // behavior of returning a promise only if no callback is provided. Wrapping
185 // a nonfunction makes it a function and pg will interpret it as a callback
186 try {
187 if (typeof config === "string") {
188 if (values instanceof Array) {
189 data.query.preparable = {
190 text: config,
191 args: values
192 };
193 callbackProvided = typeof callback === "function";
194 callback = callbackProvided ? patchCallback(callback) : callback;
195 }
196 else {
197 data.query.text = config;
198 if (callback) {
199 callbackProvided = typeof callback === "function";
200 callback = callbackProvided ? patchCallback(callback) : callback;
201 }
202 else {
203 callbackProvided = typeof values === "function";
204 values = callbackProvided ? patchCallback(values) : values;
205 }
206 }
207 }
208 else {
209 if (typeof config.name === "string") {
210 data.query.plan = config.name;
211 }
212 else if (config.values instanceof Array) {
213 data.query.preparable = {
214 text: config.text,
215 args: config.values
216 };
217 }
218 else if (config.cursor) {
219 data.query.text = (_a = config.cursor) === null || _a === void 0 ? void 0 : _a.text;
220 }
221 else {
222 data.query.text = config.text;
223 }
224 if (callback) {
225 callbackProvided = typeof callback === "function";
226 callback = patchCallback(callback);
227 }
228 else if (values) {
229 callbackProvided = typeof values === "function";
230 values = callbackProvided ? patchCallback(values) : values;
231 }
232 else {
233 callbackProvided = typeof config.callback === "function";
234 config.callback = callbackProvided ? patchCallback(config.callback) : config.callback;
235 }
236 }
237 }
238 catch (e) {
239 // if our logic here throws, bail out and just let pg do its thing
240 return originalClientQuery.apply(this, arguments);
241 }
242 arguments[0] = config;
243 arguments[1] = values;
244 arguments[2] = callback;
245 arguments.length = (arguments.length > 3) ? arguments.length : 3;
246 try {
247 queryResult = originalClientQuery.apply(this, arguments);
248 }
249 catch (err) {
250 patchCallback()(err, undefined);
251 throw err;
252 }
253 if (!callbackProvided) {
254 if ((queryResult instanceof Promise)) {
255 return queryResult
256 // pass resolved promise after publishing the event
257 .then(function (result) {
258 patchCallback()(undefined, result);
259 return new _this._Promise(function (resolve, reject) {
260 resolve(result);
261 });
262 })
263 // pass along rejected promise after publishing the error
264 .catch(function (error) {
265 patchCallback()(error, undefined);
266 return new _this._Promise(function (resolve, reject) {
267 reject(error);
268 });
269 });
270 }
271 // Result could be a Cursor, QueryStream or Readable Stream
272 else {
273 var command = queryResult.text ? queryResult.text : "";
274 if (queryResult.cursor) {
275 command = (_b = queryResult.cursor) === null || _b === void 0 ? void 0 : _b.text;
276 }
277 if (command) {
278 var res = {
279 command: command,
280 rowCount: 0,
281 };
282 patchCallback()(undefined, res);
283 }
284 }
285 }
286 return queryResult;
287 };
288 return originalPg;
289}
290exports.postgres6 = {
291 versionSpecifier: "6.*",
292 patch: postgres6PatchFunction
293};
294exports.postgres = {
295 versionSpecifier: ">=7.* <=8.*",
296 patch: postgresLatestPatchFunction,
297 publisherName: publisherName
298};
299function enable() {
300 diagnostic_channel_1.channel.registerMonkeyPatch("pg", exports.postgres6);
301 diagnostic_channel_1.channel.registerMonkeyPatch("pg", exports.postgres);
302}
303exports.enable = enable;
304//# sourceMappingURL=pg.pub.js.map
\No newline at end of file