Skip to content

Commit e8bc1c5

Browse files
authored
Allow type of promise used to be varying. (#103)
1 parent 109d943 commit e8bc1c5

6 files changed

Lines changed: 149 additions & 28 deletions

File tree

packages/packages/google-gax/lib/api_callable.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,14 @@ Canceller.prototype.call = function(aFunc, argument) {
121121
/**
122122
* PromiseCanceller is Canceller, but it holds a promise when
123123
* the API call finishes.
124+
* @param {Function} PromiseCtor - A constructor for a promise that implements
125+
* the ES6 specification of promise.
124126
* @constructor
125127
* @private
126128
*/
127-
function PromiseCanceller() {
129+
function PromiseCanceller(PromiseCtor) {
128130
var self = this;
129-
this.promise = new Promise(function(resolve, reject) {
131+
this.promise = new PromiseCtor(function(resolve, reject) {
130132
Canceller.call(self, function(err) {
131133
if (err) {
132134
reject(err);
@@ -286,7 +288,7 @@ NormalApiCaller.prototype.init = function(settings, callback) {
286288
if (callback) {
287289
return new Canceller(callback);
288290
}
289-
return new PromiseCanceller();
291+
return new PromiseCanceller(settings.promise);
290292
};
291293

292294
NormalApiCaller.prototype.wrap = function(func) {

packages/packages/google-gax/lib/gax.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@
5959
* @property {boolean=} isBundling - If set to false and the call is configured
6060
* for bundling, bundling is not performed.
6161
* @property {BackoffSettings=} longrunning - BackoffSettings used for polling.
62+
* @property {Function=} promise - A constructor for a promise that implements the ES6
63+
* specification of promise which will be used to create promises. If not
64+
* provided, native promises will be used.
6265
* @example
6366
* // suppress bundling for bundled method.
6467
* api.bundlingMethod(
@@ -148,6 +151,9 @@
148151
* the page streaming request.
149152
* @param {Object} settings.otherArgs - Additional arguments to be passed to
150153
* the API calls.
154+
* @param {Function=} settings.promise - A constructor for a promise that
155+
* implements the ES6 specification of promise. If not provided, native promises
156+
* will be used.
151157
*
152158
* @constructor
153159
*/
@@ -163,6 +169,7 @@ function CallSettings(settings) {
163169
this.isBundling = ('isBundling' in settings) ? settings.isBundling : true;
164170
this.longrunning =
165171
('longrunning' in settings) ? settings.longrunning : null;
172+
this.promise = ('promise' in settings) ? settings.promise : Promise;
166173
}
167174
exports.CallSettings = CallSettings;
168175

@@ -185,6 +192,7 @@ CallSettings.prototype.merge = function merge(options) {
185192
var otherArgs = this.otherArgs;
186193
var isBundling = this.isBundling;
187194
var longrunning = this.longrunning;
195+
var promise = this.promise;
188196
if ('timeout' in options) {
189197
timeout = options.timeout;
190198
}
@@ -224,6 +232,10 @@ CallSettings.prototype.merge = function merge(options) {
224232
longrunning = options.longrunning;
225233
}
226234

235+
if ('promise' in options) {
236+
promise = options.promise;
237+
}
238+
227239
return new CallSettings({
228240
timeout: timeout,
229241
retry: retry,
@@ -232,7 +244,9 @@ CallSettings.prototype.merge = function merge(options) {
232244
autoPaginate: autoPaginate,
233245
pageToken: pageToken,
234246
otherArgs: otherArgs,
235-
isBundling: isBundling});
247+
isBundling: isBundling,
248+
promise: promise
249+
});
236250
};
237251

238252
/**
@@ -515,12 +529,14 @@ function mergeRetryOptions(retry, overrides) {
515529
* those codes.
516530
* @param {Object} otherArgs - the non-request arguments to be passed to the API
517531
* calls.
532+
* @param {Function=} promise - A constructor for a promise that implements the
533+
* ES6 specification of promise. If not provided, native promises will be used.
518534
* @return {Object} A mapping from method name to CallSettings, or null if the
519535
* service is not found in the config.
520536
*/
521537
exports.constructSettings = function constructSettings(
522538
serviceName, clientConfig, configOverrides,
523-
retryNames, otherArgs) {
539+
retryNames, otherArgs, promise) {
524540
otherArgs = otherArgs || {};
525541
var defaults = {};
526542

@@ -564,7 +580,8 @@ exports.constructSettings = function constructSettings(
564580
retry: retry,
565581
bundleOptions:
566582
bundlingConfig ? createBundleOptions(bundlingConfig) : null,
567-
otherArgs: otherArgs
583+
otherArgs: otherArgs,
584+
promise: promise || Promise
568585
});
569586
}
570587
return defaults;

packages/packages/google-gax/lib/grpc.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ var gax = require('./gax');
4848
* @param {Object=} options.grpc - When specified, this will be used
4949
* for the 'grpc' module in this context. By default, it will load the grpc
5050
* module in the standard way.
51+
* @param {Function=} options.promise - A constructor for a promise that
52+
* implements the ES6 specification of promise. If not provided, native promises
53+
* will be used.
5154
* @constructor
5255
*/
5356
function GrpcClient(options) {
@@ -57,6 +60,7 @@ function GrpcClient(options) {
5760
options = options || {};
5861
this.auth = options.auth || autoAuth(options);
5962
this.grpc = options.grpc || require('grpc');
63+
this.promise = options.promise || Promise;
6064
}
6165
module.exports = GrpcClient;
6266

@@ -121,7 +125,8 @@ GrpcClient.prototype.constructSettings = function constructSettings(
121125
clientConfig,
122126
configOverrides,
123127
this.grpc.status,
124-
{metadata: metadata});
128+
{metadata: metadata},
129+
this.promise);
125130
};
126131

127132
/**
@@ -140,7 +145,8 @@ GrpcClient.prototype.createStub = function(
140145
options = options || {};
141146
var self = this;
142147
var serviceAddress = servicePath + ':' + port;
143-
return new Promise(function(resolve, reject) {
148+
var PromiseCtor = this.promise;
149+
return new PromiseCtor(function(resolve, reject) {
144150
self.auth.getAuthClient(function(err, auth) {
145151
if (err) {
146152
reject(err);

packages/packages/google-gax/lib/longrunning.js

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ LongrunningApiCaller.prototype._wrapOperation = function(
113113
var operation = new Operation(
114114
rawResponse,
115115
longrunningDescriptor,
116-
backoffSettings
116+
backoffSettings,
117+
settings
117118
);
118119

119120
callback(null, operation, rawResponse);
@@ -130,8 +131,11 @@ LongrunningApiCaller.prototype._wrapOperation = function(
130131
* operations service client and unpacking mechanisms for the operation.
131132
* @param {BackoffSettings} backoffSettings - The backoff settings used in
132133
* in polling the operation.
134+
* @param {CallOptions=} callOptions - CallOptions used in making get operation
135+
* requests.
133136
*/
134-
function Operation(grpcOp, longrunningDescriptor, backoffSettings) {
137+
function Operation(
138+
grpcOp, longrunningDescriptor, backoffSettings, callOptions) {
135139
events.EventEmitter.call(this);
136140
this.completeListeners = 0;
137141
this.hasActiveListeners = false;
@@ -141,8 +145,9 @@ function Operation(grpcOp, longrunningDescriptor, backoffSettings) {
141145
this.result = null;
142146
this.metadata = null;
143147
this.backoffSettings = backoffSettings;
144-
this.unpackResponse_(grpcOp);
145-
this.listenForEvents_();
148+
this._unpackResponse(grpcOp);
149+
this._listenForEvents();
150+
this._callOptions = callOptions;
146151
}
147152
util.inherits(Operation, events.EventEmitter);
148153

@@ -156,7 +161,7 @@ util.inherits(Operation, events.EventEmitter);
156161
*
157162
* @private
158163
*/
159-
Operation.prototype.listenForEvents_ = function() {
164+
Operation.prototype._listenForEvents = function() {
160165
var self = this;
161166

162167
this.on('newListener', function(event) {
@@ -221,28 +226,33 @@ Operation.prototype.getOperation = function(callback) {
221226

222227
function promisifyResponse() {
223228
if (!callback) {
224-
if (self.latestResponse.error) {
225-
var error = new Error(self.latestReponse.error.message);
226-
error.code = self.latestReponse.error.code;
227-
return Promise.reject(error);
228-
}
229-
return Promise.resolve([self.result, self.metadata, self.latestResponse]);
229+
var PromiseCtor = self._callOptions.promise;
230+
return new PromiseCtor(function(resolve, reject) {
231+
if (self.latestResponse.error) {
232+
var error = new Error(self.latestReponse.error.message);
233+
error.code = self.latestReponse.error.code;
234+
reject(error);
235+
} else {
236+
resolve([self.result, self.metadata, self.latestResponse]);
237+
}
238+
});
230239
}
231240
return;
232241
}
233242

234243
if (this.latestResponse.done) {
235-
this.unpackResponse_(this.latestResponse, callback);
244+
this._unpackResponse(this.latestResponse, callback);
236245
return promisifyResponse();
237246
}
238247

239248
this.currentCallPromise_ =
240-
operationsClient.getOperation({name: this.latestResponse.name});
249+
operationsClient.getOperation(
250+
{name: this.latestResponse.name}, this._callOptions);
241251

242252
var noCallbackPromise = this.currentCallPromise_
243253
.then(function(responses) {
244254
self.latestResponse = responses[0];
245-
self.unpackResponse_(responses[0], callback);
255+
self._unpackResponse(responses[0], callback);
246256
return promisifyResponse();
247257
});
248258

@@ -251,7 +261,7 @@ Operation.prototype.getOperation = function(callback) {
251261
}
252262
};
253263

254-
Operation.prototype.unpackResponse_ = function(op, callback) {
264+
Operation.prototype._unpackResponse = function(op, callback) {
255265
var responseDecoder = this.longrunningDescriptor.responseDecoder;
256266
var metadataDecoder = this.longrunningDescriptor.metadataDecoder;
257267
var response;
@@ -353,8 +363,8 @@ Operation.prototype.startPolling_ = function() {
353363
*/
354364
Operation.prototype.promise = function() {
355365
var self = this;
356-
357-
return new Promise(function(resolve, reject) {
366+
var PromiseCtor = this._callOptions.promise;
367+
return new PromiseCtor(function(resolve, reject) {
358368
self
359369
.on('error', reject)
360370
.on('complete', function(result, metadata, rawResponse) {
@@ -363,7 +373,22 @@ Operation.prototype.promise = function() {
363373
});
364374
};
365375

366-
exports.operation = function(op, longrunningDescriptor, backoffSettings) {
367-
return new Operation(op, longrunningDescriptor, backoffSettings);
368-
};
376+
/**
377+
* Method used to create Operation objects.
378+
*
379+
* @constructor
380+
*
381+
* @param {google.longrunning.Operation} op - The operation to be wrapped.
382+
* @param {LongrunningDescriptor} longrunningDescriptor - This defines the
383+
* operations service client and unpacking mechanisms for the operation.
384+
* @param {BackoffSettings} backoffSettings - The backoff settings used in
385+
* in polling the operation.
386+
* @param {CallOptions=} callOptions - CallOptions used in making get operation
387+
* requests.
388+
*/
389+
exports.operation =
390+
function(op, longrunningDescriptor, backoffSettings, callOptions) {
391+
return new Operation(
392+
op, longrunningDescriptor, backoffSettings, callOptions);
393+
};
369394

packages/packages/google-gax/test/api_callable.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,25 @@ describe('Promise', function() {
158158
done();
159159
})).to.be.undefined;
160160
});
161+
162+
it('uses a provided promise module.', function(done) {
163+
var called = false;
164+
function MockPromise(resolver) {
165+
called = true;
166+
return new Promise(resolver);
167+
}
168+
169+
function func(argument, metadata, options, callback) {
170+
callback(null, 42);
171+
}
172+
var apiCall = createApiCall(func);
173+
apiCall(null, {promise: MockPromise}).then(function(response) {
174+
expect(response).to.be.an('array');
175+
expect(response[0]).to.eq(42);
176+
expect(called).to.be.true;
177+
done();
178+
}).catch(done);
179+
});
161180
});
162181

163182
describe('retryable', function() {

packages/packages/google-gax/test/longrunning.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,28 @@ describe('longrunning', function() {
311311
done();
312312
});
313313
});
314+
315+
it('uses provided promise constructor.', function(done) {
316+
var func = function(argument, metadata, options, callback) {
317+
callback(null, PENDING_OP);
318+
};
319+
320+
var called = false;
321+
function MockPromise(executor) {
322+
var promise = new Promise(executor);
323+
called = true;
324+
return promise;
325+
}
326+
327+
var client = mockOperationsClient();
328+
var apiCall = createApiCall(func, client);
329+
apiCall(null, {promise: MockPromise}).then(function(responses) {
330+
var operation = responses[0];
331+
operation.getOperation();
332+
expect(called).to.be.true;
333+
done();
334+
});
335+
});
314336
});
315337

316338
describe('promise', function() {
@@ -362,6 +384,36 @@ describe('longrunning', function() {
362384
done();
363385
});
364386
});
387+
388+
it('uses provided promise constructor', function(done) {
389+
var client = mockOperationsClient();
390+
var desc = new longrunning.LongrunningDescriptor(
391+
client, mockDecoder, mockDecoder);
392+
var initialRetryDelayMillis = 1;
393+
var retryDelayMultiplier = 2;
394+
var maxRetryDelayMillis = 3;
395+
var totalTimeoutMillis = 4;
396+
var unusedRpcValue = 0;
397+
var backoff = gax.createBackoffSettings(
398+
initialRetryDelayMillis,
399+
retryDelayMultiplier,
400+
maxRetryDelayMillis,
401+
unusedRpcValue,
402+
unusedRpcValue,
403+
unusedRpcValue,
404+
totalTimeoutMillis);
405+
var called = false;
406+
function MockPromise(executor) {
407+
var promise = new Promise(executor);
408+
called = true;
409+
return promise;
410+
}
411+
var operation = longrunning.operation(
412+
SUCCESSFUL_OP, desc, backoff, {promise: MockPromise});
413+
operation.promise();
414+
expect(called).to.be.true;
415+
done();
416+
});
365417
});
366418

367419
describe('cancel', function() {

0 commit comments

Comments
 (0)