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