diff --git a/src/index.ts b/src/index.ts index 93ecd1050..94d538e76 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,6 +40,7 @@ import { PagedCallback, PagedOptionsWithFilter, CLOUD_RESOURCE_HEADER, + NormalCallback, } from './common'; import {Session} from './session'; import {SessionPool} from './session-pool'; @@ -75,6 +76,12 @@ export type GetInstanceConfigsCallback = PagedCallback< instanceAdmin.spanner.admin.instance.v1.IListInstanceConfigsResponse >; +export interface GetInstanceConfigOptions { + gaxOptions?: CallOptions; +} +export type GetInstanceConfigResponse = [IInstanceConfig]; +export type GetInstanceConfigCallback = NormalCallback; + export interface SpannerOptions extends GrpcClientOptions { apiEndpoint?: string; servicePath?: string; @@ -682,6 +689,9 @@ class Spanner extends GrpcService { * @property {string} 0.name The unique identifier for the instance config. * @property {string} 0.displayName The name of the instance config as it * appears in UIs. + * @property {google.spanner.admin.instance.v1.IReplicaInfo[]} 0.replicas The replicas used by + * this instance config. + * @property {string[]} 0.leaderOptions The possible leader options for this instance config. * @property {object} 1 A query object to receive more results. * @property {object} 2 The full API response. */ @@ -693,6 +703,9 @@ class Spanner extends GrpcService { * config. * @param {string} instanceConfigs.displayName The name of the instance config * as it appears in UIs. + * @param {google.spanner.admin.instance.v1.IReplicaInfo[]} instanceConfigs.replicas The replicas used by + * this instance config. + * @param {string[]} instanceConfigs.leaderOptions The possible leader options for this instance config. * @param {object} nextQuery A query object to receive more results. * @param {object} apiResponse The full API response. */ @@ -857,6 +870,103 @@ class Spanner extends GrpcService { }); } + getInstanceConfig(name: string): Promise; + getInstanceConfig( + name: string, + options: GetInstanceConfigOptions + ): Promise; + getInstanceConfig(name: string, callback: GetInstanceConfigCallback): void; + getInstanceConfig( + name: string, + options: GetInstanceConfigOptions, + callback: GetInstanceConfigCallback + ): void; + /** + * Gets the instance configuration with the specified name. + */ + /** + * @typedef {array} GetInstanceConfigResponse + * @property {object[]} 0 The metadata of the instance config. + * @property {string} 0.name The unique identifier for the instance config. + * @property {string} 0.displayName The name of the instance config as it + * appears in UIs. + * @property {google.spanner.admin.instance.v1.IReplicaInfo[]} 0.replicas The replicas used by + * this instance config. + * @property {string[]} 0.leaderOptions The possible leader options for this instance config. + */ + /** + * @callback GetInstanceConfigCallback + * @param {?Error} err Request error, if any. + * @param {object} instanceConfig The metadata of the instance config. + * @param {string} instanceConfig.name The unique identifier for the instance + * config. + * @param {string} instanceConfig.displayName The name of the instance config + * as it appears in UIs. + * @param {google.spanner.admin.instance.v1.IReplicaInfo[]} instanceConfig.replicas The replicas used by + * this instance config. + * @param {string[]} 0.leaderOptions The possible leader options for this instance config. + */ + /** + * Get a specific instance config. + * + * Wrapper around {@link v1.InstanceAdminClient#getInstanceConfig}. + * + * @see {@link v1.InstanceAdminClient#getInstanceConfig} + * @see [GetInstanceConfig API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.GetInstanceConfig) + * + * @param {string} [name] The name of the instance config to get. + * @param {GetInstanceConfigCallback} [callback] Callback function. + * @returns {Promise} + * + * @example + * const {Spanner} = require('@google-cloud/spanner'); + * const spanner = new Spanner(); + * + * spanner.getInstanceConfig('nam6', function(err, instanceConfig) { + * // `instanceConfig` is an instance configuration descriptor. + * }); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * spanner.getInstanceConfig().then(function(data) { + * const instanceConfig = data[0]; + * }); + */ + getInstanceConfig( + name: string, + optionsOrCallback?: GetInstanceConfigOptions | GetInstanceConfigCallback, + cb?: GetInstanceConfigCallback + ): Promise | void { + const callback = + typeof optionsOrCallback === 'function' ? optionsOrCallback : cb; + const options = + typeof optionsOrCallback === 'object' + ? optionsOrCallback + : ({} as GetInstanceConfigOptions); + + const reqOpts = extend( + {}, + { + name: 'projects/' + this.projectId + '/instanceConfigs/' + name, + } + ); + const gaxOpts = extend({}, options.gaxOptions); + + return this.request( + { + client: 'InstanceAdminClient', + method: 'getInstanceConfig', + reqOpts, + gaxOpts, + headers: this.resourceHeader_, + }, + (err, instanceConfig) => { + callback!(err, instanceConfig); + } + ); + } + /** * Get a reference to an Instance object. * @@ -1290,5 +1400,6 @@ export {Transaction}; * Reference to {@link v1.SpannerClient} */ import * as protos from '../protos/protos'; +import IInstanceConfig = instanceAdmin.spanner.admin.instance.v1.IInstanceConfig; export {v1, protos}; export default {Spanner}; diff --git a/system-test/spanner.ts b/system-test/spanner.ts index 8bfae4fcb..e95d4765b 100644 --- a/system-test/spanner.ts +++ b/system-test/spanner.ts @@ -933,6 +933,31 @@ describe('Spanner', () => { }) ); }); + + it('should get an instanceConfig', function (done) { + if (IS_EMULATOR_ENABLED) { + this.skip(); + } + spanner.getInstanceConfig('nam6', (err, instanceConfig) => { + assert.ifError(err); + assert(instanceConfig!.displayName); + done(); + }); + }); + + it('should get an instanceConfig in promise mode', function (done) { + if (IS_EMULATOR_ENABLED) { + this.skip(); + } + spanner + .getInstanceConfig('nam6') + .then(data => { + const instanceConfig = data[0]; + assert(instanceConfig.displayName); + done(); + }) + .catch(done); + }); }); describe('Databases', () => { diff --git a/test/index.ts b/test/index.ts index 2a3aad6a0..92a4a9e7d 100644 --- a/test/index.ts +++ b/test/index.ts @@ -31,7 +31,11 @@ import * as sinon from 'sinon'; import * as spnr from '../src'; import {Duplex} from 'stream'; import {CreateInstanceRequest} from '../src/index'; -import {GetInstanceConfigsOptions, GetInstancesOptions} from '../src'; +import { + GetInstanceConfigOptions, + GetInstanceConfigsOptions, + GetInstancesOptions, +} from '../src'; import {CLOUD_RESOURCE_HEADER} from '../src/common'; // Verify that CLOUD_RESOURCE_HEADER is set to a correct value. @@ -1286,6 +1290,61 @@ describe('Spanner', () => { }); }); + describe('getInstanceConfig', () => { + beforeEach(() => { + spanner.request = util.noop; + }); + + it('should make and return the correct request', () => { + const options: GetInstanceConfigOptions = { + gaxOptions: {timeout: 5}, + }; + const expectedReqOpts = { + name: `projects/${spanner.projectId}/instanceConfigs/nam1`, + }; + + function callback() {} + + const returnValue = {}; + + spanner.request = config => { + assert.strictEqual(config.client, 'InstanceAdminClient'); + assert.strictEqual(config.method, 'getInstanceConfig'); + + const reqOpts = config.reqOpts; + assert.deepStrictEqual(reqOpts, expectedReqOpts); + assert.notStrictEqual(reqOpts, options); + + const gaxOpts = config.gaxOpts; + assert.deepStrictEqual(gaxOpts, options.gaxOptions); + assert.deepStrictEqual(config.headers, spanner.resourceHeader_); + + return returnValue; + }; + + const returnedValue = spanner.getInstanceConfig( + 'nam1', + options, + callback + ); + assert.strictEqual(returnedValue, returnValue); + }); + + it('should not require options', done => { + spanner.request = config => { + const reqOpts = config.reqOpts; + assert.deepStrictEqual(reqOpts, { + name: `projects/${spanner.projectId}/instanceConfigs/nam1`, + }); + assert.deepStrictEqual(config.gaxOpts, {}); + + done(); + }; + + spanner.getInstanceConfig('nam1', assert.ifError); + }); + }); + describe('instance', () => { const NAME = 'instance-name';