1 4
/*!
2 4
 * Copyright 2016 Google Inc. All Rights Reserved.
3 4
 *
4 4
 * Licensed under the Apache License, Version 2.0 (the "License");
5 4
 * you may not use this file except in compliance with the License.
6 4
 * You may obtain a copy of the License at
7 4
 *
8 4
 *      http://www.apache.org/licenses/LICENSE-2.0
9 4
 *
10 4
 * Unless required by applicable law or agreed to in writing, software
11 4
 * distributed under the License is distributed on an "AS IS" BASIS,
12 4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 4
 * See the License for the specific language governing permissions and
14 4
 * limitations under the License.
15 4
 */
16 4

17 4
import {GrpcService, GrpcServiceConfig} from './common-grpc/service';
18 4
import {PreciseDate} from '@google-cloud/precise-date';
19 4
import {replaceProjectIdToken} from '@google-cloud/projectify';
20 4
import {promisifyAll} from '@google-cloud/promisify';
21 4
import * as extend from 'extend';
22 4
import {GoogleAuth, GoogleAuthOptions} from 'google-auth-library';
23 4
import * as path from 'path';
24 4
import {common as p} from 'protobufjs';
25 4
import * as streamEvents from 'stream-events';
26 4
import * as through from 'through2';
27 4
import {codec, Float, Int, Numeric, SpannerDate, Struct} from './codec';
28 4
import {Backup} from './backup';
29 4
import {Database} from './database';
30 4
import {
31 4
  Instance,
32 4
  CreateInstanceCallback,
33 4
  CreateInstanceResponse,
34 4
} from './instance';
35 4
import {grpc, GrpcClientOptions, CallOptions} from 'google-gax';
36 4
import {google as instanceAdmin} from '../protos/protos';
37 4
import {
38 4
  PagedOptions,
39 4
  PagedResponse,
40 4
  PagedCallback,
41 4
  PagedOptionsWithFilter,
42 4
  CLOUD_RESOURCE_HEADER,
43 4
} from './common';
44 4
import {Session} from './session';
45 4
import {SessionPool} from './session-pool';
46 4
import {Table} from './table';
47 4
import {PartitionedDml, Snapshot, Transaction} from './transaction';
48 4
import grpcGcpModule = require('grpc-gcp');
49 4
const grpcGcp = grpcGcpModule(grpc);
50 4
import * as v1 from './v1';
51 4

52 4
// eslint-disable-next-line @typescript-eslint/no-var-requires
53 4
const gcpApiConfig = require('./spanner_grpc_config.json');
54 4

55 4
export type IOperation = instanceAdmin.longrunning.IOperation;
56 4

57 4
export type GetInstancesOptions = PagedOptionsWithFilter;
58 4

59 4
export type GetInstancesResponse = PagedResponse<
60 4
  Instance,
61 4
  instanceAdmin.spanner.admin.instance.v1.IListInstancesResponse
62 4
>;
63 4
export type GetInstancesCallback = PagedCallback<
64 4
  Instance,
65 4
  instanceAdmin.spanner.admin.instance.v1.IListInstancesResponse
66 4
>;
67 4

68 4
export type GetInstanceConfigsOptions = PagedOptions;
69 4
export type GetInstanceConfigsResponse = PagedResponse<
70 4
  instanceAdmin.spanner.admin.instance.v1.IInstanceConfig,
71 4
  instanceAdmin.spanner.admin.instance.v1.IListInstanceConfigsResponse
72 4
>;
73 4
export type GetInstanceConfigsCallback = PagedCallback<
74 4
  instanceAdmin.spanner.admin.instance.v1.IInstanceConfig,
75 4
  instanceAdmin.spanner.admin.instance.v1.IListInstanceConfigsResponse
76 4
>;
77 4

78 4
export interface SpannerOptions extends GrpcClientOptions {
79 4
  apiEndpoint?: string;
80 4
  servicePath?: string;
81 4
  port?: number;
82 4
  sslCreds?: grpc.ChannelCredentials;
83 4
}
84 4
export interface RequestConfig {
85 4
  client: string;
86 4
  method: string;
87 4
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
88 4
  reqOpts: any;
89 4
  gaxOpts?: CallOptions;
90 4
  headers: {[k: string]: string};
91 4
}
92 4
export interface CreateInstanceRequest {
93 4
  config?: string;
94 4
  nodes?: number;
95 4
  displayName?: string;
96 4
  labels?: {[k: string]: string} | null;
97 4
  gaxOptions?: CallOptions;
98 4
}
99 4
/**
100 4
 * Translates enum values to string keys.
101 4
 *
102 4
 * @param E enum type.
103 4
 */
104 4
export type EnumKey<E extends {[index: string]: unknown}> = keyof E;
105 4

106 4
/**
107 4
 * Translates an enum property of an object from enum value to enum key, leaving
108 4
 * all other properties as-is.
109 4
 *
110 4
 * @param T type containing properties to translate.
111 4
 * @param U name of the enum property.
112 4
 * @param E enum type to translate.
113 4
 */
114 4
export type TranslateEnumKeys<
115 4
  T,
116 4
  U extends keyof T,
117 4
  E extends {[index: string]: unknown}
118 4
> = {
119 4
  [P in keyof T]: P extends U ? EnumKey<E> | null | undefined : T[P];
120 4
};
121 4

122 4
/**
123 4
 * [Cloud Spanner](https://cloud.google.com/spanner) is a highly scalable,
124 4
 * transactional, managed, NewSQL database service. Cloud Spanner solves the
125 4
 * need for a horizontally-scaling database with consistent global transaction
126 4
 * and SQL semantics. With Cloud Spanner you don't need to choose between
127 4
 * consistency and horizontal scaling — you get both.
128 4
 *
129 4
 * @class
130 4
 *
131 4
 * @see [Cloud Spanner Documentation](https://cloud.google.com/spanner/docs)
132 4
 * @see [Cloud Spanner Concepts](https://cloud.google.com/spanner/docs/concepts)
133 4
 *
134 4
 * @example <caption>Install the client library with <a
135 4
 * href="https://www.npmjs.com/">npm</a>:</caption> npm install --save
136 4
 * @google-cloud/spanner
137 4
 *
138 4
 * @example <caption>Create a client that uses <a
139 4
 * href="https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application">Application
140 4
 * Default Credentials (ADC)</a>:</caption> const client = new Spanner();
141 4
 *
142 4
 * @example <caption>Create a client with <a
143 4
 * href="https://cloud.google.com/docs/authentication/production#obtaining_and_providing_service_account_credentials_manually">explicit
144 4
 * credentials</a>:</caption> const client = new Spanner({ projectId:
145 4
 * 'your-project-id', keyFilename: '/path/to/keyfile.json'
146 4
 * });
147 4
 *
148 4
 * @example <caption>include:samples/quickstart.js</caption>
149 4
 * region_tag:spanner_quickstart
150 4
 * Full quickstart example:
151 4
 *
152 4
 * @param {ClientConfig} [options] Configuration options.
153 4
 */
