googleapis / nodejs-spanner

Compare fe003c0 ... +91 ... 8a79b15

Showing 19 of 98 files from the diff.
Other files ignored by Codecov
test/instance.ts has changed.
test/database.ts has changed.
synth.metadata has changed.
CHANGELOG.md has changed.
test/spanner.ts has changed.
protos/protos.js has changed.
test/table.ts has changed.
README.md has changed.
src/.eslintrc.yml was deleted.
samples/README.md has changed.
tsconfig.json has changed.
test/codec.ts has changed.
samples/dml.js has changed.
test/index.ts has changed.
test/backup.ts has changed.
package.json has changed.
synth.py has changed.
test/session.ts has changed.
samples/crud.js has changed.
.kokoro/test.sh has changed.

@@ -18,7 +18,8 @@
Loading
18 18
 * @module spanner/session
19 19
 */
20 20
21 -
import {GrpcServiceObject} from './common-grpc/service-object';
21 +
// eslint-disable-next-line @typescript-eslint/no-var-requires
22 +
const common = require('./common-grpc/service-object');
22 23
import {promisifyAll} from '@google-cloud/promisify';
23 24
import * as extend from 'extend';
24 25
import * as r from 'teeny-request';
@@ -34,9 +35,9 @@
Loading
34 35
  CreateSessionCallback,
35 36
  CreateSessionOptions,
36 37
} from './database';
37 -
import {ServiceObjectConfig, DeleteCallback} from '@google-cloud/common';
38 -
import {NormalCallback} from './common';
39 -
import {ServiceError} from 'grpc';
38 +
import {ServiceObjectConfig} from '@google-cloud/common';
39 +
import {NormalCallback, CLOUD_RESOURCE_HEADER} from './common';
40 +
import {grpc, CallOptions} from 'google-gax';
40 41
41 42
export type GetSessionResponse = [Session, r.Response];
42 43
@@ -55,7 +56,9 @@
Loading
55 56
56 57
export type KeepAliveCallback = NormalCallback<google.spanner.v1.IResultSet>;
57 58
export type KeepAliveResponse = [google.spanner.v1.IResultSet];
58 -
export type DeleteResponse = [r.Response];
59 +
export type DeleteSessionResponse = [google.protobuf.IEmpty];
60 +
export type DeleteSessionCallback = NormalCallback<google.protobuf.IEmpty>;
61 +
59 62
/**
60 63
 * Create a Session object to interact with a Cloud Spanner session.
61 64
 *
@@ -94,13 +97,14 @@
Loading
94 97
 * //-
95 98
 * const session = database.session('session-name');
96 99
 */
