From 9f997cb78fa6102519f900f31996e588b3c3fb4e Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 24 Apr 2020 11:35:30 -0400 Subject: [PATCH 01/17] fix(types)!: listing methods in index.ts --- src/common.ts | 16 +++--- src/database.ts | 6 ++- src/index.ts | 116 +++++++++++++++++++++-------------------- src/instance.ts | 20 +++---- system-test/spanner.ts | 2 +- test/index.ts | 55 ++++++++++--------- test/spanner.ts | 3 +- 7 files changed, 113 insertions(+), 105 deletions(-) diff --git a/src/common.ts b/src/common.ts index 6df373f86..bf01486c8 100644 --- a/src/common.ts +++ b/src/common.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import {ServiceError, CallOptions} from 'grpc'; -import {Operation as GaxOperation} from 'google-gax'; +import {ServiceError} from 'grpc'; +import {Operation as GaxOperation, CallOptions} from 'google-gax'; import {google as instanceAdmin} from '../protos/protos'; import {google as databaseAdmin} from '../protos/protos'; @@ -33,9 +33,7 @@ export interface ResourceCallback { response?: Response ): void; } -export type PagedResponse = - | [Item[]] - | [Item[], {} | null, Response]; +export type PagedResponse = [Item[], {} | null, Response]; export type RequestCallback = R extends void ? NormalCallback @@ -63,8 +61,8 @@ export interface LongRunningCallback { ): void; } -export type PagedRequest

