Compare fe003c0 ... +97 ... e6908af

Showing 20 of 101 files from the diff.
Newly tracked file
.mocharc.js changed.
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,51 @@
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';
25 -
import {promisify, promisifyAll} from '@google-cloud/promisify';
26 -
import arrify = require('arrify');
24 +
// eslint-disable-next-line @typescript-eslint/no-var-requires
25 +
const common = require('./common-grpc/service-object');
26 +
import {promisify, promisifyAll, callbackifyAll} from '@google-cloud/promisify';
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,
45 +
  GetDatabaseOperationsCallback,
41 46
} from './instance';
42 47
import {PartialResultStream, Row} from './partial-result-stream';
43 48
import {Session} from './session';
44 49
import {
50 +
  isSessionNotFoundError,
45 51
  SessionPool,
46 -
  SessionPoolOptions,
47 52
  SessionPoolCloseCallback,
48 53
  SessionPoolInterface,
49 -
  isSessionNotFoundError,
54 +
  SessionPoolOptions,
50 55
} from './session-pool';
51 -
import {Table, CreateTableCallback, CreateTableResponse} from './table';
56 +
import {CreateTableCallback, CreateTableResponse, Table} from './table';
52 57
import {
58 +
  ExecuteSqlRequest,
59 +
  RunCallback,
60 +
  RunResponse,
61 +
  RunUpdateCallback,
53 62
  Snapshot,
54 63
  TimestampBounds,
55 64
  Transaction,
56 -
  ExecuteSqlRequest,
57 -
  RunUpdateCallback,
58 -
  RunResponse,
59 -
  RunCallback,
60 65
} from './transaction';
61 66
import {
62 67
  AsyncRunTransactionCallback,
@@ -65,23 +70,21 @@
Loading
65 70
  RunTransactionOptions,
66 71
  TransactionRunner,
67 72
} from './transaction-runner';
68 -
69 -
import {google} from '../protos/protos';
70 73
import {
71 74
  IOperation,
72 -
  Schema,
75 +
  LongRunningCallback,
76 +
  NormalCallback,
77 +
  PagedOptionsWithFilter,
78 +
  CLOUD_RESOURCE_HEADER,
79 +
  PagedResponse,
73 80
  RequestCallback,
74 -
  PagedRequest,
75 81
  ResourceCallback,
76 -
  PagedResponse,
77 -
  NormalCallback,
78 -
  LongRunningCallback,
82 +
  Schema,
79 83
} from './common';
80 -
import {ServiceError, CallOptions} from 'grpc';
81 -
import {Readable, Transform, Duplex} from 'stream';
84 +
import {Duplex, Readable, Transform} from 'stream';
82 85
import {PreciseDate} from '@google-cloud/precise-date';
83 -
import {google as spannerClient} from '../protos/protos';
84 86
import {EnumKey, RequestConfig, TranslateEnumKeys} from '.';
87 +
import arrify = require('arrify');
85 88
86 89
type CreateBatchTransactionCallback = ResourceCallback<
87 90
  BatchTransaction,
@@ -120,7 +123,7 @@
Loading
120 123
121 124
type ResultSetStats = spannerClient.spanner.v1.ResultSetStats;
122 125
123 -
type GetSessionsOptions = PagedRequest<google.spanner.v1.IListSessionsRequest>;
126 +
export type GetSessionsOptions = PagedOptionsWithFilter;
124 127
125 128
/**
126 129
 * IDatabase structure with database state enum translated to string form.
@@ -166,7 +169,9 @@
Loading
166 169
>;
167 170
168 171
export type GetDatabaseConfig = GetConfig &
169 -
  databaseAdmin.spanner.admin.database.v1.GetDatabaseRequest;
172 +
  databaseAdmin.spanner.admin.database.v1.GetDatabaseRequest & {
173 +
    gaxOptions?: CallOptions;
174 +
  };
170 175
type DatabaseCloseResponse = [google.protobuf.IEmpty];
171 176
172 177
export type CreateSessionResponse = [
@@ -175,8 +180,8 @@
Loading
175 180
];
176 181
177 182
export interface CreateSessionOptions {
178 -
  name?: string | null;
179 183
  labels?: {[k: string]: string} | null;
184 +
  gaxOptions?: CallOptions;
180 185
}
181 186
182 187
export type CreateSessionCallback = ResourceCallback<
@@ -198,7 +203,10 @@
Loading
198 203
  spannerClient.spanner.v1.IBatchCreateSessionsResponse
199 204
>;
200 205
201 -
export type DatabaseDeleteCallback = NormalCallback<r.Response>;
206 +
export type DatabaseDeleteResponse = [databaseAdmin.protobuf.IEmpty];
207 +
export type DatabaseDeleteCallback = NormalCallback<
208 +
  databaseAdmin.protobuf.IEmpty
209 +
>;
202 210
203 211
export interface CancelableDuplex extends Duplex {
204 212
  cancel(): void;
@@ -212,6 +220,11 @@
Loading
212 220
  databaseAdmin.longrunning.IOperation
213 221
];
214 222
223 +
export type GetRestoreInfoCallback = NormalCallback<IRestoreInfoTranslatedEnum>;
224 +
export type GetStateCallback = NormalCallback<
225 +
  EnumKey<typeof databaseAdmin.spanner.admin.database.v1.Database.State>
226 +
>;
227 +
215 228
interface DatabaseRequest {
216 229
  (
217 230
    config: RequestConfig,
@@ -237,11 +250,12 @@
Loading
237 250
 * const instance = spanner.instance('my-instance');
238 251
 * const database = instance.database('my-database');
239 252
 */