97 -
export class Session extends GrpcServiceObject {
100 +
export class Session extends common.GrpcServiceObject {
98 101
  id!: string;
99 102
  formattedName_?: string;
100 103
  type?: types;
101 104
  txn?: Transaction;
102 105
  lastUsed?: number;
103 -
  lastError?: ServiceError;
106 +
  lastError?: grpc.ServiceError;
107 +
  resourceHeader_: {[k: string]: string};
104 108
  constructor(database: Database, name?: string) {
105 109
    const methods = {
106 110
      /**
@@ -231,15 +235,19 @@
Loading
231 235
      },
232 236
    } as {}) as ServiceObjectConfig);
233 237
238 +
    this.resourceHeader_ = {
239 +
      [CLOUD_RESOURCE_HEADER]: (this.parent as Database).formattedName_,
240 +
    };
234 241
    this.request = database.request;
235 242
    this.requestStream = database.requestStream;
236 243
237 244
    if (name) {
238 245
      this.formattedName_ = Session.formatName_(database.formattedName_, name);
239 246
    }
240 247
  }
241 -
  delete(): Promise<DeleteResponse>;
242 -
  delete(callback: DeleteCallback): void;
248 +
  delete(gaxOptions?: CallOptions): Promise<DeleteSessionResponse>;
249 +
  delete(callback: DeleteSessionCallback): void;
250 +
  delete(gaxOptions: CallOptions, callback: DeleteSessionCallback): void;
243 251
  /**
244 252
   * Delete a session.
245 253
   *
@@ -248,8 +256,10 @@
Loading
248 256
   * @see {@link v1.SpannerClient#deleteSession}
249 257
   * @see [DeleteSession API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.DeleteSession)
250 258
   *
251 -
   * @param {BasicCallback} [callback] Callback function.
252 -
   * @returns {Promise<BasicResponse>}
259 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
260 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
261 +
   * @param {DeleteSessionCallback} [callback] Callback function.
262 +
   * @returns {Promise<DeleteSessionResponse>}
253 263
   *
254 264
   * @example
255 265
   * session.delete(function(err, apiResponse) {
@@ -267,7 +277,15 @@
Loading
267 277
   *   const apiResponse = data[0];
268 278
   * });
269 279
   */
270 -
  delete(callback?: DeleteCallback): void | Promise<DeleteResponse> {
280 +
  delete(
281 +
    optionsOrCallback?: CallOptions | DeleteSessionCallback,
282 +
    cb?: DeleteSessionCallback
283 +
  ): void | Promise<DeleteSessionResponse> {
284 +
    const gaxOpts =
285 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
286 +
    const callback =
287 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
288 +
271 289
    const reqOpts = {
272 290
      name: this.formattedName_,
273 291
    };
@@ -276,12 +294,18 @@
Loading
276 294
        client: 'SpannerClient',
277 295
        method: 'deleteSession',
278 296
        reqOpts,
297 +
        gaxOpts,
298 +
        headers: this.resourceHeader_,
279 299
      },
280 300
      callback!
281 301
    );
282 302
  }
283 -
  getMetadata(): Promise<GetSessionMetadataResponse>;
303 +
  getMetadata(gaxOptions?: CallOptions): Promise<GetSessionMetadataResponse>;
284 304
  getMetadata(callback: GetSessionMetadataCallback): void;
305 +
  getMetadata(
306 +
    gaxOptions: CallOptions,
307 +
    callback: GetSessionMetadataCallback
308 +
  ): void;
285 309
  /**
286 310
   * @typedef {array} GetSessionMetadataResponse
287 311
   * @property {object} 0 The session's metadata.
@@ -301,6 +325,8 @@
Loading
301 325
   * @see {@link v1.SpannerClient#getSession}
302 326
   * @see [GetSession API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.GetSession)
303 327
   *
328 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
329 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
304 330
   * @param {GetSessionMetadataCallback} [callback] Callback function.
305 331
   * @returns {Promise<GetSessionMetadataResponse>}
306 332
   *
@@ -316,8 +342,14 @@
Loading
316 342
   * });
317 343
   */
318 344
  getMetadata(
319 -
    callback?: GetSessionMetadataCallback
345 +
    optionsOrCallback?: CallOptions | GetSessionMetadataCallback,
346 +
    cb?: GetSessionMetadataCallback
320 347
  ): void | Promise<GetSessionMetadataResponse> {
348 +
    const gaxOpts =
349 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
350 +
    const callback =
351 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
352 +
321 353
    const reqOpts = {
322 354
      name: this.formattedName_,
323 355
    };
@@ -326,15 +358,25 @@
Loading
326 358
        client: 'SpannerClient',
327 359
        method: 'getSession',
328 360
        reqOpts,
361 +
        gaxOpts,
362 +
        headers: this.resourceHeader_,
329 363
      },
330 -
      callback!
364 +
      (err, resp) => {
365 +
        if (resp) {
366 +
          this.metadata = resp;
367 +
        }
368 +
        callback!(err, resp);
369 +
      }
331 370
    );
332 371
  }
333 -
  keepAlive(): Promise<KeepAliveResponse>;
372 +
  keepAlive(gaxOptions?: CallOptions): Promise<KeepAliveResponse>;
334 373
  keepAlive(callback: KeepAliveCallback): void;
374 +
  keepAlive(gaxOptions: CallOptions, callback: KeepAliveCallback): void;
335 375
  /**
336 376
   * Ping the session with `SELECT 1` to prevent it from expiring.
337 377
   *
378 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
379 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
338 380
   * @param {BasicCallback} [callback] Callback function.
339 381
   * @returns {Promise<BasicResponse>}
340 382
   *
@@ -345,7 +387,15 @@
Loading
345 387
   *   }
346 388
   * });
347 389
   */
348 -
  keepAlive(callback?: KeepAliveCallback): void | Promise<KeepAliveResponse> {
390 +
  keepAlive(
391 +
    optionsOrCallback?: CallOptions | KeepAliveCallback,
392 +
    cb?: KeepAliveCallback
393 +
  ): void | Promise<KeepAliveResponse> {
394 +
    const gaxOpts =
395 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
396 +
    const callback =
397 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
398 +
349 399
    const reqOpts = {
350 400
      session: this.formattedName_,
351 401
      sql: 'SELECT 1',
@@ -355,6 +405,8 @@
Loading
355 405
        client: 'SpannerClient',
356 406
        method: 'executeSql',
357 407
        reqOpts,
408 +
        gaxOpts,
409 +
        headers: this.resourceHeader_,
358 410
      },
359 411
      callback!
360 412
    );

@@ -15,51 +15,47 @@
Loading
15 15
 */
16 16
17 17
import {GrpcService, GrpcServiceConfig} from './common-grpc/service';
18 -
import {paginator} from '@google-cloud/paginator';
19 18
import {PreciseDate} from '@google-cloud/precise-date';
20 19
import {replaceProjectIdToken} from '@google-cloud/projectify';
21 20
import {promisifyAll} from '@google-cloud/promisify';
22 21
import * as extend from 'extend';
23 22
import {GoogleAuth, GoogleAuthOptions} from 'google-auth-library';
24 -
import * as is from 'is';
25 23
import * as path from 'path';
26 24
import {common as p} from 'protobufjs';
27 25
import * as streamEvents from 'stream-events';
28 26
import * as through from 'through2';
29 -
import {codec, Float, Int, SpannerDate, Struct} from './codec';
27 +
import {codec, Float, Int, Numeric, SpannerDate, Struct} from './codec';
30 28
import {Backup} from './backup';
31 29
import {Database} from './database';
32 30
import {
33 31
  Instance,
34 32
  CreateInstanceCallback,
35 33
  CreateInstanceResponse,
36 34
} from './instance';
35 +
import {grpc, GrpcClientOptions, CallOptions} from 'google-gax';
37 36
import {google as instanceAdmin} from '../protos/protos';
38 -
import {PagedRequest, PagedResponse, PagedCallback} from './common';
37 +
import {
38 +
  PagedOptions,
39 +
  PagedResponse,
40 +
  PagedCallback,
41 +
  PagedOptionsWithFilter,
42 +
  CLOUD_RESOURCE_HEADER,
43 +
} from './common';
39 44
import {Session} from './session';
40 45
import {SessionPool} from './session-pool';
41 46
import {Table} from './table';
42 47
import {PartitionedDml, Snapshot, Transaction} from './transaction';
43 -
import {GrpcClientOptions} from 'google-gax';
44 -
import {ChannelCredentials} from 'grpc';
45 -
import {
46 -
  createGcpApiConfig,
47 -
  gcpCallInvocationTransformer,
48 -
  gcpChannelFactoryOverride,
49 -
} from 'grpc-gcp';
48 +
import grpcGcpModule = require('grpc-gcp');
49 +
const grpcGcp = grpcGcpModule(grpc);
50 50
import * as v1 from './v1';
51 -
import * as grpc from 'grpc';
52 51
53 52
// eslint-disable-next-line @typescript-eslint/no-var-requires
54 53
const gcpApiConfig = require('./spanner_grpc_config.json');
55 54
56 55
export type IOperation = instanceAdmin.longrunning.IOperation;
57 56
58 -
export type GetInstancesRequest = PagedRequest<
59 -
  instanceAdmin.spanner.admin.instance.v1.IListInstancesRequest & {
60 -
    maxResults?: number;
61 -
  }
62 -
>;
57 +
export type GetInstancesOptions = PagedOptionsWithFilter;
58 +
63 59
export type GetInstancesResponse = PagedResponse<
64 60
  Instance,
65 61
  instanceAdmin.spanner.admin.instance.v1.IListInstancesResponse
@@ -69,37 +65,36 @@
Loading
69 65
  instanceAdmin.spanner.admin.instance.v1.IListInstancesResponse
70 66
>;
71 67
72 -
export type GetInstanceConfigsRequest = PagedRequest<
73 -
  instanceAdmin.spanner.admin.instance.v1.IListInstanceConfigsRequest & {
74 -
    maxResults?: number;
75 -
  }
76 -
>;
68 +
export type GetInstanceConfigsOptions = PagedOptions;
77 69
export type GetInstanceConfigsResponse = PagedResponse<
78 -
  instanceAdmin.spanner.admin.instance.v1.InstanceConfig,
70 +
  instanceAdmin.spanner.admin.instance.v1.IInstanceConfig,
79 71
  instanceAdmin.spanner.admin.instance.v1.IListInstanceConfigsResponse
80 72
>;
81 73
export type GetInstanceConfigsCallback = PagedCallback<
82 -
  instanceAdmin.spanner.admin.instance.v1.InstanceConfig,
74 +
  instanceAdmin.spanner.admin.instance.v1.IInstanceConfig,
83 75
  instanceAdmin.spanner.admin.instance.v1.IListInstanceConfigsResponse
84 76
>;
85 77
86 78
export interface SpannerOptions extends GrpcClientOptions {
87 79
  apiEndpoint?: string;
88 80
  servicePath?: string;
89 81
  port?: number;
90 -
  sslCreds?: ChannelCredentials;
82 +
  sslCreds?: grpc.ChannelCredentials;
91 83
}
92 84
export interface RequestConfig {
93 85
  client: string;
94 86
  method: string;
95 87
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
96 88
  reqOpts: any;
97 -
  gaxOpts?: {};
89 +
  gaxOpts?: CallOptions;
90 +
  headers: {[k: string]: string};
98 91
}
99 92
export interface CreateInstanceRequest {
100 -
  config: string;
93 +
  config?: string;
101 94
  nodes?: number;
95 +
  displayName?: string;
102 96
  labels?: {[k: string]: string} | null;
97 +
  gaxOptions?: CallOptions;
103 98
}
104 99
/**
105 100
 * Translates enum values to string keys.
@@ -161,7 +156,8 @@
Loading
161 156
  auth: GoogleAuth;
162 157
  clients_: Map<string, {}>;
163 158
  instances_: Map<string, Instance>;
164 -
  getInstancesStream: Function;
159 +
  projectFormattedName_: string;
160 +
  resourceHeader_: {[k: string]: string};
165 161
166 162
  /**
167 163
   * Placeholder used to auto populate a column with the commit timestamp.
@@ -225,9 +221,9 @@
Loading
225 221
        libVersion: require('../../package.json').version,
226 222
        scopes,
227 223
        // Enable grpc-gcp support
228 -
        'grpc.callInvocationTransformer': gcpCallInvocationTransformer,
229 -
        'grpc.channelFactoryOverride': gcpChannelFactoryOverride,
230 -
        'grpc.gcpApiConfig': createGcpApiConfig(gcpApiConfig),
224 +
        'grpc.callInvocationTransformer': grpcGcp.gcpCallInvocationTransformer,
225 +
        'grpc.channelFactoryOverride': grpcGcp.gcpChannelFactoryOverride,
226 +
        'grpc.gcpApiConfig': grpcGcp.createGcpApiConfig(gcpApiConfig),
231 227
        grpc,
232 228
      },
233 229
      options || {}
@@ -262,43 +258,10 @@
Loading
262 258
    this.auth = new GoogleAuth(this.options);
263 259
    this.clients_ = new Map();
264 260
    this.instances_ = new Map();
265 -
266 -
    /**
267 -
     * Get a list of {@link Instance} objects as a readable object stream.
268 -
     *
269 -
     * Wrapper around {@link v1.InstanceAdminClient#listInstances}.
270 -
     *
271 -
     * @see {@link v1.InstanceAdminClient#listInstances}
272 -
     * @see [ListInstances API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstances)
273 -
     *
274 -
     * @method Spanner#getInstancesStream
275 -
     * @param {GetInstancesRequest} [query] Query object for listing instances.
276 -
     * @returns {ReadableStream} A readable stream that emits {@link Instance}
277 -
     *     instances.
278 -
     *
279 -
     * @example
280 -
     * const {Spanner} = require('@google-cloud/spanner');
281 -
     * const spanner = new Spanner();
282 -
     *
283 -
     * spanner.getInstancesStream()
284 -
     *   .on('error', console.error)
285 -
     *   .on('data', function(instance) {
286 -
     *     // `instance` is an `Instance` object.
287 -
     *   })
288 -
     *   .on('end', function() {
289 -
     *     // All instances retrieved.
290 -
     *   });
291 -
     *
292 -
     * //-
293 -
     * // If you anticipate many results, you can end a stream early to prevent
294 -
     * // unnecessary processing and API requests.
295 -
     * //-
296 -
     * spanner.getInstancesStream()
297 -
     *   .on('data', function(instance) {
298 -
     *     this.end();
299 -
     *   });
300 -
     */
301 -
    this.getInstancesStream = paginator.streamify('getInstances');
261 +
    this.projectFormattedName_ = 'projects/' + this.projectId;
262 +
    this.resourceHeader_ = {
263 +
      [CLOUD_RESOURCE_HEADER]: this.projectFormattedName_,
264 +
    };
302 265
  }
303 266
304 267
  createInstance(
@@ -324,6 +287,11 @@
Loading
324 287
   *     be used to control how resource metrics are aggregated. And they can
325 288
   *     be used as arguments to policy management rules (e.g. route,
326 289
   *     firewall, load balancing, etc.).
290 +
   * @property {string} [displayName] The descriptive name for this instance
291 +
   *     as it appears in UIs. Must be unique per project and between 4 and 30
292 +
   *     characters in length.
293 +
   *     Defaults to the instance unique identifier '<instance>' of the full
294 +
   *     instance name of the form 'projects/<project>/instances/<instance>'.
327 295
   */
328 296
  /**
329 297
   * @typedef {array} CreateInstanceResponse
@@ -406,30 +374,33 @@
Loading
406 374
      );
407 375
    }
408 376
    const formattedName = Instance.formatName_(this.projectId, name);
409 -
    const shortName = formattedName.split('/').pop();
377 +
    const displayName = config.displayName || formattedName.split('/').pop();
410 378
    const reqOpts = {
411 -
      parent: 'projects/' + this.projectId,
412 -
      instanceId: shortName,
379 +
      parent: this.projectFormattedName_,
380 +
      instanceId: formattedName.split('/').pop(),
413 381
      instance: extend(
414 382
        {
415 383
          name: formattedName,
416 -
          displayName: shortName,
384 +
          displayName,
417 385
          nodeCount: config.nodes || 1,
418 386
        },
419 387
        config
420 388
      ),
421 389
    };
422 390
423 391
    delete reqOpts.instance.nodes;
392 +
    delete reqOpts.instance.gaxOptions;
424 393
425 -
    if (config.config.indexOf('/') === -1) {
394 +
    if (config.config!.indexOf('/') === -1) {
426 395
      reqOpts.instance.config = `projects/${this.projectId}/instanceConfigs/${config.config}`;
427 396
    }
428 397
    this.request(
429 398
      {
430 399
        client: 'InstanceAdminClient',
431 400
        method: 'createInstance',
432 401
        reqOpts,
402 +
        gaxOpts: config.gaxOptions,
403 +
        headers: this.resourceHeader_,
433 404
      },
434 405
      (err, operation, resp) => {
435 406
        if (err) {
@@ -442,18 +413,18 @@
Loading
442 413
    );
443 414
  }
444 415
445 -
  getInstances(query?: GetInstancesRequest): Promise<GetInstancesResponse>;
416 +
  getInstances(options?: GetInstancesOptions): Promise<GetInstancesResponse>;
446 417
  getInstances(callback: GetInstancesCallback): void;
447 418
  getInstances(
448 -
    query: GetInstancesRequest,
419 +
    query: GetInstancesOptions,
449 420
    callback: GetInstancesCallback
450 421
  ): void;
451 422
  /**
452 423
   * Query object for listing instances.
453 424
   *
454 -
   * @typedef {object} GetInstancesRequest
455 -
   * @property {boolean} [autoPaginate=true] Have pagination handled
456 -
   *     automatically.
425 +
   * @typedef {object} GetInstancesOptions
426 +
   * @property {object} [gaxOptions] Request configuration options, outlined
427 +
   *     here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
457 428
   * @property {string} [filter] An expression for filtering the results of the
458 429
   *     request. Filter rules are case insensitive. The fields eligible for
459 430
   *     filtering are:
@@ -468,21 +439,21 @@
Loading
468 439
   *     - **`labels.env:dev`** The instance's label env has the value dev.
469 440
   *     - **`name:howl labels.env:dev`** The instance's name is howl and it has
470 441
   *       the label env with value dev.
471 -
   * @property {number} [maxApiCalls] Maximum number of API calls to make.
472 -
   * @property {number} [maxResults] Maximum number of items to return.
473 442
   * @property {number} [pageSize] Maximum number of results per page.
474 443
   * @property {string} [pageToken] A previously-returned page token
475 444
   *     representing part of the larger set of results to view.
476 445
   */
477 446
  /**
478 447
   * @typedef {array} GetInstancesResponse
479 448
   * @property {Instance[]} 0 Array of {@link Instance} instances.
480 -
   * @property {object} 1 The full API response.
449 +
   * @property {object} 1 A query object to receive more results.
450 +
   * @property {object} 2 The full API response.
481 451
   */
482 452
  /**
483 453
   * @callback GetInstancesCallback
484 454
   * @param {?Error} err Request error, if any.
485 455
   * @param {Instance[]} instances Array of {@link Instance} instances.
456 +
   * @param {string} nextQuery A query object to receive more results.
486 457
   * @param {object} apiResponse The full API response.
487 458
   */
488 459
  /**
@@ -493,7 +464,7 @@
Loading
493 464
   * @see {@link v1.InstanceAdminClient#listInstances}
494 465
   * @see [ListInstances API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstances)
495 466
   *
496 -
   * @param {GetInstancesRequest} [query] Query object for listing instances.
467 +
   * @param {GetInstancesOptions} [options] Query object for listing instances.
497 468
   * @param {GetInstancesCallback} [callback] Callback function.
498 469
   * @returns {Promise<GetInstancesResponse>}
499 470
   *
@@ -517,7 +488,9 @@
Loading
517 488
   * }
518 489
   *
519 490
   * spanner.getInstances({
520 -
   *   autoPaginate: false
491 +
   *   gaxOptions: {
492 +
   *     autoPaginate: false,
493 +
   *   }
521 494
   * }, callback);
522 495
   *
523 496
   * //-
@@ -528,26 +501,50 @@
Loading
528 501
   * });
529 502
   */
530 503
  getInstances(
531 -
    query?: GetInstancesRequest | GetInstancesCallback,
532 -
    callback?: GetInstancesCallback
504 +
    optionsOrCallback?: GetInstancesOptions | GetInstancesCallback,
505 +
    cb?: GetInstancesCallback
533 506
  ): Promise<GetInstancesResponse> | void {
534 507
    // eslint-disable-next-line @typescript-eslint/no-this-alias
535 508
    const self = this;
536 -
    if (is.fn(query)) {
537 -
      callback = query as GetInstancesCallback;
538 -
      query = {};
539 -
    }
540 -
    const reqOpts = extend({}, query, {
509 +
    const options =
510 +
      typeof optionsOrCallback === 'object'
511 +
        ? optionsOrCallback
512 +
        : ({} as GetInstancesOptions);
513 +
    const callback =
514 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
515 +
516 +
    const gaxOpts = extend(true, {}, options.gaxOptions);
517 +
518 +
    let reqOpts = extend({}, options, {
541 519
      parent: 'projects/' + this.projectId,
542 520
    });
521 +
522 +
    delete reqOpts.gaxOptions;
523 +
524 +
    // Copy over pageSize and pageToken values from gaxOptions.
525 +
    // However values set on options take precedence.
526 +
    if (gaxOpts) {
527 +
      reqOpts = extend(
528 +
        {},
529 +
        {
530 +
          pageSize: gaxOpts.pageSize,
531 +
          pageToken: gaxOpts.pageToken,
532 +
        },
533 +
        reqOpts
534 +
      );
535 +
      delete gaxOpts.pageToken;
536 +
      delete gaxOpts.pageSize;
537 +
    }
538 +
543 539
    this.request(
544 540
      {
545 541
        client: 'InstanceAdminClient',
546 542
        method: 'listInstances',
547 543
        reqOpts,
548 -
        gaxOpts: query,
544 +
        gaxOpts,
545 +
        headers: this.resourceHeader_,
549 546
      },
550 -
      (err, instances, ...args) => {
547 +
      (err, instances, nextPageRequest, ...args) => {
551 548
        let instanceInstances: Instance[] | null = null;
552 549
        if (instances) {
553 550
          instanceInstances = instances.map(instance => {
@@ -556,38 +553,108 @@
Loading
556 553
            return instanceInstance;
557 554
          });
558 555
        }
559 -
        callback!(err, instanceInstances, ...args);
556 +
        const nextQuery = nextPageRequest!
557 +
          ? extend({}, options, nextPageRequest!)
558 +
          : null;
559 +
        callback!(err, instanceInstances, nextQuery, ...args);
560 560
      }
561 561
    );
562 562
  }
563 563
564 +
  /**
565 +
   * Get a list of {@link Instance} objects as a readable object stream.
566 +
   *
567 +
   * Wrapper around {@link v1.InstanceAdminClient#listInstances}.
568 +
   *
569 +
   * @see {@link v1.InstanceAdminClient#listInstances}
570 +
   * @see [ListInstances API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstances)
571 +
   *
572 +
   * @method Spanner#getInstancesStream
573 +
   * @param {GetInstancesOptions} [options] Query object for listing instances.
574 +
   * @returns {ReadableStream} A readable stream that emits {@link Instance}
575 +
   *     instances.
576 +
   *
577 +
   * @example
578 +
   * const {Spanner} = require('@google-cloud/spanner');
579 +
   * const spanner = new Spanner();
580 +
   *
581 +
   * spanner.getInstancesStream()
582 +
   *   .on('error', console.error)
583 +
   *   .on('data', function(instance) {
584 +
   *     // `instance` is an `Instance` object.
585 +
   *   })
586 +
   *   .on('end', function() {
587 +
   *     // All instances retrieved.
588 +
   *   });
589 +
   *
590 +
   * //-
591 +
   * // If you anticipate many results, you can end a stream early to prevent
592 +
   * // unnecessary processing and API requests.
593 +
   * //-
594 +
   * spanner.getInstancesStream()
595 +
   *   .on('data', function(instance) {
596 +
   *     this.end();
597 +
   *   });
598 +
   */
599 +
  getInstancesStream(options: GetInstancesOptions = {}): NodeJS.ReadableStream {
600 +
    const gaxOpts = extend(true, {}, options.gaxOptions);
601 +
602 +
    let reqOpts = extend({}, options, {
603 +
      parent: 'projects/' + this.projectId,
604 +
    });
605 +
    delete reqOpts.gaxOptions;
606 +
607 +
    // Copy over pageSize and pageToken values from gaxOptions.
608 +
    // However values set on options take precedence.
609 +
    if (gaxOpts) {
610 +
      reqOpts = extend(
611 +
        {},
612 +
        {
613 +
          pageSize: gaxOpts.pageSize,
614 +
          pageToken: gaxOpts.pageToken,
615 +
        },
616 +
        reqOpts
617 +
      );
618 +
      delete gaxOpts.pageSize;
619 +
      delete gaxOpts.pageToken;
620 +
    }
621 +
622 +
    return this.requestStream({
623 +
      client: 'InstanceAdminClient',
624 +
      method: 'listInstancesStream',
625 +
      reqOpts,
626 +
      gaxOpts,
627 +
      headers: this.resourceHeader_,
628 +
    });
629 +
  }
630 +
564 631
  getInstanceConfigs(
565 -
    query?: GetInstanceConfigsRequest
632 +
    query?: GetInstanceConfigsOptions
566 633
  ): Promise<GetInstanceConfigsResponse>;
567 634
  getInstanceConfigs(callback: GetInstanceConfigsCallback): void;
568 635
  getInstanceConfigs(
569 -
    query: GetInstanceConfigsRequest,
636 +
    query: GetInstanceConfigsOptions,
570 637
    callback: GetInstanceConfigsCallback
571 638
  ): void;
572 639
  /**
573 -
   * Query object for listing instance configs.
640 +
   * Lists the supported instance configurations for a given project.
574 641
   *
575 -
   * @typedef {object} GetInstanceConfigsRequest
576 -
   * @property {boolean} [autoPaginate=true] Have pagination handled
577 -
   *     automatically.
578 -
   * @property {number} [maxApiCalls] Maximum number of API calls to make.
579 -
   * @property {number} [maxResults] Maximum number of items to return.
642 +
   * @typedef {object} GetInstanceConfigsOptions
580 643
   * @property {number} [pageSize] Maximum number of results per page.
581 644
   * @property {string} [pageToken] A previously-returned page token
582 645
   *     representing part of the larger set of results to view.
646 +
   * @property {object} [gaxOptions] Request configuration options, outlined
647 +
   *     here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
648 +
583 649
   */
584 650
  /**
585 651
   * @typedef {array} GetInstanceConfigsResponse
586 652
   * @property {object[]} 0 List of all available instance configs.
587 653
   * @property {string} 0.name The unique identifier for the instance config.
588 654
   * @property {string} 0.displayName The name of the instance config as it
589 655
   *     appears in UIs.
590 -
   * @property {object} 1 The full API response.
656 +
   * @property {object} 1 A query object to receive more results.
657 +
   * @property {object} 2 The full API response.
591 658
   */
592 659
  /**
593 660
   * @callback GetInstanceConfigsCallback
@@ -597,6 +664,7 @@
Loading
597 664
   *     config.
598 665
   * @param {string} instanceConfigs.displayName The name of the instance config
599 666
   *     as it appears in UIs.
667 +
   * @param {object} nextQuery A query object to receive more results.
600 668
   * @param {object} apiResponse The full API response.
601 669
   */
602 670
  /**
@@ -607,7 +675,7 @@
Loading
607 675
   * @see {@link v1.InstanceAdminClient#listInstanceConfigs}
608 676
   * @see [ListInstanceConfigs API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstanceConfigs)
609 677
   *
610 -
   * @param {GetInstanceConfigsRequest} [query] Query object for listing instance
678 +
   * @param {GetInstanceConfigsOptions} [options] Query object for listing instance
611 679
   *     configs.
612 680
   * @param {GetInstanceConfigsCallback} [callback] Callback function.
613 681
   * @returns {Promise<GetInstanceConfigsResponse>}
@@ -632,7 +700,9 @@
Loading
632 700
   * }
633 701
   *
634 702
   * spanner.getInstanceConfigs({
635 -
   *   autoPaginate: false
703 +
   *   gaxOptions: {
704 +
   *     autoPaginate: false,
705 +
   *   }
636 706
   * }, callback);
637 707
   *
638 708
   * //-
@@ -643,28 +713,51 @@
Loading
643 713
   * });
644 714
   */
645 715
  getInstanceConfigs(
646 -
    queryOrCallback?: GetInstanceConfigsRequest | GetInstanceConfigsCallback,
716 +
    optionsOrCallback?: GetInstanceConfigsOptions | GetInstanceConfigsCallback,
647 717
    cb?: GetInstanceConfigsCallback
648 718
  ): Promise<GetInstanceConfigsResponse> | void {
649 719
    const callback =
650 -
      typeof queryOrCallback === 'function'
651 -
        ? (queryOrCallback as GetInstanceConfigsCallback)
652 -
        : cb;
653 -
    const query =
654 -
      typeof queryOrCallback === 'object'
655 -
        ? (queryOrCallback as GetInstanceConfigsRequest)
656 -
        : {};
657 -
    const reqOpts = extend({}, query, {
720 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
721 +
    const options =
722 +
      typeof optionsOrCallback === 'object'
723 +
        ? optionsOrCallback
724 +
        : ({} as GetInstanceConfigsOptions);
725 +
726 +
    const gaxOpts = extend(true, {}, options.gaxOptions);
727 +
    let reqOpts = extend({}, options, {
658 728
      parent: 'projects/' + this.projectId,
659 729
    });
730 +
    delete reqOpts.gaxOptions;
731 +
732 +
    // Copy over pageSize and pageToken values from gaxOptions.
733 +
    // However values set on options take precedence.
734 +
    if (gaxOpts) {
735 +
      reqOpts = extend(
736 +
        {},
737 +
        {
738 +
          pageSize: gaxOpts.pageSize,
739 +
          pageToken: gaxOpts.pageToken,
740 +
        },
741 +
        reqOpts
742 +
      );
743 +
      delete gaxOpts.pageSize;
744 +
      delete gaxOpts.pageToken;
745 +
    }
746 +
660 747
    return this.request(
661 748
      {
662 749
        client: 'InstanceAdminClient',
663 750
        method: 'listInstanceConfigs',
664 751
        reqOpts,
665 -
        gaxOpts: query,
752 +
        gaxOpts,
753 +
        headers: this.resourceHeader_,
666 754
      },
667 -
      callback
755 +
      (err, instanceConfigs, nextPageRequest, ...args) => {
756 +
        const nextQuery = nextPageRequest!
757 +
          ? extend({}, options, nextPageRequest!)
758 +
          : null;
759 +
        callback!(err, instanceConfigs, nextQuery, ...args);
760 +
      }
668 761
    );
669 762
  }
670 763
@@ -677,7 +770,7 @@
Loading
677 770
   * @see [ListInstanceConfigs API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstanceConfigs)
678 771
   *
679 772
   * @method Spanner#getInstanceConfigsStream
680 -
   * @param {GetInstanceConfigsRequest} [query] Query object for listing instance
773 +
   * @param {GetInstanceConfigsOptions} [options] Query object for listing instance
681 774
   *     configs.
682 775
   * @returns {ReadableStream} A readable stream that emits instance configs.
683 776
   *
@@ -702,16 +795,36 @@
Loading
702 795
   *   });
703 796
   */
704 797
  getInstanceConfigsStream(
705 -
    query?: GetInstanceConfigsRequest
798 +
    options: GetInstanceConfigsOptions = {}
706 799
  ): NodeJS.ReadableStream {
707 -
    const reqOpts = extend({}, query, {
800 +
    const gaxOpts = extend(true, {}, options.gaxOptions);
801 +
802 +
    let reqOpts = extend({}, options, {
708 803
      parent: 'projects/' + this.projectId,
709 804
    });
805 +
806 +
    // Copy over pageSize and pageToken values from gaxOptions.
807 +
    // However values set on options take precedence.
808 +
    if (gaxOpts) {
809 +
      reqOpts = extend(
810 +
        {},
811 +
        {
812 +
          pageSize: gaxOpts.pageSize,
813 +
          pageToken: gaxOpts.pageToken,
814 +
        },
815 +
        reqOpts
816 +
      );
817 +
      delete gaxOpts.pageSize;
818 +
      delete gaxOpts.pageToken;
819 +
    }
820 +
821 +
    delete reqOpts.gaxOptions;
710 822
    return this.requestStream({
711 823
      client: 'InstanceAdminClient',
712 824
      method: 'listInstanceConfigsStream',
713 825
      reqOpts,
714 -
      gaxOpts: query,
826 +
      gaxOpts,
827 +
      headers: this.resourceHeader_,
715 828
    });
716 829
  }
717 830
@@ -764,7 +877,12 @@
Loading
764 877
      const requestFn = gaxClient[config.method].bind(
765 878
        gaxClient,
766 879
        reqOpts,
767 -
        config.gaxOpts
880 +
        // Add headers to `gaxOpts`
881 +
        extend(true, {}, config.gaxOpts, {
882 +
          otherArgs: {
883 +
            headers: config.headers,
884 +
          },
885 +
        })
768 886
      );
769 887
      callback(null, requestFn);
770 888
    });
@@ -783,7 +901,7 @@
Loading
783 901
   */
784 902
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
785 903
  request(config: any, callback?: any): any {
786 -
    if (is.fn(callback)) {
904 +
    if (typeof callback === 'function') {
787 905
      this.prepareGapicRequest_(config, (err, requestFn) => {
788 906
        if (err) {
789 907
          callback(err);
@@ -939,6 +1057,20 @@
Loading
939 1057
    return new codec.Int(value);
940 1058
  }
941 1059
1060 +
  /**
1061 +
   * Helper function to get a Cloud Spanner Numeric object.
1062 +
   *
1063 +
   * @param {string} value The numeric value as a string.
1064 +
   * @returns {Numeric}
1065 +
   *
1066 +
   * @example
1067 +
   * const {Spanner} = require('@google-cloud/spanner');
1068 +
   * const numeric = Spanner.numeric("3.141592653");
1069 +
   */
1070 +
  static numeric(value): Numeric {
1071 +
    return new codec.Numeric(value);
1072 +
  }
1073 +
942 1074
  /**
943 1075
   * Helper function to get a Cloud Spanner Struct object.
944 1076
   *
@@ -969,9 +1101,9 @@
Loading
969 1101
  exclude: [
970 1102
    'date',
971 1103
    'float',
972 -
    'getInstanceConfigs',
973 1104
    'instance',
974 1105
    'int',
1106 +
    'numeric',
975 1107
    'operation',
976 1108
    'timestamp',
977 1109
  ],

@@ -16,7 +16,7 @@
Loading
16 16
17 17
import {promisifyAll} from '@google-cloud/promisify';
18 18
import * as through from 'through2';
19 -
import {Operation as GaxOperation} from 'google-gax';
19 +
import {Operation as GaxOperation, CallOptions} from 'google-gax';
20 20
import {Database, UpdateSchemaCallback, UpdateSchemaResponse} from './database';
21 21
import {PartialResultStream, Row} from './partial-result-stream';
22 22
import {
@@ -90,8 +90,16 @@
Loading
90 90
     */
91 91
    this.name = name;
92 92
  }
93 -
  create(schema: Schema): Promise<CreateTableResponse>;
93 +
  create(
94 +
    schema: Schema,
95 +
    gaxOptions?: CallOptions
96 +
  ): Promise<CreateTableResponse>;
94 97
  create(schema: Schema, callback: CreateTableCallback): void;
98 +
  create(
99 +
    schema: Schema,
100 +
    gaxOptions: CallOptions,
101 +
    callback: CreateTableCallback
102 +
  ): void;
95 103
  /**
96 104
   * Create a table.
97 105
   *
@@ -143,9 +151,15 @@
Loading
143 151
   */
144 152
  create(
145 153
    schema: Schema,
146 -
    callback?: CreateTableCallback
154 +
    gaxOptionsOrCallback?: CallOptions | CreateTableCallback,
155 +
    cb?: CreateTableCallback
147 156
  ): Promise<CreateTableResponse> | void {
148 -
    this.database.createTable(schema, callback!);
157 +
    const gaxOptions =
158 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
159 +
    const callback =
160 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
161 +
162 +
    this.database.createTable(schema, gaxOptions, callback!);
149 163
  }
150 164
  /**
151 165
   * Create a readable object stream to receive rows from the database using key
@@ -236,8 +250,9 @@
Loading
236 250
237 251
    return proxyStream as PartialResultStream;
238 252
  }
239 -
  delete(): Promise<DropTableResponse>;
253 +
  delete(gaxOptions?: CallOptions): Promise<DropTableResponse>;
240 254
  delete(callback: DropTableCallback): void;
255 +
  delete(gaxOptions: CallOptions, callback: DropTableCallback): void;
241 256
  /**
242 257
   * Delete the table. Not to be confused with {@link Table#deleteRows}.
243 258
   *
@@ -246,6 +261,8 @@
Loading
246 261
   * @see {@link Database#updateSchema}
247 262
   *
248 263
   * @throws {TypeError} If any arguments are passed in.
264 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
265 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
249 266
   * @param {LongRunningOperationCallback} [callback] Callback function.
250 267
   * @returns {Promise<LongRunningOperationResponse>}
251 268
   *
@@ -281,20 +298,31 @@
Loading
281 298
   *     // Table deleted successfully.
282 299
   *   });
283 300
   */
284 -
  delete(callback?: DropTableCallback): Promise<DropTableResponse> | void {
285 -
    if (callback && typeof callback !== 'function') {
286 -
      throw new TypeError(
287 -
        'Unexpected argument, please see Table#deleteRows to delete rows.'
288 -
      );
289 -
    }
301 +
  delete(
302 +
    gaxOptionsOrCallback?: CallOptions | DropTableCallback,
303 +
    cb?: DropTableCallback
304 +
  ): Promise<DropTableResponse> | void {
305 +
    const gaxOptions =
306 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
307 +
    const callback =
308 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
290 309
291 310
    return this.database.updateSchema(
292 311
      'DROP TABLE `' + this.name + '`',
312 +
      gaxOptions,
293 313
      callback!
294 314
    );
295 315
  }
296 -
  deleteRows(keys: Key[]): Promise<DeleteRowsResponse>;
316 +
  deleteRows(
317 +
    keys: Key[],
318 +
    gaxOptions?: CallOptions
319 +
  ): Promise<DeleteRowsResponse>;
297 320
  deleteRows(keys: Key[], callback: DeleteRowsCallback): void;
321 +
  deleteRows(
322 +
    keys: Key[],
323 +
    gaxOptions: CallOptions,
324 +
    callback: DeleteRowsCallback
325 +
  ): void;
298 326
  /**
299 327
   * Delete rows from this table.
300 328
   *
@@ -303,6 +331,8 @@
Loading
303 331
   * @param {array} keys The keys for the rows to delete. If using a
304 332
   *     composite key, provide an array within this array. See the example
305 333
   * below.
334 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
335 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
306 336
   * @param {BasicCallback} [callback] Callback function.
307 337
   * @returns {Promise<BasicResponse>}
308 338
   *
@@ -342,18 +372,27 @@
Loading
342 372
   */
343 373
  deleteRows(
344 374
    keys: Key[],
345 -
    callback?: DeleteRowsCallback
375 +
    gaxOptionsOrCallback?: CallOptions | DeleteRowsCallback,
376 +
    cb?: DeleteRowsCallback
346 377
  ): Promise<DeleteRowsResponse> | void {
347 -
    return this._mutate('deleteRows', keys, callback!);
378 +
    const gaxOptions =
379 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
380 +
    const callback =
381 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
382 +
383 +
    return this._mutate('deleteRows', keys, gaxOptions, callback!);
348 384
  }
349 -
  drop(): Promise<DropTableResponse>;
385 +
  drop(gaxOptions?: CallOptions): Promise<DropTableResponse>;
350 386
  drop(callback: DropTableCallback): void;
387 +
  drop(gaxOptions: CallOptions, callback: DropTableCallback): void;
351 388
  /**
352 389
   * Drop the table.
353 390
   *
354 391
   * @see {@link Table#delete}
355 392
   * @see {@link Database#updateSchema}
356 393
   *
394 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
395 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
357 396
   * @param {LongRunningOperationCallback} [callback] Callback function.
358 397
   * @returns {Promise<LongRunningOperationResponse>}
359 398
   *
@@ -389,18 +428,36 @@
Loading
389 428
   *     // Table dropped successfully.
390 429
   *   });
391 430
   */
392 -
  drop(callback?: DropTableCallback): Promise<DropTableResponse> | void {
393 -
    return this.delete(callback!);
431 +
  drop(
432 +
    gaxOptionsOrCallback?: CallOptions | DropTableCallback,
433 +
    cb?: DropTableCallback
434 +
  ): Promise<DropTableResponse> | void {
435 +
    const gaxOptions =
436 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
437 +
    const callback =
438 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
439 +
440 +
    return this.delete(gaxOptions, callback!);
394 441
  }
395 -
  insert(rows: object | object[]): Promise<InsertRowsResponse>;
442 +
  insert(
443 +
    rows: object | object[],
444 +
    gaxOptions?: CallOptions
445 +
  ): Promise<InsertRowsResponse>;
396 446
  insert(rows: object | object[], callback: InsertRowsCallback): void;
447 +
  insert(
448 +
    rows: object | object[],
449 +
    gaxOptions: CallOptions,
450 +
    callback: InsertRowsCallback
451 +
  ): void;
397 452
  /**
398 453
   * Insert rows of data into this table.
399 454
   *
400 455
   * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit)
401 456
   *
402 457
   * @param {object|object[]} rows A map of names to values of data to insert
403 458
   *     into this table.
459 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
460 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
404 461
   * @param {BasicCallback} [callback] Callback function.
405 462
   * @returns {Promise<BasicResponse>}
406 463
   *
@@ -452,9 +509,15 @@
Loading
452 509
   */
453 510
  insert(
454 511
    rows: object | object[],
455 -
    callback?: InsertRowsCallback
512 +
    gaxOptionsOrCallback?: CallOptions | InsertRowsCallback,
513 +
    cb?: InsertRowsCallback
456 514
  ): Promise<InsertRowsResponse> | void {
457 -
    this._mutate('insert', rows, callback!);
515 +
    const gaxOptions =
516 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
517 +
    const callback =
518 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
519 +
520 +
    this._mutate('insert', rows, gaxOptions, callback!);
458 521
  }
459 522
  read(request: ReadRequest, options?: TimestampBounds): Promise<ReadResponse>;
460 523
  read(request: ReadRequest, callback: ReadCallback): void;
@@ -634,15 +697,25 @@
Loading
634 697
      .on('data', (row: Row) => rows.push(row))
635 698
      .on('end', () => callback!(null, rows));
636 699
  }
637 -
  replace(rows: object | object[]): Promise<ReplaceRowsResponse>;
700 +
  replace(
701 +
    rows: object | object[],
702 +
    gaxOptions?: CallOptions
703 +
  ): Promise<ReplaceRowsResponse>;
638 704
  replace(rows: object | object[], callback: ReplaceRowsCallback): void;
705 +
  replace(
706 +
    rows: object | object[],
707 +
    gaxOptions: CallOptions,
708 +
    callback: ReplaceRowsCallback
709 +
  ): void;
639 710
  /**
640 711
   * Replace rows of data within this table.
641 712
   *
642 713
   * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit)
643 714
   *
644 715
   * @param {object|object[]} rows A map of names to values of data to insert
645 716
   *     into this table.
717 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
718 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
646 719
   * @param {BasicCallback} [callback] Callback function.
647 720
   * @returns {Promise<BasicResponse>}
648 721
   *
@@ -677,19 +750,35 @@
Loading
677 750
   */
678 751
  replace(
679 752
    rows: object | object[],
680 -
    callback?: ReplaceRowsCallback
753 +
    gaxOptionsOrCallback?: CallOptions | ReplaceRowsCallback,
754 +
    cb?: ReplaceRowsCallback
681 755
  ): Promise<ReplaceRowsResponse> | void {
682 -
    this._mutate('replace', rows, callback!);
756 +
    const gaxOptions =
757 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
758 +
    const callback =
759 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
760 +
761 +
    this._mutate('replace', rows, gaxOptions, callback!);
683 762
  }
684 -
  update(rows: object | object[]): Promise<UpdateRowsResponse>;
763 +
  update(
764 +
    rows: object | object[],
765 +
    gaxOptions?: CallOptions
766 +
  ): Promise<UpdateRowsResponse>;
685 767
  update(rows: object | object[], callback: UpdateRowsCallback): void;
768 +
  update(
769 +
    rows: object | object[],
770 +
    gaxOptions: CallOptions,
771 +
    callback: UpdateRowsCallback
772 +
  ): void;
686 773
  /**
687 774
   * Update rows of data within this table.
688 775
   *
689 776
   * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit)
690 777
   *
691 778
   * @param {object|object[]} rows A map of names to values of data to insert
692 779
   *     into this table.
780 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
781 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
693 782
   * @param {BasicCallback} [callback] Callback function.
694 783
   * @returns {Promise<BasicResponse>}
695 784
   *
@@ -728,19 +817,36 @@
Loading
728 817
   */
729 818
  update(
730 819
    rows: object | object[],
731 -
    callback?: UpdateRowsCallback
820 +
    gaxOptionsOrCallback?: CallOptions | UpdateRowsCallback,
821 +
    cb?: UpdateRowsCallback
732 822
  ): Promise<UpdateRowsResponse> | void {
733 -
    this._mutate('update', rows, callback!);
823 +
    const gaxOptions =
824 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
825 +
    const callback =
826 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
827 +
828 +
    this._mutate('update', rows, gaxOptions, callback!);
734 829
  }
735 -
  upsert(rows: object | object[]): Promise<UpsertRowsResponse>;
830 +
  upsert(
831 +
    rows: object | object[],
832 +
    gaxOptions?: CallOptions
833 +
  ): Promise<UpsertRowsResponse>;
736 834
  upsert(rows: object | object[], callback: UpsertRowsCallback): void;
835 +
  upsert(
836 +
    rows: object | object[],
837 +
    gaxOptions: CallOptions,
838 +
    callback: UpsertRowsCallback
839 +
  ): void;
737 840
  /**
738 841
   * Insert or update rows of data within this table.
739 842
   *
740 843
   * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit)
741 844
   *
742 845
   * @param {object|object[]} rows A map of names to values of data to insert
743 846
   *     into this table.
847 +
   *
848 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
849 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
744 850
   * @param {BasicCallback} [callback] Callback function.
745 851
   * @returns {Promise<BasicResponse>}
746 852
   *
@@ -775,9 +881,15 @@
Loading
775 881
   */
776 882
  upsert(
777 883
    rows: object | object[],
778 -
    callback?: UpsertRowsCallback
884 +
    gaxOptionsOrCallback?: CallOptions | UpsertRowsCallback,
885 +
    cb?: UpsertRowsCallback
779 886
  ): Promise<UpsertRowsResponse> | void {
780 -
    this._mutate('upsert', rows, callback!);
887 +
    const gaxOptions =
888 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
889 +
    const callback =
890 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
891 +
892 +
    this._mutate('upsert', rows, gaxOptions, callback!);
781 893
  }
782 894
  /**
783 895
   * Creates a new transaction and applies the desired mutation via
@@ -795,6 +907,7 @@
Loading
795 907
  private _mutate(
796 908
    method: 'deleteRows' | 'insert' | 'replace' | 'update' | 'upsert',
797 909
    rows: object | object[],
910 +
    gaxOptions: CallOptions = {},
798 911
    callback: CommitCallback
799 912
  ): void {
800 913
    this.database.runTransaction((err, transaction) => {
@@ -804,7 +917,7 @@
Loading
804 917
      }
805 918
806 919
      transaction![method](this.name, rows as Key[]);
807 -
      transaction!.commit(callback);
920 +
      transaction!.commit(gaxOptions, callback);
808 921
    });
809 922
  }
810 923
}

@@ -17,46 +17,50 @@
Loading
17 17
import {
18 18
  ApiError,
19 19
  ExistsCallback,
20 +
  GetConfig,
20 21
  Metadata,
21 22
  ServiceObjectConfig,
22 -
  GetConfig,
23 23
} from '@google-cloud/common';
24 -
import {GrpcServiceObject} from './common-grpc/service-object';
24 +
// eslint-disable-next-line @typescript-eslint/no-var-requires
25 +
const common = require('./common-grpc/service-object');
25 26
import {promisify, promisifyAll} from '@google-cloud/promisify';
26 -
import arrify = require('arrify');
27 27
import * as extend from 'extend';
28 28
import * as r from 'teeny-request';
29 29
import * as streamEvents from 'stream-events';
30 30
import * as through from 'through2';
31 -
import {Operation as GaxOperation} from 'google-gax';
31 +
import {CallOptions, grpc, Operation as GaxOperation} from 'google-gax';
32 32
import {Backup} from './backup';
33 33
import {BatchTransaction, TransactionIdentifier} from './batch-transaction';
34 -
import {google as databaseAdmin} from '../protos/protos';
35 34
import {
36 -
  Instance,
37 -
  CreateDatabaseOptions,
35 +
  google as databaseAdmin,
36 +
  google,
37 +
  google as spannerClient,
38 +
} from '../protos/protos';
39 +
import {
38 40
  CreateDatabaseCallback,
41 +
  CreateDatabaseOptions,
39 42
  GetDatabaseOperationsOptions,
40 43
  GetDatabaseOperationsResponse,
44 +
  Instance,
41 45
} from './instance';
42 46
import {PartialResultStream, Row} from './partial-result-stream';
43 47
import {Session} from './session';
44 48
import {
49 +
  isSessionNotFoundError,
45 50
  SessionPool,
46 -
  SessionPoolOptions,
47 51
  SessionPoolCloseCallback,
48 52
  SessionPoolInterface,
49 -
  isSessionNotFoundError,
53 +
  SessionPoolOptions,
50 54
} from './session-pool';
51 -
import {Table, CreateTableCallback, CreateTableResponse} from './table';
55 +
import {CreateTableCallback, CreateTableResponse, Table} from './table';
52 56
import {
57 +
  ExecuteSqlRequest,
58 +
  RunCallback,
59 +
  RunResponse,
60 +
  RunUpdateCallback,
53 61
  Snapshot,
54 62
  TimestampBounds,
55 63
  Transaction,
56 -
  ExecuteSqlRequest,
57 -
  RunUpdateCallback,
58 -
  RunResponse,
59 -
  RunCallback,
60 64
} from './transaction';
61 65
import {
62 66
  AsyncRunTransactionCallback,
@@ -65,23 +69,21 @@
Loading
65 69
  RunTransactionOptions,
66 70
  TransactionRunner,
67 71
} from './transaction-runner';
68 -
69 -
import {google} from '../protos/protos';
70 72
import {
71 73
  IOperation,
72 -
  Schema,
74 +
  LongRunningCallback,
75 +
  NormalCallback,
76 +
  PagedOptionsWithFilter,
77 +
  CLOUD_RESOURCE_HEADER,
78 +
  PagedResponse,
73 79
  RequestCallback,
74 -
  PagedRequest,
75 80
  ResourceCallback,
76 -
  PagedResponse,
77 -
  NormalCallback,
78 -
  LongRunningCallback,
81 +
  Schema,
79 82
} from './common';
80 -
import {ServiceError, CallOptions} from 'grpc';
81 -
import {Readable, Transform, Duplex} from 'stream';
83 +
import {Duplex, Readable, Transform} from 'stream';
82 84
import {PreciseDate} from '@google-cloud/precise-date';
83 -
import {google as spannerClient} from '../protos/protos';
84 85
import {EnumKey, RequestConfig, TranslateEnumKeys} from '.';
86 +
import arrify = require('arrify');
85 87
86 88
type CreateBatchTransactionCallback = ResourceCallback<
87 89
  BatchTransaction,
@@ -120,7 +122,7 @@
Loading
120 122
121 123
type ResultSetStats = spannerClient.spanner.v1.ResultSetStats;
122 124
123 -
type GetSessionsOptions = PagedRequest<google.spanner.v1.IListSessionsRequest>;
125 +
export type GetSessionsOptions = PagedOptionsWithFilter;
124 126
125 127
/**
126 128
 * IDatabase structure with database state enum translated to string form.
@@ -166,7 +168,9 @@
Loading
166 168
>;
167 169
168 170
export type GetDatabaseConfig = GetConfig &
169 -
  databaseAdmin.spanner.admin.database.v1.GetDatabaseRequest;
171 +
  databaseAdmin.spanner.admin.database.v1.GetDatabaseRequest & {
172 +
    gaxOptions?: CallOptions;
173 +
  };
170 174
type DatabaseCloseResponse = [google.protobuf.IEmpty];
171 175
172 176
export type CreateSessionResponse = [
@@ -175,8 +179,8 @@
Loading
175 179
];
176 180
177 181
export interface CreateSessionOptions {
178 -
  name?: string | null;
179 182
  labels?: {[k: string]: string} | null;
183 +
  gaxOptions?: CallOptions;
180 184
}
181 185
182 186
export type CreateSessionCallback = ResourceCallback<
@@ -198,7 +202,10 @@
Loading
198 202
  spannerClient.spanner.v1.IBatchCreateSessionsResponse
199 203
>;
200 204
201 -
export type DatabaseDeleteCallback = NormalCallback<r.Response>;
205 +
export type DatabaseDeleteResponse = [databaseAdmin.protobuf.IEmpty];
206 +
export type DatabaseDeleteCallback = NormalCallback<
207 +
  databaseAdmin.protobuf.IEmpty
208 +
>;
202 209
203 210
export interface CancelableDuplex extends Duplex {
204 211
  cancel(): void;
@@ -237,11 +244,12 @@
Loading
237 244
 * const instance = spanner.instance('my-instance');
238 245
 * const database = instance.database('my-database');
239 246
 */
240 -
class Database extends GrpcServiceObject {
247 +
class Database extends common.GrpcServiceObject {
241 248
  private instance: Instance;
242 249
  formattedName_: string;
243 250
  pool_: SessionPoolInterface;
244 251
  queryOptions_?: spannerClient.spanner.v1.ExecuteSqlRequest.IQueryOptions;
252 +
  resourceHeader_: {[k: string]: string};
245 253
  request: DatabaseRequest;
246 254
  constructor(
247 255
    instance: Instance,
@@ -304,7 +312,41 @@
Loading
304 312
        options: CreateDatabaseOptions,
305 313
        callback: CreateDatabaseCallback
306 314
      ) => {
307 -
        return instance.createDatabase(formattedName_, options, callback);
315 +
        const pool = this.pool_ as SessionPool;
316 +
        if (pool._pending > 0) {
317 +
          // If there are BatchCreateSessions requests pending, then we should
318 +
          // wait until these have finished before we try to create the database.
319 +
          // Otherwise the results of these requests might be propagated to
320 +
          // client requests that are submitted after the database has been
321 +
          // created. If the pending requests have not finished within 10 seconds,
322 +
          // they will be ignored and the database creation will proceed.
323 +
          let timeout;
324 +
          const promises = [
325 +
            new Promise<void>(
326 +
              resolve => (timeout = setTimeout(resolve, 10000))
327 +
            ),
328 +
            new Promise<void>(resolve => {
329 +
              pool
330 +
                .on('available', () => {
331 +
                  if (pool._pending === 0) {
332 +
                    clearTimeout(timeout);
333 +
                    resolve();
334 +
                  }
335 +
                })
336 +
                .on('createError', () => {
337 +
                  if (pool._pending === 0) {
338 +
                    clearTimeout(timeout);
339 +
                    resolve();
340 +
                  }
341 +
                });
342 +
            }),
343 +
          ];
344 +
          Promise.race(promises).then(() =>
345 +
            instance.createDatabase(formattedName_, options, callback)
346 +
          );
347 +
        } else {
348 +
          return instance.createDatabase(formattedName_, options, callback);
349 +
        }
308 350
      },
309 351
    } as {}) as ServiceObjectConfig);
310 352
@@ -314,6 +356,9 @@
Loading
314 356
        : new SessionPool(this, poolOptions);
315 357
    this.formattedName_ = formattedName_;
316 358
    this.instance = instance;
359 +
    this.resourceHeader_ = {
360 +
      [CLOUD_RESOURCE_HEADER]: this.formattedName_,
361 +
    };
317 362
    this.request = instance.request;
318 363
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
319 364
    this.requestStream = instance.requestStream as any;
@@ -417,6 +462,8 @@
Loading
417 462
        client: 'SpannerClient',
418 463
        method: 'batchCreateSessions',
419 464
        reqOpts,
465 +
        gaxOpts: options.gaxOptions,
466 +
        headers: this.resourceHeader_,
420 467
      },
421 468
      (err, resp) => {
422 469
        if (err) {
@@ -555,12 +602,13 @@
Loading
555 602
        ? (optionsOrCallback as TimestampBounds)
556 603
        : {};
557 604
558 -
    this.createSession((err, session, resp) => {
605 +
    this.pool_.getReadSession((err, session) => {
559 606
      if (err) {
560 -
        callback!(err, null, resp);
607 +
        callback!(err, null, undefined);
561 608
        return;
562 609
      }
563 610
      const transaction = this.batchTransaction({session: session!}, options);
611 +
      this._releaseOnEnd(session!, transaction);
564 612
      transaction.begin((err, resp) => {
565 613
        if (err) {
566 614
          callback!(err, null, resp!);
@@ -576,6 +624,20 @@
Loading
576 624
    options: CreateSessionOptions,
577 625
    callback: CreateSessionCallback
578 626
  ): void;
627 +
  /**
628 +
   * Create a new session.
629 +
   *
630 +
   * @typedef {object} CreateSessionOptions
631 +
   * @property {Object.<string, string>} [labels] The labels for the session.
632 +
   *
633 +
   *   * Label keys must be between 1 and 63 characters long and must conform to
634 +
   *     the following regular expression: `[a-z]([-a-z0-9]*[a-z0-9])?`.
635 +
   *   * Label values must be between 0 and 63 characters long and must conform
636 +
   *     to the regular expression `([a-z]([-a-z0-9]*[a-z0-9])?)?`.
637 +
   *   * No more than 64 labels can be associated with a given session.
638 +
   * @property {object} [gaxOptions] Request configuration options, outlined
639 +
   *     here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
640 +
   */
579 641
  /**
580 642
   * @typedef {array} CreateSessionResponse
581 643
   * @property {Session} 0 The newly created session.
@@ -637,10 +699,8 @@
Loading
637 699
    cb?: CreateSessionCallback
638 700
  ): void | Promise<CreateSessionResponse> {
639 701
    const callback =
640 -
      typeof optionsOrCallback === 'function'
641 -
        ? (optionsOrCallback as CreateSessionCallback)
642 -
        : cb!;
643 -
    const gaxOpts =
702 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
703 +
    const options =
644 704
      typeof optionsOrCallback === 'object' && optionsOrCallback
645 705
        ? extend({}, optionsOrCallback)
646 706
        : ({} as CreateSessionOptions);
@@ -649,17 +709,17 @@
Loading
649 709
      database: this.formattedName_,
650 710
    };
651 711
652 -
    if (gaxOpts.labels) {
653 -
      reqOpts.session = {labels: gaxOpts.labels};
654 -
      delete gaxOpts.labels;
712 +
    if (options.labels) {
713 +
      reqOpts.session = {labels: options.labels};
655 714
    }
656 715
657 716
    this.request<google.spanner.v1.ISession>(
658 717
      {
659 718
        client: 'SpannerClient',
660 719
        method: 'createSession',
661 720
        reqOpts,
662 -
        gaxOpts,
721 +
        gaxOpts: options.gaxOptions,
722 +
        headers: this.resourceHeader_,
663 723
      },
664 724
      (err, resp) => {
665 725
        if (err) {
@@ -672,8 +732,16 @@
Loading
672 732
      }
673 733
    );
674 734
  }
675 -
  createTable(schema: Schema): Promise<CreateTableResponse>;
676 -
  createTable(schema: Schema, callback?: CreateTableCallback): void;
735 +
  createTable(
736 +
    schema: Schema,
737 +
    gaxOptions?: CallOptions
738 +
  ): Promise<CreateTableResponse>;
739 +
  createTable(schema: Schema, callback: CreateTableCallback): void;
740 +
  createTable(
741 +
    schema: Schema,
742 +
    gaxOptions: CallOptions,
743 +
    callback: CreateTableCallback
744 +
  ): void;
677 745
  /**
678 746
   * @typedef {array} CreateTableResponse
679 747
   * @property {Table} 0 The new {@link Table}.
@@ -697,6 +765,8 @@
Loading
697 765
   * @see {@link Database#updateSchema}
698 766
   *
699 767
   * @param {string} schema A DDL CREATE statement describing the table.
768 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
769 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
700 770
   * @param {CreateTableCallback} [callback] Callback function.
701 771
   * @returns {Promise<CreateTableResponse>}
702 772
   *
@@ -743,9 +813,15 @@
Loading
743 813
   */
744 814
  createTable(
745 815
    schema: Schema,
746 -
    callback?: CreateTableCallback
816 +
    gaxOptionsOrCallback?: CallOptions | CreateTableCallback,
817 +
    cb?: CreateTableCallback
747 818
  ): void | Promise<CreateTableResponse> {
748 -
    this.updateSchema(schema, (err, operation, resp) => {
819 +
    const gaxOptions =
820 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
821 +
    const callback =
822 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
823 +
824 +
    this.updateSchema(schema, gaxOptions, (err, operation, resp) => {
749 825
      if (err) {
750 826
        callback!(err, null, null, resp!);
751 827
        return;
@@ -776,17 +852,21 @@
Loading
776 852
      }
777 853
    });
778 854
  }
779 -
  delete(): Promise<[r.Response]>;
855 +
  delete(gaxOptions?: CallOptions): Promise<DatabaseDeleteResponse>;
780 856
  delete(callback: DatabaseDeleteCallback): void;
857 +
  delete(gaxOptions: CallOptions, callback: DatabaseDeleteCallback): void;
781 858
  /**
782 859
   * Delete the database.
783 860
   *
784 861
   * Wrapper around {@link v1.DatabaseAdminClient#dropDatabase}.
785 862
   *
786 863
   * @see {@link v1.DatabaseAdminClient#dropDatabase}
787 864
   * @see [DropDatabase API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.DropDatabase)
788 -
   * @param {BasicCallback} [callback] Callback function.
789 -
   * @returns {Promise<BasicResponse>}
865 +
   *
866 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
867 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
868 +
   * @param {DatabaseDeleteCallback} [callback] Callback function.
869 +
   * @returns {Promise<DatabaseDeleteResponse>}
790 870
   *
791 871
   * @example
792 872
   * const {Spanner} = require('@google-cloud/spanner');
@@ -810,7 +890,15 @@
Loading
810 890
   *   const apiResponse = data[0];
811 891
   * });
812 892
   */
813 -
  delete(callback?: DatabaseDeleteCallback): void | Promise<[r.Response]> {
893 +
  delete(
894 +
    optionsOrCallback?: CallOptions | DatabaseDeleteCallback,
895 +
    cb?: DatabaseDeleteCallback
896 +
  ): void | Promise<DatabaseDeleteResponse> {
897 +
    const gaxOpts =
898 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
899 +
    const callback =
900 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
901 +
814 902
    const reqOpts: databaseAdmin.spanner.admin.database.v1.IDropDatabaseRequest = {
815 903
      database: this.formattedName_,
816 904
    };
@@ -820,13 +908,16 @@
Loading
820 908
          client: 'DatabaseAdminClient',
821 909
          method: 'dropDatabase',
822 910
          reqOpts,
911 +
          gaxOpts,
912 +
          headers: this.resourceHeader_,
823 913
        },
824 914
        callback!
825 915
      );
826 916
    });
827 917
  }
828 -
  exists(): Promise<[boolean]>;
918 +
  exists(gaxOptions?: CallOptions): Promise<[boolean]>;
829 919
  exists(callback: ExistsCallback): void;
920 +
  exists(gaxOptions: CallOptions, callback: ExistsCallback): void;
830 921
  /**
831 922
   * @typedef {array} DatabaseExistsResponse
832 923
   * @property {boolean} 0 Whether the {@link Database} exists.
@@ -840,6 +931,8 @@
Loading
840 931
   * Check if a database exists.
841 932
   *
842 933
   * @method Database#exists
934 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
935 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
843 936
   * @param {DatabaseExistsCallback} [callback] Callback function.
844 937
   * @returns {Promise<DatabaseExistsResponse>}
845 938
   *
@@ -859,10 +952,18 @@
Loading
859 952
   *   const exists = data[0];
860 953
   * });
861 954
   */
862 -
  exists(callback?: ExistsCallback): void | Promise<[boolean]> {
955 +
  exists(
956 +
    gaxOptionsOrCallback?: CallOptions | ExistsCallback,
957 +
    cb?: ExistsCallback
958 +
  ): void | Promise<[boolean]> {
959 +
    const gaxOptions =
960 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
961 +
    const callback =
962 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
963 +
863 964
    const NOT_FOUND = 5;
864 965
865 -
    this.getMetadata(err => {
966 +
    this.getMetadata(gaxOptions, err => {
866 967
      if (err && (err as ApiError).code !== NOT_FOUND) {
867 968
        callback!(err);
868 969
        return;
@@ -928,14 +1029,14 @@
Loading
928 1029
        : ({} as GetDatabaseConfig);
929 1030
    const callback =
930 1031
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
931 -
    this.getMetadata((err, metadata) => {
1032 +
    this.getMetadata(options.gaxOptions!, (err, metadata) => {
932 1033
      if (err) {
933 1034
        if (options.autoCreate && (err as ApiError).code === 5) {
934 1035
          this.create(
935 1036
            options,
936 1037
            (err, database: Database, operation: GaxOperation) => {
937 1038
              if (err) {
938 -
                callback!(err);
1039 +
                callback!(err as grpc.ServiceError);
939 1040
                return;
940 1041
              }
941 1042
              operation
@@ -954,8 +1055,9 @@
Loading
954 1055
      callback!(null, this, metadata as r.Response);
955 1056
    });
956 1057
  }
957 -
  getMetadata(): Promise<GetMetadataResponse>;
1058 +
  getMetadata(gaxOptions?: CallOptions): Promise<GetMetadataResponse>;
958 1059
  getMetadata(callback: GetMetadataCallback): void;
1060 +
  getMetadata(gaxOptions: CallOptions, callback: GetMetadataCallback): void;
959 1061
  /**
960 1062
   * @typedef {array} GetDatabaseMetadataResponse
961 1063
   * @property {object} 0 The {@link Database} metadata.
@@ -974,7 +1076,8 @@
Loading
974 1076
   *
975 1077
   * @see {@link v1.DatabaseAdminClient#getDatabase}
976 1078
   * @see [GetDatabase API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabase)
977 -
   *
1079 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
1080 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
978 1081
   * @param {GetMetadataCallback} [callback] Callback function.
979 1082
   * @returns {Promise<GetMetadataResponse>}
980 1083
   *
@@ -1002,8 +1105,18 @@
Loading
1002 1105
   * });
1003 1106
   */
1004 1107
  getMetadata(
1005 -
    callback?: GetMetadataCallback
1108 +
    gaxOptionsOrCallback?: CallOptions | GetMetadataCallback,
1109 +
    cb?: GetMetadataCallback
1006 1110
  ): void | Promise<GetMetadataResponse> {
1111 +
    const callback =
1112 +
      typeof gaxOptionsOrCallback === 'function'
1113 +
        ? (gaxOptionsOrCallback as GetMetadataCallback)
1114 +
        : cb;
1115 +
    const gaxOpts =
1116 +
      typeof gaxOptionsOrCallback === 'object'
1117 +
        ? (gaxOptionsOrCallback as CallOptions)
1118 +
        : {};
1119 +
1007 1120
    const reqOpts: databaseAdmin.spanner.admin.database.v1.IGetDatabaseRequest = {
1008 1121
      name: this.formattedName_,
1009 1122
    };
@@ -1012,8 +1125,15 @@
Loading
1012 1125
        client: 'DatabaseAdminClient',
1013 1126
        method: 'getDatabase',
1014 1127
        reqOpts,
1128 +
        gaxOpts,
1129 +
        headers: this.resourceHeader_,
1015 1130
      },
1016 -
      callback!
1131 +
      (err, resp) => {
1132 +
        if (resp) {
1133 +
          this.metadata = resp;
1134 +
        }
1135 +
        callback!(err, resp);
1136 +
      }
1017 1137
    );
1018 1138
  }
1019 1139
@@ -1029,6 +1149,8 @@
Loading
1029 1149
   * @see {@link #getMetadata}
1030 1150
   *
1031 1151
   * @method Database#getRestoreInfo
1152 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
1153 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
1032 1154
   * @returns {Promise<IRestoreInfoTranslatedEnum | undefined>} When resolved,
1033 1155
   *     contains the restore information for the database if it was restored
1034 1156
   *     from a backup.
@@ -1041,8 +1163,10 @@
Loading
1041 1163
   * const restoreInfo = await database.getRestoreInfo();
1042 1164
   * console.log(`Database restored from ${restoreInfo.backupInfo.backup}`);
1043 1165
   */
1044 -
  async getRestoreInfo(): Promise<IRestoreInfoTranslatedEnum | undefined> {
1045 -
    const [metadata] = await this.getMetadata();
1166 +
  async getRestoreInfo(
1167 +
    options?: CallOptions
1168 +
  ): Promise<IRestoreInfoTranslatedEnum | undefined> {
1169 +
    const [metadata] = await this.getMetadata(options);
1046 1170
    return metadata.restoreInfo ? metadata.restoreInfo : undefined;
1047 1171
  }
1048 1172
@@ -1055,6 +1179,8 @@
Loading
1055 1179
   * @see {@link #getMetadata}
1056 1180
   *
1057 1181
   * @method Database#getState
1182 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
1183 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
1058 1184
   * @returns {Promise<EnumKey<typeof, databaseAdmin.spanner.admin.database.v1.Database.State> | undefined>}
1059 1185
   *     When resolved, contains the current state of the database if the state
1060 1186
   *     is defined.
@@ -1067,16 +1193,19 @@
Loading
1067 1193
   * const state = await database.getState();
1068 1194
   * const isReady = (state === 'READY');
1069 1195
   */
1070 -
  async getState(): Promise<
1196 +
  async getState(
1197 +
    options?: CallOptions
1198 +
  ): Promise<
1071 1199
    | EnumKey<typeof databaseAdmin.spanner.admin.database.v1.Database.State>
1072 1200
    | undefined
1073 1201
  > {
1074 -
    const [metadata] = await this.getMetadata();
1202 +
    const [metadata] = await this.getMetadata(options);
1075 1203
    return metadata.state || undefined;
1076 1204
  }
1077 1205
1078 -
  getSchema(): Promise<GetSchemaResponse>;
1206 +
  getSchema(options?: CallOptions): Promise<GetSchemaResponse>;
1079 1207
  getSchema(callback: GetSchemaCallback): void;
1208 +
  getSchema(options: CallOptions, callback: GetSchemaCallback): void;
1080 1209
  /**
1081 1210
   * @typedef {array} GetSchemaResponse
1082 1211
   * @property {string[]} 0 An array of database DDL statements.
@@ -1097,6 +1226,8 @@
Loading
1097 1226
   * @see [Data Definition Language (DDL)](https://cloud.google.com/spanner/docs/data-definition-language)
1098 1227
   * @see [GetDatabaseDdl API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDdl)
1099 1228
   *
1229 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
1230 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
1100 1231
   * @param {GetSchemaCallback} [callback] Callback function.
1101 1232
   * @returns {Promise<GetSchemaResponse>}
1102 1233
   *
@@ -1117,7 +1248,15 @@
Loading
1117 1248
   *   const apiResponse = data[1];
1118 1249
   * });
1119 1250
   */
1120 -
  getSchema(callback?: GetSchemaCallback): void | Promise<GetSchemaResponse> {
1251 +
  getSchema(
1252 +
    optionsOrCallback?: CallOptions | GetSchemaCallback,
1253 +
    cb?: GetSchemaCallback
1254 +
  ): void | Promise<GetSchemaResponse> {
1255 +
    const gaxOpts =
1256 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
1257 +
    const callback =
1258 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
1259 +
1121 1260
    const reqOpts: databaseAdmin.spanner.admin.database.v1.IGetDatabaseDdlRequest = {
1122 1261
      database: this.formattedName_,
1123 1262
    };
@@ -1128,6 +1267,8 @@
Loading
1128 1267
        client: 'DatabaseAdminClient',
1129 1268
        method: 'getDatabaseDdl',
1130 1269
        reqOpts,
1270 +
        gaxOpts,
1271 +
        headers: this.resourceHeader_,
1131 1272
      },
1132 1273
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
1133 1274
      (err, statements, ...args: any[]) => {
@@ -1141,9 +1282,7 @@
Loading
1141 1282
  /**
1142 1283
   * Options object for listing sessions.
1143 1284
   *
1144 -
   * @typedef {object} GetSessionsRequest
1145 -
   * @property {boolean} [autoPaginate=true] Have pagination handled
1146 -
   *     automatically.
1285 +
   * @typedef {object} GetSessionsOptions
1147 1286
   * @property {string} [filter] An expression for filtering the results of the
1148 1287
   *     request. Filter rules are case insensitive. The fields eligible for
1149 1288
   *     filtering are:
@@ -1158,21 +1297,23 @@
Loading
1158 1297
   *     - **`labels.env:dev`** The instance's label env has the value dev.
1159 1298
   *     - **`name:howl labels.env:dev`** The instance's name is howl and it has
1160 1299
   *       the label env with value dev.
1161 -
   * @property {number} [maxApiCalls] Maximum number of API calls to make.
1162 -
   * @property {number} [maxResults] Maximum number of items to return.
1163 1300
   * @property {number} [pageSize] Maximum number of results per page.
1164 1301
   * @property {string} [pageToken] A previously-returned page token
1165 1302
   *     representing part of the larger set of results to view.
1303 +
   * @property {object} [gaxOptions] Request configuration options, outlined
1304 +
   *     here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
1166 1305
   */
1167 1306
  /**
1168 1307
   * @typedef {array} GetSessionsResponse
1169 1308
   * @property {Session[]} 0 Array of {@link Session} instances.
1170 -
   * @property {object} 1 The full API response.
1309 +
   * @property {object} 1 A query object to receive more results.
1310 +
   * @property {object} 2 The full API response.
1171 1311
   */
1172 1312
  /**
1173 1313
   * @callback GetSessionsCallback
1174 1314
   * @param {?Error} err Request error, if any.
1175 1315
   * @param {Session[]} instances Array of {@link Session} instances.
1316 +
   * @param {object} nextQuery A query object to receive more results.
1176 1317
   * @param {object} apiResponse The full API response.
1177 1318
   */
1178 1319
  /**
@@ -1210,7 +1351,7 @@
Loading
1210 1351
   * }
1211 1352
   *
1212 1353
   * database.getInstances({
1213 -
   *   autoPaginate: false
1354 +
   *   gaxOptions: {autoPaginate: false}
1214 1355
   * }, callback);
1215 1356
   *
1216 1357
   * //-
@@ -1227,19 +1368,32 @@
Loading
1227 1368
    // eslint-disable-next-line @typescript-eslint/no-this-alias
1228 1369
    const self = this;
1229 1370
    const callback =
1230 -
      typeof optionsOrCallback === 'function'
1231 -
        ? (optionsOrCallback as GetSessionsCallback)
1232 -
        : cb;
1371 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
1233 1372
    const options =
1234 1373
      typeof optionsOrCallback === 'object'
1235 -
        ? (optionsOrCallback as GetSessionsOptions)
1236 -
        : {gaxOptions: {}};
1237 -
    const gaxOpts: CallOptions = options.gaxOptions as CallOptions;
1238 -
    const reqOpts = extend({}, options, {
1374 +
        ? optionsOrCallback
1375 +
        : ({} as GetSessionsOptions);
1376 +
    const gaxOpts = extend(true, {}, options.gaxOptions);
1377 +
    let reqOpts = extend({}, options, {
1239 1378
      database: this.formattedName_,
1240 1379
    });
1241 -
1242 1380
    delete reqOpts.gaxOptions;
1381 +
1382 +
    // Copy over pageSize and pageToken values from gaxOptions.
1383 +
    // However values set on options take precedence.
1384 +
    if (gaxOpts) {
1385 +
      reqOpts = extend(
1386 +
        {},
1387 +
        {
1388 +
          pageSize: gaxOpts.pageSize,
1389 +
          pageToken: gaxOpts.pageToken,
1390 +
        },
1391 +
        reqOpts
1392 +
      );
1393 +
      delete gaxOpts.pageSize;
1394 +
      delete gaxOpts.pageToken;
1395 +
    }
1396 +
1243 1397
    this.request<
1244 1398
      google.spanner.v1.ISession,
1245 1399
      google.spanner.v1.IListSessionsResponse
@@ -1249,8 +1403,9 @@
Loading
1249 1403
        method: 'listSessions',
1250 1404
        reqOpts,
1251 1405
        gaxOpts,
1406 +
        headers: this.resourceHeader_,
1252 1407
      },
1253 -
      (err, sessions, ...args) => {
1408 +
      (err, sessions, nextPageRequest, ...args) => {
1254 1409
        let sessionInstances: Session[] | null = null;
1255 1410
        if (sessions) {
1256 1411
          sessionInstances = sessions.map(metadata => {
@@ -1259,10 +1414,84 @@
Loading
1259 1414
            return session;
1260 1415
          });
1261 1416
        }
1262 -
        callback!(err, sessionInstances!, ...args);
1417 +
        const nextQuery = nextPageRequest!
1418 +
          ? extend({}, options, nextPageRequest!)
1419 +
          : null;
1420 +
        callback!(err, sessionInstances!, nextQuery, ...args);
1263 1421
      }
1264 1422
    );
1265 1423
  }
1424 +
1425 +
  /**
1426 +
   * Get a list of sessions as a readable object stream.
1427 +
   *
1428 +
   * Wrapper around {@link v1.SpannerClient#listSessions}
1429 +
   *
1430 +
   * @see {@link v1.SpannerClient#listSessions}
1431 +
   * @see [ListSessions API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.ListSessions)
1432 +
   *
1433 +
   * @method Spanner#getSessionsStream
1434 +
   * @param {GetSessionsOptions} [options] Options object for listing sessions.
1435 +
   * @returns {ReadableStream} A readable stream that emits {@link Session}
1436 +
   *     instances.
1437 +
   *
1438 +
   * @example
1439 +
   * const {Spanner} = require('@google-cloud/spanner');
1440 +
   * const spanner = new Spanner();
1441 +
   *
1442 +
   * const instance = spanner.instance('my-instance');
1443 +
   * const database = instance.database('my-database');
1444 +
   *
1445 +
   * database.getSessionsStream()
1446 +
   *   .on('error', console.error)
1447 +
   *   .on('data', function(database) {
1448 +
   *     // `sessions` is a `Session` object.
1449 +
   *   })
1450 +
   *   .on('end', function() {
1451 +
   *     // All sessions retrieved.
1452 +
   *   });
1453 +
   *
1454 +
   * //-
1455 +
   * // If you anticipate many results, you can end a stream early to prevent
1456 +
   * // unnecessary processing and API requests.
1457 +
   * //-
1458 +
   * database.getSessionsStream()
1459 +
   *   .on('data', function(session) {
1460 +
   *     this.end();
1461 +
   *   });
1462 +
   */
1463 +
  getSessionsStream(options: GetSessionsOptions = {}): NodeJS.ReadableStream {
1464 +
    const gaxOpts = extend(true, {}, options.gaxOptions);
1465 +
1466 +
    let reqOpts = extend({}, options, {
1467 +
      database: this.formattedName_,
1468 +
    });
1469 +
    delete reqOpts.gaxOptions;
1470 +
1471 +
    // Copy over pageSize and pageToken values from gaxOptions.
1472 +
    // However values set on options take precedence.
1473 +
    if (gaxOpts) {
1474 +
      reqOpts = extend(
1475 +
        {},
1476 +
        {
1477 +
          pageSize: gaxOpts.pageSize,
1478 +
          pageToken: gaxOpts.pageToken,
1479 +
        },
1480 +
        reqOpts
1481 +
      );
1482 +
      delete gaxOpts.pageSize;
1483 +
      delete gaxOpts.pageToken;
1484 +
    }
1485 +
1486 +
    return this.requestStream({
1487 +
      client: 'SpannerClient',
1488 +
      method: 'listSessionsStream',
1489 +
      reqOpts,
1490 +
      gaxOpts,
1491 +
      headers: this.resourceHeader_,
1492 +
    });
1493 +
  }
1494 +
1266 1495
  getSnapshot(options?: TimestampBounds): Promise<[Snapshot]>;
1267 1496
  getSnapshot(callback: GetSnapshotCallback): void;
1268 1497
  getSnapshot(options: TimestampBounds, callback: GetSnapshotCallback): void;
@@ -1284,6 +1513,12 @@
Loading
1284 1513
   * called to release the underlying {@link Session}. **Failure to do could
1285 1514
   * result in a Session leak.**
1286 1515
   *
1516 +
   * **NOTE:** Since the returned {@link Snapshot} transaction is not a
1517 +
   * single-use transaction, it is invalid to set the `minReadTimestamp` and
1518 +
   * `maxStaleness` parameters in {@link TimestampBounds} as those parameters
1519 +
   * can only be set for single-use transactions.
1520 +
   * https://cloud.google.com/spanner/docs/reference/rest/v1/TransactionOptions#bounded-staleness
1521 +
   *
1287 1522
   * @see {@link v1.SpannerClient#beginTransaction}
1288 1523
   *
1289 1524
   * @param {TimestampBounds} [options] Timestamp bounds.
@@ -1404,7 +1639,7 @@
Loading
1404 1639
      if (!err) {
1405 1640
        this._releaseOnEnd(session!, transaction!);
1406 1641
      }
1407 -
      callback!(err, transaction);
1642 +
      callback!(err as grpc.ServiceError | null, transaction);
1408 1643
    });
1409 1644
  }
1410 1645
@@ -1529,7 +1764,7 @@
Loading
1529 1764
        requestStream.cancel();
1530 1765
      }
1531 1766
    };
1532 -
    function destroyStream(err: ServiceError) {
1767 +
    function destroyStream(err: grpc.ServiceError) {
1533 1768
      waitForSessionStream.destroy(err);
1534 1769
    }
1535 1770
    function releaseSession() {
@@ -1628,6 +1863,7 @@
Loading
1628 1863
        method: 'restoreDatabase',
1629 1864
        reqOpts,
1630 1865
        gaxOpts,
1866 +
        headers: this.resourceHeader_,
1631 1867
      },
1632 1868
      (err, operation, resp) => {
1633 1869
        if (err) {
@@ -1859,20 +2095,41 @@
Loading
1859 2095
        return;
1860 2096
      }
1861 2097
1862 -
      const transaction = session!.partitionedDml();
2098 +
      this._runPartitionedUpdate(session!, query, callback);
2099 +
    });
2100 +
  }
2101 +
2102 +
  _runPartitionedUpdate(
2103 +
    session: Session,
2104 +
    query: string | ExecuteSqlRequest,
2105 +
    callback?: RunUpdateCallback
2106 +
  ): void | Promise<number> {
2107 +
    const transaction = session.partitionedDml();
2108 +
2109 +
    transaction.begin(err => {
2110 +
      if (err) {
2111 +
        this.pool_.release(session!);
2112 +
        callback!(err, 0);
2113 +
        return;
2114 +
      }
1863 2115
1864 -
      transaction.begin(err => {
2116 +
      transaction.runUpdate(query, (err, updateCount) => {
1865 2117
        if (err) {
2118 +
          if (err.code !== grpc.status.ABORTED) {
2119 +
            this.pool_.release(session!);
2120 +
            callback!(err, 0);
2121 +
            return;
2122 +
          }
2123 +
          this._runPartitionedUpdate(session, query, callback);
2124 +
        } else {
1866 2125
          this.pool_.release(session!);
1867 -
          callback!(err, 0);
2126 +
          callback!(null, updateCount);
1868 2127
          return;
1869 2128
        }
1870 -
1871 -
        this._releaseOnEnd(session!, transaction);
1872 -
        transaction.runUpdate(query, callback!);
1873 2129
      });
1874 2130
    });
1875 2131
  }
2132 +
1876 2133
  /**
1877 2134
   * Create a readable object stream to receive resulting rows from a SQL
1878 2135
   * statement.
@@ -2018,12 +2275,15 @@
Loading
2018 2275
      dataStream
2019 2276
        .once('data', () => (dataReceived = true))
2020 2277
        .once('error', err => {
2021 -
          if (!dataReceived && isSessionNotFoundError(err)) {
2278 +
          if (
2279 +
            !dataReceived &&
2280 +
            isSessionNotFoundError(err as grpc.ServiceError)
2281 +
          ) {
2022 2282
            // If it is a 'Session not found' error and we have not yet received
2023 2283
            // any data, we can safely retry the query on a new session.
2024 2284
            // Register the error on the session so the pool can discard it.
2025 2285
            if (session) {
2026 -
              session.lastError = err;
2286 +
              session.lastError = err as grpc.ServiceError;
2027 2287
            }
2028 2288
            // Remove the current data stream from the end user stream.
2029 2289
            dataStream.unpipe(proxyStream);
@@ -2141,12 +2401,12 @@
Loading
2141 2401
        : {};
2142 2402
2143 2403
    this.pool_.getWriteSession((err, session?, transaction?) => {
2144 -
      if (err && isSessionNotFoundError(err)) {
2404 +
      if (err && isSessionNotFoundError(err as grpc.ServiceError)) {
2145 2405
        this.runTransaction(options, runFn!);
2146 2406
        return;
2147 2407
      }
2148 2408
      if (err) {
2149 -
        runFn!(err);
2409 +
        runFn!(err as grpc.ServiceError);
2150 2410
        return;
2151 2411
      }
2152 2412
@@ -2307,8 +2567,16 @@
Loading
2307 2567
    }
2308 2568
    return new Table(this, name);
2309 2569
  }
2310 -
  updateSchema(statements: Schema): Promise<UpdateSchemaResponse>;
2570 +
  updateSchema(
2571 +
    statements: Schema,
2572 +
    gaxOptions?: CallOptions
2573 +
  ): Promise<UpdateSchemaResponse>;
2311 2574
  updateSchema(statements: Schema, callback: UpdateSchemaCallback): void;
2575 +
  updateSchema(
2576 +
    statements: Schema,
2577 +
    gaxOptions: CallOptions,
2578 +
    callback: UpdateSchemaCallback
2579 +
  ): void;
2312 2580
  /**
2313 2581
   * Update the schema of the database by creating/altering/dropping tables,
2314 2582
   * columns, indexes, etc.
@@ -2327,6 +2595,8 @@
Loading
2327 2595
   * @param {string|string[]|object} statements An array of database DDL
2328 2596
   *     statements, or an
2329 2597
   *     [`UpdateDatabaseDdlRequest` object](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.UpdateDatabaseDdlRequest).
2598 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
2599 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
2330 2600
   * @param {LongRunningOperationCallback} [callback] Callback function.
2331 2601
   * @returns {Promise<LongRunningOperationResponse>}
2332 2602
   *
@@ -2384,8 +2654,14 @@
Loading
2384 2654
   */
2385 2655
  updateSchema(
2386 2656
    statements: Schema,
2387 -
    callback?: UpdateSchemaCallback
2657 +
    optionsOrCallback?: CallOptions | UpdateSchemaCallback,
2658 +
    cb?: UpdateSchemaCallback
2388 2659
  ): Promise<UpdateSchemaResponse> | void {
2660 +
    const gaxOpts =
2661 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
2662 +
    const callback =
2663 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
2664 +
2389 2665
    if (typeof statements === 'string' || Array.isArray(statements)) {
2390 2666
      statements = {
2391 2667
        statements: arrify(statements) as string[],
@@ -2402,6 +2678,8 @@
Loading
2402 2678
        client: 'DatabaseAdminClient',
2403 2679
        method: 'updateDatabaseDdl',
2404 2680
        reqOpts,
2681 +
        gaxOpts,
2682 +
        headers: this.resourceHeader_,
2405 2683
      },
2406 2684
      callback!
2407 2685
    );
@@ -2439,13 +2717,12 @@
Loading
2439 2717
promisifyAll(Database, {
2440 2718
  exclude: [
2441 2719
    'batchTransaction',
2442 -
    'getMetadata',
2443 2720
    'getRestoreInfo',
2444 2721
    'getState',
2445 2722
    'getOperations',
2446 2723
    'runTransaction',
2724 +
    'runTransactionAsync',
2447 2725
    'table',
2448 -
    'updateSchema',
2449 2726
    'session',
2450 2727
  ],
2451 2728
});

@@ -13,18 +13,24 @@
Loading
13 13
 * limitations under the License.
14 14
 */
15 15
16 -
import {promisifyAll} from '@google-cloud/promisify';
16 +
import {promisifyAll, callbackifyAll} from '@google-cloud/promisify';
17 17
import {Instance} from './instance';
18 18
import {
19 19
  IOperation,
20 20
  LongRunningCallback,
21 21
  RequestCallback,
22 22
  ResourceCallback,
23 +
  NormalCallback,
24 +
  CLOUD_RESOURCE_HEADER,
23 25
} from './common';
24 26
import {EnumKey, Spanner, RequestConfig, TranslateEnumKeys} from '.';
25 -
import {Metadata, Operation as GaxOperation} from 'google-gax';
27 +
import {
28 +
  grpc,
29 +
  CallOptions,
30 +
  Metadata,
31 +
  Operation as GaxOperation,
32 +
} from 'google-gax';
26 33
import {DateStruct, PreciseDate} from '@google-cloud/precise-date';
27 -
import {CallOptions, status} from 'grpc';
28 34
import {google as databaseAdmin} from '../protos/protos';
29 35
import {common as p} from 'protobufjs';
30 36
@@ -64,7 +70,7 @@
Loading
64 70
  databaseAdmin.spanner.admin.database.v1.IBackup
65 71
>;
66 72
67 -
type DeleteCallback = RequestCallback<void>;
73 +
type DeleteCallback = RequestCallback<databaseAdmin.protobuf.IEmpty>;
68 74
69 75
interface BackupRequest {
70 76
  (
@@ -73,6 +79,11 @@
Loading
73 79
  ): void;
74 80
  <T>(config: RequestConfig, callback: RequestCallback<T>): void;
75 81
}
82 +
export type GetStateCallback = NormalCallback<
83 +
  EnumKey<typeof databaseAdmin.spanner.admin.database.v1.Backup.State>
84 +
>;
85 +
export type GetExpireTimeCallback = NormalCallback<PreciseDate>;
86 +
export type ExistsCallback = NormalCallback<boolean>;
76 87
/**
77 88
 * The {@link Backup} class represents a Cloud Spanner backup.
78 89
 *
@@ -90,12 +101,17 @@
Loading
90 101
  id: string;
91 102
  formattedName_: string;
92 103
  instanceFormattedName_: string;
104 +
  resourceHeader_: {[k: string]: string};
93 105
  request: BackupRequest;
106 +
  metadata?: databaseAdmin.spanner.admin.database.v1.IBackup;
94 107
  constructor(instance: Instance, name: string) {
95 108
    this.request = instance.request;
96 109
    this.instanceFormattedName_ = instance.formattedName_;
97 110
    this.formattedName_ = Backup.formatName_(instance.formattedName_, name);
98 111
    this.id = this.formattedName_.split('/').pop() || '';
112 +
    this.resourceHeader_ = {
113 +
      [CLOUD_RESOURCE_HEADER]: this.instanceFormattedName_,
114 +
    };
99 115
  }
100 116
101 117
  create(options: CreateBackupOptions): Promise<CreateBackupResponse>;
@@ -154,7 +170,7 @@
Loading
154 170
    options: CreateBackupOptions,
155 171
    callback?: CreateBackupCallback
156 172
  ): Promise<CreateBackupResponse> | void {
157 -
    const gaxOpts: CallOptions = options.gaxOptions as CallOptions;
173 +
    const gaxOpts = options.gaxOptions;
158 174
    const reqOpts: databaseAdmin.spanner.admin.database.v1.ICreateBackupRequest = {
159 175
      parent: this.instanceFormattedName_,
160 176
      backupId: this.id,
@@ -164,12 +180,13 @@
Loading
164 180
        name: this.formattedName_,
165 181
      },
166 182
    };
167 -
    return this.request(
183 +
    this.request(
168 184
      {
169 185
        client: 'DatabaseAdminClient',
170 186
        method: 'createBackup',
171 187
        reqOpts,
172 188
        gaxOpts,
189 +
        headers: this.resourceHeader_,
173 190
      },
174 191
      (err, operation, resp) => {
175 192
        if (err) {
@@ -181,7 +198,6 @@
Loading
181 198
    );
182 199
  }
183 200
184 -
  getMetadata(): Promise<GetMetadataResponse>;
185 201
  getMetadata(gaxOptions?: CallOptions): Promise<GetMetadataResponse>;
186 202
  getMetadata(callback: GetMetadataCallback): void;
187 203
  getMetadata(gaxOptions: CallOptions, callback: GetMetadataCallback): void;
@@ -231,19 +247,29 @@
Loading
231 247
    const reqOpts: databaseAdmin.spanner.admin.database.v1.IGetBackupRequest = {
232 248
      name: this.formattedName_,
233 249
    };
234 -
    return this.request<IBackupTranslatedEnum>(
250 +
    this.request<IBackupTranslatedEnum>(
235 251
      {
236 252
        client: 'DatabaseAdminClient',
237 253
        method: 'getBackup',
238 254
        reqOpts,
239 255
        gaxOpts,
256 +
        headers: this.resourceHeader_,
240 257
      },
241 258
      (err, response) => {
259 +
        if (response) {
260 +
          this.metadata = response;
261 +
        }
242 262
        callback!(err, response);
243 263
      }
244 264
    );
245 265
  }
246 266
267 +
  getState(): Promise<
268 +
    | EnumKey<typeof databaseAdmin.spanner.admin.database.v1.Backup.State>
269 +
    | undefined
270 +
    | null
271 +
  >;
272 +
  getState(callback: GetStateCallback): void;
247 273
  /**
248 274
   * Retrieves the state of the backup.
249 275
   *
@@ -252,6 +278,7 @@
Loading
252 278
   * @see {@link #getMetadata}
253 279
   *
254 280
   * @method Backup#getState
281 +
   * @param {GetStateCallback} [callback] Callback function.
255 282
   * @returns {Promise<EnumKey<typeof, databaseAdmin.spanner.admin.database.v1.Backup.State> | undefined>}
256 283
   *     When resolved, contains the current state of the backup if it exists.
257 284
   *
@@ -266,11 +293,14 @@
Loading
266 293
  async getState(): Promise<
267 294
    | EnumKey<typeof databaseAdmin.spanner.admin.database.v1.Backup.State>
268 295
    | undefined
296 +
    | null
269 297
  > {
270 298
    const [backupInfo] = await this.getMetadata();
271 -
    return backupInfo.state || undefined;
299 +
    return backupInfo.state;
272 300
  }
273 301
302 +
  getExpireTime(): Promise<PreciseDate | undefined>;
303 +
  getExpireTime(callback: GetExpireTimeCallback): void;
274 304
  /**
275 305
   * Retrieves the expiry time of the backup.
276 306
   *
@@ -294,6 +324,8 @@
Loading
294 324
    return new PreciseDate(backupInfo.expireTime as DateStruct);
295 325
  }
296 326
327 +
  exists(): Promise<boolean>;
328 +
  exists(callback: ExistsCallback): void;
297 329
  /**
298 330
   * Checks whether the backup exists.
299 331
   *
@@ -318,7 +350,7 @@
Loading
318 350
      // Found therefore it exists
319 351
      return true;
320 352
    } catch (err) {
321 -
      if (err.code === status.NOT_FOUND) {
353 +
      if (err.code === grpc.status.NOT_FOUND) {
322 354
        return false;
323 355
      }
324 356
      // Some other error occurred, rethrow
@@ -393,21 +425,21 @@
Loading
393 425
        paths: ['expire_time'],
394 426
      },
395 427
    };
396 -
    return this.request<databaseAdmin.spanner.admin.database.v1.IBackup>(
428 +
    this.request<databaseAdmin.spanner.admin.database.v1.IBackup>(
397 429
      {
398 430
        client: 'DatabaseAdminClient',
399 431
        method: 'updateBackup',
400 432
        reqOpts,
401 433
        gaxOpts,
434 +
        headers: this.resourceHeader_,
402 435
      },
403 436
      (err, response) => {
404 437
        callback!(err, response);
405 438
      }
406 439
    );
407 440
  }
408 441
409 -
  delete(): Promise<void>;
410 -
  delete(gaxOptions?: CallOptions): Promise<void>;
442 +
  delete(gaxOptions?: CallOptions): Promise<databaseAdmin.protobuf.IEmpty>;
411 443
  delete(callback: DeleteCallback): void;
412 444
  delete(gaxOptions: CallOptions, callback: DeleteCallback): void;
413 445
  /**
@@ -429,7 +461,7 @@
Loading
429 461
  delete(
430 462
    gaxOptionsOrCallback?: CallOptions | DeleteCallback,
431 463
    cb?: DeleteCallback
432 -
  ): void | Promise<void> {
464 +
  ): void | Promise<databaseAdmin.protobuf.IEmpty> {
433 465
    const callback =
434 466
      typeof gaxOptionsOrCallback === 'function'
435 467
        ? (gaxOptionsOrCallback as DeleteCallback)
@@ -441,12 +473,13 @@
Loading
441 473
    const reqOpts: databaseAdmin.spanner.admin.database.v1.IDeleteBackupRequest = {
442 474
      name: this.formattedName_,
443 475
    };
444 -
    return this.request<databaseAdmin.spanner.admin.database.v1.IBackup>(
476 +
    this.request<databaseAdmin.spanner.admin.database.v1.IBackup>(
445 477
      {
446 478
        client: 'DatabaseAdminClient',
447 479
        method: 'deleteBackup',
448 480
        reqOpts,
449 481
        gaxOpts,
482 +
        headers: this.resourceHeader_,
450 483
      },
451 484
      err => {
452 485
        callback!(err);
@@ -488,6 +521,15 @@
Loading
488 521
  exclude: ['getState', 'getExpireTime', 'exists'],
489 522
});
490 523
524 +
/*! Developer Documentation
525 +
 *
526 +
 * All async methods (except for streams) will return a Promise in the event
527 +
 * that a callback is omitted.
528 +
 */
529 +
callbackifyAll(Backup, {
530 +
  exclude: ['create', 'getMetadata', 'updateExpireTime', 'delete'],
531 +
});
532 +
491 533
/**
492 534
 * Reference to the {@link Backup} class.
493 535
 * @name module:@google-cloud/spanner.Backup

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Learn more Showing 3 files with coverage changes found.

New file .prettierrc.js
New
Loading file...
New file .mocharc.js
New
Loading file...
Changes in src/common.ts
-21
+21
Loading file...

93 Commits

Hiding 1 contexual commits Hiding 6 contexual commits
+171
+242
-71
Hiding 2 contexual commits
+39
+63
-2
-22
Hiding 1 contexual commits
+4
+19
+1
-16
Hiding 3 contexual commits
+43
+4
+1
+38
+22
+22
+32
+32
Hiding 2 contexual commits
+6
+6
+37
+59
-2
-20
-24
+2
+22
+26
+26
Hiding 2 contexual commits
Hiding 1 contexual commits
+2 Files
+45
+22
+23
Hiding 1 contexual commits
+6
+6