diff --git a/packages/google-cloud-bigquery-storage/src/v1beta1/big_query_storage_client.ts b/packages/google-cloud-bigquery-storage/src/v1beta1/big_query_storage_client.ts index 5f41cbd976e..e85d0072dc2 100644 --- a/packages/google-cloud-bigquery-storage/src/v1beta1/big_query_storage_client.ts +++ b/packages/google-cloud-bigquery-storage/src/v1beta1/big_query_storage_client.ts @@ -43,8 +43,13 @@ export class BigQueryStorageClient { private _innerApiCalls: {[name: string]: Function}; private _pathTemplates: {[name: string]: gax.PathTemplate}; private _terminated = false; + private _opts: ClientOptions; + private _gaxModule: typeof gax | typeof gax.fallback; + private _gaxGrpc: gax.GrpcClient | gax.fallback.GrpcClient; + private _protos: {}; + private _defaults: {[method: string]: gax.CallSettings}; auth: gax.GoogleAuth; - bigQueryStorageStub: Promise<{[name: string]: Function}>; + bigQueryStorageStub?: Promise<{[name: string]: Function}>; /** * Construct an instance of BigQueryStorageClient. @@ -68,8 +73,6 @@ export class BigQueryStorageClient { * app is running in an environment which supports * {@link https://developers.google.com/identity/protocols/application-default-credentials Application Default Credentials}, * your project ID will be detected automatically. - * @param {function} [options.promise] - Custom promise module to use instead - * of native Promises. * @param {string} [options.apiEndpoint] - The domain name of the * API remote host. */ @@ -99,25 +102,28 @@ export class BigQueryStorageClient { // If we are in browser, we are already using fallback because of the // "browser" field in package.json. // But if we were explicitly requested to use fallback, let's do it now. - const gaxModule = !isBrowser && opts.fallback ? gax.fallback : gax; + this._gaxModule = !isBrowser && opts.fallback ? gax.fallback : gax; // Create a `gaxGrpc` object, with any grpc-specific options // sent to the client. opts.scopes = (this.constructor as typeof BigQueryStorageClient).scopes; - const gaxGrpc = new gaxModule.GrpcClient(opts); + this._gaxGrpc = new this._gaxModule.GrpcClient(opts); + + // Save options to use in initialize() method. + this._opts = opts; // Save the auth object to the client, for use by other methods. - this.auth = gaxGrpc.auth as gax.GoogleAuth; + this.auth = this._gaxGrpc.auth as gax.GoogleAuth; // Determine the client header string. - const clientHeader = [`gax/${gaxModule.version}`, `gapic/${version}`]; + const clientHeader = [`gax/${this._gaxModule.version}`, `gapic/${version}`]; if (typeof process !== 'undefined' && 'versions' in process) { clientHeader.push(`gl-node/${process.versions.node}`); } else { - clientHeader.push(`gl-web/${gaxModule.version}`); + clientHeader.push(`gl-web/${this._gaxModule.version}`); } if (!opts.fallback) { - clientHeader.push(`grpc/${gaxGrpc.grpcVersion}`); + clientHeader.push(`grpc/${this._gaxGrpc.grpcVersion}`); } if (opts.libName && opts.libVersion) { clientHeader.push(`${opts.libName}/${opts.libVersion}`); @@ -133,7 +139,7 @@ export class BigQueryStorageClient { 'protos', 'protos.json' ); - const protos = gaxGrpc.loadProto( + this._protos = this._gaxGrpc.loadProto( opts.fallback ? require('../../protos/protos.json') : nodejsProtoPath ); @@ -141,10 +147,10 @@ export class BigQueryStorageClient { // identifiers to uniquely identify resources within the API. // Create useful helper objects for these. this._pathTemplates = { - readSessionPathTemplate: new gaxModule.PathTemplate( + readSessionPathTemplate: new this._gaxModule.PathTemplate( 'projects/{project}/locations/{location}/sessions/{session}' ), - streamPathTemplate: new gaxModule.PathTemplate( + streamPathTemplate: new this._gaxModule.PathTemplate( 'projects/{project}/locations/{location}/streams/{stream}' ), }; @@ -152,11 +158,13 @@ export class BigQueryStorageClient { // Some of the methods on this service provide streaming responses. // Provide descriptors for these. this._descriptors.stream = { - readRows: new gaxModule.StreamDescriptor(gax.StreamType.SERVER_STREAMING), + readRows: new this._gaxModule.StreamDescriptor( + gax.StreamType.SERVER_STREAMING + ), }; // Put together the default options sent with requests. - const defaults = gaxGrpc.constructSettings( + this._defaults = this._gaxGrpc.constructSettings( 'google.cloud.bigquery.storage.v1beta1.BigQueryStorage', gapicConfig as gax.ClientConfig, opts.clientConfig || {}, @@ -167,17 +175,36 @@ export class BigQueryStorageClient { // of calling the API is handled in `google-gax`, with this code // merely providing the destination and request information. this._innerApiCalls = {}; + } + + /** + * Initialize the client. + * Performs asynchronous operations (such as authentication) and prepares the client. + * This function will be called automatically when any class method is called for the + * first time, but if you need to initialize it before calling an actual method, + * feel free to call initialize() directly. + * + * You can await on this method if you want to make sure the client is initialized. + * + * @returns {Promise} A promise that resolves to an authenticated service stub. + */ + initialize() { + // If the client stub promise is already initialized, return immediately. + if (this.bigQueryStorageStub) { + return this.bigQueryStorageStub; + } // Put together the "service stub" for // google.cloud.bigquery.storage.v1beta1.BigQueryStorage. - this.bigQueryStorageStub = gaxGrpc.createStub( - opts.fallback - ? (protos as protobuf.Root).lookupService( + this.bigQueryStorageStub = this._gaxGrpc.createStub( + this._opts.fallback + ? (this._protos as protobuf.Root).lookupService( 'google.cloud.bigquery.storage.v1beta1.BigQueryStorage' ) : // tslint:disable-next-line no-any - (protos as any).google.cloud.bigquery.storage.v1beta1.BigQueryStorage, - opts + (this._protos as any).google.cloud.bigquery.storage.v1beta1 + .BigQueryStorage, + this._opts ) as Promise<{[method: string]: Function}>; // Iterate over each of the methods that the service provides @@ -203,9 +230,9 @@ export class BigQueryStorageClient { } ); - const apiCall = gaxModule.createApiCall( + const apiCall = this._gaxModule.createApiCall( innerCallPromise, - defaults[methodName], + this._defaults[methodName], this._descriptors.page[methodName] || this._descriptors.stream[methodName] || this._descriptors.longrunning[methodName] @@ -219,6 +246,8 @@ export class BigQueryStorageClient { return apiCall(argument, callOptions, callback); }; } + + return this.bigQueryStorageStub; } /** @@ -386,6 +415,7 @@ export class BigQueryStorageClient { 'table_reference.project_id': request.tableReference!.projectId || '', 'table_reference.dataset_id': request.tableReference!.datasetId || '', }); + this.initialize(); return this._innerApiCalls.createReadSession(request, options, callback); } batchCreateReadSessionStreams( @@ -473,6 +503,7 @@ export class BigQueryStorageClient { ] = gax.routingHeader.fromParams({ 'session.name': request.session!.name || '', }); + this.initialize(); return this._innerApiCalls.batchCreateReadSessionStreams( request, options, @@ -570,6 +601,7 @@ export class BigQueryStorageClient { ] = gax.routingHeader.fromParams({ 'stream.name': request.stream!.name || '', }); + this.initialize(); return this._innerApiCalls.finalizeStream(request, options, callback); } splitReadStream( @@ -670,6 +702,7 @@ export class BigQueryStorageClient { ] = gax.routingHeader.fromParams({ 'original_stream.name': request.originalStream!.name || '', }); + this.initialize(); return this._innerApiCalls.splitReadStream(request, options, callback); } @@ -708,6 +741,7 @@ export class BigQueryStorageClient { ] = gax.routingHeader.fromParams({ 'read_position.stream.name': request.readPosition!.stream!.name || '', }); + this.initialize(); return this._innerApiCalls.readRows(request, options); } @@ -822,8 +856,9 @@ export class BigQueryStorageClient { * The client will no longer be usable and all future behavior is undefined. */ close(): Promise { + this.initialize(); if (!this._terminated) { - return this.bigQueryStorageStub.then(stub => { + return this.bigQueryStorageStub!.then(stub => { this._terminated = true; stub.close(); }); diff --git a/packages/google-cloud-bigquery-storage/synth.metadata b/packages/google-cloud-bigquery-storage/synth.metadata index 3600eb7341d..4d0b0a1a89b 100644 --- a/packages/google-cloud-bigquery-storage/synth.metadata +++ b/packages/google-cloud-bigquery-storage/synth.metadata @@ -1,13 +1,13 @@ { - "updateTime": "2020-03-05T12:45:42.538924Z", + "updateTime": "2020-03-05T23:02:10.150448Z", "sources": [ { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "638253bf86d1ce1c314108a089b7351440c2f0bf", - "internalRef": "298971070", - "log": "638253bf86d1ce1c314108a089b7351440c2f0bf\nfix: add java_multiple_files option for automl text_sentiment.proto\n\nPiperOrigin-RevId: 298971070\n\n373d655703bf914fb8b0b1cc4071d772bac0e0d1\nUpdate Recs AI Beta public bazel file\n\nPiperOrigin-RevId: 298961623\n\ndcc5d00fc8a8d8b56f16194d7c682027b2c66a3b\nfix: add java_multiple_files option for automl classification.proto\n\nPiperOrigin-RevId: 298953301\n\na3f791827266f3496a6a5201d58adc4bb265c2a3\nchore: automl/v1 publish annotations and retry config\n\nPiperOrigin-RevId: 298942178\n\n01c681586d8d6dbd60155289b587aee678530bd9\nMark return_immediately in PullRequest deprecated.\n\nPiperOrigin-RevId: 298893281\n\nc9f5e9c4bfed54bbd09227e990e7bded5f90f31c\nRemove out of date documentation for predicate support on the Storage API\n\nPiperOrigin-RevId: 298883309\n\nfd5b3b8238d783b04692a113ffe07c0363f5de0f\ngenerate webrisk v1 proto\n\nPiperOrigin-RevId: 298847934\n\n541b1ded4abadcc38e8178680b0677f65594ea6f\nUpdate cloud asset api v1p4beta1.\n\nPiperOrigin-RevId: 298686266\n\nc0d171acecb4f5b0bfd2c4ca34fc54716574e300\n Updated to include the Notification v1 API.\n\nPiperOrigin-RevId: 298652775\n\n2346a9186c0bff2c9cc439f2459d558068637e05\nAdd Service Directory v1beta1 protos and configs\n\nPiperOrigin-RevId: 298625638\n\n" + "sha": "f0b581b5bdf803e45201ecdb3688b60e381628a8", + "internalRef": "299181282", + "log": "f0b581b5bdf803e45201ecdb3688b60e381628a8\nfix: recommendationengine/v1beta1 update some comments\n\nPiperOrigin-RevId: 299181282\n\n10e9a0a833dc85ff8f05b2c67ebe5ac785fe04ff\nbuild: add generated BUILD file for Routes Preferred API\n\nPiperOrigin-RevId: 299164808\n\n86738c956a8238d7c77f729be78b0ed887a6c913\npublish v1p1beta1: update with absolute address in comments\n\nPiperOrigin-RevId: 299152383\n\n73d9f2ad4591de45c2e1f352bc99d70cbd2a6d95\npublish v1: update with absolute address in comments\n\nPiperOrigin-RevId: 299147194\n\nd2158f24cb77b0b0ccfe68af784c6a628705e3c6\npublish v1beta2: update with absolute address in comments\n\nPiperOrigin-RevId: 299147086\n\n7fca61292c11b4cd5b352cee1a50bf88819dd63b\npublish v1p2beta1: update with absolute address in comments\n\nPiperOrigin-RevId: 299146903\n\n583b7321624736e2c490e328f4b1957335779295\npublish v1p3beta1: update with absolute address in comments\n\nPiperOrigin-RevId: 299146674\n\n" } }, { diff --git a/packages/google-cloud-bigquery-storage/test/gapic-big_query_storage-v1beta1.ts b/packages/google-cloud-bigquery-storage/test/gapic-big_query_storage-v1beta1.ts index 4b9fa589b7a..28001512c10 100644 --- a/packages/google-cloud-bigquery-storage/test/gapic-big_query_storage-v1beta1.ts +++ b/packages/google-cloud-bigquery-storage/test/gapic-big_query_storage-v1beta1.ts @@ -105,12 +105,30 @@ describe('v1beta1.BigQueryStorageClient', () => { }); assert(client); }); + it('has initialize method and supports deferred initialization', async () => { + const client = new bigquerystorageModule.v1beta1.BigQueryStorageClient({ + credentials: {client_email: 'bogus', private_key: 'bogus'}, + projectId: 'bogus', + }); + assert.strictEqual(client.bigQueryStorageStub, undefined); + await client.initialize(); + assert(client.bigQueryStorageStub); + }); + it('has close method', () => { + const client = new bigquerystorageModule.v1beta1.BigQueryStorageClient({ + credentials: {client_email: 'bogus', private_key: 'bogus'}, + projectId: 'bogus', + }); + client.close(); + }); describe('createReadSession', () => { it('invokes createReadSession without error', done => { const client = new bigquerystorageModule.v1beta1.BigQueryStorageClient({ credentials: {client_email: 'bogus', private_key: 'bogus'}, projectId: 'bogus', }); + // Initialize client before mocking + client.initialize(); // Mock request const request: protosTypes.google.cloud.bigquery.storage.v1beta1.ICreateReadSessionRequest = {}; request.tableReference = {}; @@ -137,6 +155,8 @@ describe('v1beta1.BigQueryStorageClient', () => { credentials: {client_email: 'bogus', private_key: 'bogus'}, projectId: 'bogus', }); + // Initialize client before mocking + client.initialize(); // Mock request const request: protosTypes.google.cloud.bigquery.storage.v1beta1.ICreateReadSessionRequest = {}; request.tableReference = {}; @@ -165,6 +185,8 @@ describe('v1beta1.BigQueryStorageClient', () => { credentials: {client_email: 'bogus', private_key: 'bogus'}, projectId: 'bogus', }); + // Initialize client before mocking + client.initialize(); // Mock request const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IBatchCreateReadSessionStreamsRequest = {}; request.session = {}; @@ -189,6 +211,8 @@ describe('v1beta1.BigQueryStorageClient', () => { credentials: {client_email: 'bogus', private_key: 'bogus'}, projectId: 'bogus', }); + // Initialize client before mocking + client.initialize(); // Mock request const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IBatchCreateReadSessionStreamsRequest = {}; request.session = {}; @@ -218,6 +242,8 @@ describe('v1beta1.BigQueryStorageClient', () => { credentials: {client_email: 'bogus', private_key: 'bogus'}, projectId: 'bogus', }); + // Initialize client before mocking + client.initialize(); // Mock request const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IFinalizeStreamRequest = {}; request.stream = {}; @@ -242,6 +268,8 @@ describe('v1beta1.BigQueryStorageClient', () => { credentials: {client_email: 'bogus', private_key: 'bogus'}, projectId: 'bogus', }); + // Initialize client before mocking + client.initialize(); // Mock request const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IFinalizeStreamRequest = {}; request.stream = {}; @@ -268,6 +296,8 @@ describe('v1beta1.BigQueryStorageClient', () => { credentials: {client_email: 'bogus', private_key: 'bogus'}, projectId: 'bogus', }); + // Initialize client before mocking + client.initialize(); // Mock request const request: protosTypes.google.cloud.bigquery.storage.v1beta1.ISplitReadStreamRequest = {}; request.originalStream = {}; @@ -292,6 +322,8 @@ describe('v1beta1.BigQueryStorageClient', () => { credentials: {client_email: 'bogus', private_key: 'bogus'}, projectId: 'bogus', }); + // Initialize client before mocking + client.initialize(); // Mock request const request: protosTypes.google.cloud.bigquery.storage.v1beta1.ISplitReadStreamRequest = {}; request.originalStream = {}; @@ -318,6 +350,8 @@ describe('v1beta1.BigQueryStorageClient', () => { credentials: {client_email: 'bogus', private_key: 'bogus'}, projectId: 'bogus', }); + // Initialize client before mocking + client.initialize(); // Mock request const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IReadRowsRequest = {}; request.readPosition = {}; @@ -346,6 +380,8 @@ describe('v1beta1.BigQueryStorageClient', () => { credentials: {client_email: 'bogus', private_key: 'bogus'}, projectId: 'bogus', }); + // Initialize client before mocking + client.initialize(); // Mock request const request: protosTypes.google.cloud.bigquery.storage.v1beta1.IReadRowsRequest = {}; request.readPosition = {};