240 -
class Database extends GrpcServiceObject {
253 +
class Database extends common.GrpcServiceObject {
241 254
  private instance: Instance;
242 255
  formattedName_: string;
243 256
  pool_: SessionPoolInterface;
244 257
  queryOptions_?: spannerClient.spanner.v1.ExecuteSqlRequest.IQueryOptions;
258 +
  resourceHeader_: {[k: string]: string};
245 259
  request: DatabaseRequest;
246 260
  constructor(
247 261
    instance: Instance,
@@ -304,7 +318,41 @@
Loading
304 318
        options: CreateDatabaseOptions,
305 319
        callback: CreateDatabaseCallback
306 320
      ) => {
307 -
        return instance.createDatabase(formattedName_, options, callback);
321 +
        const pool = this.pool_ as SessionPool;
322 +
        if (pool._pending > 0) {
323 +
          // If there are BatchCreateSessions requests pending, then we should
324 +
          // wait until these have finished before we try to create the database.
325 +
          // Otherwise the results of these requests might be propagated to
326 +
          // client requests that are submitted after the database has been
327 +
          // created. If the pending requests have not finished within 10 seconds,
328 +
          // they will be ignored and the database creation will proceed.
329 +
          let timeout;
330 +
          const promises = [
331 +
            new Promise<void>(
332 +
              resolve => (timeout = setTimeout(resolve, 10000))
333 +
            ),
334 +
            new Promise<void>(resolve => {
335 +
              pool
336 +
                .on('available', () => {
337 +
                  if (pool._pending === 0) {
338 +
                    clearTimeout(timeout);
339 +
                    resolve();
340 +
                  }
341 +
                })
342 +
                .on('createError', () => {
343 +
                  if (pool._pending === 0) {
344 +
                    clearTimeout(timeout);
345 +
                    resolve();
346 +
                  }
347 +
                });
348 +
            }),
349 +
          ];
350 +
          Promise.race(promises).then(() =>
351 +
            instance.createDatabase(formattedName_, options, callback)
352 +
          );
353 +
        } else {
354 +
          return instance.createDatabase(formattedName_, options, callback);
355 +
        }
308 356
      },
309 357
    } as {}) as ServiceObjectConfig);
310 358
@@ -314,6 +362,9 @@
Loading
314 362
        : new SessionPool(this, poolOptions);
315 363
    this.formattedName_ = formattedName_;
316 364
    this.instance = instance;
365 +
    this.resourceHeader_ = {
366 +
      [CLOUD_RESOURCE_HEADER]: this.formattedName_,
367 +
    };
317 368
    this.request = instance.request;
318 369
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
319 370
    this.requestStream = instance.requestStream as any;
@@ -417,6 +468,8 @@
Loading
417 468
        client: 'SpannerClient',
418 469
        method: 'batchCreateSessions',
419 470
        reqOpts,
471 +
        gaxOpts: options.gaxOptions,
472 +
        headers: this.resourceHeader_,
420 473
      },