154 4
class Spanner extends GrpcService {
155 4
  options: GoogleAuthOptions;
156 4
  auth: GoogleAuth;
157 4
  clients_: Map<string, {}>;
158 4
  instances_: Map<string, Instance>;
159 4
  projectFormattedName_: string;
160 4
  resourceHeader_: {[k: string]: string};
161 4

162 4
  /**
163 4
   * Placeholder used to auto populate a column with the commit timestamp.
164 4
   * This can only be used for timestamp columns that have set the option
165 4
   * "(allow_commit_timestamp=true)" in the schema.
166 4
   *
167 4
   * @type {string}
168 4
   */
169 4
  static COMMIT_TIMESTAMP = 'spanner.commit_timestamp()';
170 4

171 4
  /**
172 4
   * Gets the configured Spanner emulator host from an environment variable.
173 4
   */
174 4
  static getSpannerEmulatorHost():
175 4
    | {endpoint: string; port?: number}
176 4
    | undefined {
177 4
    const endpointWithPort = process.env.SPANNER_EMULATOR_HOST;
178 4
    if (endpointWithPort) {
179 4
      if (
180 4
        endpointWithPort.startsWith('http:') ||
181 4
        endpointWithPort.startsWith('https:')
182 4
      ) {
183 4
        throw new Error(
184 4
          'SPANNER_EMULATOR_HOST must not start with a protocol specification (http/https)'
185 4
        );
186 4
      }
187 4
      const index = endpointWithPort.indexOf(':');
188 4
      if (index > -1) {
189 4
        const portName = endpointWithPort.substring(index + 1);
190 4
        const port = +portName;
191 4
        if (!port || port < 1 || port > 65535) {
192 4
          throw new Error(`Invalid port number: ${portName}`);
193 4
        }
194 4
        return {
195 4
          endpoint: endpointWithPort.substring(0, index),
196 4
          port: +endpointWithPort.substring(index + 1),
197 4
        };
198 4
      }
199 4
      return {endpoint: endpointWithPort};
200 4
    }
201 4
    return undefined;
202 4
  }
203 4

204 4
  constructor(options?: SpannerOptions) {
205 4
    const scopes: Array<{}> = [];
206 4
    const clientClasses = [
207 4
      v1.DatabaseAdminClient,
208 4
      v1.InstanceAdminClient,
209 4
      v1.SpannerClient,
210 4
    ];
211 4
    for (const clientClass of clientClasses) {
212 4
      for (const scope of clientClass.scopes) {
213 4
        if (scopes.indexOf(scope) === -1) {
214 4
          scopes.push(scope);
215 4
        }
216 4
      }
217 4
    }
218 4
    options = (Object.assign(
219 4
      {
220 4
        libName: 'gccl',
221 4
        libVersion: require('../../package.json').version,
222 4
        scopes,
223 4
        // Enable grpc-gcp support
224 4
        'grpc.callInvocationTransformer': grpcGcp.gcpCallInvocationTransformer,
225 4
        'grpc.channelFactoryOverride': grpcGcp.gcpChannelFactoryOverride,
226 4
        'grpc.gcpApiConfig': grpcGcp.createGcpApiConfig(gcpApiConfig),
227 4
        grpc,
228 4
      },
229 4
      options || {}
230 4
    ) as {}) as SpannerOptions;
231 4
    const emulatorHost = Spanner.getSpannerEmulatorHost();
232 4
    if (
233 4
      emulatorHost &&
234 4
      emulatorHost.endpoint &&
235 4
      emulatorHost.endpoint.length > 0
236 4
    ) {
237 4
      options.servicePath = emulatorHost.endpoint;
238 4
      options.port = emulatorHost.port;
239 4
      options.sslCreds = grpc.credentials.createInsecure();
240 4
    }
241 4
    const config = ({
242 4
      baseUrl:
243 4
        options.apiEndpoint ||
244 4
        options.servicePath ||
245 4
        v1.SpannerClient.servicePath,
246 4
      protosDir: path.resolve(__dirname, '../protos'),
247 4
      protoServices: {
248 4
        Operations: {
249 4
          path: 'google/longrunning/operations.proto',
250 4
          service: 'longrunning',
251 4
        },
252 4
      },
253 4
      scopes: ['https://www.googleapis.com/auth/cloud-platform'],
254 4
      packageJson: require('../../package.json'),
255 4
    } as {}) as GrpcServiceConfig;
256 4
    super(config, options);
257 4
    this.options = options;
258 4
    this.auth = new GoogleAuth(this.options);
259 4
    this.clients_ = new Map();
260 4
    this.instances_ = new Map();
261 4
    this.projectFormattedName_ = 'projects/' + this.projectId;
262 4
    this.resourceHeader_ = {
263 4
      [CLOUD_RESOURCE_HEADER]: this.projectFormattedName_,
264 4
    };
265 4
  }
266 4

267 4
  createInstance(
268 4
    name: string,
269 4
    config: CreateInstanceRequest
270 4
  ): Promise<CreateInstanceResponse>;
271 4
  createInstance(
272 4
    name: string,
273 4
    config: CreateInstanceRequest,
274 4
    callback: CreateInstanceCallback
275 4
  ): void;
276 4
  /**
277 4
   * Config for the new instance.
278 4
   *
279 4
   * @typedef {object} CreateInstanceRequest
280 4
   * @property {string} config The name of the instance's configuration.
281 4
   * @property {number} [nodes=1] The number of nodes allocated to this instance.
282 4
   *     Defaults to 1.
283 4
   * @property {Object.<string, string>} [labels] Labels are a flexible and
284 4
   *     lightweight mechanism for organizing cloud resources into groups that
285 4
   *     reflect a customer's organizational needs and deployment strategies.
286 4
   *     Cloud Labels can be used to filter collections of resources. They can
287 4
   *     be used to control how resource metrics are aggregated. And they can
288 4
   *     be used as arguments to policy management rules (e.g. route,
289 4
   *     firewall, load balancing, etc.).
290 4
   * @property {string} [displayName] The descriptive name for this instance
291 4
   *     as it appears in UIs. Must be unique per project and between 4 and 30
292 4
   *     characters in length.
293 4
   *     Defaults to the instance unique identifier '<instance>' of the full
294 4
   *     instance name of the form 'projects/<project>/instances/<instance>'.
295 4
   */
296 4
  /**
297 4
   * @typedef {array} CreateInstanceResponse
298 4
   * @property {Instance} 0 The new {@link Instance}.
299 4
   * @property {Operation} 1 An operation object that can be used to check
300 4
   *     the status of the request.
301 4
   * @property {IOperation} 2 The full API response.
302 4
   */
303 4
  /**
304 4
   * @callback CreateInstanceCallback
305 4
   * @param {?Error} err Request error, if any.
306 4
   * @param {Instance} instance The new {@link Instance}.
307 4
   * @param {Operation} operation An operation object that can be used to
308 4
   *     check the status of the request.
309 4
   * @param {IOperation} apiResponse The full API response.
310 4
   */
311 4
  /**
312 4
   * Create an instance.
313 4
   *
314 4
   * Wrapper around {@link v1.InstanceAdminClient#createInstance}.
315 4
   *
316 4
   * @see {@link v1.InstanceAdminClient#createInstance}
317 4
   * @see [CreateInstace API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.CreateInstance)
318 4
   *
319 4
   * @throws {Error} If a name is not provided.
320 4
   * @throws {Error} If a configuration object is not provided.
321 4
   *
322 4
   * @param {string} name The name of the instance to be created.
323 4
   * @param {CreateInstanceRequest} config Configuration object.
324 4
   * @param {CreateInstanceCallback} [callback] Callback function.
325 4
   * @returns {Promise<CreateInstanceResponse>}
326 4
   *
327 4
   * @example
328 4
   * const {Spanner} = require('@google-cloud/spanner');
329 4
   * const spanner = new Spanner();
330 4
   *
331 4
   * const config = {
332 4
   *   config: 'regional-us-central1',
333 4
   *   nodes: 1
334 4
   * };
335 4
   *
336 4
   * function callback(err, instance, operation, apiResponse) {
337 4
   *   if (err) {
338 4
   *     // Error handling omitted.
339 4
   *   }
340 4
   *
341 4
   *   operation
342 4
   *     .on('error', function(err) {})
343 4
   *     .on('complete', function() {
344 4
   *       // Instance created successfully.
345 4
   *     });
346 4
   * }
347 4
   *
348 4
   * spanner.createInstance('new-instance-name', config, callback);
349 4
   *
350 4
   * //-
351 4
   * // If the callback is omitted, we'll return a Promise.
352 4
   * //-
353 4
   * spanner.createInstance('new-instance-name', config)
354 4
   *   .then(function(data) {
355 4
   *     const instance = data[0];
356 4
   *     const operation = data[1];
357 4
   *     return operation.promise();
358 4
   *   })
359 4
   *   .then(function() {
360 4
   *     // Instance created successfully.
361 4
   *   });
362 4
   */
363 4
  createInstance(
364 4
    name: string,
365 4
    config: CreateInstanceRequest,
366 4
    callback?: CreateInstanceCallback
367 4
  ): void | Promise<CreateInstanceResponse> {
368 4
    if (!name) {
369 4
      throw new Error('A name is required to create an instance.');
370 4
    }
371 4
    if (!config) {
372 4
      throw new Error(
373 4
        ['A configuration object is required to create an instance.'].join('')
374 4
      );
375 4
    }
376 4
    const formattedName = Instance.formatName_(this.projectId, name);
377 4
    const displayName = config.displayName || formattedName.split('/').pop();
378 4
    const reqOpts = {
379 4
      parent: this.projectFormattedName_,
380 4
      instanceId: formattedName.split('/').pop(),
381 4
      instance: extend(
382 4
        {
383 4
          name: formattedName,
384 4
          displayName,
385 4
          nodeCount: config.nodes || 1,
386 4
        },
387 4
        config
388 4
      ),
389 4
    };
390 4

391 4
    delete reqOpts.instance.nodes;
392 4
    delete reqOpts.instance.gaxOptions;
393 4

394 4
    if (config.config!.indexOf('/') === -1) {
395 4
      reqOpts.instance.config = `projects/${this.projectId}/instanceConfigs/${config.config}`;
396 4
    }
397 4
    this.request(
398 4
      {
399 4
        client: 'InstanceAdminClient',
400 4
        method: 'createInstance',
401 4
        reqOpts,
402 4
        gaxOpts: config.gaxOptions,
403 4
        headers: this.resourceHeader_,
404 4
      },
405 4
      (err, operation, resp) => {
406 4
        if (err) {
407 4
          callback!(err, null, null, resp);
408 4
          return;
409 4
        }
410 4
        const instance = this.instance(formattedName);
411 4
        callback!(null, instance, operation, resp);
412 4
      }
413 4
    );
414 4
  }
415 4

416 4
  getInstances(options?: GetInstancesOptions): Promise<GetInstancesResponse>;
417 4
  getInstances(callback: GetInstancesCallback): void;
418 4
  getInstances(
419 4
    query: GetInstancesOptions,
420 4
    callback: GetInstancesCallback
421 4
  ): void;
422 4
  /**
423 4
   * Query object for listing instances.
424 4
   *
425 4
   * @typedef {object} GetInstancesOptions
426 4
   * @property {object} [gaxOptions] Request configuration options, outlined
427 4
   *     here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
428 4
   * @property {string} [filter] An expression for filtering the results of the
429 4
   *     request. Filter rules are case insensitive. The fields eligible for
430 4
   *     filtering are:
431 4
   *     - **`name`**
432 4
   *     - **`display_name`**
433 4
   *     - **`labels.key`** where key is the name of a label
434 4
   *
435 4
   *     Some examples of using filters are:
436 4
   *     - **`name:*`** The instance has a name.
437 4
   *     - **`name:Howl`** The instance's name is howl.
438 4
   *     - **`labels.env:*`** The instance has the label env.
439 4
   *     - **`labels.env:dev`** The instance's label env has the value dev.
440 4
   *     - **`name:howl labels.env:dev`** The instance's name is howl and it has
441 4
   *       the label env with value dev.
442 4
   * @property {number} [pageSize] Maximum number of results per page.
443 4
   * @property {string} [pageToken] A previously-returned page token
444 4
   *     representing part of the larger set of results to view.
445 4
   */
446 4
  /**
447 4
   * @typedef {array} GetInstancesResponse
448 4
   * @property {Instance[]} 0 Array of {@link Instance} instances.
449 4
   * @property {object} 1 A query object to receive more results.
450 4
   * @property {object} 2 The full API response.
451 4
   */
452 4
  /**
453 4
   * @callback GetInstancesCallback
454 4
   * @param {?Error} err Request error, if any.
455 4
   * @param {Instance[]} instances Array of {@link Instance} instances.
456 4
   * @param {string} nextQuery A query object to receive more results.
457 4
   * @param {object} apiResponse The full API response.
458 4
   */
459 4
  /**
460 4
   * Get a list of instances.
461 4
   *
462 4
   * Wrapper around {@link v1.InstanceAdminClient#listInstances}.
463 4
   *
464 4
   * @see {@link v1.InstanceAdminClient#listInstances}
465 4
   * @see [ListInstances API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstances)
466 4
   *
467 4
   * @param {GetInstancesOptions} [options] Query object for listing instances.
468 4
   * @param {GetInstancesCallback} [callback] Callback function.
469 4
   * @returns {Promise<GetInstancesResponse>}
470 4
   *
471 4
   * @example
472 4
   * const {Spanner} = require('@google-cloud/spanner');
473 4
   * const spanner = new Spanner();
474 4
   *
475 4
   * spanner.getInstances(function(err, instances) {
476 4
   *   // `instances` is an array of `Instance` objects.
477 4
   * });
478 4
   *
479 4
   * //-
480 4
   * // To control how many API requests are made and page through the results
481 4
   * // manually, set `autoPaginate` to `false`.
482 4
   * //-
483 4
   * function callback(err, instances, nextQuery, apiResponse) {
484 4
   *   if (nextQuery) {
485 4
   *     // More results exist.
486 4
   *     spanner.getInstances(nextQuery, callback);
487 4
   *   }
488 4
   * }
489 4
   *
490 4
   * spanner.getInstances({
491 4
   *   gaxOptions: {
492 4
   *     autoPaginate: false,
493 4
   *   }
494 4
   * }, callback);
495 4
   *
496 4
   * //-
497 4
   * // If the callback is omitted, we'll return a Promise.
498 4
   * //-
499 4
   * spanner.getInstances().then(function(data) {
500 4
   *   const instances = data[0];
501 4
   * });
502 4
   */
503 4
  getInstances(
504 4
    optionsOrCallback?: GetInstancesOptions | GetInstancesCallback,
505 4
    cb?: GetInstancesCallback
506 4
  ): Promise<GetInstancesResponse> | void {
507 4
    // eslint-disable-next-line @typescript-eslint/no-this-alias
508 4
    const self = this;
509 4
    const options =
510 4
      typeof optionsOrCallback === 'object'
511 4
        ? optionsOrCallback
512 4
        : ({} as GetInstancesOptions);
513 4
    const callback =
514 4
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
515 4

516 4
    const gaxOpts = extend(true, {}, options.gaxOptions);
517 4

518 4
    let reqOpts = extend({}, options, {
519 4
      parent: 'projects/' + this.projectId,
520 4
    });
521 4

522 4
    delete reqOpts.gaxOptions;
523 4

524 4
    // Copy over pageSize and pageToken values from gaxOptions.
525 4
    // However values set on options take precedence.
526 4
    if (gaxOpts) {
527 4
      reqOpts = extend(
528 4
        {},
529 4
        {
530 4
          pageSize: gaxOpts.pageSize,
531 4
          pageToken: gaxOpts.pageToken,
532 4
        },
533 4
        reqOpts
534 4
      );
535 4
      delete gaxOpts.pageToken;
536 4
      delete gaxOpts.pageSize;
537 4
    }
538 4

539 4
    this.request(
540 4
      {
541 4
        client: 'InstanceAdminClient',
542 4
        method: 'listInstances',
543 4
        reqOpts,
544 4
        gaxOpts,
545 4
        headers: this.resourceHeader_,
546 4
      },
547 4
      (err, instances, nextPageRequest, ...args) => {
548 4
        let instanceInstances: Instance[] | null = null;
549 4
        if (instances) {
550 4
          instanceInstances = instances.map(instance => {
551 4
            const instanceInstance = self.instance(instance.name);
552 4
            instanceInstance.metadata = instance;
553 4
            return instanceInstance;
554 4
          });
555 4
        }
556 4
        const nextQuery = nextPageRequest!
557 4
          ? extend({}, options, nextPageRequest!)
558 4
          : null;
559 4
        callback!(err, instanceInstances, nextQuery, ...args);
560 4
      }
561 4
    );
562 4
  }
563 4

564 4
  /**
565 4
   * Get a list of {@link Instance} objects as a readable object stream.
566 4
   *
567 4
   * Wrapper around {@link v1.InstanceAdminClient#listInstances}.
568 4
   *
569 4
   * @see {@link v1.InstanceAdminClient#listInstances}
570 4
   * @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 4
   *
572 4
   * @method Spanner#getInstancesStream
573 4
   * @param {GetInstancesOptions} [options] Query object for listing instances.
574 4
   * @returns {ReadableStream} A readable stream that emits {@link Instance}
575 4
   *     instances.
576 4
   *
577 4
   * @example
578 4
   * const {Spanner} = require('@google-cloud/spanner');
579 4
   * const spanner = new Spanner();
580 4
   *
581 4
   * spanner.getInstancesStream()
582 4
   *   .on('error', console.error)
583 4
   *   .on('data', function(instance) {
584 4
   *     // `instance` is an `Instance` object.
585 4
   *   })
586 4
   *   .on('end', function() {
587 4
   *     // All instances retrieved.
588 4
   *   });
589 4
   *
590 4
   * //-
591 4
   * // If you anticipate many results, you can end a stream early to prevent
592 4
   * // unnecessary processing and API requests.
593 4
   * //-
594 4
   * spanner.getInstancesStream()
595 4
   *   .on('data', function(instance) {
596 4
   *     this.end();
597 4
   *   });
598 4
   */
599 4
  getInstancesStream(options: GetInstancesOptions = {}): NodeJS.ReadableStream {
600 4
    const gaxOpts = extend(true, {}, options.gaxOptions);
601 4

602 4
    let reqOpts = extend({}, options, {
603 4
      parent: 'projects/' + this.projectId,
604 4
    });
605 4
    delete reqOpts.gaxOptions;
606 4

607 4
    // Copy over pageSize and pageToken values from gaxOptions.
608 4
    // However values set on options take precedence.
609 4
    if (gaxOpts) {
610 4
      reqOpts = extend(
611 4
        {},
612 4
        {
613 4
          pageSize: gaxOpts.pageSize,
614 4
          pageToken: gaxOpts.pageToken,
615 4
        },
616 4
        reqOpts
617 4
      );
618 4
      delete gaxOpts.pageSize;
619 4
      delete gaxOpts.pageToken;
620 4
    }
621 4

622 4
    return this.requestStream({
623 4
      client: 'InstanceAdminClient',
624 4
      method: 'listInstancesStream',
625 4
      reqOpts,
626 4
      gaxOpts,
627 4
      headers: this.resourceHeader_,
628 4
    });
629 3
  }
630 4

631 4
  getInstanceConfigs(
632 4
    query?: GetInstanceConfigsOptions
633 4
  ): Promise<GetInstanceConfigsResponse>;
634 4
  getInstanceConfigs(callback: GetInstanceConfigsCallback): void;
635 4
  getInstanceConfigs(
636 4
    query: GetInstanceConfigsOptions,
637 4
    callback: GetInstanceConfigsCallback
638 4
  ): void;
639 4
  /**
640 4
   * Lists the supported instance configurations for a given project.
641 4
   *
642 4
   * @typedef {object} GetInstanceConfigsOptions
643 4
   * @property {number} [pageSize] Maximum number of results per page.
644 4
   * @property {string} [pageToken] A previously-returned page token
645 4
   *     representing part of the larger set of results to view.
646 4
   * @property {object} [gaxOptions] Request configuration options, outlined
647 4
   *     here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
648 4

649 4
   */
650 4
  /**
651 4
   * @typedef {array} GetInstanceConfigsResponse
652 4
   * @property {object[]} 0 List of all available instance configs.
653 4
   * @property {string} 0.name The unique identifier for the instance config.
654 4
   * @property {string} 0.displayName The name of the instance config as it
655 4
   *     appears in UIs.
656 4
   * @property {object} 1 A query object to receive more results.
657 4
   * @property {object} 2 The full API response.
658 4
   */
659 4
  /**
660 4
   * @callback GetInstanceConfigsCallback
661 4
   * @param {?Error} err Request error, if any.
662 4
   * @param {object[]} instanceConfigs List of all available instance configs.
663 4
   * @param {string} instanceConfigs.name The unique identifier for the instance
664 4
   *     config.
665 4
   * @param {string} instanceConfigs.displayName The name of the instance config
666 4
   *     as it appears in UIs.
667 4
   * @param {object} nextQuery A query object to receive more results.
668 4
   * @param {object} apiResponse The full API response.
669 4
   */
670 4
  /**
671 4
   * Get a list of instance configs.
672 4
   *
673 4
   * Wrapper around {@link v1.InstanceAdminClient#listInstanceConfigs}.
674 4
   *
675 4
   * @see {@link v1.InstanceAdminClient#listInstanceConfigs}
676 4
   * @see [ListInstanceConfigs API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstanceConfigs)
677 4
   *
678 4
   * @param {GetInstanceConfigsOptions} [options] Query object for listing instance
679 4
   *     configs.
680 4
   * @param {GetInstanceConfigsCallback} [callback] Callback function.
681 4
   * @returns {Promise<GetInstanceConfigsResponse>}
682 4
   *
683 4
   * @example
684 4
   * const {Spanner} = require('@google-cloud/spanner');
685 4
   * const spanner = new Spanner();
686 4
   *
687 4
   * spanner.getInstanceConfigs(function(err, instanceConfigs) {
688 4
   *   // `instanceConfigs` is an array of instance configuration descriptors.
689 4
   * });
690 4
   *
691 4
   * //-
692 4
   * // To control how many API requests are made and page through the results
693 4
   * // manually, set `autoPaginate` to `false`.
694 4
   * //-
695 4
   * function callback(err, instanceConfigs, nextQuery, apiResponse) {
696 4
   *   if (nextQuery) {
697 4
   *     // More results exist.
698 4
   *     spanner.getInstanceConfigs(nextQuery, callback);
699 4
   *   }
700 4
   * }
701 4
   *
702 4
   * spanner.getInstanceConfigs({
703 4
   *   gaxOptions: {
704 4
   *     autoPaginate: false,
705 4
   *   }
706 4
   * }, callback);
707 4
   *
708 4
   * //-
709 4
   * // If the callback is omitted, we'll return a Promise.
710 4
   * //-
711 4
   * spanner.getInstanceConfigs().then(function(data) {
712 4
   *   const instanceConfigs = data[0];
713 4
   * });
714 4
   */
715 4
  getInstanceConfigs(
716 4
    optionsOrCallback?: GetInstanceConfigsOptions | GetInstanceConfigsCallback,
717 4
    cb?: GetInstanceConfigsCallback
718 4
  ): Promise<GetInstanceConfigsResponse> | void {
719 4
    const callback =
720 4
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
721 4
    const options =
722 4
      typeof optionsOrCallback === 'object'
723 4
        ? optionsOrCallback
724 4
        : ({} as GetInstanceConfigsOptions);
725 4

726 4
    const gaxOpts = extend(true, {}, options.gaxOptions);
727 4
    let reqOpts = extend({}, options, {
728 4
      parent: 'projects/' + this.projectId,
729 4
    });
730 4
    delete reqOpts.gaxOptions;
731 4

732 4
    // Copy over pageSize and pageToken values from gaxOptions.
733 4
    // However values set on options take precedence.
734 4
    if (gaxOpts) {
735 4
      reqOpts = extend(
736 4
        {},
737 4
        {
738 4
          pageSize: gaxOpts.pageSize,
739 4
          pageToken: gaxOpts.pageToken,
740 4
        },
741 4
        reqOpts
742 4
      );
743 4
      delete gaxOpts.pageSize;
744 4
      delete gaxOpts.pageToken;
745 4
    }
746 4

747 4
    return this.request(
748 4
      {
749 4
        client: 'InstanceAdminClient',
750 4
        method: 'listInstanceConfigs',
751 4
        reqOpts,
752 4
        gaxOpts,
753 4
        headers: this.resourceHeader_,
754 4
      },
755 4
      (err, instanceConfigs, nextPageRequest, ...args) => {
756 4
        const nextQuery = nextPageRequest!
757 4
          ? extend({}, options, nextPageRequest!)
758 4
          : null;
759 4
        callback!(err, instanceConfigs, nextQuery, ...args);
760 4
      }
761 4
    );
762 4
  }
763 4

764 4
  /**
765 4
   * Get a list of instance configs as a readable object stream.
766 4
   *
767 4
   * Wrapper around {@link v1.InstanceAdminClient#listInstanceConfigsStream}.
768 4
   *
769 4
   * @see {@link v1.InstanceAdminClient#listInstanceConfigsStream}
770 4
   * @see [ListInstanceConfigs API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.ListInstanceConfigs)
771 4
   *
772 4
   * @method Spanner#getInstanceConfigsStream
773 4
   * @param {GetInstanceConfigsOptions} [options] Query object for listing instance
774 4
   *     configs.
775 4
   * @returns {ReadableStream} A readable stream that emits instance configs.
776 4
   *
777 4
   * @example
778 4
   * const {Spanner} = require('@google-cloud/spanner');
779 4
   * const spanner = new Spanner();
780 4
   *
781 4
   * spanner.getInstanceConfigsStream()
782 4
   *   .on('error', console.error)
783 4
   *   .on('data', function(instanceConfig) {})
784 4
   *   .on('end', function() {
785 4
   *     // All instances retrieved.
786 4
   *   });
787 4
   *
788 4
   * //-
789 4
   * // If you anticipate many results, you can end a stream early to prevent
790 4
   * // unnecessary processing and API requests.
791 4
   * //-
792 4
   * spanner.getInstanceConfigsStream()
793 4
   *   .on('data', function(instanceConfig) {
794 4
   *     this.end();
795 4
   *   });
796 4
   */
797 4
  getInstanceConfigsStream(
798 4
    options: GetInstanceConfigsOptions = {}
799 4
  ): NodeJS.ReadableStream {
800 4
    const gaxOpts = extend(true, {}, options.gaxOptions);
801 4

802 4
    let reqOpts = extend({}, options, {
803 4
      parent: 'projects/' + this.projectId,
804 4
    });
805 4

806 4
    // Copy over pageSize and pageToken values from gaxOptions.
807 4
    // However values set on options take precedence.
808 4
    if (gaxOpts) {
809 4
      reqOpts = extend(
810 4
        {},
811 4
        {
812 4
          pageSize: gaxOpts.pageSize,
813 4
          pageToken: gaxOpts.pageToken,
814 4
        },
815 4
        reqOpts
816 4
      );
817 4
      delete gaxOpts.pageSize;
818 4
      delete gaxOpts.pageToken;
819 4
    }
820 4

821 4
    delete reqOpts.gaxOptions;
822 4
    return this.requestStream({
823 4
      client: 'InstanceAdminClient',
824 4
      method: 'listInstanceConfigsStream',
825 4
      reqOpts,
826 4
      gaxOpts,
827 4
      headers: this.resourceHeader_,
828 4
    });
829 3
  }
830 4

831 4
  /**
832 4
   * Get a reference to an Instance object.
833 4
   *
834 4
   * @throws {Error} If a name is not provided.
835 4
   *
836 4
   * @param {string} name The name of the instance.
837 4
   * @returns {Instance} An Instance object.
838 4
   *
839 4
   * @example
840 4
   * const {Spanner} = require('@google-cloud/spanner');
841 4
   * const spanner = new Spanner();
842 4
   * const instance = spanner.instance('my-instance');
843 4
   */
844 4
  instance(name: string): Instance {
845 4
    if (!name) {
846 4
      throw new Error('A name is required to access an Instance object.');
847 4
    }
848 4
    const key = name.split('/').pop()!;
849 4
    if (!this.instances_.has(key)) {
850 4
      this.instances_.set(key, new Instance(this, name));
851 4
    }
852 4
    return this.instances_.get(key)!;
853 4
  }
854 4

855 4
  /**
856 4
   * Prepare a gapic request. This will cache the GAX client and replace
857 4
   * {{projectId}} placeholders, if necessary.
858 4
   *
859 4
   * @private
860 4
   *
861 4
   * @param {object} config Request config
862 4
   * @param {function} callback Callback function
863 4
   */
864 4
  prepareGapicRequest_(config, callback) {
865 4
    this.auth.getProjectId((err, projectId) => {
866 4
      if (err) {
867 4
        callback(err);
868 4
        return;
869 4
      }
870 4
      const clientName = config.client;
871 4
      if (!this.clients_.has(clientName)) {
872 4
        this.clients_.set(clientName, new v1[clientName](this.options));
873 4
      }
874 4
      const gaxClient = this.clients_.get(clientName)!;
875 4
      let reqOpts = extend(true, {}, config.reqOpts);
876 4
      reqOpts = replaceProjectIdToken(reqOpts, projectId!);
877 4
      const requestFn = gaxClient[config.method].bind(
878 4
        gaxClient,
879 4
        reqOpts,
880 4
        // Add headers to `gaxOpts`
881 4
        extend(true, {}, config.gaxOpts, {
882 4
          otherArgs: {
883 4
            headers: config.headers,
884 4
          },
885 4
        })
886 4
      );
887 4
      callback(null, requestFn);
888 4
    });
889 4
  }
890 4

891 4
  /**
892 4
   * Funnel all API requests through this method to be sure we have a project
893 4
   * ID.
894 4
   *
895 4
   * @param {object} config Configuration object.
896 4
   * @param {object} config.gaxOpts GAX options.
897 4
   * @param {function} config.method The gax method to call.
898 4
   * @param {object} config.reqOpts Request options.
899 4
   * @param {function} [callback] Callback function.
900 4
   * @returns {Promise}
901 4
   */
902 4
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
903 4
  request(config: any, callback?: any): any {
904 4
    if (typeof callback === 'function') {
905 4
      this.prepareGapicRequest_(config, (err, requestFn) => {
906 4
        if (err) {
907 4
          callback(err);
908 4
        } else {
909 4
          requestFn(callback);
910 4
        }
911 4
      });
912 4
    } else {
913 4
      return new Promise((resolve, reject) => {
914 4
        this.prepareGapicRequest_(config, (err, requestFn) => {
915 4
          if (err) {
916 4
            reject(err);
917 4
          } else {
918 4
            resolve(requestFn());
919 4
          }
920 4
        });
921 4
      });
922 4
    }
923 4
  }
924 4

925 4
  /**
926 4
   * Funnel all streaming API requests through this method to be sure we have a
927 4
   * project ID.
928 4
   *
929 4
   * @param {object} config Configuration object.
930 4
   * @param {object} config.gaxOpts GAX options.
931 4
   * @param {function} config.method The gax method to call.
932 4
   * @param {object} config.reqOpts Request options.
933 4
   * @param {function} [callback] Callback function.
934 4
   * @returns {Stream}
935 4
   */
936 4
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
937 4
  requestStream(config): any {
938 4
    const stream = streamEvents(through.obj());
939 4
    stream.once('reading', () => {
940 4
      this.prepareGapicRequest_(config, (err, requestFn) => {
941 4
        if (err) {
942 4
          stream.destroy(err);
943 4
          return;
944 4
        }
945 4
        requestFn()
946 4
          .on('error', err => {
947 4
            stream.destroy(err);
948 4
          })
949 4
          .pipe(stream);
950 4
      });
951 4
    });
952 4
    return stream;
953 4
  }
954 4

955 4
  static date(dateString?: string);
956 4
  static date(year: number, month: number, date: number);
957 4
  /**
958 4
   * Helper function to get a Cloud Spanner Date object.
959 4
   *
960 4
   * DATE types represent a logical calendar date, independent of time zone.
961 4
   * DATE values do not represent a specific 24-hour period. Rather, a given
962 4
   * DATE value represents a different 24-hour period when interpreted in a
963 4
   * different time zone. Because of this, all values passed to
964 4
   * {@link Spanner.date} will be interpreted as local time.
965 4
   *
966 4
   * To represent an absolute point in time, use {@link Spanner.timestamp}.
967 4
   *
968 4
   * @param {string|number} [date] String representing the date or number
969 4
   *     representing the year.
970 4
   * @param {number} [month] Number representing the month.
971 4
   * @param {number} [date] Number representing the date.
972 4
   * @returns {SpannerDate}
973 4
   *
974 4
   * @example
975 4
   * const {Spanner} = require('@google-cloud/spanner');
976 4
   * const date = Spanner.date('08-20-1969');
977 4
   */
978 4
  static date(
979 4
    dateStringOrYear?: string | number,
980 4
    month?: number,
981 4
    date?: number
982 4
  ): SpannerDate {
983 4
    if (typeof dateStringOrYear === 'number') {
984 4
      return new codec.SpannerDate(dateStringOrYear, month!, date!);
985 4
    }
986 4
    return new codec.SpannerDate(dateStringOrYear);
987 4
  }
988 4

989 4
  /**
990 4
   * Date object with nanosecond precision. Supports all standard Date arguments
991 4
   * in addition to several custom types.
992 4
   * @external PreciseDate
993 4
   * @see {@link https://github.com/googleapis/nodejs-precise-date|PreciseDate}
994 4
   */
995 4
  /**
996 4
   * Helper function to get a Cloud Spanner Timestamp object.
997 4
   *
998 4
   * String timestamps should have a canonical format of
999 4
   * `YYYY-[M]M-[D]D[( |T)[H]H:[M]M:[S]S[.DDDDDDDDD]]Z`
1000 4
   *
1001 4
   * **Timestamp values must be expressed in Zulu time and cannot include a UTC
1002 4
   * offset.**
1003 4
   *
1004 4
   * @see https://cloud.google.com/spanner/docs/data-types#timestamp-type
1005 4
   *
1006 4
   * @param {string|number|google.protobuf.Timestamp|external:PreciseDate}
1007 4
   *     [timestamp] Either a RFC 3339 timestamp formatted string or a
1008 4
   *     {@link google.protobuf.Timestamp} object. If a PreciseDate is given, it
1009 4
   *     will return that timestamp as is.
1010 4
   * @returns {external:PreciseDate}
1011 4
   *
1012 4
   * @example
1013 4
   * const timestamp = Spanner.timestamp('2019-02-08T10:34:29.481145231Z');
1014 4
   *
1015 4
   * @example <caption>With a `google.protobuf.Timestamp` object</caption>
1016 4
   * const [seconds, nanos] = process.hrtime();
1017 4
   * const timestamp = Spanner.timestamp({seconds, nanos});
1018 4
   *
1019 4
   * @example <caption>With a Date timestamp</caption>
1020 4
   * const timestamp = Spanner.timestamp(Date.now());
1021 4
   */
1022 4
  static timestamp(
1023 4
    value?: string | number | p.ITimestamp | PreciseDate
1024 4
  ): PreciseDate {
1025 4
    value = value || Date.now();
1026 4
    if (value instanceof PreciseDate) {
1027 4
      return value;
1028 4
    }
1029 4
    return new PreciseDate(value as number);
1030 4
  }
1031 4

1032 4
  /**
1033 4
   * Helper function to get a Cloud Spanner Float64 object.
1034 4
   *
1035 4
   * @param {string|number} value The float as a number or string.
1036 4
   * @returns {Float}
1037 4
   *
1038 4
   * @example
1039 4
   * const {Spanner} = require('@google-cloud/spanner');
1040 4
   * const float = Spanner.float(10);
1041 4
   */
1042 4
  static float(value): Float {
1043 4
    return new codec.Float(value);
1044 4
  }
1045 4

1046 4
  /**
1047 4
   * Helper function to get a Cloud Spanner Int64 object.
1048 4
   *
1049 4
   * @param {string|number} value The int as a number or string.
1050 4
   * @returns {Int}
1051 4
   *
1052 4
   * @example
1053 4
   * const {Spanner} = require('@google-cloud/spanner');
1054 4
   * const int = Spanner.int(10);
1055 4
   */
1056 4
  static int(value): Int {
1057 4
    return new codec.Int(value);
1058 4
  }
1059 4

1060 4
  /**
1061 4
   * Helper function to get a Cloud Spanner Numeric object.
1062 4
   *
1063 4
   * @param {string} value The numeric value as a string.
1064 4
   * @returns {Numeric}
1065 4
   *
1066 4
   * @example
1067 4
   * const {Spanner} = require('@google-cloud/spanner');
1068 4
   * const numeric = Spanner.numeric("3.141592653");
1069 4
   */
1070 4
  static numeric(value): Numeric {
1071 4
    return new codec.Numeric(value);
1072 4
  }
1073 4

1074 4
  /**
1075 4
   * Helper function to get a Cloud Spanner Struct object.
1076 4
   *
1077 4
   * @param {object} value The struct as a JSON object.
1078 4
   * @returns {Struct}
1079 4
   *
1080 4
   * @example
1081 4
   * const {Spanner} = require('@google-cloud/spanner');
1082 4
   * const struct = Spanner.struct({
1083 4
   *   user: 'bob',
1084 4
   *   age: 32
1085 4
   * });
1086 4
   */
1087 4
  static struct(value?): Struct {
1088 4
    if (Array.isArray(value)) {
1089 4
      return codec.Struct.fromArray(value);
1090 4
    }
1091 4
    return codec.Struct.fromJSON(value);
1092 4
  }
1093 4
}
1094 4

