UNPKG

12.1 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.enable = exports.postgres7 = 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 postgres7PatchFunction(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 callbackProvided = !!callback; // Starting in pg@7.x+, Promise is returned only if !callbackProvided
138 var data = {
139 query: {},
140 database: {
141 host: this.connectionParameters.host,
142 port: this.connectionParameters.port
143 },
144 result: null,
145 error: null,
146 duration: 0,
147 time: new Date()
148 };
149 var start = process.hrtime();
150 var queryResult;
151 function patchCallback(cb) {
152 if (cb && cb[diagnosticOriginalFunc]) {
153 cb = cb[diagnosticOriginalFunc];
154 }
155 var trackingCallback = diagnostic_channel_1.channel.bindToContext(function (err, res) {
156 var end = process.hrtime(start);
157 data.result = res && { rowCount: res.rowCount, command: res.command };
158 data.error = err;
159 data.duration = Math.ceil((end[0] * 1e3) + (end[1] / 1e6));
160 diagnostic_channel_1.channel.publish(publisherName, data);
161 if (err) {
162 if (cb) {
163 return cb.apply(this, arguments);
164 }
165 else if (queryResult && queryResult instanceof events_1.EventEmitter) {
166 queryResult.emit("error", err);
167 }
168 }
169 else if (cb) {
170 cb.apply(this, arguments);
171 }
172 });
173 try {
174 Object.defineProperty(trackingCallback, diagnosticOriginalFunc, { value: cb });
175 return trackingCallback;
176 }
177 catch (e) {
178 // this should never happen, but bailout in case it does
179 return cb;
180 }
181 }
182 // Only try to wrap the callback if it is a function. We want to keep the same
183 // behavior of returning a promise only if no callback is provided. Wrapping
184 // a nonfunction makes it a function and pg will interpret it as a callback
185 try {
186 if (typeof config === "string") {
187 if (values instanceof Array) {
188 data.query.preparable = {
189 text: config,
190 args: values
191 };
192 callbackProvided = typeof callback === "function";
193 callback = callbackProvided ? patchCallback(callback) : callback;
194 }
195 else {
196 data.query.text = config;
197 if (callback) {
198 callbackProvided = typeof callback === "function";
199 callback = callbackProvided ? patchCallback(callback) : callback;
200 }
201 else {
202 callbackProvided = typeof values === "function";
203 values = callbackProvided ? patchCallback(values) : values;
204 }
205 }
206 }
207 else {
208 if (typeof config.name === "string") {
209 data.query.plan = config.name;
210 }
211 else if (config.values instanceof Array) {
212 data.query.preparable = {
213 text: config.text,
214 args: config.values
215 };
216 }
217 else {
218 data.query.text = config.text;
219 }
220 if (callback) {
221 callbackProvided = typeof callback === "function";
222 callback = patchCallback(callback);
223 }
224 else if (values) {
225 callbackProvided = typeof values === "function";
226 values = callbackProvided ? patchCallback(values) : values;
227 }
228 else {
229 callbackProvided = typeof config.callback === "function";
230 config.callback = callbackProvided ? patchCallback(config.callback) : config.callback;
231 }
232 }
233 }
234 catch (e) {
235 // if our logic here throws, bail out and just let pg do its thing
236 return originalClientQuery.apply(this, arguments);
237 }
238 arguments[0] = config;
239 arguments[1] = values;
240 arguments[2] = callback;
241 arguments.length = (arguments.length > 3) ? arguments.length : 3;
242 queryResult = originalClientQuery.apply(this, arguments);
243 if (!callbackProvided) {
244 // no callback, so create a pass along promise
245 return queryResult
246 // pass resolved promise after publishing the event
247 .then(function (result) {
248 patchCallback()(undefined, result);
249 return new _this._Promise(function (resolve, reject) {
250 resolve(result);
251 });
252 })
253 // pass along rejected promise after publishing the error
254 .catch(function (error) {
255 patchCallback()(error, undefined);
256 return new _this._Promise(function (resolve, reject) {
257 reject(error);
258 });
259 });
260 }
261 return queryResult;
262 };
263 return originalPg;
264}
265exports.postgres6 = {
266 versionSpecifier: "6.*",
267 patch: postgres6PatchFunction
268};
269exports.postgres7 = {
270 versionSpecifier: ">=7.* <=8.*",
271 patch: postgres7PatchFunction,
272 publisherName: publisherName
273};
274function enable() {
275 diagnostic_channel_1.channel.registerMonkeyPatch("pg", exports.postgres6);
276 diagnostic_channel_1.channel.registerMonkeyPatch("pg", exports.postgres7);
277}
278exports.enable = enable;
279//# sourceMappingURL=pg.pub.js.map
\No newline at end of file