= P & { - autoPaginate?: boolean; - maxApiCalls?: number; +export interface PagedOptions { + pageSize?: number; + pageToken?: string; gaxOptions?: CallOptions; -}; +} diff --git a/src/database.ts b/src/database.ts index 4874e0a51..ede94b5cf 100644 --- a/src/database.ts +++ b/src/database.ts @@ -71,7 +71,7 @@ import { IOperation, Schema, RequestCallback, - PagedRequest, + PagedOptions, ResourceCallback, PagedResponse, NormalCallback, @@ -120,7 +120,9 @@ type PoolRequestCallback = RequestCallback; type ResultSetStats = spannerClient.spanner.v1.ResultSetStats; -type GetSessionsOptions = PagedRequest; +interface GetSessionsOptions extends PagedOptions { + filter?: string; +} /** * IDatabase structure with database state enum translated to string form. diff --git a/src/index.ts b/src/index.ts index d8c6b861a..57ab57c5f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,7 +21,6 @@ import {replaceProjectIdToken} from '@google-cloud/projectify'; import {promisifyAll} from '@google-cloud/promisify'; import * as extend from 'extend'; import {GoogleAuth, GoogleAuthOptions} from 'google-auth-library'; -import * as is from 'is'; import * as path from 'path'; import {common as p} from 'protobufjs'; import * as streamEvents from 'stream-events'; @@ -35,7 +34,7 @@ import { CreateInstanceResponse, } from './instance'; import {google as instanceAdmin} from '../protos/protos'; -import {PagedRequest, PagedResponse, PagedCallback} from './common'; +import {PagedOptions, PagedResponse, PagedCallback} from './common'; import {Session} from './session'; import {SessionPool} from './session-pool'; import {Table} from './table'; @@ -55,11 +54,9 @@ const gcpApiConfig = require('./spanner_grpc_config.json'); export type IOperation = instanceAdmin.longrunning.IOperation; -export type GetInstancesRequest = PagedRequest< - instanceAdmin.spanner.admin.instance.v1.IListInstancesRequest & { - maxResults?: number; - } ->; +export interface GetInstancesOptions extends PagedOptions { + filter?: string; +} export type GetInstancesResponse = PagedResponse< Instance, instanceAdmin.spanner.admin.instance.v1.IListInstancesResponse @@ -69,11 +66,7 @@ export type GetInstancesCallback = PagedCallback< instanceAdmin.spanner.admin.instance.v1.IListInstancesResponse >; -export type GetInstanceConfigsRequest = PagedRequest< - instanceAdmin.spanner.admin.instance.v1.IListInstanceConfigsRequest & { - maxResults?: number; - } ->; +export type GetInstanceConfigsOptions = PagedOptions; export type GetInstanceConfigsResponse = PagedResponse< instanceAdmin.spanner.admin.instance.v1.InstanceConfig, instanceAdmin.spanner.admin.instance.v1.IListInstanceConfigsResponse @@ -272,7 +265,7 @@ class Spanner extends GrpcService { * @see [ListInstances API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstances) * * @method Spanner#getInstancesStream - * @param {GetInstancesRequest} [query] Query object for listing instances. + * @param {GetInstancesOptions} [options] Query object for listing instances. * @returns {ReadableStream} A readable stream that emits {@link Instance} * instances. * @@ -442,18 +435,18 @@ class Spanner extends GrpcService { ); } - getInstances(query?: GetInstancesRequest): Promise; + getInstances(options?: GetInstancesOptions): Promise; getInstances(callback: GetInstancesCallback): void; getInstances( - query: GetInstancesRequest, + query: GetInstancesOptions, callback: GetInstancesCallback ): void; /** * Query object for listing instances. * - * @typedef {object} GetInstancesRequest - * @property {boolean} [autoPaginate=true] Have pagination handled - * automatically. + * @typedef {object} GetInstancesOptions + * @property {object} [gaxOptions] Request configuration options, outlined + * here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions. * @property {string} [filter] An expression for filtering the results of the * request. Filter rules are case insensitive. The fields eligible for * filtering are: @@ -468,8 +461,6 @@ class Spanner extends GrpcService { * - **`labels.env:dev`** The instance's label env has the value dev. * - **`name:howl labels.env:dev`** The instance's name is howl and it has * the label env with value dev. - * @property {number} [maxApiCalls] Maximum number of API calls to make. - * @property {number} [maxResults] Maximum number of items to return. * @property {number} [pageSize] Maximum number of results per page. * @property {string} [pageToken] A previously-returned page token * representing part of the larger set of results to view. @@ -477,12 +468,14 @@ class Spanner extends GrpcService { /** * @typedef {array} GetInstancesResponse * @property {Instance[]} 0 Array of {@link Instance} instances. + * @param {object} nextQuery A query object to to receive more results. * @property {object} 1 The full API response. */ /** * @callback GetInstancesCallback * @param {?Error} err Request error, if any. * @param {Instance[]} instances Array of {@link Instance} instances. + * @param {string} nextQuery A query object to to receive more results. * @param {object} apiResponse The full API response. */ /** @@ -493,7 +486,7 @@ class Spanner extends GrpcService { * @see {@link v1.InstanceAdminClient#listInstances} * @see [ListInstances API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstances) * - * @param {GetInstancesRequest} [query] Query object for listing instances. + * @param {GetInstancesOptions} [options] Query object for listing instances. * @param {GetInstancesCallback} [callback] Callback function. * @returns {Promise} * @@ -517,7 +510,9 @@ class Spanner extends GrpcService { * } * * spanner.getInstances({ - * autoPaginate: false + * gaxOptions: { + * autoPaginate: false, + * } * }, callback); * * //- @@ -528,24 +523,30 @@ class Spanner extends GrpcService { * }); */ getInstances( - query?: GetInstancesRequest | GetInstancesCallback, - callback?: GetInstancesCallback + optionsOrCallback?: GetInstancesOptions | GetInstancesCallback, + cb?: GetInstancesCallback ): Promise | void { // eslint-disable-next-line @typescript-eslint/no-this-alias const self = this; - if (is.fn(query)) { - callback = query as GetInstancesCallback; - query = {}; - } - const reqOpts = extend({}, query, { + const options = + typeof optionsOrCallback === 'object' + ? optionsOrCallback + : ({} as GetInstancesOptions); + const callback = + typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!; + + const reqOpts = extend({}, options, { parent: 'projects/' + this.projectId, }); + + delete reqOpts.gaxOptions; + this.request( { client: 'InstanceAdminClient', method: 'listInstances', reqOpts, - gaxOpts: query, + gaxOpts: options.gaxOptions, }, (err, instances, ...args) => { let instanceInstances: Instance[] | null = null; @@ -562,24 +563,23 @@ class Spanner extends GrpcService { } getInstanceConfigs( - query?: GetInstanceConfigsRequest + query?: GetInstanceConfigsOptions ): Promise; getInstanceConfigs(callback: GetInstanceConfigsCallback): void; getInstanceConfigs( - query: GetInstanceConfigsRequest, + query: GetInstanceConfigsOptions, callback: GetInstanceConfigsCallback ): void; /** - * Query object for listing instance configs. + * Lists the supported instance configurations for a given project. * - * @typedef {object} GetInstanceConfigsRequest - * @property {boolean} [autoPaginate=true] Have pagination handled - * automatically. - * @property {number} [maxApiCalls] Maximum number of API calls to make. - * @property {number} [maxResults] Maximum number of items to return. + * @typedef {object} GetInstanceConfigsOptions * @property {number} [pageSize] Maximum number of results per page. * @property {string} [pageToken] A previously-returned page token * representing part of the larger set of results to view. + * @property {object} [gaxOptions] Request configuration options, outlined + * here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions. + */ /** * @typedef {array} GetInstanceConfigsResponse @@ -587,6 +587,7 @@ 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. + * @param {object} nextQuery A query object to to receive more results. * @property {object} 1 The full API response. */ /** @@ -597,7 +598,7 @@ class Spanner extends GrpcService { * config. * @param {string} instanceConfigs.displayName The name of the instance config * as it appears in UIs. - * @param {object} apiResponse The full API response. + * @param {object} nextQuery A query object to to receive more results. * @param {object} apiResponse The full API response. */ /** * Get a list of instance configs. @@ -607,7 +608,7 @@ class Spanner extends GrpcService { * @see {@link v1.InstanceAdminClient#listInstanceConfigs} * @see [ListInstanceConfigs API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstanceConfigs) * - * @param {GetInstanceConfigsRequest} [query] Query object for listing instance + * @param {GetInstanceConfigsOptions} [options] Query object for listing instance * configs. * @param {GetInstanceConfigsCallback} [callback] Callback function. * @returns {Promise} @@ -632,7 +633,9 @@ class Spanner extends GrpcService { * } * * spanner.getInstanceConfigs({ - * autoPaginate: false + * gaxOptions: { + * autoPaginate: false, + * } * }, callback); * * //- @@ -643,26 +646,26 @@ class Spanner extends GrpcService { * }); */ getInstanceConfigs( - queryOrCallback?: GetInstanceConfigsRequest | GetInstanceConfigsCallback, + optionsOrCallback?: GetInstanceConfigsOptions | GetInstanceConfigsCallback, cb?: GetInstanceConfigsCallback ): Promise | void { const callback = - typeof queryOrCallback === 'function' - ? (queryOrCallback as GetInstanceConfigsCallback) - : cb; - const query = - typeof queryOrCallback === 'object' - ? (queryOrCallback as GetInstanceConfigsRequest) - : {}; - const reqOpts = extend({}, query, { + typeof optionsOrCallback === 'function' ? optionsOrCallback : cb; + const options = + typeof optionsOrCallback === 'object' + ? optionsOrCallback + : ({} as GetInstanceConfigsOptions); + const reqOpts = extend({}, options, { parent: 'projects/' + this.projectId, }); + delete reqOpts.gaxOptions; + return this.request( { client: 'InstanceAdminClient', method: 'listInstanceConfigs', reqOpts, - gaxOpts: query, + gaxOpts: options.gaxOptions, }, callback ); @@ -677,7 +680,7 @@ class Spanner extends GrpcService { * @see [ListInstanceConfigs API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstanceConfigs) * * @method Spanner#getInstanceConfigsStream - * @param {GetInstanceConfigsRequest} [query] Query object for listing instance + * @param {GetInstanceConfigsOptions} [options] Query object for listing instance * configs. * @returns {ReadableStream} A readable stream that emits instance configs. * @@ -702,16 +705,17 @@ class Spanner extends GrpcService { * }); */ getInstanceConfigsStream( - query?: GetInstanceConfigsRequest + options?: GetInstanceConfigsOptions ): NodeJS.ReadableStream { - const reqOpts = extend({}, query, { + const reqOpts = extend({}, options, { parent: 'projects/' + this.projectId, }); + delete reqOpts.gaxOptions; return this.requestStream({ client: 'InstanceAdminClient', method: 'listInstanceConfigsStream', reqOpts, - gaxOpts: query, + gaxOpts: options?.gaxOptions, }); } @@ -783,7 +787,7 @@ class Spanner extends GrpcService { */ // eslint-disable-next-line @typescript-eslint/no-explicit-any request(config: any, callback?: any): any { - if (is.fn(callback)) { + if (typeof callback === 'function') { this.prepareGapicRequest_(config, (err, requestFn) => { if (err) { callback(err); diff --git a/src/instance.ts b/src/instance.ts index 0a060ff50..b6b213633 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -27,7 +27,7 @@ import {Spanner, RequestConfig} from '.'; import {CallOptions, ServiceError} from 'grpc'; import { RequestCallback, - PagedRequest, + PagedOptions, PagedResponse, LongRunningCallback, NormalCallback, @@ -102,23 +102,23 @@ export type SetInstanceMetadataCallback = ResourceCallback< GaxOperation, IOperation >; -export type GetBackupsOptions = PagedRequest< - databaseAdmin.spanner.admin.database.v1.IListBackupsRequest ->; +export interface GetBackupsOptions extends PagedOptions { + filter?: string; +} export type GetBackupsCallback = RequestCallback< Backup, databaseAdmin.spanner.admin.database.v1.IListBackupsResponse >; -export type GetBackupOperationsOptions = PagedRequest< - databaseAdmin.spanner.admin.database.v1.IListBackupOperationsRequest ->; +export interface GetBackupOperationsOptions extends PagedOptions { + filter?: string; +} export type GetBackupOperationsCallback = RequestCallback< IOperation, databaseAdmin.spanner.admin.database.v1.IListBackupOperationsResponse >; -export type GetDatabaseOperationsOptions = PagedRequest< - databaseAdmin.spanner.admin.database.v1.IListDatabaseOperationsRequest ->; +export interface GetDatabaseOperationsOptions extends PagedOptions { + filter?: string; +} export type GetDatabaseOperationsCallback = RequestCallback< IOperation, databaseAdmin.spanner.admin.database.v1.IListDatabaseOperationsResponse diff --git a/system-test/spanner.ts b/system-test/spanner.ts index 3fc00dab3..5638a1d0b 100644 --- a/system-test/spanner.ts +++ b/system-test/spanner.ts @@ -1135,7 +1135,7 @@ describe('Spanner', () => { }); const [page2] = await instance.getBackups({ pageSize: 1, - pageToken: resp1!.nextPageToken, + pageToken: resp1!.nextPageToken!, gaxOptions: {autoPaginate: false}, }); const [page3] = await instance.getBackups({ diff --git a/test/index.ts b/test/index.ts index 65c686634..fa9fca5f9 100644 --- a/test/index.ts +++ b/test/index.ts @@ -30,7 +30,7 @@ import * as sinon from 'sinon'; import * as spnr from '../src'; import * as grpc from 'grpc'; import {CreateInstanceRequest} from '../src/index'; -import {GetInstanceConfigsRequest, GetInstancesRequest} from '../src'; +import {GetInstanceConfigsOptions, GetInstancesOptions} from '../src'; // eslint-disable-next-line @typescript-eslint/no-var-requires const apiConfig = require('../src/spanner_grpc_config.json'); @@ -646,17 +646,17 @@ describe('Spanner', () => { }); describe('getInstances', () => { - const QUERY = { - a: 'b', + const OPTIONS: GetInstancesOptions = { + filter: 'b', }; - const ORIGINAL_QUERY = extend({}, QUERY); + const ORIGINAL_OPTIONS = extend({}, OPTIONS); beforeEach(() => { spanner.request = util.noop; }); it('should make the correct request', done => { - const expectedReqOpts = extend({}, QUERY, { + const expectedReqOpts = extend({}, OPTIONS, { parent: 'projects/' + spanner.projectId, }); @@ -665,15 +665,15 @@ describe('Spanner', () => { assert.strictEqual(config.method, 'listInstances'); assert.deepStrictEqual(config.reqOpts, expectedReqOpts); - assert.notStrictEqual(config.reqOpts, QUERY); - assert.deepStrictEqual(QUERY, ORIGINAL_QUERY); + assert.notStrictEqual(config.reqOpts, OPTIONS); + assert.deepStrictEqual(OPTIONS, ORIGINAL_OPTIONS); - assert.strictEqual(config.gaxOpts, QUERY); + assert.strictEqual(config.gaxOpts, OPTIONS.gaxOptions); done(); }; - spanner.getInstances(QUERY as GetInstancesRequest, assert.ifError); + spanner.getInstances(OPTIONS as GetInstancesOptions, assert.ifError); }); it('should not require a query', done => { @@ -682,7 +682,7 @@ describe('Spanner', () => { parent: 'projects/' + spanner.projectId, }); - assert.deepStrictEqual(config.gaxOpts, {}); + assert.strictEqual(config.gaxOpts, undefined); done(); }; @@ -700,7 +700,7 @@ describe('Spanner', () => { }); it('should execute callback with original arguments', done => { - spanner.getInstances(QUERY as GetInstancesRequest, (...args) => { + spanner.getInstances(OPTIONS as GetInstancesOptions, (...args) => { assert.deepStrictEqual(args, GAX_RESPONSE_ARGS); done(); }); @@ -730,7 +730,7 @@ describe('Spanner', () => { return fakeInstanceInstance; }; - spanner.getInstances(QUERY as GetInstancesRequest, (...args) => { + spanner.getInstances(OPTIONS as GetInstancesOptions, (...args) => { assert.ifError(args[0]); assert.strictEqual(args[0], GAX_RESPONSE_ARGS[0]); const instance = args[1]!.pop(); @@ -749,10 +749,14 @@ describe('Spanner', () => { }); it('should make and return the correct request', () => { - const query = {a: 'b'}; - const expectedQuery = extend({}, query, { + const options: GetInstanceConfigsOptions = { + pageSize: 5, + gaxOptions: {autoPaginate: false}, + }; + const expectedQuery = extend({}, options, { parent: 'projects/' + spanner.projectId, }); + delete expectedQuery.gaxOptions; function callback() {} @@ -764,20 +768,17 @@ describe('Spanner', () => { const reqOpts = config.reqOpts; assert.deepStrictEqual(reqOpts, expectedQuery); - assert.notStrictEqual(reqOpts, query); + assert.notStrictEqual(reqOpts, options); const gaxOpts = config.gaxOpts; - assert.strictEqual(gaxOpts, query); + assert.strictEqual(gaxOpts, options.gaxOptions); assert.strictEqual(callback_, callback); return returnValue; }; - const returnedValue = spanner.getInstanceConfigs( - query as GetInstanceConfigsRequest, - callback - ); + const returnedValue = spanner.getInstanceConfigs(options, callback); assert.strictEqual(returnedValue, returnValue); }); @@ -800,10 +801,14 @@ describe('Spanner', () => { }); it('should make and return the correct gax API call', () => { - const query = {a: 'b'}; - const expectedQuery = extend({}, query, { + const options: GetInstanceConfigsOptions = { + pageSize: 5, + gaxOptions: {autoPaginate: false}, + }; + const expectedQuery = extend({}, options, { parent: 'projects/' + spanner.projectId, }); + delete expectedQuery.gaxOptions; const returnValue = {}; spanner.requestStream = config => { @@ -812,16 +817,16 @@ describe('Spanner', () => { const reqOpts = config.reqOpts; assert.deepStrictEqual(reqOpts, expectedQuery); - assert.notStrictEqual(reqOpts, query); + assert.notStrictEqual(reqOpts, options); const gaxOpts = config.gaxOpts; - assert.strictEqual(gaxOpts, query); + assert.strictEqual(gaxOpts, options.gaxOptions); return returnValue; }; const returnedValue = spanner.getInstanceConfigsStream( - query as GetInstanceConfigsRequest + options as GetInstanceConfigsOptions ); assert.strictEqual(returnedValue, returnValue); }); diff --git a/test/spanner.ts b/test/spanner.ts index aff073eb3..7a1b7ce11 100644 --- a/test/spanner.ts +++ b/test/spanner.ts @@ -1973,14 +1973,13 @@ describe('Spanner with mock server', () => { it('should cap results', async () => { const [instances] = await spanner.getInstances({ - maxResults: 1, + gaxOptions: {maxResults: 1}, }); assert.strictEqual(instances.length, 1); }); it('should maximize api calls', async () => { const [instances] = await spanner.getInstances({ - maxApiCalls: 1, pageSize: 1, }); assert.strictEqual(instances.length, 1); From 4ff9eede7659c22c6701ddff304efb5ff2058d65 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 24 Apr 2020 13:47:49 -0400 Subject: [PATCH 02/17] fix(types): listing methods in instance.ts --- src/backup.ts | 4 +- src/database.ts | 31 +++++++---- src/index.ts | 4 +- src/instance.ts | 136 ++++++++++++++++++++++++++--------------------- test/database.ts | 7 +-- test/instance.ts | 16 +++--- 6 files changed, 111 insertions(+), 87 deletions(-) diff --git a/src/backup.ts b/src/backup.ts index 175b218f4..992dfdd4d 100644 --- a/src/backup.ts +++ b/src/backup.ts @@ -22,9 +22,9 @@ import { ResourceCallback, } from './common'; import {EnumKey, Spanner, RequestConfig, TranslateEnumKeys} from '.'; -import {Metadata, Operation as GaxOperation} from 'google-gax'; +import {Metadata, Operation as GaxOperation, CallOptions} from 'google-gax'; import {DateStruct, PreciseDate} from '@google-cloud/precise-date'; -import {CallOptions, status} from 'grpc'; +import {status} from 'grpc'; import {google as databaseAdmin} from '../protos/protos'; import {common as p} from 'protobufjs'; diff --git a/src/database.ts b/src/database.ts index ede94b5cf..078296ab7 100644 --- a/src/database.ts +++ b/src/database.ts @@ -28,7 +28,7 @@ import * as extend from 'extend'; import * as r from 'teeny-request'; import * as streamEvents from 'stream-events'; import * as through from 'through2'; -import {Operation as GaxOperation} from 'google-gax'; +import {Operation as GaxOperation, CallOptions} from 'google-gax'; import {Backup} from './backup'; import {BatchTransaction, TransactionIdentifier} from './batch-transaction'; import {google as databaseAdmin} from '../protos/protos'; @@ -77,7 +77,7 @@ import { NormalCallback, LongRunningCallback, } from './common'; -import {ServiceError, CallOptions} from 'grpc'; +import {ServiceError} from 'grpc'; import {Readable, Transform, Duplex} from 'stream'; import {PreciseDate} from '@google-cloud/precise-date'; import {google as spannerClient} from '../protos/protos'; @@ -177,8 +177,8 @@ export type CreateSessionResponse = [ ]; export interface CreateSessionOptions { - name?: string | null; labels?: {[k: string]: string} | null; + gaxOptions?: CallOptions; } export type CreateSessionCallback = ResourceCallback< @@ -578,6 +578,18 @@ class Database extends GrpcServiceObject { options: CreateSessionOptions, callback: CreateSessionCallback ): void; + /** + * Create a new session. + * + * @typedef {object} CreateSessionOptions + * @property {Object.} [labels] The labels for the session. + * + * * Label keys must be between 1 and 63 characters long and must conform to + * the following regular expression: `[a-z]([-a-z0-9]*[a-z0-9])?`. + * * Label values must be between 0 and 63 characters long and must conform + * to the regular expression `([a-z]([-a-z0-9]*[a-z0-9])?)?`. + * * No more than 64 labels can be associated with a given session. + */ /** * @typedef {array} CreateSessionResponse * @property {Session} 0 The newly created session. @@ -639,10 +651,8 @@ class Database extends GrpcServiceObject { cb?: CreateSessionCallback ): void | Promise { const callback = - typeof optionsOrCallback === 'function' - ? (optionsOrCallback as CreateSessionCallback) - : cb!; - const gaxOpts = + typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!; + const options = typeof optionsOrCallback === 'object' && optionsOrCallback ? extend({}, optionsOrCallback) : ({} as CreateSessionOptions); @@ -651,9 +661,8 @@ class Database extends GrpcServiceObject { database: this.formattedName_, }; - if (gaxOpts.labels) { - reqOpts.session = {labels: gaxOpts.labels}; - delete gaxOpts.labels; + if (options.labels) { + reqOpts.session = {labels: options.labels}; } this.request( @@ -661,7 +670,7 @@ class Database extends GrpcServiceObject { client: 'SpannerClient', method: 'createSession', reqOpts, - gaxOpts, + gaxOpts: options.gaxOptions, }, (err, resp) => { if (err) { diff --git a/src/index.ts b/src/index.ts index 57ab57c5f..29b67d902 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,7 +39,7 @@ import {Session} from './session'; import {SessionPool} from './session-pool'; import {Table} from './table'; import {PartitionedDml, Snapshot, Transaction} from './transaction'; -import {GrpcClientOptions} from 'google-gax'; +import {GrpcClientOptions, CallOptions} from 'google-gax'; import {ChannelCredentials} from 'grpc'; import { createGcpApiConfig, @@ -87,7 +87,7 @@ export interface RequestConfig { method: string; // eslint-disable-next-line @typescript-eslint/no-explicit-any reqOpts: any; - gaxOpts?: {}; + gaxOpts?: CallOptions; } export interface CreateInstanceRequest { config: string; diff --git a/src/instance.ts b/src/instance.ts index b6b213633..115482c7a 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -79,12 +79,7 @@ export interface CreateDatabaseOptions poolCtor?: SessionPool; schema?: string; } -export interface GetDatabasesRequest - extends databaseAdmin.spanner.admin.database.v1.IListDatabasesRequest { - autoPaginate?: boolean; - maxApiCalls?: number; - maxResults?: number; -} +export type GetDatabasesOptions = PagedOptions; export type CreateInstanceCallback = LongRunningCallback; export type CreateDatabaseCallback = LongRunningCallback; export type DeleteInstanceCallback = NormalCallback< @@ -253,7 +248,7 @@ class Instance extends common.GrpcServiceObject { getBackups(options?: GetBackupsOptions): Promise; getBackups(callback: GetBackupsCallback): void; - getBackups(query: GetBackupsOptions, callback: GetBackupsCallback): void; + getBackups(options: GetBackupsOptions, callback: GetBackupsCallback): void; /** * Query object for listing backups. * @@ -264,12 +259,22 @@ class Instance extends common.GrpcServiceObject { * @property {number} [pageSize] Maximum number of results per page. * @property {string} [pageToken] A previously-returned page token * representing part of the larger set of results to view. + * @property {object} [gaxOptions] Request configuration options, outlined + * here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions. */ /** * @typedef {array} GetBackupsResponse * @property {Backup[]} 0 Array of {@link Backup} instances. + * @param {object} nextQuery A query object to to receive more results. * @property {object} 1 The full API response. */ + /** + * @callback GetBackupsCallback + * @param {?Error} err Request error, if any. + * @param {Backup[]} 0 Array of {@link Backup} instances. + * @param {object} nextQuery A query object to to receive more results. + * @param {object} apiResponse The full API response. + */ /** * List backups on the instance. * @@ -278,9 +283,7 @@ class Instance extends common.GrpcServiceObject { * @see {@link #backup} * * @param {GetBackupsOptions} [options] The query object for listing backups. - * @param {CallOptions} [options.gaxOptions] The request configuration - * options, outlined here: - * https://googleapis.github.io/gax-nodejs/classes/CallSettings.html. + * @param {GetBackupsCallback} [callback] Callback function. * @returns {Promise} When resolved, contains a paged list * of backups. * @@ -311,14 +314,11 @@ class Instance extends common.GrpcServiceObject { cb?: GetBackupsCallback ): void | Promise { const callback = - typeof optionsOrCallback === 'function' - ? (optionsOrCallback as GetBackupsCallback) - : cb!; + typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!; const options = typeof optionsOrCallback === 'object' - ? (optionsOrCallback as GetBackupsOptions) - : {gaxOptions: {}}; - const gaxOpts: CallOptions = options.gaxOptions as CallOptions; + ? optionsOrCallback + : ({} as GetBackupsOptions); const reqOpts = extend({}, options, { parent: this.formattedName_, }); @@ -332,7 +332,7 @@ class Instance extends common.GrpcServiceObject { client: 'DatabaseAdminClient', method: 'listBackups', reqOpts, - gaxOpts, + gaxOpts: options.gaxOptions, }, (err, backups, ...args) => { let backupInstances: Backup[] | null = null; @@ -365,12 +365,23 @@ class Instance extends common.GrpcServiceObject { * @property {number} [pageSize] Maximum number of results per page. * @property {string} [pageToken] A previously-returned page token * representing part of the larger set of results to view. + * @property {object} [gaxOptions] Request configuration options, outlined + * here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions. */ /** * @typedef {array} GetBackupOperationsResponse * @property {IOperation[]} 0 Array of {@link IOperation} instances. + * @param {object} nextQuery A query object to to receive more results. * @property {object} 1 The full API response. */ + /** + * @callback GetBackupOperationsCallback + * @param {?Error} err Request error, if any. + * @param {IOperation[]} 0 Array of {@link IOperation} instances. + * @param {object} nextQuery A query object to to receive more results. + * @param {object} apiResponse The full API response. + */ + /** * List pending and completed backup operations for all databases in the instance. * @@ -378,9 +389,7 @@ class Instance extends common.GrpcServiceObject { * * @param {GetBackupOperationsOptions} [options] The query object for listing * backup operations. - * @param {CallOptions} [options.gaxOptions] The request configuration - * options, outlined here: - * https://googleapis.github.io/gax-nodejs/classes/CallSettings.html. + * @param {GetBackupOperationsCallback} [callback] Callback function. * @returns {Promise} When resolved, contains a * paged list of backup operations. * @@ -413,14 +422,11 @@ class Instance extends common.GrpcServiceObject { cb?: GetBackupOperationsCallback ): void | Promise { const callback = - typeof optionsOrCallback === 'function' - ? (optionsOrCallback as GetBackupOperationsCallback) - : cb!; + typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!; const options = typeof optionsOrCallback === 'object' - ? (optionsOrCallback as GetBackupOperationsOptions) - : {gaxOptions: {}}; - const gaxOpts: CallOptions = options.gaxOptions as CallOptions; + ? optionsOrCallback + : ({} as GetBackupOperationsOptions); const reqOpts = extend({}, options, { parent: this.formattedName_, }); @@ -434,11 +440,9 @@ class Instance extends common.GrpcServiceObject { client: 'DatabaseAdminClient', method: 'listBackupOperations', reqOpts, - gaxOpts, + gaxOpts: options.gaxOptions, }, - (err, operations, ...args) => { - callback!(err, operations, ...args); - } + callback ); } @@ -460,12 +464,23 @@ class Instance extends common.GrpcServiceObject { * @property {number} [pageSize] Maximum number of results per page. * @property {string} [pageToken] A previously-returned page token * representing part of the larger set of results to view. + * @property {object} [gaxOptions] Request configuration options, outlined + * here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions. */ /** * @typedef {array} GetDatabaseOperationsResponse * @property {IOperation[]} 0 Array of {@link IOperation} instances. + * @param {object} nextQuery A query object to to receive more results. * @property {object} 1 The full API response. */ + /** + * @callback GetDatabaseOperationsCallback + * @param {?Error} err Request error, if any. + * @param {IOperation[]} 0 Array of {@link IOperation} instances. + * @param {object} nextQuery A query object to to receive more results. + * @param {object} apiResponse The full API response. + */ + /** * List pending and completed operations for all databases in the instance. * @@ -473,9 +488,7 @@ class Instance extends common.GrpcServiceObject { * * @param {GetDatabaseOperationsOptions} [options] The query object for * listing database operations. - * @param {CallOptions} [options.gaxOptions] The request configuration - * options, outlined here: - * https://googleapis.github.io/gax-nodejs/classes/CallSettings.html. + * @param {GetDatabaseOperationsCallback} [callback] Callback function. * @returns {Promise} When resolved, contains a * paged list of database operations. * @@ -509,14 +522,11 @@ class Instance extends common.GrpcServiceObject { cb?: GetDatabaseOperationsCallback ): void | Promise { const callback = - typeof optionsOrCallback === 'function' - ? (optionsOrCallback as GetDatabaseOperationsCallback) - : cb!; + typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!; const options = typeof optionsOrCallback === 'object' - ? (optionsOrCallback as GetDatabaseOperationsOptions) - : {gaxOptions: {}}; - const gaxOpts: CallOptions = options.gaxOptions as CallOptions; + ? optionsOrCallback + : ({} as GetDatabaseOperationsOptions); const reqOpts = extend({}, options, { parent: this.formattedName_, }); @@ -530,11 +540,9 @@ class Instance extends common.GrpcServiceObject { client: 'DatabaseAdminClient', method: 'listDatabaseOperations', reqOpts, - gaxOpts, + gaxOpts: options.gaxOptions, }, - (err, operations, ...args) => { - callback!(err, operations, ...args); - } + callback ); } @@ -947,33 +955,33 @@ class Instance extends common.GrpcServiceObject { }); } - getDatabases(query?: GetDatabasesRequest): Promise; + getDatabases(options?: GetDatabasesOptions): Promise; getDatabases(callback: GetDatabasesCallback): void; getDatabases( - query: GetDatabasesRequest, + options: GetDatabasesOptions, callback: GetDatabasesCallback ): void; /** * Query object for listing databases. * * @typedef {object} GetDatabasesRequest - * @property {boolean} [autoPaginate=true] Have pagination handled - * automatically. - * @property {number} [maxApiCalls] Maximum number of API calls to make. - * @property {number} [maxResults] Maximum number of items to return. * @property {number} [pageSize] Maximum number of results per page. * @property {string} [pageToken] A previously-returned page token * representing part of the larger set of results to view. + * @property {object} [gaxOptions] Request configuration options, outlined + * here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions. */ /** * @typedef {array} GetDatabasesResponse * @property {Database[]} 0 Array of {@link Database} instances. - * @property {object} 1 The full API response. + * @param {object} nextQuery A query object to to receive more results. + * @property {object} apiResponse The full API response. */ /** * @callback GetDatabasesCallback * @param {?Error} err Request error, if any. * @param {Database[]} databases Array of {@link Database} instances. + * @param {object} nextQuery A query object to to receive more results. * @param {object} apiResponse The full API response. */ /** @@ -984,7 +992,7 @@ class Instance extends common.GrpcServiceObject { * @see {@link v1.DatabaseAdminClient#listDatabases} * @see [ListDatabases API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases) * - * @param {GetDatabasesRequest} [query] Query object for listing databases. + * @param {GetDatabasesOptions} [query] Query object for listing databases. * @param {GetDatabasesCallback} [callback] Callback function. * @returns {Promise} * @@ -1010,7 +1018,7 @@ class Instance extends common.GrpcServiceObject { * } * * instance.getDatabases({ - * autoPaginate: false + * gaxOptions: {autoPaginate: false} * }, callback); * * //- @@ -1021,27 +1029,31 @@ class Instance extends common.GrpcServiceObject { * }); */ getDatabases( - queryOrCallback?: GetDatabasesRequest | GetDatabasesCallback, + optionsOrCallback?: GetDatabasesOptions | GetDatabasesCallback, cb?: GetDatabasesCallback ): void | Promise { // eslint-disable-next-line @typescript-eslint/no-this-alias const self = this; const callback = - typeof queryOrCallback === 'function' ? queryOrCallback : cb!; - const query = - typeof queryOrCallback === 'object' - ? queryOrCallback - : ({} as GetDatabasesRequest); + typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!; + const options = + typeof optionsOrCallback === 'object' + ? optionsOrCallback + : ({} as GetDatabasesOptions); - const reqOpts = extend({}, query, { + const reqOpts = extend({}, options, { parent: this.formattedName_, }); - this.request( + delete reqOpts.gaxOptions; + this.request< + IDatabase, + databaseAdmin.spanner.admin.database.v1.IListDatabasesResponse + >( { client: 'DatabaseAdminClient', method: 'listDatabases', reqOpts, - gaxOpts: query, + gaxOpts: options.gaxOptions, }, (err, rowDatabases, ...args) => { let databases: Database[] | null = null; @@ -1251,7 +1263,7 @@ class Instance extends common.GrpcServiceObject { * @see [ListDatabases API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases) * * @method Spanner#getDatabasesStream - * @param {GetDatabasesRequest} [query] Query object for listing databases. + * @param {GetDatabasesOptions} [options] Query object for listing databases. * @returns {ReadableStream} A readable stream that emits {@link Database} * instances. * diff --git a/test/database.ts b/test/database.ts index adf55fcaf..f76b90bab 100644 --- a/test/database.ts +++ b/test/database.ts @@ -1557,7 +1557,8 @@ describe('Database', () => { }); describe('createSession', () => { - const OPTIONS = {}; + const gaxOptions = {}; + const OPTIONS = {gaxOptions}; it('should make the correct request', done => { database.request = config => { @@ -1567,7 +1568,7 @@ describe('Database', () => { database: database.formattedName_, }); - assert.deepStrictEqual(config.gaxOpts, OPTIONS); + assert.deepStrictEqual(config.gaxOpts, gaxOptions); done(); }; @@ -1581,7 +1582,7 @@ describe('Database', () => { database: database.formattedName_, }); - assert.deepStrictEqual(config.gaxOpts, {}); + assert.deepStrictEqual(config.gaxOpts, undefined); done(); }; diff --git a/test/instance.ts b/test/instance.ts index ef97b1402..30c9b1655 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -765,14 +765,16 @@ describe('Instance', () => { describe('getDatabases', () => { const QUERY = { - a: 'b', - } as inst.GetDatabasesRequest; + pageSize: 3, + gaxOptions: {autoPaginate: false}, + } as inst.GetDatabasesOptions; const ORIGINAL_QUERY = extend({}, QUERY); it('should make the correct request', done => { const expectedReqOpts = extend({}, QUERY, { parent: instance.formattedName_, }); + delete expectedReqOpts.gaxOptions; instance.request = config => { assert.strictEqual(config.client, 'DatabaseAdminClient'); @@ -782,7 +784,7 @@ describe('Instance', () => { assert.notStrictEqual(config.reqOpts, QUERY); assert.deepStrictEqual(QUERY, ORIGINAL_QUERY); - assert.strictEqual(config.gaxOpts, QUERY); + assert.strictEqual(config.gaxOpts, QUERY.gaxOptions); done(); }; @@ -796,7 +798,7 @@ describe('Instance', () => { parent: instance.formattedName_, }); - assert.deepStrictEqual(config.gaxOpts, {}); + assert.deepStrictEqual(config.gaxOpts, undefined); done(); }; @@ -987,7 +989,7 @@ describe('Instance', () => { parent: instance.formattedName_, }); - assert.deepStrictEqual(config.gaxOpts, {}); + assert.deepStrictEqual(config.gaxOpts, undefined); }; await instance.getBackups(); @@ -1101,7 +1103,7 @@ describe('Instance', () => { parent: instance.formattedName_, }); - assert.deepStrictEqual(config.gaxOpts, {}); + assert.deepStrictEqual(config.gaxOpts, undefined); }; await instance.getBackupOperations(); @@ -1144,7 +1146,7 @@ describe('Instance', () => { parent: instance.formattedName_, }); - assert.deepStrictEqual(config.gaxOpts, {}); + assert.deepStrictEqual(config.gaxOpts, undefined); }; await instance.getDatabaseOperations(); From 80c3e70be667bad1e78b0c4048b239aa9c4378c6 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 24 Apr 2020 14:03:53 -0400 Subject: [PATCH 03/17] fix(types): listing methods in database.ts --- src/database.ts | 25 +++++++++++-------------- test/database.ts | 1 + 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/database.ts b/src/database.ts index 078296ab7..043d29fcf 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1152,9 +1152,7 @@ class Database extends GrpcServiceObject { /** * Options object for listing sessions. * - * @typedef {object} GetSessionsRequest - * @property {boolean} [autoPaginate=true] Have pagination handled - * automatically. + * @typedef {object} GetSessionsOptions * @property {string} [filter] An expression for filtering the results of the * request. Filter rules are case insensitive. The fields eligible for * filtering are: @@ -1169,21 +1167,23 @@ class Database extends GrpcServiceObject { * - **`labels.env:dev`** The instance's label env has the value dev. * - **`name:howl labels.env:dev`** The instance's name is howl and it has * the label env with value dev. - * @property {number} [maxApiCalls] Maximum number of API calls to make. - * @property {number} [maxResults] Maximum number of items to return. * @property {number} [pageSize] Maximum number of results per page. * @property {string} [pageToken] A previously-returned page token * representing part of the larger set of results to view. + * @property {object} [gaxOptions] Request configuration options, outlined + * here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions. */ /** * @typedef {array} GetSessionsResponse * @property {Session[]} 0 Array of {@link Session} instances. + * @param {object} nextQuery A query object to to receive more results. * @property {object} 1 The full API response. */ /** * @callback GetSessionsCallback * @param {?Error} err Request error, if any. * @param {Session[]} instances Array of {@link Session} instances. + * @param {object} nextQuery A query object to to receive more results. * @param {object} apiResponse The full API response. */ /** @@ -1221,7 +1221,7 @@ class Database extends GrpcServiceObject { * } * * database.getInstances({ - * autoPaginate: false + * gaxOptions: {autoPaginate: false} * }, callback); * * //- @@ -1238,19 +1238,16 @@ class Database extends GrpcServiceObject { // eslint-disable-next-line @typescript-eslint/no-this-alias const self = this; const callback = - typeof optionsOrCallback === 'function' - ? (optionsOrCallback as GetSessionsCallback) - : cb; + typeof optionsOrCallback === 'function' ? optionsOrCallback : cb; const options = typeof optionsOrCallback === 'object' - ? (optionsOrCallback as GetSessionsOptions) - : {gaxOptions: {}}; - const gaxOpts: CallOptions = options.gaxOptions as CallOptions; + ? optionsOrCallback + : ({} as GetSessionsOptions); const reqOpts = extend({}, options, { database: this.formattedName_, }); - delete reqOpts.gaxOptions; + this.request< google.spanner.v1.ISession, google.spanner.v1.IListSessionsResponse @@ -1259,7 +1256,7 @@ class Database extends GrpcServiceObject { client: 'SpannerClient', method: 'listSessions', reqOpts, - gaxOpts, + gaxOpts: options.gaxOptions, }, (err, sessions, ...args) => { let sessionInstances: Session[] | null = null; diff --git a/test/database.ts b/test/database.ts index f76b90bab..8051cb6c4 100644 --- a/test/database.ts +++ b/test/database.ts @@ -1907,6 +1907,7 @@ describe('Database', () => { assert.deepStrictEqual(config.reqOpts, { database: database.formattedName_, }); + assert.strictEqual(config.gaxOpts, undefined); done(); }; database.getSessions(assert.ifError); From 61fde11e21c419c72a360cb33477391f9ae405ff Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 24 Apr 2020 14:06:16 -0400 Subject: [PATCH 04/17] lint: lint --- src/instance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/instance.ts b/src/instance.ts index 115482c7a..7e7ab82b3 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -24,7 +24,7 @@ import * as extend from 'extend'; import snakeCase = require('lodash.snakecase'); import {Database, SessionPoolConstructor} from './database'; import {Spanner, RequestConfig} from '.'; -import {CallOptions, ServiceError} from 'grpc'; +import {ServiceError} from 'grpc'; import { RequestCallback, PagedOptions, From ae02a1dca927d18123c70b93884ca01b53063d98 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 24 Apr 2020 16:13:35 -0400 Subject: [PATCH 05/17] fix: coverage --- test/database.ts | 2 +- test/index.ts | 4 ++-- test/instance.ts | 18 ++++++++++-------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/test/database.ts b/test/database.ts index 8051cb6c4..db90211f9 100644 --- a/test/database.ts +++ b/test/database.ts @@ -1902,7 +1902,7 @@ describe('Database', () => { database.getSessions(options, assert.ifError); }); - it('should not require a query', done => { + it('should not require options', done => { database.request = config => { assert.deepStrictEqual(config.reqOpts, { database: database.formattedName_, diff --git a/test/index.ts b/test/index.ts index fa9fca5f9..170bcface 100644 --- a/test/index.ts +++ b/test/index.ts @@ -676,7 +676,7 @@ describe('Spanner', () => { spanner.getInstances(OPTIONS as GetInstancesOptions, assert.ifError); }); - it('should not require a query', done => { + it('should not require options', done => { spanner.request = config => { assert.deepStrictEqual(config.reqOpts, { parent: 'projects/' + spanner.projectId, @@ -782,7 +782,7 @@ describe('Spanner', () => { assert.strictEqual(returnedValue, returnValue); }); - it('should not require a query', done => { + it('should not require options', done => { spanner.request = config => { const reqOpts = config.reqOpts; assert.deepStrictEqual(reqOpts, { diff --git a/test/instance.ts b/test/instance.ts index 30c9b1655..1d7fee9e3 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -792,7 +792,7 @@ describe('Instance', () => { instance.getDatabases(QUERY, assert.ifError); }); - it('should not require a query', done => { + it('should not require options', done => { instance.request = config => { assert.deepStrictEqual(config.reqOpts, { parent: instance.formattedName_, @@ -983,16 +983,16 @@ describe('Instance', () => { await instance.getBackups(options); }); - it('should not require a query', async () => { + it('should not require options', done => { instance.request = config => { assert.deepStrictEqual(config.reqOpts, { parent: instance.formattedName_, }); - assert.deepStrictEqual(config.gaxOpts, undefined); + done(); }; - await instance.getBackups(); + instance.getBackups(assert.ifError); }); describe('error', () => { @@ -1097,16 +1097,17 @@ describe('Instance', () => { await instance.getBackupOperations(options); }); - it('should not require a query', async () => { + it('should not require options', done => { instance.request = config => { assert.deepStrictEqual(config.reqOpts, { parent: instance.formattedName_, }); assert.deepStrictEqual(config.gaxOpts, undefined); + done(); }; - await instance.getBackupOperations(); + instance.getBackupOperations(assert.ifError); }); }); @@ -1140,16 +1141,17 @@ describe('Instance', () => { await instance.getDatabaseOperations(options); }); - it('should not require a query', async () => { + it('should not require options', done => { instance.request = config => { assert.deepStrictEqual(config.reqOpts, { parent: instance.formattedName_, }); assert.deepStrictEqual(config.gaxOpts, undefined); + done(); }; - await instance.getDatabaseOperations(); + instance.getDatabaseOperations(assert.ifError); }); }); }); From 427454e0e9b79745cfff804dd82a4694485a19a8 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 28 Apr 2020 11:06:40 -0400 Subject: [PATCH 06/17] docs: typos --- src/database.ts | 2 +- src/index.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/database.ts b/src/database.ts index 043d29fcf..5e8fa08e5 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1176,7 +1176,7 @@ class Database extends GrpcServiceObject { /** * @typedef {array} GetSessionsResponse * @property {Session[]} 0 Array of {@link Session} instances. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** diff --git a/src/index.ts b/src/index.ts index 29b67d902..3c6c22d7f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -598,7 +598,8 @@ class Spanner extends GrpcService { * config. * @param {string} instanceConfigs.displayName The name of the instance config * as it appears in UIs. - * @param {object} nextQuery A query object to to receive more results. * @param {object} apiResponse The full API response. + * @param {object} nextQuery A query object to to receive more results. + * @param {object} apiResponse The full API response. */ /** * Get a list of instance configs. From a7359cfa281e1d3f08326915a90fee745819435b Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 5 May 2020 00:50:37 -0400 Subject: [PATCH 07/17] chore: pass `pageSize` and `pageToken` as reqOpts --- src/database.ts | 20 ++- src/index.ts | 66 ++++++++-- src/instance.ts | 81 ++++++++++-- test/database.ts | 70 ++++++++++- test/index.ts | 223 +++++++++++++++++++++++++++++++-- test/instance.ts | 312 ++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 713 insertions(+), 59 deletions(-) diff --git a/src/database.ts b/src/database.ts index 5e8fa08e5..dfe1c4598 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1243,11 +1243,27 @@ class Database extends GrpcServiceObject { typeof optionsOrCallback === 'object' ? optionsOrCallback : ({} as GetSessionsOptions); - const reqOpts = extend({}, options, { + const gaxOpts = extend(true, {}, options.gaxOptions); + let reqOpts = extend({}, options, { database: this.formattedName_, }); delete reqOpts.gaxOptions; + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + this.request< google.spanner.v1.ISession, google.spanner.v1.IListSessionsResponse @@ -1256,7 +1272,7 @@ class Database extends GrpcServiceObject { client: 'SpannerClient', method: 'listSessions', reqOpts, - gaxOpts: options.gaxOptions, + gaxOpts, }, (err, sessions, ...args) => { let sessionInstances: Session[] | null = null; diff --git a/src/index.ts b/src/index.ts index 3c6c22d7f..5efbd3266 100644 --- a/src/index.ts +++ b/src/index.ts @@ -535,18 +535,35 @@ class Spanner extends GrpcService { const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!; - const reqOpts = extend({}, options, { + const gaxOpts = extend(true, {}, options.gaxOptions); + + let reqOpts = extend({}, options, { parent: 'projects/' + this.projectId, }); delete reqOpts.gaxOptions; + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + this.request( { client: 'InstanceAdminClient', method: 'listInstances', reqOpts, - gaxOpts: options.gaxOptions, + gaxOpts, }, (err, instances, ...args) => { let instanceInstances: Instance[] | null = null; @@ -656,17 +673,34 @@ class Spanner extends GrpcService { typeof optionsOrCallback === 'object' ? optionsOrCallback : ({} as GetInstanceConfigsOptions); - const reqOpts = extend({}, options, { + + const gaxOpts = extend(true, {}, options.gaxOptions); + let reqOpts = extend({}, options, { parent: 'projects/' + this.projectId, }); delete reqOpts.gaxOptions; + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + return this.request( { client: 'InstanceAdminClient', method: 'listInstanceConfigs', reqOpts, - gaxOpts: options.gaxOptions, + gaxOpts, }, callback ); @@ -706,17 +740,35 @@ class Spanner extends GrpcService { * }); */ getInstanceConfigsStream( - options?: GetInstanceConfigsOptions + options: GetInstanceConfigsOptions = {} ): NodeJS.ReadableStream { - const reqOpts = extend({}, options, { + const gaxOpts = extend(true, {}, options.gaxOptions); + + let reqOpts = extend({}, options, { parent: 'projects/' + this.projectId, }); + + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + delete reqOpts.gaxOptions; return this.requestStream({ client: 'InstanceAdminClient', method: 'listInstanceConfigsStream', reqOpts, - gaxOpts: options?.gaxOptions, + gaxOpts, }); } diff --git a/src/instance.ts b/src/instance.ts index 7e7ab82b3..849d167c8 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -319,11 +319,27 @@ class Instance extends common.GrpcServiceObject { typeof optionsOrCallback === 'object' ? optionsOrCallback : ({} as GetBackupsOptions); - const reqOpts = extend({}, options, { + const gaxOpts = extend(true, {}, options.gaxOptions); + let reqOpts = extend({}, options, { parent: this.formattedName_, }); delete reqOpts.gaxOptions; + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + this.request< IBackup, databaseAdmin.spanner.admin.database.v1.IListBackupsResponse @@ -332,7 +348,7 @@ class Instance extends common.GrpcServiceObject { client: 'DatabaseAdminClient', method: 'listBackups', reqOpts, - gaxOpts: options.gaxOptions, + gaxOpts, }, (err, backups, ...args) => { let backupInstances: Backup[] | null = null; @@ -427,11 +443,27 @@ class Instance extends common.GrpcServiceObject { typeof optionsOrCallback === 'object' ? optionsOrCallback : ({} as GetBackupOperationsOptions); - const reqOpts = extend({}, options, { + const gaxOpts = extend(true, {}, options.gaxOptions); + let reqOpts = extend({}, options, { parent: this.formattedName_, }); delete reqOpts.gaxOptions; + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + this.request< IOperation, databaseAdmin.spanner.admin.database.v1.IListBackupOperationsResponse @@ -440,7 +472,7 @@ class Instance extends common.GrpcServiceObject { client: 'DatabaseAdminClient', method: 'listBackupOperations', reqOpts, - gaxOpts: options.gaxOptions, + gaxOpts, }, callback ); @@ -527,11 +559,27 @@ class Instance extends common.GrpcServiceObject { typeof optionsOrCallback === 'object' ? optionsOrCallback : ({} as GetDatabaseOperationsOptions); - const reqOpts = extend({}, options, { + const gaxOpts = extend(true, {}, options.gaxOptions); + let reqOpts = extend({}, options, { parent: this.formattedName_, }); delete reqOpts.gaxOptions; + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + this.request< IOperation, databaseAdmin.spanner.admin.database.v1.IListDatabaseOperationsResponse @@ -540,7 +588,7 @@ class Instance extends common.GrpcServiceObject { client: 'DatabaseAdminClient', method: 'listDatabaseOperations', reqOpts, - gaxOpts: options.gaxOptions, + gaxOpts, }, callback ); @@ -1041,10 +1089,27 @@ class Instance extends common.GrpcServiceObject { ? optionsOrCallback : ({} as GetDatabasesOptions); - const reqOpts = extend({}, options, { + const gaxOpts = extend(true, {}, options.gaxOptions); + let reqOpts = extend({}, options, { parent: this.formattedName_, }); delete reqOpts.gaxOptions; + + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + this.request< IDatabase, databaseAdmin.spanner.admin.database.v1.IListDatabasesResponse @@ -1053,7 +1118,7 @@ class Instance extends common.GrpcServiceObject { client: 'DatabaseAdminClient', method: 'listDatabases', reqOpts, - gaxOpts: options.gaxOptions, + gaxOpts, }, (err, rowDatabases, ...args) => { let databases: Database[] | null = null; diff --git a/test/database.ts b/test/database.ts index db90211f9..cb99df5a8 100644 --- a/test/database.ts +++ b/test/database.ts @@ -1895,7 +1895,73 @@ describe('Database', () => { assert.strictEqual(config.client, 'SpannerClient'); assert.strictEqual(config.method, 'listSessions'); assert.deepStrictEqual(config.reqOpts, expectedReqOpts); - assert.strictEqual(config.gaxOpts, gaxOpts); + assert.deepStrictEqual(config.gaxOpts, gaxOpts); + done(); + }; + + database.getSessions(options, assert.ifError); + }); + + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = {a: 'a', gaxOptions: gaxOptions}; + const expectedReqOpts = extend( + {}, + options, + { + database: database.formattedName_, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + delete expectedReqOpts.gaxOptions; + + database.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + database.getSessions(options, assert.ifError); + }); + + it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = Object.assign( + {}, + { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + } + ); + const expectedReqOpts = extend( + {}, + options, + { + database: database.formattedName_, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + delete expectedReqOpts.gaxOptions; + + database.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + done(); }; @@ -1907,7 +1973,7 @@ describe('Database', () => { assert.deepStrictEqual(config.reqOpts, { database: database.formattedName_, }); - assert.strictEqual(config.gaxOpts, undefined); + assert.deepStrictEqual(config.gaxOpts, {}); done(); }; database.getSessions(assert.ifError); diff --git a/test/index.ts b/test/index.ts index 170bcface..1a5de93a4 100644 --- a/test/index.ts +++ b/test/index.ts @@ -668,7 +668,7 @@ describe('Spanner', () => { assert.notStrictEqual(config.reqOpts, OPTIONS); assert.deepStrictEqual(OPTIONS, ORIGINAL_OPTIONS); - assert.strictEqual(config.gaxOpts, OPTIONS.gaxOptions); + assert.deepStrictEqual(config.gaxOpts, {}); done(); }; @@ -676,13 +676,74 @@ describe('Spanner', () => { spanner.getInstances(OPTIONS as GetInstancesOptions, assert.ifError); }); + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = Object.assign({}, OPTIONS, {gaxOptions}); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: 'projects/' + spanner.projectId, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + + spanner.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + spanner.getInstances(options, assert.ifError); + }); + + it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = Object.assign({}, OPTIONS, { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + }); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: 'projects/' + spanner.projectId, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + + spanner.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + spanner.getInstances(options, assert.ifError); + }); + it('should not require options', done => { spanner.request = config => { assert.deepStrictEqual(config.reqOpts, { parent: 'projects/' + spanner.projectId, }); - assert.strictEqual(config.gaxOpts, undefined); + assert.deepStrictEqual(config.gaxOpts, {}); done(); }; @@ -771,7 +832,7 @@ describe('Spanner', () => { assert.notStrictEqual(reqOpts, options); const gaxOpts = config.gaxOpts; - assert.strictEqual(gaxOpts, options.gaxOptions); + assert.deepStrictEqual(gaxOpts, options.gaxOptions); assert.strictEqual(callback_, callback); @@ -782,6 +843,67 @@ describe('Spanner', () => { assert.strictEqual(returnedValue, returnValue); }); + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = Object.assign({}, OPTIONS, {gaxOptions}); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: 'projects/' + spanner.projectId, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + + spanner.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + spanner.getInstanceConfigs(options, assert.ifError); + }); + + it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = Object.assign({}, OPTIONS, { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + }); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: 'projects/' + spanner.projectId, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + + spanner.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + spanner.getInstanceConfigs(options, assert.ifError); + }); + it('should not require options', done => { spanner.request = config => { const reqOpts = config.reqOpts; @@ -805,10 +927,10 @@ describe('Spanner', () => { pageSize: 5, gaxOptions: {autoPaginate: false}, }; - const expectedQuery = extend({}, options, { + const expectedOptions = extend({}, options, { parent: 'projects/' + spanner.projectId, }); - delete expectedQuery.gaxOptions; + delete expectedOptions.gaxOptions; const returnValue = {}; spanner.requestStream = config => { @@ -816,11 +938,11 @@ describe('Spanner', () => { assert.strictEqual(config.method, 'listInstanceConfigsStream'); const reqOpts = config.reqOpts; - assert.deepStrictEqual(reqOpts, expectedQuery); + assert.deepStrictEqual(reqOpts, expectedOptions); assert.notStrictEqual(reqOpts, options); const gaxOpts = config.gaxOpts; - assert.strictEqual(gaxOpts, options.gaxOptions); + assert.deepStrictEqual(gaxOpts, options.gaxOptions); return returnValue; }; @@ -830,6 +952,93 @@ describe('Spanner', () => { ); assert.strictEqual(returnedValue, returnValue); }); + + it('should not require options', () => { + const expectedOptions = { + parent: 'projects/' + spanner.projectId, + }; + const returnValue = {}; + + spanner.requestStream = config => { + assert.strictEqual(config.client, 'InstanceAdminClient'); + assert.strictEqual(config.method, 'listInstanceConfigsStream'); + + const reqOpts = config.reqOpts; + assert.deepStrictEqual(reqOpts, expectedOptions); + + const gaxOpts = config.gaxOpts; + assert.deepStrictEqual(gaxOpts, {}); + + return returnValue; + }; + const returnedValue = spanner.getInstanceConfigsStream(); + assert.strictEqual(returnedValue, returnValue); + }); + + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', () => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = Object.assign({}, OPTIONS, {gaxOptions}); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: 'projects/' + spanner.projectId, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + const returnValue = {}; + + spanner.requestStream = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + return returnValue; + }; + + const returnedValue = spanner.getInstanceConfigsStream(options); + assert.strictEqual(returnedValue, returnValue); + }); + + it('pageSize and pageToken in options should take precedence over over gaxOptions', () => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = Object.assign({}, OPTIONS, { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + }); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: 'projects/' + spanner.projectId, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + const returnValue = {}; + + spanner.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + return returnValue; + }; + + const returnedValue = spanner.getInstanceConfigs(options, assert.ifError); + assert.strictEqual(returnedValue, returnValue); + }); }); describe('instance', () => { diff --git a/test/instance.ts b/test/instance.ts index 1d7fee9e3..c0188488b 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -764,14 +764,14 @@ describe('Instance', () => { }); describe('getDatabases', () => { - const QUERY = { + const OPTIONS = { pageSize: 3, gaxOptions: {autoPaginate: false}, } as inst.GetDatabasesOptions; - const ORIGINAL_QUERY = extend({}, QUERY); + const ORIGINAL_OPTIONS = extend({}, OPTIONS); it('should make the correct request', done => { - const expectedReqOpts = extend({}, QUERY, { + const expectedReqOpts = extend({}, OPTIONS, { parent: instance.formattedName_, }); delete expectedReqOpts.gaxOptions; @@ -781,15 +781,78 @@ describe('Instance', () => { assert.strictEqual(config.method, 'listDatabases'); assert.deepStrictEqual(config.reqOpts, expectedReqOpts); - assert.notStrictEqual(config.reqOpts, QUERY); - assert.deepStrictEqual(QUERY, ORIGINAL_QUERY); + assert.notStrictEqual(config.reqOpts, OPTIONS); + assert.deepStrictEqual(OPTIONS, ORIGINAL_OPTIONS); + + assert.deepStrictEqual(config.gaxOpts, OPTIONS.gaxOptions); + + done(); + }; + + instance.getDatabases(OPTIONS, assert.ifError); + }); + + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = Object.assign({}, OPTIONS, {gaxOptions}); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: instance.formattedName_, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + delete expectedReqOpts.gaxOptions; + + instance.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + instance.getDatabases(options, assert.ifError); + }); + + it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = Object.assign({}, OPTIONS, { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + }); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: instance.formattedName_, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + delete expectedReqOpts.gaxOptions; - assert.strictEqual(config.gaxOpts, QUERY.gaxOptions); + instance.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); done(); }; - instance.getDatabases(QUERY, assert.ifError); + instance.getDatabases(options, assert.ifError); }); it('should not require options', done => { @@ -798,7 +861,7 @@ describe('Instance', () => { parent: instance.formattedName_, }); - assert.deepStrictEqual(config.gaxOpts, undefined); + assert.deepStrictEqual(config.gaxOpts, {}); done(); }; @@ -816,7 +879,7 @@ describe('Instance', () => { }); it('should execute callback with original arguments', done => { - instance.getDatabases(QUERY, (...args) => { + instance.getDatabases(OPTIONS, (...args) => { assert.deepStrictEqual(args, REQUEST_RESPONSE_ARGS); done(); }); @@ -847,7 +910,7 @@ describe('Instance', () => { return fakeDatabaseInstance as Database; }; - instance.getDatabases(QUERY, (...args) => { + instance.getDatabases(OPTIONS, (...args) => { assert.ifError(args[0]); assert.strictEqual(args[0], REQUEST_RESPONSE_ARGS[0]); const database = args[1]!.pop(); @@ -954,10 +1017,10 @@ describe('Instance', () => { }); describe('getBackups', () => { - const QUERY = { + const OPTIONS = { a: 'b', } as inst.GetBackupsOptions; - const ORIGINAL_QUERY = extend({}, QUERY); + const ORIGINAL_QUERY = extend({}, OPTIONS); it('should make the correct request', async () => { const gaxOpts = { @@ -965,7 +1028,7 @@ describe('Instance', () => { }; const options = {a: 'b', gaxOptions: gaxOpts}; - const expectedReqOpts = extend({}, QUERY, { + const expectedReqOpts = extend({}, OPTIONS, { parent: instance.formattedName_, }); @@ -974,21 +1037,82 @@ describe('Instance', () => { assert.strictEqual(config.method, 'listBackups'); assert.deepStrictEqual(config.reqOpts, expectedReqOpts); - assert.notStrictEqual(config.reqOpts, QUERY); - assert.deepStrictEqual(QUERY, ORIGINAL_QUERY); + assert.notStrictEqual(config.reqOpts, OPTIONS); + assert.deepStrictEqual(OPTIONS, ORIGINAL_QUERY); - assert.strictEqual(config.gaxOpts, options.gaxOptions); + assert.deepStrictEqual(config.gaxOpts, options.gaxOptions); }; await instance.getBackups(options); }); + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = Object.assign({}, OPTIONS, {gaxOptions}); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: instance.formattedName_, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + + instance.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + instance.getBackups(options, assert.ifError); + }); + + it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = Object.assign({}, OPTIONS, { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + }); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: instance.formattedName_, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + + instance.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + instance.getBackups(options, assert.ifError); + }); + it('should not require options', done => { instance.request = config => { assert.deepStrictEqual(config.reqOpts, { parent: instance.formattedName_, }); - assert.deepStrictEqual(config.gaxOpts, undefined); + assert.deepStrictEqual(config.gaxOpts, {}); done(); }; @@ -1005,7 +1129,7 @@ describe('Instance', () => { }); it('should execute callback with original arguments', done => { - instance.getBackups(QUERY, (...args) => { + instance.getBackups(OPTIONS, (...args) => { assert.deepStrictEqual(args, REQUEST_RESPONSE_ARGS); done(); }); @@ -1038,7 +1162,7 @@ describe('Instance', () => { return fakeBackupInstance as Backup; }; - instance.getBackups(QUERY, (...args) => { + instance.getBackups(OPTIONS, (...args) => { assert.ifError(args[0]); assert.strictEqual(args[0], REQUEST_RESPONSE_ARGS[0]); const backup = args[1]!.pop(); @@ -1068,10 +1192,10 @@ describe('Instance', () => { }); describe('getBackupOperations', () => { - const QUERY = { + const OPTIONS = { a: 'b', } as inst.GetBackupOperationsOptions; - const ORIGINAL_QUERY = extend({}, QUERY); + const ORIGINAL_OPTIONS = extend({}, OPTIONS); it('should make the correct request', async () => { const gaxOpts = { @@ -1079,7 +1203,7 @@ describe('Instance', () => { }; const options = {a: 'b', gaxOptions: gaxOpts}; - const expectedReqOpts = extend({}, QUERY, { + const expectedReqOpts = extend({}, OPTIONS, { parent: instance.formattedName_, }); @@ -1088,22 +1212,83 @@ describe('Instance', () => { assert.strictEqual(config.method, 'listBackupOperations'); assert.deepStrictEqual(config.reqOpts, expectedReqOpts); - assert.notStrictEqual(config.reqOpts, QUERY); - assert.deepStrictEqual(QUERY, ORIGINAL_QUERY); + assert.notStrictEqual(config.reqOpts, OPTIONS); + assert.deepStrictEqual(OPTIONS, ORIGINAL_OPTIONS); - assert.strictEqual(config.gaxOpts, options.gaxOptions); + assert.deepStrictEqual(config.gaxOpts, options.gaxOptions); }; await instance.getBackupOperations(options); }); + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = Object.assign({}, OPTIONS, {gaxOptions}); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: instance.formattedName_, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + + instance.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + instance.getBackupOperations(options, assert.ifError); + }); + + it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = Object.assign({}, OPTIONS, { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + }); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: instance.formattedName_, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + + instance.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + instance.getBackupOperations(options, assert.ifError); + }); + it('should not require options', done => { instance.request = config => { assert.deepStrictEqual(config.reqOpts, { parent: instance.formattedName_, }); - assert.deepStrictEqual(config.gaxOpts, undefined); + assert.deepStrictEqual(config.gaxOpts, {}); done(); }; @@ -1112,10 +1297,10 @@ describe('Instance', () => { }); describe('getDatabaseOperations', () => { - const QUERY = { + const OPTIONS = { a: 'b', } as inst.GetDatabaseOperationsOptions; - const ORIGINAL_QUERY = extend({}, QUERY); + const ORIGINAL_OPTIONS = extend({}, OPTIONS); it('should make the correct request', async () => { const gaxOpts = { @@ -1123,7 +1308,7 @@ describe('Instance', () => { }; const options = {a: 'b', gaxOptions: gaxOpts}; - const expectedReqOpts = extend({}, QUERY, { + const expectedReqOpts = extend({}, OPTIONS, { parent: instance.formattedName_, }); @@ -1132,22 +1317,83 @@ describe('Instance', () => { assert.strictEqual(config.method, 'listDatabaseOperations'); assert.deepStrictEqual(config.reqOpts, expectedReqOpts); - assert.notStrictEqual(config.reqOpts, QUERY); - assert.deepStrictEqual(QUERY, ORIGINAL_QUERY); + assert.notStrictEqual(config.reqOpts, OPTIONS); + assert.deepStrictEqual(OPTIONS, ORIGINAL_OPTIONS); - assert.strictEqual(config.gaxOpts, options.gaxOptions); + assert.deepStrictEqual(config.gaxOpts, options.gaxOptions); }; await instance.getDatabaseOperations(options); }); + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = Object.assign({}, OPTIONS, {gaxOptions}); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: instance.formattedName_, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + + instance.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + instance.getDatabaseOperations(options, assert.ifError); + }); + + it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = Object.assign({}, OPTIONS, { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + }); + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: instance.formattedName_, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + + instance.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + instance.getDatabaseOperations(options, assert.ifError); + }); + it('should not require options', done => { instance.request = config => { assert.deepStrictEqual(config.reqOpts, { parent: instance.formattedName_, }); - assert.deepStrictEqual(config.gaxOpts, undefined); + assert.deepStrictEqual(config.gaxOpts, {}); done(); }; From 47c1e59b2715a17a45454c9d74d9c85482225c0f Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 7 May 2020 00:27:21 -0400 Subject: [PATCH 08/17] refactor: drop paginator in instance.ts --- src/instance.ts | 113 ++++++++++++++++++++++++-------------- test/index.ts | 52 ++++++++---------- test/instance.ts | 139 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 215 insertions(+), 89 deletions(-) diff --git a/src/instance.ts b/src/instance.ts index 849d167c8..35a72a682 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -18,7 +18,6 @@ import arrify = require('arrify'); import {ServiceObjectConfig, GetConfig} from '@google-cloud/common'; // eslint-disable-next-line @typescript-eslint/no-var-requires const common = require('./common-grpc/service-object'); -import {paginator} from '@google-cloud/paginator'; import {promisifyAll} from '@google-cloud/promisify'; import * as extend from 'extend'; import snakeCase = require('lodash.snakecase'); @@ -149,7 +148,7 @@ interface InstanceRequest { class Instance extends common.GrpcServiceObject { formattedName_: string; request: InstanceRequest; - requestStream: (config?: RequestConfig) => Duplex; + requestStream: (config: RequestConfig) => Duplex; databases_: Map; metadata?: IInstance; constructor(spanner: Spanner, name: string) { @@ -1040,7 +1039,7 @@ class Instance extends common.GrpcServiceObject { * @see {@link v1.DatabaseAdminClient#listDatabases} * @see [ListDatabases API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases) * - * @param {GetDatabasesOptions} [query] Query object for listing databases. + * @param {GetDatabasesOptions} [options] Query object for listing databases. * @param {GetDatabasesCallback} [callback] Callback function. * @returns {Promise} * @@ -1133,6 +1132,75 @@ class Instance extends common.GrpcServiceObject { } ); } + + /** + * Get a list of databases as a readable object stream. + * + * Wrapper around {@link v1.DatabaseAdminClient#listDatabases}. + * + * @see {@link v1.DatabaseAdminClient#listDatabases} + * @see [ListDatabases API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases) + * + * @method Spanner#getDatabasesStream + * @param {GetDatabasesOptions} [options] Query object for listing databases. + * @returns {ReadableStream} A readable stream that emits {@link Database} + * instances. + * + * @example + * const {Spanner} = require('@google-cloud/spanner'); + * const spanner = new Spanner(); + * + * const instance = spanner.instance('my-instance'); + * + * instance.getDatabasesStream() + * .on('error', console.error) + * .on('data', function(database) { + * // `database` is a `Database` object. + * }) + * .on('end', function() { + * // All databases retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * instance.getDatabasesStream() + * .on('data', function(database) { + * this.end(); + * }); + */ + getDatabasesStream(options: GetDatabasesOptions = {}): NodeJS.ReadableStream { + const gaxOpts = extend(true, {}, options.gaxOptions); + + let reqOpts = extend({}, options, { + parent: this.formattedName_, + }); + delete reqOpts.gaxOptions; + + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + + return this.requestStream({ + client: 'DatabaseAdminClient', + method: 'listDatabasesStream', + reqOpts, + gaxOpts, + }); + } + getMetadata( options?: GetInstanceMetadataOptions ): Promise; @@ -1319,45 +1387,6 @@ class Instance extends common.GrpcServiceObject { } } -/** - * Get a list of databases as a readable object stream. - * - * Wrapper around {@link v1.DatabaseAdminClient#listDatabases}. - * - * @see {@link v1.DatabaseAdminClient#listDatabases} - * @see [ListDatabases API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.ListDatabases) - * - * @method Spanner#getDatabasesStream - * @param {GetDatabasesOptions} [options] Query object for listing databases. - * @returns {ReadableStream} A readable stream that emits {@link Database} - * instances. - * - * @example - * const {Spanner} = require('@google-cloud/spanner'); - * const spanner = new Spanner(); - * - * const instance = spanner.instance('my-instance'); - * - * instance.getDatabasesStream() - * .on('error', console.error) - * .on('data', function(database) { - * // `database` is a `Database` object. - * }) - * .on('end', function() { - * // All databases retrieved. - * }); - * - * //- - * // If you anticipate many results, you can end a stream early to prevent - * // unnecessary processing and API requests. - * //- - * instance.getDatabasesStream() - * .on('data', function(database) { - * this.end(); - * }); - */ -Instance.prototype.getDatabasesStream = paginator.streamify('getDatabases'); - /*! Developer Documentation * * All async methods (except for streams) will return a Promise in the event diff --git a/test/index.ts b/test/index.ts index 1a5de93a4..b4496d2c4 100644 --- a/test/index.ts +++ b/test/index.ts @@ -61,14 +61,6 @@ const fakeGrpcGcp = { }, }; -const fakePaginator = { - paginator: { - streamify(methodName) { - return methodName; - }, - }, -}; - let promisified = false; const fakePfy = extend({}, pfy, { promisifyAll(klass, options) { @@ -142,7 +134,6 @@ describe('Spanner', () => { './common-grpc/service': { GrpcService: FakeGrpcService, }, - '@google-cloud/paginator': fakePaginator, '@google-cloud/promisify': fakePfy, '@google-cloud/projectify': { replaceProjectIdToken: fakeReplaceProjectIdToken, @@ -202,10 +193,6 @@ describe('Spanner', () => { assert(promisified); }); - it('should streamify the correct methods', () => { - assert.strictEqual(spanner.getInstancesStream, 'getInstances'); - }); - it('should create an auth instance from google-auth-library', () => { assert.deepStrictEqual( getFake(spanner.auth).calledWith_[0], @@ -922,12 +909,13 @@ describe('Spanner', () => { spanner.requestStream = util.noop; }); + const OPTIONS = { + gaxOptions: {autoPaginate: false}, + }; + const returnValue = {}; + it('should make and return the correct gax API call', () => { - const options: GetInstanceConfigsOptions = { - pageSize: 5, - gaxOptions: {autoPaginate: false}, - }; - const expectedOptions = extend({}, options, { + const expectedOptions = extend({}, OPTIONS, { parent: 'projects/' + spanner.projectId, }); delete expectedOptions.gaxOptions; @@ -939,16 +927,16 @@ describe('Spanner', () => { const reqOpts = config.reqOpts; assert.deepStrictEqual(reqOpts, expectedOptions); - assert.notStrictEqual(reqOpts, options); + assert.notStrictEqual(reqOpts, OPTIONS); const gaxOpts = config.gaxOpts; - assert.deepStrictEqual(gaxOpts, options.gaxOptions); + assert.deepStrictEqual(gaxOpts, OPTIONS.gaxOptions); return returnValue; }; const returnedValue = spanner.getInstanceConfigsStream( - options as GetInstanceConfigsOptions + OPTIONS as GetInstanceConfigsOptions ); assert.strictEqual(returnedValue, returnValue); }); @@ -980,16 +968,17 @@ describe('Spanner', () => { const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; const expectedGaxOpts = {timeout: 1000}; - const options = Object.assign({}, OPTIONS, {gaxOptions}); + const options = {gaxOptions}; const expectedReqOpts = extend( + true, {}, - OPTIONS, + options, { parent: 'projects/' + spanner.projectId, }, {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} ); - const returnValue = {}; + delete expectedReqOpts.gaxOptions; spanner.requestStream = config => { assert.deepStrictEqual(config.reqOpts, expectedReqOpts); @@ -1012,11 +1001,14 @@ describe('Spanner', () => { const optionsPageSize = 5; const optionsPageToken = 'optionsToken'; - const options = Object.assign({}, OPTIONS, { - pageSize: optionsPageSize, - pageToken: optionsPageToken, - gaxOptions, - }); + const options = Object.assign( + {}, + { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + } + ); const expectedReqOpts = extend( {}, OPTIONS, @@ -1025,7 +1017,7 @@ describe('Spanner', () => { }, {pageSize: optionsPageSize, pageToken: optionsPageToken} ); - const returnValue = {}; + delete expectedReqOpts.gaxOptions; spanner.request = config => { assert.deepStrictEqual(config.reqOpts, expectedReqOpts); diff --git a/test/instance.ts b/test/instance.ts index c0188488b..a4e90e7bf 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -25,9 +25,10 @@ import * as pfy from '@google-cloud/promisify'; import {ServiceError} from 'grpc'; import * as sinon from 'sinon'; import snakeCase = require('lodash.snakecase'); +import {Duplex} from 'stream'; import * as inst from '../src/instance'; -import {Spanner, Database} from '../src'; +import {Spanner, Database, RequestConfig} from '../src'; import arrify = require('arrify'); import {SessionPoolOptions} from '../src/session-pool'; import {Backup} from '../src/backup'; @@ -145,14 +146,16 @@ describe('Instance', () => { it('should localize the requestStream function', done => { const spannerInstance = extend({}, SPANNER); + const CONFIG = {}; - spannerInstance.requestStream = function () { + spannerInstance.requestStream = function (config) { assert.strictEqual(this, spannerInstance); + assert.strictEqual(config, CONFIG); done(); }; const instance = new Instance(spannerInstance, NAME); - instance.requestStream(); + instance.requestStream(CONFIG as RequestConfig); }); it('should inherit from ServiceObject', done => { @@ -764,8 +767,9 @@ describe('Instance', () => { }); describe('getDatabases', () => { + const pageSize = 3; const OPTIONS = { - pageSize: 3, + pageSize, gaxOptions: {autoPaginate: false}, } as inst.GetDatabasesOptions; const ORIGINAL_OPTIONS = extend({}, OPTIONS); @@ -793,14 +797,13 @@ describe('Instance', () => { }); it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { - const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; const expectedGaxOpts = {timeout: 1000}; - const options = Object.assign({}, OPTIONS, {gaxOptions}); + const options = {gaxOptions}; const expectedReqOpts = extend( {}, - OPTIONS, + options, { parent: instance.formattedName_, }, @@ -821,18 +824,17 @@ describe('Instance', () => { }); it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { - const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; const expectedGaxOpts = {timeout: 1000}; const optionsPageSize = 5; const optionsPageToken = 'optionsToken'; - const options = Object.assign({}, OPTIONS, { + const options = { pageSize: optionsPageSize, pageToken: optionsPageToken, gaxOptions, - }); + }; const expectedReqOpts = extend( {}, OPTIONS, @@ -923,6 +925,111 @@ describe('Instance', () => { }); }); + describe('getDatabasesStream', () => { + const OPTIONS = { + gaxOptions: {autoPaginate: false}, + } as inst.GetDatabasesOptions; + const returnValue = {}; + + it('should make and return the correct gax API call', () => { + const expectedReqOpts = extend({}, OPTIONS, { + parent: instance.formattedName_, + }); + delete expectedReqOpts.gaxOptions; + + instance.requestStream = config => { + assert.strictEqual(config.client, 'DatabaseAdminClient'); + assert.strictEqual(config.method, 'listDatabasesStream'); + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + + assert.notStrictEqual(config.reqOpts, OPTIONS); + + assert.deepStrictEqual(config.gaxOpts, OPTIONS.gaxOptions); + return returnValue as Duplex; + }; + + const returnedValue = instance.getDatabasesStream(OPTIONS); + assert.strictEqual(returnedValue, returnValue); + }); + + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = {gaxOptions}; + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: instance.formattedName_, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + delete expectedReqOpts.gaxOptions; + + instance.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + instance.getDatabases(options, assert.ifError); + }); + + it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + }; + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: instance.formattedName_, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + delete expectedReqOpts.gaxOptions; + + instance.request = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + done(); + }; + + instance.getDatabases(options, assert.ifError); + }); + + it('should not require options', done => { + instance.request = config => { + assert.deepStrictEqual(config.reqOpts, { + parent: instance.formattedName_, + }); + + assert.deepStrictEqual(config.gaxOpts, {}); + + done(); + }; + + instance.getDatabases(assert.ifError); + }); + }); + describe('getMetadata', () => { it('should correctly call and return request', () => { const requestReturnValue = {}; @@ -1020,7 +1127,7 @@ describe('Instance', () => { const OPTIONS = { a: 'b', } as inst.GetBackupsOptions; - const ORIGINAL_QUERY = extend({}, OPTIONS); + const ORIGINAL_OPTIONS = extend({}, OPTIONS); it('should make the correct request', async () => { const gaxOpts = { @@ -1038,7 +1145,7 @@ describe('Instance', () => { assert.deepStrictEqual(config.reqOpts, expectedReqOpts); assert.notStrictEqual(config.reqOpts, OPTIONS); - assert.deepStrictEqual(OPTIONS, ORIGINAL_QUERY); + assert.deepStrictEqual(OPTIONS, ORIGINAL_OPTIONS); assert.deepStrictEqual(config.gaxOpts, options.gaxOptions); }; @@ -1051,10 +1158,9 @@ describe('Instance', () => { const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; const expectedGaxOpts = {timeout: 1000}; - const options = Object.assign({}, OPTIONS, {gaxOptions}); + const options = {gaxOptions}; const expectedReqOpts = extend( {}, - OPTIONS, { parent: instance.formattedName_, }, @@ -1081,14 +1187,13 @@ describe('Instance', () => { const optionsPageSize = 5; const optionsPageToken = 'optionsToken'; - const options = Object.assign({}, OPTIONS, { + const options = { pageSize: optionsPageSize, pageToken: optionsPageToken, gaxOptions, - }); + }; const expectedReqOpts = extend( {}, - OPTIONS, { parent: instance.formattedName_, }, From 01aa00d781465bbe4b14d24e339fa5961c83997a Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 7 May 2020 02:05:26 -0400 Subject: [PATCH 09/17] refactor: drop paginator in index.ts --- src/index.ts | 105 ++++++++++++++++++++++++++++++------------------- test/index.ts | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 39 deletions(-) diff --git a/src/index.ts b/src/index.ts index 5efbd3266..29d41e05f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,7 +15,6 @@ */ import {GrpcService, GrpcServiceConfig} from './common-grpc/service'; -import {paginator} from '@google-cloud/paginator'; import {PreciseDate} from '@google-cloud/precise-date'; import {replaceProjectIdToken} from '@google-cloud/projectify'; import {promisifyAll} from '@google-cloud/promisify'; @@ -154,7 +153,6 @@ class Spanner extends GrpcService { auth: GoogleAuth; clients_: Map; instances_: Map; - getInstancesStream: Function; /** * Placeholder used to auto populate a column with the commit timestamp. @@ -255,43 +253,6 @@ class Spanner extends GrpcService { this.auth = new GoogleAuth(this.options); this.clients_ = new Map(); this.instances_ = new Map(); - - /** - * Get a list of {@link Instance} objects as a readable object stream. - * - * Wrapper around {@link v1.InstanceAdminClient#listInstances}. - * - * @see {@link v1.InstanceAdminClient#listInstances} - * @see [ListInstances API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstances) - * - * @method Spanner#getInstancesStream - * @param {GetInstancesOptions} [options] Query object for listing instances. - * @returns {ReadableStream} A readable stream that emits {@link Instance} - * instances. - * - * @example - * const {Spanner} = require('@google-cloud/spanner'); - * const spanner = new Spanner(); - * - * spanner.getInstancesStream() - * .on('error', console.error) - * .on('data', function(instance) { - * // `instance` is an `Instance` object. - * }) - * .on('end', function() { - * // All instances retrieved. - * }); - * - * //- - * // If you anticipate many results, you can end a stream early to prevent - * // unnecessary processing and API requests. - * //- - * spanner.getInstancesStream() - * .on('data', function(instance) { - * this.end(); - * }); - */ - this.getInstancesStream = paginator.streamify('getInstances'); } createInstance( @@ -579,6 +540,72 @@ class Spanner extends GrpcService { ); } + /** + * Get a list of {@link Instance} objects as a readable object stream. + * + * Wrapper around {@link v1.InstanceAdminClient#listInstances}. + * + * @see {@link v1.InstanceAdminClient#listInstances} + * @see [ListInstances API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstances) + * + * @method Spanner#getInstancesStream + * @param {GetInstancesOptions} [options] Query object for listing instances. + * @returns {ReadableStream} A readable stream that emits {@link Instance} + * instances. + * + * @example + * const {Spanner} = require('@google-cloud/spanner'); + * const spanner = new Spanner(); + * + * spanner.getInstancesStream() + * .on('error', console.error) + * .on('data', function(instance) { + * // `instance` is an `Instance` object. + * }) + * .on('end', function() { + * // All instances retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * spanner.getInstancesStream() + * .on('data', function(instance) { + * this.end(); + * }); + */ + getInstancesStream(options: GetInstancesOptions = {}): NodeJS.ReadableStream { + const gaxOpts = extend(true, {}, options.gaxOptions); + + let reqOpts = extend({}, options, { + parent: 'projects/' + this.projectId, + }); + delete reqOpts.gaxOptions; + + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + + return this.requestStream({ + client: 'InstanceAdminClient', + method: 'listInstancesStream', + reqOpts, + gaxOpts, + }); + } + getInstanceConfigs( query?: GetInstanceConfigsOptions ): Promise; diff --git a/test/index.ts b/test/index.ts index b4496d2c4..f7fee10a1 100644 --- a/test/index.ts +++ b/test/index.ts @@ -29,6 +29,7 @@ import * as pfy from '@google-cloud/promisify'; import * as sinon from 'sinon'; import * as spnr from '../src'; import * as grpc from 'grpc'; +import {Duplex} from 'stream'; import {CreateInstanceRequest} from '../src/index'; import {GetInstanceConfigsOptions, GetInstancesOptions} from '../src'; @@ -791,6 +792,111 @@ describe('Spanner', () => { }); }); + describe('getInstancesStream', () => { + const OPTIONS: GetInstancesOptions = { + filter: 'b', + }; + const ORIGINAL_OPTIONS = extend({}, OPTIONS); + const returnValue = {}; + + it('should make and return the correct gax API call', () => { + const expectedReqOpts = extend({}, OPTIONS, { + parent: 'projects/' + spanner.projectId, + }); + + spanner.requestStream = config => { + assert.strictEqual(config.client, 'InstanceAdminClient'); + assert.strictEqual(config.method, 'listInstancesStream'); + + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.reqOpts, OPTIONS); + assert.deepStrictEqual(OPTIONS, ORIGINAL_OPTIONS); + + assert.deepStrictEqual(config.gaxOpts, {}); + return returnValue as Duplex; + }; + + const returnedValue = spanner.getInstancesStream(OPTIONS); + assert.strictEqual(returnedValue, returnValue); + }); + + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', () => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = {gaxOptions}; + const expectedReqOpts = extend( + {}, + { + parent: 'projects/' + spanner.projectId, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + + spanner.requestStream = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + return returnValue; + }; + + const returnedValue = spanner.getInstancesStream(options); + assert.strictEqual(returnedValue, returnValue); + }); + + it('pageSize and pageToken in options should take precedence over over gaxOptions', () => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + }; + const expectedReqOpts = extend( + {}, + { + parent: 'projects/' + spanner.projectId, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + + spanner.requestStream = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + return returnValue; + }; + + const returnedValue = spanner.getInstancesStream(options); + assert.strictEqual(returnedValue, returnValue); + }); + + it('should not require options', () => { + spanner.requestStream = config => { + assert.deepStrictEqual(config.reqOpts, { + parent: 'projects/' + spanner.projectId, + }); + + assert.deepStrictEqual(config.gaxOpts, {}); + + return returnValue; + }; + + const returnedValue = spanner.getInstancesStream(); + assert.strictEqual(returnedValue, returnValue); + }); + }); + describe('getInstanceConfigs', () => { beforeEach(() => { spanner.request = util.noop; From 4ffe38ef1dbad00ce0be153b30447fe3706e76fe Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 7 May 2020 02:05:59 -0400 Subject: [PATCH 10/17] feat: add getBackupsStream function --- src/instance.ts | 68 ++++++++++++++++++++++ test/instance.ts | 148 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 191 insertions(+), 25 deletions(-) diff --git a/src/instance.ts b/src/instance.ts index 35a72a682..1d2ceaf87 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -362,6 +362,74 @@ class Instance extends common.GrpcServiceObject { ); } + /** + * Get a list of backups as a readable object stream. + * + * Wrapper around {@link v1.DatabaseAdminClient#listBackups}. + * + * @see {@link v1.DatabaseAdminClient#listBackups} + * @see [ListBackups API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.ListBackups) + * + * @method Spanner#getBackupsStream + * @param {GetBackupOptions} [options] Query object for listing backups. + * @returns {ReadableStream} A readable stream that emits {@link Backup} + * instances. + * + * @example + * const {Spanner} = require('@google-cloud/spanner'); + * const spanner = new Spanner(); + * + * const instance = spanner.instance('my-instance'); + * + * instance.getBackupsStream() + * .on('error', console.error) + * .on('data', function(database) { + * // `backups` is a `Backup` object. + * }) + * .on('end', function() { + * // All backups retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * instance.getBackupsStream() + * .on('data', function(database) { + * this.end(); + * }); + */ + getBackupsStream(options: GetBackupsOptions = {}): NodeJS.ReadableStream { + const gaxOpts = extend(true, {}, options.gaxOptions); + + let reqOpts = extend({}, options, { + parent: this.formattedName_, + }); + delete reqOpts.gaxOptions; + + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + + return this.requestStream({ + client: 'DatabaseAdminClient', + method: 'listBackupsStream', + reqOpts, + gaxOpts, + }); + } + getBackupOperations( options?: GetBackupOperationsOptions ): Promise; diff --git a/test/instance.ts b/test/instance.ts index a4e90e7bf..04b005c6f 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -34,14 +34,6 @@ import {SessionPoolOptions} from '../src/session-pool'; import {Backup} from '../src/backup'; import {PreciseDate} from '@google-cloud/precise-date'; -const fakePaginator = { - paginator: { - streamify(methodName) { - return methodName; - }, - }, -}; - let promisified = false; const fakePfy = extend({}, pfy, { promisifyAll(klass, options) { @@ -95,7 +87,6 @@ describe('Instance', () => { GrpcServiceObject: FakeGrpcServiceObject, }, '@google-cloud/promisify': fakePfy, - '@google-cloud/paginator': fakePaginator, './database.js': {Database: FakeDatabase}, './backup.js': {Backup: FakeBackup}, }).Instance; @@ -929,7 +920,7 @@ describe('Instance', () => { const OPTIONS = { gaxOptions: {autoPaginate: false}, } as inst.GetDatabasesOptions; - const returnValue = {}; + const returnValue = {} as Duplex; it('should make and return the correct gax API call', () => { const expectedReqOpts = extend({}, OPTIONS, { @@ -945,14 +936,14 @@ describe('Instance', () => { assert.notStrictEqual(config.reqOpts, OPTIONS); assert.deepStrictEqual(config.gaxOpts, OPTIONS.gaxOptions); - return returnValue as Duplex; + return returnValue; }; const returnedValue = instance.getDatabasesStream(OPTIONS); assert.strictEqual(returnedValue, returnValue); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', () => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -960,27 +951,26 @@ describe('Instance', () => { const options = {gaxOptions}; const expectedReqOpts = extend( {}, - OPTIONS, { parent: instance.formattedName_, }, {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} ); - delete expectedReqOpts.gaxOptions; - instance.request = config => { + instance.requestStream = config => { assert.deepStrictEqual(config.reqOpts, expectedReqOpts); assert.notStrictEqual(config.gaxOpts, gaxOptions); assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); - done(); + return returnValue; }; - instance.getDatabases(options, assert.ifError); + const returnedValue = instance.getDatabasesStream(options); + assert.strictEqual(returnedValue, returnValue); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + it('pageSize and pageToken in options should take precedence over over gaxOptions', () => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1003,30 +993,32 @@ describe('Instance', () => { ); delete expectedReqOpts.gaxOptions; - instance.request = config => { + instance.requestStream = config => { assert.deepStrictEqual(config.reqOpts, expectedReqOpts); assert.notStrictEqual(config.gaxOpts, gaxOptions); assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); - done(); + return returnValue; }; - instance.getDatabases(options, assert.ifError); + const returnedValue = instance.getDatabasesStream(options); + assert.strictEqual(returnedValue, returnValue); }); - it('should not require options', done => { - instance.request = config => { + it('should not require options', () => { + instance.requestStream = config => { assert.deepStrictEqual(config.reqOpts, { parent: instance.formattedName_, }); assert.deepStrictEqual(config.gaxOpts, {}); - done(); + return returnValue; }; - instance.getDatabases(assert.ifError); + const returnedValue = instance.getDatabasesStream(); + assert.strictEqual(returnedValue, returnValue); }); }); @@ -1279,6 +1271,112 @@ describe('Instance', () => { }); }); + describe('getBackupsStream', () => { + const OPTIONS = { + gaxOptions: {autoPaginate: false}, + } as inst.GetDatabasesOptions; + const returnValue = {} as Duplex; + + it('should make and return the correct gax API call', () => { + const expectedReqOpts = extend({}, OPTIONS, { + parent: instance.formattedName_, + }); + delete expectedReqOpts.gaxOptions; + + instance.requestStream = config => { + assert.strictEqual(config.client, 'DatabaseAdminClient'); + assert.strictEqual(config.method, 'listBackupsStream'); + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + + assert.notStrictEqual(config.reqOpts, OPTIONS); + + assert.deepStrictEqual(config.gaxOpts, OPTIONS.gaxOptions); + return returnValue; + }; + + const returnedValue = instance.getBackupsStream(OPTIONS); + assert.strictEqual(returnedValue, returnValue); + }); + + it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', () => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = {gaxOptions}; + const expectedReqOpts = extend( + {}, + { + parent: instance.formattedName_, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + + instance.requestStream = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + return returnValue; + }; + + const returnedValue = instance.getBackupsStream(options); + assert.strictEqual(returnedValue, returnValue); + }); + + it('pageSize and pageToken in options should take precedence over over gaxOptions', () => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + }; + const expectedReqOpts = extend( + {}, + OPTIONS, + { + parent: instance.formattedName_, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + delete expectedReqOpts.gaxOptions; + + instance.requestStream = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + return returnValue; + }; + + const returnedValue = instance.getBackupsStream(options); + assert.strictEqual(returnedValue, returnValue); + }); + + it('should not require options', () => { + instance.requestStream = config => { + assert.deepStrictEqual(config.reqOpts, { + parent: instance.formattedName_, + }); + + assert.deepStrictEqual(config.gaxOpts, {}); + + return returnValue; + }; + + const returnedValue = instance.getBackupsStream(); + assert.strictEqual(returnedValue, returnValue); + }); + }); + describe('backup', () => { const BACKUP_NAME = 'backup-name'; From e84907623afda2249569df48ab08c2a46f281549 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 7 May 2020 02:07:24 -0400 Subject: [PATCH 11/17] chore: remove paginator dependency from package.json --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 2a3aeae0d..c122e3376 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,6 @@ }, "dependencies": { "@google-cloud/common": "^3.0.0", - "@google-cloud/paginator": "^3.0.0", "@google-cloud/precise-date": "^2.0.0", "@google-cloud/projectify": "^2.0.0", "@google-cloud/promisify": "^2.0.0", From 956e7e6174933430a962e52e3c442996884e7061 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 7 May 2020 03:01:02 -0400 Subject: [PATCH 12/17] chore: PR comments --- src/common.ts | 4 ++++ src/database.ts | 8 ++++---- src/index.ts | 20 ++++++++++++-------- src/instance.ts | 16 +++++++--------- test/database.ts | 4 ++-- test/index.ts | 16 ++++++++-------- test/instance.ts | 24 ++++++++++++------------ 7 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/common.ts b/src/common.ts index bf01486c8..8958c7a9a 100644 --- a/src/common.ts +++ b/src/common.ts @@ -66,3 +66,7 @@ export interface PagedOptions { pageToken?: string; gaxOptions?: CallOptions; } + +export interface PagedOptionsWithFilter extends PagedOptions { + filter?: string; +} diff --git a/src/database.ts b/src/database.ts index dfe1c4598..f337f3613 100644 --- a/src/database.ts +++ b/src/database.ts @@ -71,11 +71,11 @@ import { IOperation, Schema, RequestCallback, - PagedOptions, ResourceCallback, PagedResponse, NormalCallback, LongRunningCallback, + PagedOptionsWithFilter, } from './common'; import {ServiceError} from 'grpc'; import {Readable, Transform, Duplex} from 'stream'; @@ -120,9 +120,7 @@ type PoolRequestCallback = RequestCallback; type ResultSetStats = spannerClient.spanner.v1.ResultSetStats; -interface GetSessionsOptions extends PagedOptions { - filter?: string; -} +type GetSessionsOptions = PagedOptionsWithFilter; /** * IDatabase structure with database state enum translated to string form. @@ -589,6 +587,8 @@ class Database extends GrpcServiceObject { * * Label values must be between 0 and 63 characters long and must conform * to the regular expression `([a-z]([-a-z0-9]*[a-z0-9])?)?`. * * No more than 64 labels can be associated with a given session. + * @property {object} [gaxOptions] Request configuration options, outlined + * here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions. */ /** * @typedef {array} CreateSessionResponse diff --git a/src/index.ts b/src/index.ts index 29d41e05f..bbbf2826f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,7 +33,12 @@ import { CreateInstanceResponse, } from './instance'; import {google as instanceAdmin} from '../protos/protos'; -import {PagedOptions, PagedResponse, PagedCallback} from './common'; +import { + PagedOptions, + PagedResponse, + PagedCallback, + PagedOptionsWithFilter, +} from './common'; import {Session} from './session'; import {SessionPool} from './session-pool'; import {Table} from './table'; @@ -53,9 +58,8 @@ const gcpApiConfig = require('./spanner_grpc_config.json'); export type IOperation = instanceAdmin.longrunning.IOperation; -export interface GetInstancesOptions extends PagedOptions { - filter?: string; -} +export type GetInstancesOptions = PagedOptionsWithFilter; + export type GetInstancesResponse = PagedResponse< Instance, instanceAdmin.spanner.admin.instance.v1.IListInstancesResponse @@ -429,14 +433,14 @@ class Spanner extends GrpcService { /** * @typedef {array} GetInstancesResponse * @property {Instance[]} 0 Array of {@link Instance} instances. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** * @callback GetInstancesCallback * @param {?Error} err Request error, if any. * @param {Instance[]} instances Array of {@link Instance} instances. - * @param {string} nextQuery A query object to to receive more results. + * @param {string} nextQuery A query object to receive more results. * @param {object} apiResponse The full API response. */ /** @@ -631,7 +635,7 @@ 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. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** @@ -642,7 +646,7 @@ class Spanner extends GrpcService { * config. * @param {string} instanceConfigs.displayName The name of the instance config * as it appears in UIs. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @param {object} apiResponse The full API response. */ /** diff --git a/src/instance.ts b/src/instance.ts index 1d2ceaf87..3662669c4 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -31,6 +31,7 @@ import { LongRunningCallback, NormalCallback, ResourceCallback, + PagedOptionsWithFilter, } from './common'; import {Duplex} from 'stream'; import {SessionPoolOptions, SessionPool} from './session-pool'; @@ -96,23 +97,20 @@ export type SetInstanceMetadataCallback = ResourceCallback< GaxOperation, IOperation >; -export interface GetBackupsOptions extends PagedOptions { - filter?: string; -} +export type GetBackupsOptions = PagedOptionsWithFilter; + export type GetBackupsCallback = RequestCallback< Backup, databaseAdmin.spanner.admin.database.v1.IListBackupsResponse >; -export interface GetBackupOperationsOptions extends PagedOptions { - filter?: string; -} +export type GetBackupOperationsOptions = PagedOptionsWithFilter; + export type GetBackupOperationsCallback = RequestCallback< IOperation, databaseAdmin.spanner.admin.database.v1.IListBackupOperationsResponse >; -export interface GetDatabaseOperationsOptions extends PagedOptions { - filter?: string; -} +export type GetDatabaseOperationsOptions = PagedOptionsWithFilter; + export type GetDatabaseOperationsCallback = RequestCallback< IOperation, databaseAdmin.spanner.admin.database.v1.IListDatabaseOperationsResponse diff --git a/test/database.ts b/test/database.ts index cb99df5a8..6da72ce34 100644 --- a/test/database.ts +++ b/test/database.ts @@ -1902,7 +1902,7 @@ describe('Database', () => { database.getSessions(options, assert.ifError); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + it('should pass pageSize and pageToken from gaxOptions into reqOpts', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1930,7 +1930,7 @@ describe('Database', () => { database.getSessions(options, assert.ifError); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + it('pageSize and pageToken in options should take precedence over gaxOptions', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; diff --git a/test/index.ts b/test/index.ts index f7fee10a1..5d4a94468 100644 --- a/test/index.ts +++ b/test/index.ts @@ -664,7 +664,7 @@ describe('Spanner', () => { spanner.getInstances(OPTIONS as GetInstancesOptions, assert.ifError); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + it('should pass pageSize and pageToken from gaxOptions into reqOpts', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -691,7 +691,7 @@ describe('Spanner', () => { spanner.getInstances(options, assert.ifError); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + it('pageSize and pageToken in options should take precedence over gaxOptions', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -820,7 +820,7 @@ describe('Spanner', () => { assert.strictEqual(returnedValue, returnValue); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', () => { + it('should pass pageSize and pageToken from gaxOptions into reqOpts', () => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -847,7 +847,7 @@ describe('Spanner', () => { assert.strictEqual(returnedValue, returnValue); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', () => { + it('pageSize and pageToken in options should take precedence over gaxOptions', () => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -936,7 +936,7 @@ describe('Spanner', () => { assert.strictEqual(returnedValue, returnValue); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + it('should pass pageSize and pageToken from gaxOptions into reqOpts', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -963,7 +963,7 @@ describe('Spanner', () => { spanner.getInstanceConfigs(options, assert.ifError); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + it('pageSize and pageToken in options should take precedence over gaxOptions', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1069,7 +1069,7 @@ describe('Spanner', () => { assert.strictEqual(returnedValue, returnValue); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', () => { + it('should pass pageSize and pageToken from gaxOptions into reqOpts', () => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1099,7 +1099,7 @@ describe('Spanner', () => { assert.strictEqual(returnedValue, returnValue); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', () => { + it('pageSize and pageToken in options should take precedence over gaxOptions', () => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; diff --git a/test/instance.ts b/test/instance.ts index 04b005c6f..68dcadfac 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -787,7 +787,7 @@ describe('Instance', () => { instance.getDatabases(OPTIONS, assert.ifError); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + it('should pass pageSize and pageToken from gaxOptions into reqOpts', done => { const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; const expectedGaxOpts = {timeout: 1000}; @@ -814,7 +814,7 @@ describe('Instance', () => { instance.getDatabases(options, assert.ifError); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + it('pageSize and pageToken in options should take precedence over gaxOptions', done => { const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; const expectedGaxOpts = {timeout: 1000}; @@ -943,7 +943,7 @@ describe('Instance', () => { assert.strictEqual(returnedValue, returnValue); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', () => { + it('should pass pageSize and pageToken from gaxOptions into reqOpts', () => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -970,7 +970,7 @@ describe('Instance', () => { assert.strictEqual(returnedValue, returnValue); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', () => { + it('pageSize and pageToken in options should take precedence over gaxOptions', () => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1145,7 +1145,7 @@ describe('Instance', () => { await instance.getBackups(options); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + it('should pass pageSize and pageToken from gaxOptions into reqOpts', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1171,7 +1171,7 @@ describe('Instance', () => { instance.getBackups(options, assert.ifError); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + it('pageSize and pageToken in options should take precedence over gaxOptions', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1298,7 +1298,7 @@ describe('Instance', () => { assert.strictEqual(returnedValue, returnValue); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', () => { + it('should pass pageSize and pageToken from gaxOptions into reqOpts', () => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1325,7 +1325,7 @@ describe('Instance', () => { assert.strictEqual(returnedValue, returnValue); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', () => { + it('pageSize and pageToken in options should take precedence over gaxOptions', () => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1424,7 +1424,7 @@ describe('Instance', () => { await instance.getBackupOperations(options); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + it('should pass pageSize and pageToken from gaxOptions into reqOpts', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1451,7 +1451,7 @@ describe('Instance', () => { instance.getBackupOperations(options, assert.ifError); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + it('pageSize and pageToken in options should take precedence over gaxOptions', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1529,7 +1529,7 @@ describe('Instance', () => { await instance.getDatabaseOperations(options); }); - it('should respect pageSize & pageToken on gaxOptions, pass values in reqOpts only', done => { + it('should pass pageSize and pageToken from gaxOptions into reqOpts', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; @@ -1556,7 +1556,7 @@ describe('Instance', () => { instance.getDatabaseOperations(options, assert.ifError); }); - it('pageSize and pageToken in options should take precedence over over gaxOptions', done => { + it('pageSize and pageToken in options should take precedence over gaxOptions', done => { const pageSize = 3; const pageToken = 'token'; const gaxOptions = {pageSize, pageToken, timeout: 1000}; From 58133d1ec3ae43b9244643ff94e9161dc8c18fbd Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 7 May 2020 03:05:00 -0400 Subject: [PATCH 13/17] chore: typos --- src/database.ts | 2 +- src/instance.ts | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/database.ts b/src/database.ts index f337f3613..51fe9fbbe 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1183,7 +1183,7 @@ class Database extends GrpcServiceObject { * @callback GetSessionsCallback * @param {?Error} err Request error, if any. * @param {Session[]} instances Array of {@link Session} instances. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @param {object} apiResponse The full API response. */ /** diff --git a/src/instance.ts b/src/instance.ts index 3662669c4..cc925921e 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -262,14 +262,14 @@ class Instance extends common.GrpcServiceObject { /** * @typedef {array} GetBackupsResponse * @property {Backup[]} 0 Array of {@link Backup} instances. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** * @callback GetBackupsCallback * @param {?Error} err Request error, if any. * @param {Backup[]} 0 Array of {@link Backup} instances. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @param {object} apiResponse The full API response. */ /** @@ -452,14 +452,14 @@ class Instance extends common.GrpcServiceObject { /** * @typedef {array} GetBackupOperationsResponse * @property {IOperation[]} 0 Array of {@link IOperation} instances. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** * @callback GetBackupOperationsCallback * @param {?Error} err Request error, if any. * @param {IOperation[]} 0 Array of {@link IOperation} instances. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @param {object} apiResponse The full API response. */ @@ -567,14 +567,14 @@ class Instance extends common.GrpcServiceObject { /** * @typedef {array} GetDatabaseOperationsResponse * @property {IOperation[]} 0 Array of {@link IOperation} instances. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** * @callback GetDatabaseOperationsCallback * @param {?Error} err Request error, if any. * @param {IOperation[]} 0 Array of {@link IOperation} instances. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @param {object} apiResponse The full API response. */ @@ -1087,14 +1087,14 @@ class Instance extends common.GrpcServiceObject { /** * @typedef {array} GetDatabasesResponse * @property {Database[]} 0 Array of {@link Database} instances. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @property {object} apiResponse The full API response. */ /** * @callback GetDatabasesCallback * @param {?Error} err Request error, if any. * @param {Database[]} databases Array of {@link Database} instances. - * @param {object} nextQuery A query object to to receive more results. + * @param {object} nextQuery A query object to receive more results. * @param {object} apiResponse The full API response. */ /** From 393e5da8c50786f9931b98cd5497a58cc49f2caf Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 7 May 2020 09:52:06 -0400 Subject: [PATCH 14/17] fix: fix --- package.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index c122e3376..5b2cc8e19 100644 --- a/package.json +++ b/package.json @@ -59,9 +59,8 @@ "events-intercept": "^2.0.0", "extend": "^3.0.2", "google-auth-library": "^6.0.0", - "google-gax": "^2.1.0", - "grpc": "^1.21.1", - "grpc-gcp": "^0.1.1", + "google-gax": "^2.3.1", + "grpc-gcp": "^0.3.2", "is": "^3.2.1", "lodash.snakecase": "^4.1.1", "merge-stream": "^2.0.0", @@ -112,7 +111,7 @@ "time-span": "^4.0.0", "tmp": "^0.2.0", "typescript": "^3.8.3", - "uuid": "^7.0.0", + "uuid": "^8.0.0", "yargs": "^15.0.0" } } From 67ce6231141eb6c31d092ce95791d5df2add8c09 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 7 May 2020 18:05:11 -0400 Subject: [PATCH 15/17] feat: add getSessionsStream functions --- src/database.ts | 72 +++++++++++++++++++++++++++++++- test/database.ts | 106 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 176 insertions(+), 2 deletions(-) diff --git a/src/database.ts b/src/database.ts index 2c946ab5f..11c3e8372 100644 --- a/src/database.ts +++ b/src/database.ts @@ -119,7 +119,7 @@ type PoolRequestCallback = RequestCallback; type ResultSetStats = spannerClient.spanner.v1.ResultSetStats; -type GetSessionsOptions = PagedOptionsWithFilter; +export type GetSessionsOptions = PagedOptionsWithFilter; /** * IDatabase structure with database state enum translated to string form. @@ -1286,6 +1286,76 @@ class Database extends GrpcServiceObject { } ); } + + /** + * Get a list of sessions as a readable object stream. + * + * Wrapper around {@link v1.SpannerClient#listSessions} + * + * @see {@link v1.SpannerClient#listSessions} + * @see [ListSessions API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.ListSessions) + * + * @method Spanner#getSessionsStream + * @param {GetSessionsOptions} [options] Options object for listing sessions. + * @returns {ReadableStream} A readable stream that emits {@link Session} + * instances. + * + * @example + * const {Spanner} = require('@google-cloud/spanner'); + * const spanner = new Spanner(); + * + * const instance = spanner.instance('my-instance'); + * const database = instance.database('my-database'); + * + * database.getSessionsStream() + * .on('error', console.error) + * .on('data', function(database) { + * // `sessions` is a `Session` object. + * }) + * .on('end', function() { + * // All sessions retrieved. + * }); + * + * //- + * // If you anticipate many results, you can end a stream early to prevent + * // unnecessary processing and API requests. + * //- + * database.getSessionsStream() + * .on('data', function(session) { + * this.end(); + * }); + */ + getSessionsStream(options: GetSessionsOptions = {}): NodeJS.ReadableStream { + const gaxOpts = extend(true, {}, options.gaxOptions); + + let reqOpts = extend({}, options, { + database: this.formattedName_, + }); + delete reqOpts.gaxOptions; + + // Copy over pageSize and pageToken values from gaxOptions. + // However values set on options take precedence. + if (gaxOpts) { + reqOpts = extend( + {}, + { + pageSize: gaxOpts.pageSize, + pageToken: gaxOpts.pageToken, + }, + reqOpts + ); + delete gaxOpts.pageSize; + delete gaxOpts.pageToken; + } + + return this.requestStream({ + client: 'SpannerClient', + method: 'listSessionsStream', + reqOpts, + gaxOpts, + }); + } + getSnapshot(options?: TimestampBounds): Promise<[Snapshot]>; getSnapshot(callback: GetSnapshotCallback): void; getSnapshot(options: TimestampBounds, callback: GetSnapshotCallback): void; diff --git a/test/database.ts b/test/database.ts index 9f70b179e..48eba6bcf 100644 --- a/test/database.ts +++ b/test/database.ts @@ -23,7 +23,7 @@ import * as extend from 'extend'; import {ApiError, util} from '@google-cloud/common'; import * as proxyquire from 'proxyquire'; import * as sinon from 'sinon'; -import {Transform} from 'stream'; +import {Transform, Duplex} from 'stream'; import * as through from 'through2'; import * as pfy from '@google-cloud/promisify'; import {grpc} from 'google-gax'; @@ -2016,6 +2016,110 @@ describe('Database', () => { }); }); + describe('getSessionsStream', () => { + const OPTIONS = { + gaxOptions: {autoPaginate: false}, + } as db.GetSessionsOptions; + const returnValue = {} as Duplex; + + it('should make and return the correct gax API call', () => { + const expectedReqOpts = extend({}, OPTIONS, { + database: database.formattedName_, + }); + delete expectedReqOpts.gaxOptions; + + database.requestStream = config => { + assert.strictEqual(config.client, 'SpannerClient'); + assert.strictEqual(config.method, 'listSessionsStream'); + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + + assert.notStrictEqual(config.reqOpts, OPTIONS); + + assert.deepStrictEqual(config.gaxOpts, OPTIONS.gaxOptions); + return returnValue; + }; + + const returnedValue = database.getSessionsStream(OPTIONS); + assert.strictEqual(returnedValue, returnValue); + }); + + it('should pass pageSize and pageToken from gaxOptions into reqOpts', () => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + const options = {gaxOptions}; + const expectedReqOpts = extend( + {}, + { + database: database.formattedName_, + }, + {pageSize: gaxOptions.pageSize, pageToken: gaxOptions.pageToken} + ); + + database.requestStream = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + return returnValue; + }; + + const returnedValue = database.getSessionsStream(options); + assert.strictEqual(returnedValue, returnValue); + }); + + it('pageSize and pageToken in options should take precedence over gaxOptions', () => { + const pageSize = 3; + const pageToken = 'token'; + const gaxOptions = {pageSize, pageToken, timeout: 1000}; + const expectedGaxOpts = {timeout: 1000}; + + const optionsPageSize = 5; + const optionsPageToken = 'optionsToken'; + const options = { + pageSize: optionsPageSize, + pageToken: optionsPageToken, + gaxOptions, + }; + const expectedReqOpts = extend( + {}, + { + database: database.formattedName_, + }, + {pageSize: optionsPageSize, pageToken: optionsPageToken} + ); + + database.requestStream = config => { + assert.deepStrictEqual(config.reqOpts, expectedReqOpts); + assert.notStrictEqual(config.gaxOpts, gaxOptions); + assert.notDeepStrictEqual(config.gaxOpts, gaxOptions); + assert.deepStrictEqual(config.gaxOpts, expectedGaxOpts); + + return returnValue; + }; + + const returnedValue = database.getSessionsStream(options); + assert.strictEqual(returnedValue, returnValue); + }); + + it('should not require options', () => { + database.requestStream = config => { + assert.deepStrictEqual(config.reqOpts, { + database: database.formattedName_, + }); + + assert.deepStrictEqual(config.gaxOpts, {}); + + return returnValue; + }; + + const returnedValue = database.getSessionsStream(); + assert.strictEqual(returnedValue, returnValue); + }); + }); + describe('runPartitionedUpdate', () => { const QUERY = { sql: 'INSERT INTO `MyTable` (Key, Thing) VALUES(@key, @thing)', From 9c4fa0e8bc45768baa4e49fe6ac01a107e6165cc Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 8 May 2020 10:49:46 -0400 Subject: [PATCH 16/17] fix: docs --- src/database.ts | 2 +- src/index.ts | 4 ++-- src/instance.ts | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/database.ts b/src/database.ts index 11c3e8372..d35c47ee5 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1175,7 +1175,7 @@ class Database extends GrpcServiceObject { /** * @typedef {array} GetSessionsResponse * @property {Session[]} 0 Array of {@link Session} instances. - * @param {object} nextQuery A query object to receive more results. + * @property {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** diff --git a/src/index.ts b/src/index.ts index 2f6fca6e2..4be8bdd00 100644 --- a/src/index.ts +++ b/src/index.ts @@ -428,7 +428,7 @@ class Spanner extends GrpcService { /** * @typedef {array} GetInstancesResponse * @property {Instance[]} 0 Array of {@link Instance} instances. - * @param {object} nextQuery A query object to receive more results. + * @property {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** @@ -630,7 +630,7 @@ 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. - * @param {object} nextQuery A query object to receive more results. + * @property {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** diff --git a/src/instance.ts b/src/instance.ts index 95b2ba1cb..2aa0c8be7 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -261,7 +261,7 @@ class Instance extends common.GrpcServiceObject { /** * @typedef {array} GetBackupsResponse * @property {Backup[]} 0 Array of {@link Backup} instances. - * @param {object} nextQuery A query object to receive more results. + * @property {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** @@ -453,7 +453,7 @@ class Instance extends common.GrpcServiceObject { /** * @typedef {array} GetBackupOperationsResponse * @property {IOperation[]} 0 Array of {@link IOperation} instances. - * @param {object} nextQuery A query object to receive more results. + * @property {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** @@ -570,7 +570,7 @@ class Instance extends common.GrpcServiceObject { /** * @typedef {array} GetDatabaseOperationsResponse * @property {IOperation[]} 0 Array of {@link IOperation} instances. - * @param {object} nextQuery A query object to receive more results. + * @property {object} nextQuery A query object to receive more results. * @property {object} 1 The full API response. */ /** @@ -1092,7 +1092,7 @@ class Instance extends common.GrpcServiceObject { /** * @typedef {array} GetDatabasesResponse * @property {Database[]} 0 Array of {@link Database} instances. - * @param {object} nextQuery A query object to receive more results. + * @property {object} nextQuery A query object to receive more results. * @property {object} apiResponse The full API response. */ /** From dc7a6b0989df8daead25b648f1b2892b3e368a50 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 13 May 2020 16:51:25 -0400 Subject: [PATCH 17/17] fix(docs): nextQuery in GetResourcesResponse --- src/database.ts | 4 ++-- src/index.ts | 8 ++++---- src/instance.ts | 12 ++++++------ system-test/spanner.ts | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/database.ts b/src/database.ts index d35c47ee5..93f8741cc 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1175,8 +1175,8 @@ class Database extends GrpcServiceObject { /** * @typedef {array} GetSessionsResponse * @property {Session[]} 0 Array of {@link Session} instances. - * @property {object} nextQuery A query object to receive more results. - * @property {object} 1 The full API response. + * @property {object} 1 A query object to receive more results. + * @property {object} 2 The full API response. */ /** * @callback GetSessionsCallback diff --git a/src/index.ts b/src/index.ts index 4be8bdd00..c312ee445 100644 --- a/src/index.ts +++ b/src/index.ts @@ -428,8 +428,8 @@ class Spanner extends GrpcService { /** * @typedef {array} GetInstancesResponse * @property {Instance[]} 0 Array of {@link Instance} instances. - * @property {object} nextQuery A query object to receive more results. - * @property {object} 1 The full API response. + * @property {object} 1 A query object to receive more results. + * @property {object} 2 The full API response. */ /** * @callback GetInstancesCallback @@ -630,8 +630,8 @@ 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 {object} nextQuery A query object to receive more results. - * @property {object} 1 The full API response. + * @property {object} 1 A query object to receive more results. + * @property {object} 2 The full API response. */ /** * @callback GetInstanceConfigsCallback diff --git a/src/instance.ts b/src/instance.ts index 2aa0c8be7..5aaeae164 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -261,8 +261,8 @@ class Instance extends common.GrpcServiceObject { /** * @typedef {array} GetBackupsResponse * @property {Backup[]} 0 Array of {@link Backup} instances. - * @property {object} nextQuery A query object to receive more results. - * @property {object} 1 The full API response. + * @property {object} 1 A query object to receive more results. + * @property {object} 2 The full API response. */ /** * @callback GetBackupsCallback @@ -453,8 +453,8 @@ class Instance extends common.GrpcServiceObject { /** * @typedef {array} GetBackupOperationsResponse * @property {IOperation[]} 0 Array of {@link IOperation} instances. - * @property {object} nextQuery A query object to receive more results. - * @property {object} 1 The full API response. + * @property {object} 1 A query object to receive more results. + * @property {object} 2 The full API response. */ /** * @callback GetBackupOperationsCallback @@ -570,8 +570,8 @@ class Instance extends common.GrpcServiceObject { /** * @typedef {array} GetDatabaseOperationsResponse * @property {IOperation[]} 0 Array of {@link IOperation} instances. - * @property {object} nextQuery A query object to receive more results. - * @property {object} 1 The full API response. + * @property {object} 1 A query object to receive more results. + * @property {object} 2 The full API response. */ /** * @callback GetDatabaseOperationsCallback diff --git a/system-test/spanner.ts b/system-test/spanner.ts index ee00378c0..5bd3622d5 100644 --- a/system-test/spanner.ts +++ b/system-test/spanner.ts @@ -3516,7 +3516,7 @@ describe('Spanner', () => { }); } - table.read(query, (err, rows) => { + table.read(query as ReadRequest, (err, rows) => { test.assertions(err, rows); done(); });