1095 4
/*! Developer Documentation
1096 4
 *
1097 4
 * All async methods (except for streams) will return a Promise in the event
1098 4
 * that a callback is omitted.
1099 4
 */
1100 4
promisifyAll(Spanner, {
1101 4
  exclude: [
1102 4
    'date',
1103 4
    'float',
1104 4
    'instance',
1105 4
    'int',
1106 4
    'numeric',
1107 4
    'operation',
1108 4
    'timestamp',
1109 4
  ],
1110 4
});
1111 4

1112 4
/**
1113 4
 * The default export of the `@google-cloud/spanner` package is the
1114 4
 * {@link Spanner} class.
1115 4
 *
1116 4
 * See {@link Spanner} and {@link ClientConfig} for client methods and
1117 4
 * configuration options.
1118 4
 *
1119 4
 * @module {constructor} @google-cloud/spanner
1120 4
 * @alias nodejs-spanner
1121 4
 *
1122 4
 * @example <caption>Install the client library with <a
1123 4
 * href="https://www.npmjs.com/">npm</a>:</caption> npm install --save
1124 4
 * @google-cloud/spanner
1125 4
 *
1126 4
 * @example <caption>Import the client library</caption>
1127 4
 * const {Spanner} = require('@google-cloud/spanner');
1128 4
 *
1129 4
 * @example <caption>Create a client that uses <a
1130 4
 * href="https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application">Application
1131 4
 * Default Credentials (ADC)</a>:</caption> const client = new Spanner();
1132 4
 *
1133 4
 * @example <caption>Create a client with <a
1134 4
 * href="https://cloud.google.com/docs/authentication/production#obtaining_and_providing_service_account_credentials_manually">explicit
1135 4
 * credentials</a>:</caption> const client = new Spanner({ projectId:
1136 4
 * 'your-project-id', keyFilename: '/path/to/keyfile.json'
1137 4
 * });
1138 4
 *
1139 4
 * @example <caption>include:samples/quickstart.js</caption>
1140 4
 * region_tag:spanner_quickstart
1141 4
 * Full quickstart example:
1142 4
 */