421 474
      (err, resp) => {
422 475
        if (err) {
@@ -555,12 +608,13 @@
Loading
555 608
        ? (optionsOrCallback as TimestampBounds)
556 609
        : {};
557 610
558 -
    this.createSession((err, session, resp) => {
611 +
    this.pool_.getReadSession((err, session) => {
559 612
      if (err) {
560 -
        callback!(err, null, resp);
613 +
        callback!(err, null, undefined);
561 614
        return;
562 615
      }
563 616
      const transaction = this.batchTransaction({session: session!}, options);
617 +
      this._releaseOnEnd(session!, transaction);
564 618
      transaction.begin((err, resp) => {
565 619
        if (err) {
566 620
          callback!(err, null, resp!);
@@ -576,6 +630,20 @@
Loading
576 630
    options: CreateSessionOptions,
577 631
    callback: CreateSessionCallback
578 632
  ): void;
633 +
  /**
634 +
   * Create a new session.
635 +
   *
636 +
   * @typedef {object} CreateSessionOptions
637 +
   * @property {Object.<string, string>} [labels] The labels for the session.
638 +
   *
639 +
   *   * Label keys must be between 1 and 63 characters long and must conform to
640 +
   *     the following regular expression: `[a-z]([-a-z0-9]*[a-z0-9])?`.
641 +
   *   * Label values must be between 0 and 63 characters long and must conform
642 +
   *     to the regular expression `([a-z]([-a-z0-9]*[a-z0-9])?)?`.
643 +
   *   * No more than 64 labels can be associated with a given session.
644 +
   * @property {object} [gaxOptions] Request configuration options, outlined
645 +
   *     here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
646 +
   */
579 647
  /**
580 648
   * @typedef {array} CreateSessionResponse
581 649
   * @property {Session} 0 The newly created session.
@@ -637,10 +705,8 @@
Loading
637 705
    cb?: CreateSessionCallback
638 706
  ): void | Promise<CreateSessionResponse> {
639 707
    const callback =
640 -
      typeof optionsOrCallback === 'function'
641 -
        ? (optionsOrCallback as CreateSessionCallback)
642 -
        : cb!;
643 -
    const gaxOpts =
708 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
709 +
    const options =
644 710
      typeof optionsOrCallback === 'object' && optionsOrCallback
645 711
        ? extend({}, optionsOrCallback)
646 712
        : ({} as CreateSessionOptions);
@@ -649,17 +715,17 @@
Loading
649 715
      database: this.formattedName_,
650 716
    };
651 717
652 -
    if (gaxOpts.labels) {
653 -
      reqOpts.session = {labels: gaxOpts.labels};
654 -
      delete gaxOpts.labels;
718 +
    if (options.labels) {
719 +
      reqOpts.session = {labels: options.labels};
655 720
    }
656 721
657 722
    this.request<google.spanner.v1.ISession>(
658 723
      {
659 724
        client: 'SpannerClient',
660 725
        method: 'createSession',
661 726
        reqOpts,
662 -
        gaxOpts,
727 +
        gaxOpts: options.gaxOptions,
728 +
        headers: this.resourceHeader_,
663 729
      },
664 730
      (err, resp) => {
665 731
        if (err) {
@@ -672,8 +738,16 @@
Loading
672 738
      }
673 739
    );
674 740
  }
675 -
  createTable(schema: Schema): Promise<CreateTableResponse>;
676 -
  createTable(schema: Schema, callback?: CreateTableCallback): void;
741 +
  createTable(
742 +
    schema: Schema,
743 +
    gaxOptions?: CallOptions
744 +
  ): Promise<CreateTableResponse>;
745 +
  createTable(schema: Schema, callback: CreateTableCallback): void;
746 +
  createTable(
747 +
    schema: Schema,
748 +
    gaxOptions: CallOptions,
749 +
    callback: CreateTableCallback
750 +
  ): void;
677 751
  /**
678 752
   * @typedef {array} CreateTableResponse
679 753
   * @property {Table} 0 The new {@link Table}.
@@ -697,6 +771,8 @@
Loading
697 771
   * @see {@link Database#updateSchema}
698 772
   *
699 773
   * @param {string} schema A DDL CREATE statement describing the table.
774 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
775 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
700 776
   * @param {CreateTableCallback} [callback] Callback function.
701 777
   * @returns {Promise<CreateTableResponse>}
702 778
   *
@@ -743,9 +819,15 @@
Loading
743 819
   */
744 820
  createTable(
745 821
    schema: Schema,
746 -
    callback?: CreateTableCallback
822 +
    gaxOptionsOrCallback?: CallOptions | CreateTableCallback,
823 +
    cb?: CreateTableCallback
747 824
  ): void | Promise<CreateTableResponse> {
748 -
    this.updateSchema(schema, (err, operation, resp) => {
825 +
    const gaxOptions =
826 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
827 +
    const callback =
828 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
829 +
830 +
    this.updateSchema(schema, gaxOptions, (err, operation, resp) => {
749 831
      if (err) {
750 832
        callback!(err, null, null, resp!);
751 833
        return;
@@ -776,17 +858,21 @@
Loading
776 858
      }
777 859
    });
778 860
  }
779 -
  delete(): Promise<[r.Response]>;
861 +
  delete(gaxOptions?: CallOptions): Promise<DatabaseDeleteResponse>;
780 862
  delete(callback: DatabaseDeleteCallback): void;
863 +
  delete(gaxOptions: CallOptions, callback: DatabaseDeleteCallback): void;
781 864
  /**
782 865
   * Delete the database.
783 866
   *
784 867
   * Wrapper around {@link v1.DatabaseAdminClient#dropDatabase}.
785 868
   *
786 869
   * @see {@link v1.DatabaseAdminClient#dropDatabase}
787 870
   * @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>}
871 +
   *
872 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
873 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
874 +
   * @param {DatabaseDeleteCallback} [callback] Callback function.
875 +
   * @returns {Promise<DatabaseDeleteResponse>}
790 876
   *
791 877
   * @example
792 878
   * const {Spanner} = require('@google-cloud/spanner');
@@ -810,7 +896,15 @@
Loading
810 896
   *   const apiResponse = data[0];
811 897
   * });
812 898
   */
813 -
  delete(callback?: DatabaseDeleteCallback): void | Promise<[r.Response]> {
899 +
  delete(
900 +
    optionsOrCallback?: CallOptions | DatabaseDeleteCallback,
901 +
    cb?: DatabaseDeleteCallback
902 +
  ): void | Promise<DatabaseDeleteResponse> {
903 +
    const gaxOpts =
904 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
905 +
    const callback =
906 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
907 +
814 908
    const reqOpts: databaseAdmin.spanner.admin.database.v1.IDropDatabaseRequest = {
815 909
      database: this.formattedName_,
816 910
    };
@@ -820,13 +914,16 @@
Loading
820 914
          client: 'DatabaseAdminClient',
821 915
          method: 'dropDatabase',
822 916
          reqOpts,
917 +
          gaxOpts,
918 +
          headers: this.resourceHeader_,
823 919
        },
824 920
        callback!
825 921
      );
826 922
    });
827 923
  }
828 -
  exists(): Promise<[boolean]>;
924 +
  exists(gaxOptions?: CallOptions): Promise<[boolean]>;
829 925
  exists(callback: ExistsCallback): void;
926 +
  exists(gaxOptions: CallOptions, callback: ExistsCallback): void;
830 927
  /**
831 928
   * @typedef {array} DatabaseExistsResponse
832 929
   * @property {boolean} 0 Whether the {@link Database} exists.
@@ -840,6 +937,8 @@
Loading
840 937
   * Check if a database exists.
841 938
   *
842 939
   * @method Database#exists
940 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
941 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
843 942
   * @param {DatabaseExistsCallback} [callback] Callback function.
844 943
   * @returns {Promise<DatabaseExistsResponse>}
845 944
   *
@@ -859,10 +958,18 @@
Loading
859 958
   *   const exists = data[0];
860 959
   * });
861 960
   */
862 -
  exists(callback?: ExistsCallback): void | Promise<[boolean]> {
961 +
  exists(
962 +
    gaxOptionsOrCallback?: CallOptions | ExistsCallback,
963 +
    cb?: ExistsCallback
964 +
  ): void | Promise<[boolean]> {
965 +
    const gaxOptions =
966 +
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
967 +
    const callback =
968 +
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
969 +
863 970
    const NOT_FOUND = 5;
864 971
865 -
    this.getMetadata(err => {
972 +
    this.getMetadata(gaxOptions, err => {
866 973
      if (err && (err as ApiError).code !== NOT_FOUND) {
867 974
        callback!(err);
868 975
        return;
@@ -928,14 +1035,14 @@
Loading
928 1035
        : ({} as GetDatabaseConfig);
929 1036
    const callback =
930 1037
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
931 -
    this.getMetadata((err, metadata) => {
1038 +
    this.getMetadata(options.gaxOptions!, (err, metadata) => {
932 1039
      if (err) {
933 1040
        if (options.autoCreate && (err as ApiError).code === 5) {
934 1041
          this.create(
935 1042
            options,
936 1043
            (err, database: Database, operation: GaxOperation) => {
937 1044
              if (err) {
938 -
                callback!(err);
1045 +
                callback!(err as grpc.ServiceError);
939 1046
                return;
940 1047
              }
941 1048
              operation
@@ -954,8 +1061,9 @@
Loading
954 1061
      callback!(null, this, metadata as r.Response);
955 1062
    });
956 1063
  }
957 -
  getMetadata(): Promise<GetMetadataResponse>;
1064 +
  getMetadata(gaxOptions?: CallOptions): Promise<GetMetadataResponse>;
958 1065
  getMetadata(callback: GetMetadataCallback): void;
1066 +
  getMetadata(gaxOptions: CallOptions, callback: GetMetadataCallback): void;
959 1067
  /**
960 1068
   * @typedef {array} GetDatabaseMetadataResponse
961 1069
   * @property {object} 0 The {@link Database} metadata.
@@ -974,7 +1082,8 @@
Loading
974 1082
   *
975 1083
   * @see {@link v1.DatabaseAdminClient#getDatabase}
976 1084
   * @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 -
   *
1085 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
1086 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
978 1087
   * @param {GetMetadataCallback} [callback] Callback function.
979 1088
   * @returns {Promise<GetMetadataResponse>}
980 1089
   *
@@ -1002,8 +1111,18 @@
Loading
1002 1111
   * });
1003 1112
   */
1004 1113
  getMetadata(
1005 -
    callback?: GetMetadataCallback
1114 +
    gaxOptionsOrCallback?: CallOptions | GetMetadataCallback,
1115 +
    cb?: GetMetadataCallback
1006 1116
  ): void | Promise<GetMetadataResponse> {
1117 +
    const callback =
1118 +
      typeof gaxOptionsOrCallback === 'function'
1119 +
        ? (gaxOptionsOrCallback as GetMetadataCallback)
1120 +
        : cb;
1121 +
    const gaxOpts =
1122 +
      typeof gaxOptionsOrCallback === 'object'
1123 +
        ? (gaxOptionsOrCallback as CallOptions)
1124 +
        : {};
1125 +
1007 1126
    const reqOpts: databaseAdmin.spanner.admin.database.v1.IGetDatabaseRequest = {
1008 1127
      name: this.formattedName_,
1009 1128
    };
@@ -1012,11 +1131,23 @@
Loading
1012 1131
        client: 'DatabaseAdminClient',
1013 1132
        method: 'getDatabase',
1014 1133
        reqOpts,
1134 +
        gaxOpts,
1135 +
        headers: this.resourceHeader_,
1015 1136
      },
1016 -
      callback!
1137 +
      (err, resp) => {
1138 +
        if (resp) {
1139 +
          this.metadata = resp;
1140 +
        }
1141 +
        callback!(err, resp);
1142 +
      }
1017 1143
    );
1018 1144
  }
1019 1145
1146 +
  getRestoreInfo(
1147 +
    options?: CallOptions
1148 +
  ): Promise<IRestoreInfoTranslatedEnum | undefined>;
1149 +
  getRestoreInfo(callback: GetRestoreInfoCallback): void;
1150 +
  getRestoreInfo(options: CallOptions, callback: GetRestoreInfoCallback): void;
1020 1151
  /**
1021 1152
   * {@link google.spanner.admin.database.v1#RestoreInfo} structure with restore
1022 1153
   * source type enum translated to string form.
@@ -1029,6 +1160,9 @@
Loading
1029 1160
   * @see {@link #getMetadata}
1030 1161
   *
1031 1162
   * @method Database#getRestoreInfo
1163 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
1164 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
1165 +
   * @param {GetRestoreInfoCallback} [callback] Callback function.
1032 1166
   * @returns {Promise<IRestoreInfoTranslatedEnum | undefined>} When resolved,
1033 1167
   *     contains the restore information for the database if it was restored
1034 1168
   *     from a backup.
@@ -1041,11 +1175,24 @@
Loading
1041 1175
   * const restoreInfo = await database.getRestoreInfo();
1042 1176
   * console.log(`Database restored from ${restoreInfo.backupInfo.backup}`);
1043 1177
   */
1044 -
  async getRestoreInfo(): Promise<IRestoreInfoTranslatedEnum | undefined> {
1045 -
    const [metadata] = await this.getMetadata();
1178 +
  async getRestoreInfo(
1179 +
    optionsOrCallback?: CallOptions | GetRestoreInfoCallback
1180 +
  ): Promise<IRestoreInfoTranslatedEnum | undefined> {
1181 +
    const gaxOptions =
1182 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
1183 +
1184 +
    const [metadata] = await this.getMetadata(gaxOptions);
1046 1185
    return metadata.restoreInfo ? metadata.restoreInfo : undefined;
1047 1186
  }
1048 1187
1188 +
  getState(
1189 +
    options?: CallOptions
1190 +
  ): Promise<
1191 +
    | EnumKey<typeof databaseAdmin.spanner.admin.database.v1.Database.State>
1192 +
    | undefined
1193 +
  >;
1194 +
  getState(callback: GetStateCallback): void;
1195 +
  getState(options: CallOptions, callback: GetStateCallback): void;
1049 1196
  /**
1050 1197
   * Retrieves the state of the database.
1051 1198
   *
@@ -1055,6 +1202,9 @@
Loading
1055 1202
   * @see {@link #getMetadata}
1056 1203
   *
1057 1204
   * @method Database#getState
1205 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
1206 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
1207 +
   * @param {GetStateCallback} [callback] Callback function.
1058 1208
   * @returns {Promise<EnumKey<typeof, databaseAdmin.spanner.admin.database.v1.Database.State> | undefined>}
1059 1209
   *     When resolved, contains the current state of the database if the state
1060 1210
   *     is defined.
@@ -1067,16 +1217,22 @@
Loading
1067 1217
   * const state = await database.getState();
1068 1218
   * const isReady = (state === 'READY');
1069 1219
   */
1070 -
  async getState(): Promise<
1220 +
  async getState(
1221 +
    optionsOrCallback?: CallOptions | GetStateCallback
1222 +
  ): Promise<
1071 1223
    | EnumKey<typeof databaseAdmin.spanner.admin.database.v1.Database.State>
1072 1224
    | undefined
1073 1225
  > {
1074 -
    const [metadata] = await this.getMetadata();
1226 +
    const gaxOptions =
1227 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
1228 +
1229 +
    const [metadata] = await this.getMetadata(gaxOptions);
1075 1230
    return metadata.state || undefined;
1076 1231
  }
1077 1232
1078 -
  getSchema(): Promise<GetSchemaResponse>;
1233 +
  getSchema(options?: CallOptions): Promise<GetSchemaResponse>;
1079 1234
  getSchema(callback: GetSchemaCallback): void;
1235 +
  getSchema(options: CallOptions, callback: GetSchemaCallback): void;
1080 1236
  /**
1081 1237
   * @typedef {array} GetSchemaResponse
1082 1238
   * @property {string[]} 0 An array of database DDL statements.
@@ -1097,6 +1253,8 @@
Loading
1097 1253
   * @see [Data Definition Language (DDL)](https://cloud.google.com/spanner/docs/data-definition-language)
1098 1254
   * @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 1255
   *
1256 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
1257 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
1100 1258
   * @param {GetSchemaCallback} [callback] Callback function.
1101 1259
   * @returns {Promise<GetSchemaResponse>}
1102 1260
   *
@@ -1117,7 +1275,15 @@
Loading
1117 1275
   *   const apiResponse = data[1];
1118 1276
   * });
1119 1277
   */
1120 -
  getSchema(callback?: GetSchemaCallback): void | Promise<GetSchemaResponse> {
1278 +
  getSchema(
1279 +
    optionsOrCallback?: CallOptions | GetSchemaCallback,
1280 +
    cb?: GetSchemaCallback
1281 +
  ): void | Promise<GetSchemaResponse> {
1282 +
    const gaxOpts =
1283 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
1284 +
    const callback =
1285 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
1286 +
1121 1287
    const reqOpts: databaseAdmin.spanner.admin.database.v1.IGetDatabaseDdlRequest = {
1122 1288
      database: this.formattedName_,
1123 1289
    };
@@ -1128,6 +1294,8 @@
Loading
1128 1294
        client: 'DatabaseAdminClient',
1129 1295
        method: 'getDatabaseDdl',
1130 1296
        reqOpts,
1297 +
        gaxOpts,
1298 +
        headers: this.resourceHeader_,
1131 1299
      },
1132 1300
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
1133 1301
      (err, statements, ...args: any[]) => {
@@ -1141,9 +1309,7 @@
Loading
1141 1309
  /**
1142 1310
   * Options object for listing sessions.
1143 1311
   *
1144 -
   * @typedef {object} GetSessionsRequest
1145 -
   * @property {boolean} [autoPaginate=true] Have pagination handled
1146 -
   *     automatically.
1312 +
   * @typedef {object} GetSessionsOptions
1147 1313
   * @property {string} [filter] An expression for filtering the results of the
1148 1314
   *     request. Filter rules are case insensitive. The fields eligible for
1149 1315
   *     filtering are:
@@ -1158,21 +1324,23 @@
Loading
1158 1324
   *     - **`labels.env:dev`** The instance's label env has the value dev.
1159 1325
   *     - **`name:howl labels.env:dev`** The instance's name is howl and it has
1160 1326
   *       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 1327
   * @property {number} [pageSize] Maximum number of results per page.
1164 1328
   * @property {string} [pageToken] A previously-returned page token
1165 1329
   *     representing part of the larger set of results to view.
1330 +
   * @property {object} [gaxOptions] Request configuration options, outlined
1331 +
   *     here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
1166 1332
   */
1167 1333
  /**
1168 1334
   * @typedef {array} GetSessionsResponse
1169 1335
   * @property {Session[]} 0 Array of {@link Session} instances.
1170 -
   * @property {object} 1 The full API response.
1336 +
   * @property {object} 1 A query object to receive more results.
1337 +
   * @property {object} 2 The full API response.
1171 1338
   */
1172 1339
  /**
1173 1340
   * @callback GetSessionsCallback
1174 1341
   * @param {?Error} err Request error, if any.
1175 1342
   * @param {Session[]} instances Array of {@link Session} instances.
1343 +
   * @param {object} nextQuery A query object to receive more results.
1176 1344
   * @param {object} apiResponse The full API response.
1177 1345
   */
1178 1346
  /**
@@ -1210,7 +1378,7 @@
Loading
1210 1378
   * }
1211 1379
   *
1212 1380
   * database.getInstances({
1213 -
   *   autoPaginate: false
1381 +
   *   gaxOptions: {autoPaginate: false}
1214 1382
   * }, callback);
1215 1383
   *
1216 1384
   * //-
@@ -1227,19 +1395,32 @@
Loading
1227 1395
    // eslint-disable-next-line @typescript-eslint/no-this-alias
1228 1396
    const self = this;
1229 1397
    const callback =
1230 -
      typeof optionsOrCallback === 'function'
1231 -
        ? (optionsOrCallback as GetSessionsCallback)
1232 -
        : cb;
1398 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
1233 1399
    const options =
1234 1400
      typeof optionsOrCallback === 'object'
1235 -
        ? (optionsOrCallback as GetSessionsOptions)
1236 -
        : {gaxOptions: {}};
1237 -
    const gaxOpts: CallOptions = options.gaxOptions as CallOptions;
1238 -
    const reqOpts = extend({}, options, {
1401 +
        ? optionsOrCallback
1402 +
        : ({} as GetSessionsOptions);
1403 +
    const gaxOpts = extend(true, {}, options.gaxOptions);
1404 +
    let reqOpts = extend({}, options, {
1239 1405
      database: this.formattedName_,
1240 1406
    });
1241 -
1242 1407
    delete reqOpts.gaxOptions;
1408 +
1409 +
    // Copy over pageSize and pageToken values from gaxOptions.
1410 +
    // However values set on options take precedence.
1411 +
    if (gaxOpts) {
1412 +
      reqOpts = extend(
1413 +
        {},
1414 +
        {
1415 +
          pageSize: gaxOpts.pageSize,
1416 +
          pageToken: gaxOpts.pageToken,
1417 +
        },
1418 +
        reqOpts
1419 +
      );
1420 +
      delete gaxOpts.pageSize;
1421 +
      delete gaxOpts.pageToken;
1422 +
    }
1423 +
1243 1424
    this.request<
1244 1425
      google.spanner.v1.ISession,
1245 1426
      google.spanner.v1.IListSessionsResponse
@@ -1249,8 +1430,9 @@
Loading
1249 1430
        method: 'listSessions',
1250 1431
        reqOpts,
1251 1432
        gaxOpts,
1433 +
        headers: this.resourceHeader_,
1252 1434
      },
1253 -
      (err, sessions, ...args) => {
1435 +
      (err, sessions, nextPageRequest, ...args) => {
1254 1436
        let sessionInstances: Session[] | null = null;
1255 1437
        if (sessions) {
1256 1438
          sessionInstances = sessions.map(metadata => {
@@ -1259,10 +1441,84 @@
Loading
1259 1441
            return session;
1260 1442
          });
1261 1443
        }
1262 -
        callback!(err, sessionInstances!, ...args);
1444 +
        const nextQuery = nextPageRequest!
1445 +
          ? extend({}, options, nextPageRequest!)
1446 +
          : null;
1447 +
        callback!(err, sessionInstances!, nextQuery, ...args);
1263 1448
      }
1264 1449
    );
1265 1450
  }
1451 +
1452 +
  /**
1453 +
   * Get a list of sessions as a readable object stream.
1454 +
   *
1455 +
   * Wrapper around {@link v1.SpannerClient#listSessions}
1456 +
   *
1457 +
   * @see {@link v1.SpannerClient#listSessions}
1458 +
   * @see [ListSessions API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.ListSessions)
1459 +
   *
1460 +
   * @method Spanner#getSessionsStream
1461 +
   * @param {GetSessionsOptions} [options] Options object for listing sessions.
1462 +
   * @returns {ReadableStream} A readable stream that emits {@link Session}
1463 +
   *     instances.
1464 +
   *
1465 +
   * @example
1466 +
   * const {Spanner} = require('@google-cloud/spanner');
1467 +
   * const spanner = new Spanner();
1468 +
   *
1469 +
   * const instance = spanner.instance('my-instance');
1470 +
   * const database = instance.database('my-database');
1471 +
   *
1472 +
   * database.getSessionsStream()
1473 +
   *   .on('error', console.error)
1474 +
   *   .on('data', function(database) {
1475 +
   *     // `sessions` is a `Session` object.
1476 +
   *   })
1477 +
   *   .on('end', function() {
1478 +
   *     // All sessions retrieved.
1479 +
   *   });
1480 +
   *
1481 +
   * //-
1482 +
   * // If you anticipate many results, you can end a stream early to prevent
1483 +
   * // unnecessary processing and API requests.
1484 +
   * //-
1485 +
   * database.getSessionsStream()
1486 +
   *   .on('data', function(session) {
1487 +
   *     this.end();
1488 +
   *   });
1489 +
   */
1490 +
  getSessionsStream(options: GetSessionsOptions = {}): NodeJS.ReadableStream {
1491 +
    const gaxOpts = extend(true, {}, options.gaxOptions);
1492 +
1493 +
    let reqOpts = extend({}, options, {
1494 +
      database: this.formattedName_,
1495 +
    });
1496 +
    delete reqOpts.gaxOptions;
1497 +
1498 +
    // Copy over pageSize and pageToken values from gaxOptions.
1499 +
    // However values set on options take precedence.
1500 +
    if (gaxOpts) {
1501 +
      reqOpts = extend(
1502 +
        {},
1503 +
        {
1504 +
          pageSize: gaxOpts.pageSize,
1505 +
          pageToken: gaxOpts.pageToken,
1506 +
        },
1507 +
        reqOpts
1508 +
      );
1509 +
      delete gaxOpts.pageSize;
1510 +
      delete gaxOpts.pageToken;
1511 +
    }
1512 +
1513 +
    return this.requestStream({
1514 +
      client: 'SpannerClient',
1515 +
      method: 'listSessionsStream',
1516 +
      reqOpts,
1517 +
      gaxOpts,
1518 +
      headers: this.resourceHeader_,
1519 +
    });
1520 +
  }
1521 +
1266 1522
  getSnapshot(options?: TimestampBounds): Promise<[Snapshot]>;
1267 1523
  getSnapshot(callback: GetSnapshotCallback): void;
1268 1524
  getSnapshot(options: TimestampBounds, callback: GetSnapshotCallback): void;
@@ -1284,6 +1540,12 @@
Loading
1284 1540
   * called to release the underlying {@link Session}. **Failure to do could
1285 1541
   * result in a Session leak.**
1286 1542
   *
1543 +
   * **NOTE:** Since the returned {@link Snapshot} transaction is not a
1544 +
   * single-use transaction, it is invalid to set the `minReadTimestamp` and
1545 +
   * `maxStaleness` parameters in {@link TimestampBounds} as those parameters
1546 +
   * can only be set for single-use transactions.
1547 +
   * https://cloud.google.com/spanner/docs/reference/rest/v1/TransactionOptions#bounded-staleness
1548 +
   *
1287 1549
   * @see {@link v1.SpannerClient#beginTransaction}
1288 1550
   *
1289 1551
   * @param {TimestampBounds} [options] Timestamp bounds.
@@ -1404,10 +1666,18 @@
Loading
1404 1666
      if (!err) {
1405 1667
        this._releaseOnEnd(session!, transaction!);
1406 1668
      }
1407 -
      callback!(err, transaction);
1669 +
      callback!(err as grpc.ServiceError | null, transaction);
1408 1670
    });
1409 1671
  }
1410 1672
1673 +
  getOperations(
1674 +
    options?: GetDatabaseOperationsOptions
1675 +
  ): Promise<GetDatabaseOperationsResponse>;
1676 +
  getOperations(callback: GetDatabaseOperationsCallback): void;
1677 +
  getOperations(
1678 +
    options: GetDatabaseOperationsOptions,
1679 +
    callback: GetDatabaseOperationsCallback
1680 +
  ): void;
1411 1681
  /**
1412 1682
   * Query object for listing database operations.
1413 1683
   *
@@ -1418,6 +1688,9 @@
Loading
1418 1688
   * @property {number} [pageSize] Maximum number of results per page.
1419 1689
   * @property {string} [pageToken] A previously-returned page token
1420 1690
   *     representing part of the larger set of results to view.
1691 +
   * @property {object} [gaxOptions] Request configuration options, outlined
1692 +
   *     here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
1693 +
   * @param {GetDatabaseOperationsCallback} [callback] Callback function.
1421 1694
   */
1422 1695
  /**
1423 1696
   * @typedef {array} GetDatabaseOperationsResponse
@@ -1459,8 +1732,12 @@
Loading
1459 1732
   * } while (pageToken);
1460 1733
   */
1461 1734
  async getOperations(
1462 -
    options?: GetDatabaseOperationsOptions
1735 +
    optionsOrCallback?:
1736 +
      | GetDatabaseOperationsOptions
1737 +
      | GetDatabaseOperationsCallback
1463 1738
  ): Promise<GetDatabaseOperationsResponse> {
1739 +
    const options =
1740 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
1464 1741
    // Create a query that lists database operations only on this database from
1465 1742
    // the instance. Operation name will be prefixed with the database path for
1466 1743
    // all operations on this database
@@ -1529,7 +1806,7 @@
Loading
1529 1806
        requestStream.cancel();
1530 1807
      }
1531 1808
    };
1532 -
    function destroyStream(err: ServiceError) {
1809 +
    function destroyStream(err: grpc.ServiceError) {
1533 1810
      waitForSessionStream.destroy(err);
1534 1811
    }
1535 1812
    function releaseSession() {
@@ -1628,6 +1905,7 @@
Loading
1628 1905
        method: 'restoreDatabase',
1629 1906
        reqOpts,
1630 1907
        gaxOpts,
1908 +
        headers: this.resourceHeader_,
1631 1909
      },
1632 1910
      (err, operation, resp) => {
1633 1911
        if (err) {
@@ -1859,20 +2137,41 @@
Loading
1859 2137
        return;
1860 2138
      }
1861 2139
1862 -
      const transaction = session!.partitionedDml();
2140 +
      this._runPartitionedUpdate(session!, query, callback);
2141 +
    });
2142 +
  }
2143 +
2144 +
  _runPartitionedUpdate(
2145 +
    session: Session,
2146 +
    query: string | ExecuteSqlRequest,
2147 +
    callback?: RunUpdateCallback
2148 +
  ): void | Promise<number> {
2149 +
    const transaction = session.partitionedDml();
2150 +
2151 +
    transaction.begin(err => {
2152 +
      if (err) {
2153 +
        this.pool_.release(session!);
2154 +
        callback!(err, 0);
2155 +
        return;
2156 +
      }
1863 2157
1864 -
      transaction.begin(err => {
2158 +
      transaction.runUpdate(query, (err, updateCount) => {
1865 2159
        if (err) {
2160 +
          if (err.code !== grpc.status.ABORTED) {
2161 +
            this.pool_.release(session!);
2162 +
            callback!(err, 0);
2163 +
            return;
2164 +
          }
2165 +
          this._runPartitionedUpdate(session, query, callback);
2166 +
        } else {
1866 2167
          this.pool_.release(session!);
1867 -
          callback!(err, 0);
2168 +
          callback!(null, updateCount);
1868 2169
          return;
1869 2170
        }
1870 -
1871 -
        this._releaseOnEnd(session!, transaction);
1872 -
        transaction.runUpdate(query, callback!);
1873 2171
      });
1874 2172
    });
1875 2173
  }
2174 +
1876 2175
  /**
1877 2176
   * Create a readable object stream to receive resulting rows from a SQL
1878 2177
   * statement.
@@ -2018,12 +2317,15 @@
Loading
2018 2317
      dataStream
2019 2318
        .once('data', () => (dataReceived = true))
2020 2319
        .once('error', err => {
2021 -
          if (!dataReceived && isSessionNotFoundError(err)) {
2320 +
          if (
2321 +
            !dataReceived &&
2322 +
            isSessionNotFoundError(err as grpc.ServiceError)
2323 +
          ) {
2022 2324
            // If it is a 'Session not found' error and we have not yet received
2023 2325
            // any data, we can safely retry the query on a new session.
2024 2326
            // Register the error on the session so the pool can discard it.
2025 2327
            if (session) {
2026 -
              session.lastError = err;
2328 +
              session.lastError = err as grpc.ServiceError;
2027 2329
            }
2028 2330
            // Remove the current data stream from the end user stream.
2029 2331
            dataStream.unpipe(proxyStream);
@@ -2141,12 +2443,12 @@
Loading
2141 2443
        : {};
2142 2444
2143 2445
    this.pool_.getWriteSession((err, session?, transaction?) => {
2144 -
      if (err && isSessionNotFoundError(err)) {
2446 +
      if (err && isSessionNotFoundError(err as grpc.ServiceError)) {
2145 2447
        this.runTransaction(options, runFn!);
2146 2448
        return;
2147 2449
      }
2148 2450
      if (err) {
2149 -
        runFn!(err);
2451 +
        runFn!(err as grpc.ServiceError);
2150 2452
        return;
2151 2453
      }
2152 2454
@@ -2307,8 +2609,16 @@
Loading
2307 2609
    }
2308 2610
    return new Table(this, name);
2309 2611
  }
2310 -
  updateSchema(statements: Schema): Promise<UpdateSchemaResponse>;
2612 +
  updateSchema(
2613 +
    statements: Schema,
2614 +
    gaxOptions?: CallOptions
2615 +
  ): Promise<UpdateSchemaResponse>;
2311 2616
  updateSchema(statements: Schema, callback: UpdateSchemaCallback): void;
2617 +
  updateSchema(
2618 +
    statements: Schema,
2619 +
    gaxOptions: CallOptions,
2620 +
    callback: UpdateSchemaCallback
2621 +
  ): void;
2312 2622
  /**
2313 2623
   * Update the schema of the database by creating/altering/dropping tables,
2314 2624
   * columns, indexes, etc.
@@ -2327,6 +2637,8 @@
Loading
2327 2637
   * @param {string|string[]|object} statements An array of database DDL
2328 2638
   *     statements, or an
2329 2639
   *     [`UpdateDatabaseDdlRequest` object](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.UpdateDatabaseDdlRequest).
2640 +
   * @param {object} [gaxOptions] Request configuration options, outlined here:
2641 +
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
2330 2642
   * @param {LongRunningOperationCallback} [callback] Callback function.
2331 2643
   * @returns {Promise<LongRunningOperationResponse>}
2332 2644
   *
@@ -2384,8 +2696,14 @@
Loading
2384 2696
   */
2385 2697
  updateSchema(
2386 2698
    statements: Schema,
2387 -
    callback?: UpdateSchemaCallback
2699 +
    optionsOrCallback?: CallOptions | UpdateSchemaCallback,
2700 +
    cb?: UpdateSchemaCallback
2388 2701
  ): Promise<UpdateSchemaResponse> | void {
2702 +
    const gaxOpts =
2703 +
      typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
2704 +
    const callback =
2705 +
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
2706 +
2389 2707
    if (typeof statements === 'string' || Array.isArray(statements)) {
2390 2708
      statements = {
2391 2709
        statements: arrify(statements) as string[],
@@ -2402,6 +2720,8 @@
Loading
2402 2720
        client: 'DatabaseAdminClient',
2403 2721
        method: 'updateDatabaseDdl',
2404 2722
        reqOpts,
2723 +
        gaxOpts,
2724 +
        headers: this.resourceHeader_,
2405 2725
      },
2406 2726
      callback!
2407 2727
    );
@@ -2439,17 +2759,49 @@
Loading
2439 2759
promisifyAll(Database, {
2440 2760
  exclude: [
2441 2761
    'batchTransaction',
2442 -
    'getMetadata',
2443 2762
    'getRestoreInfo',
2444 2763
    'getState',
2445 2764
    'getOperations',
2446 2765
    'runTransaction',
2766 +
    'runTransactionAsync',
2447 2767
    'table',
2448 -
    'updateSchema',
2449 2768
    'session',
2450 2769
  ],
2451 2770
});
2452 2771
2772 +
/*! Developer Documentation
2773 +
 *
2774 +
 * All async methods (except for streams) will return a Promise in the event
2775 +
 * that a callback is omitted.
2776 +
 */
2777 +
callbackifyAll(Database, {
2778 +
  exclude: [
2779 +
    'create',
2780 +
    'batchCreateSessions',
2781 +
    'batchTransaction',
2782 +
    'close',
2783 +
    'createBatchTransaction',
2784 +
    'createSession',
2785 +
    'createTable',
2786 +
    'delete',
2787 +
    'exists',
2788 +
    'get',
2789 +
    'getMetadata',
2790 +
    'getSchema',
2791 +
    'getSessions',
2792 +
    'getSnapshot',
2793 +
    'getTransaction',
2794 +
    'restore',
2795 +
    'run',
2796 +
    'runPartitionedUpdate',
2797 +
    'runTransaction',
2798 +
    'runTransactionAsync',
2799 +
    'session',
2800 +
    'table',
2801 +
    'updateSchema',
2802 +
  ],
2803 +
});
2804 +
2453 2805
/**
2454 2806
 * Reference to the {@link Database} class.
2455 2807
 * @name module:@google-cloud/spanner.Database

@@ -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...

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...

99 Commits

Hiding 4 contexual commits
+76
+76
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