1143 4
export {Spanner};
1144 4

1145 4
/**
1146 4
 * {@link Instance} class.
1147 4
 *
1148 4
 * @name Spanner.Instance
1149 4
 * @see Instance
1150 4
 * @type {Constructor}
1151 4
 */
1152 4
export {Instance};
1153 4

1154 4
/**
1155 4
 * {@link Database} class.
1156 4
 *
1157 4
 * @name Spanner.Database
1158 4
 * @see Database
1159 4
 * @type {Constructor}
1160 4
 */
1161 4
export {Database};
1162 4

1163 4
/**
1164 4
 * {@link Backup} class.
1165 4
 *
1166 4
 * @name Spanner.Backup
1167 4
 * @see Backup
1168 4
 * @type {Constructor}
1169 4
 */
1170 4
export {Backup};
1171 4

1172 4
/**
1173 4
 * {@link Session} class.
1174 4
 *
1175 4
 * @name Spanner.Session
1176 4
 * @see Session
1177 4
 * @type {Constructor}
1178 4
 */
1179 4
export {Session};
1180 4

1181 4
/**
1182 4
 * {@link SessionPool} class.
1183 4
 *
1184 4
 * @name Spanner.SessionPool
1185 4
 * @see SessionPool
1186 4
 * @type {Constructor}
1187 4
 */
1188 4
export {SessionPool};
1189 4

1190 4
/**
1191 4
 * {@link Table} class.
1192 4
 *
1193 4
 * @name Spanner.Table
1194 4
 * @see Table
1195 4
 * @type {Constructor}
1196 4
 */
1197 4
export {Table};
1198 4

1199 4
/**
1200 4
 * {@link PartitionedDml} class.
1201 4
 *
1202 4
 * @name Spanner.PartitionedDml
1203 4
 * @see PartitionedDml
1204 4
 * @type {Constructor}
1205 4
 */
1206 4
export {PartitionedDml};
1207 4

1208 4
/**
1209 4
 * {@link Snapshot} class.
1210 4
 *
1211 4
 * @name Spanner.Snapshot
1212 4
 * @see Snapshot
1213 4
 * @type {Constructor}
1214 4
 */
1215 4
export {Snapshot};
1216 4

1217 4
/**
1218 4
 * {@link Transaction} class.
1219 4
 *
1220 4
 * @name Spanner.Transaction
1221 4
 * @see Transaction
1222 4
 * @type {Constructor}
1223 4
 */
1224 4
export {Transaction};
1225 4

1226 4
/**
1227 4
 * @type {object}
1228 4
 * @property {constructor} DatabaseAdminClient
1229 4
 *   Reference to {@link v1.DatabaseAdminClient}
1230 4
 * @property {constructor} InstanceAdminClient
1231 4
 *   Reference to {@link v1.InstanceAdminClient}
1232 4
 * @property {constructor} SpannerClient
1233 4
 *   Reference to {@link v1.SpannerClient}
1234 4
 */
1235 4
import * as protos from '../protos/protos';
1236 4
export {v1, protos};
1237 4
export default {Spanner};

Read our documentation on viewing source code .

Loading