// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ** This file is automatically generated by gapic-generator-typescript. **
// ** https://github.com/googleapis/gapic-generator-typescript **
// ** All changes to this file may be overwritten. **

/* global window */
import type * as gax from 'google-gax';
import type {
  Callback,
  CallOptions,
  Descriptors,
  ClientOptions,
} from 'google-gax';
import {PassThrough} from 'stream';
import * as protos from '../../protos/protos';
import jsonProtos = require('../../protos/protos.json');
import {loggingUtils as logging, decodeAnyProtosInArray} from 'google-gax';

/**
 * Client JSON configuration object, loaded from
 * `src/v1/spanner_executor_proxy_client_config.json`.
 * This file defines retry strategy and timeouts for all API methods in this library.
 */
import * as gapicConfig from './spanner_executor_proxy_client_config.json';
const version = require('../../../package.json').version;

/**
 *  Service that executes SpannerActions asynchronously.
 * @class
 * @memberof v1
 */
export class SpannerExecutorProxyClient {
  private _terminated = false;
  private _opts: ClientOptions;
  private _providedCustomServicePath: boolean;
  private _gaxModule: typeof gax | typeof gax.fallback;
  private _gaxGrpc: gax.GrpcClient | gax.fallback.GrpcClient;
  private _protos: {};
  private _defaults: {[method: string]: gax.CallSettings};
  private _universeDomain: string;
  private _servicePath: string;
  private _log = logging.log('executor');

  auth: gax.GoogleAuth;
  descriptors: Descriptors = {
    page: {},
    stream: {},
    longrunning: {},
    batching: {},
  };
  warn: (code: string, message: string, warnType?: string) => void;
  innerApiCalls: {[name: string]: Function};
  pathTemplates: {[name: string]: gax.PathTemplate};
  spannerExecutorProxyStub?: Promise<{[name: string]: Function}>;

  /**
   * Construct an instance of SpannerExecutorProxyClient.
   *
   * @param {object} [options] - The configuration object.
   * The options accepted by the constructor are described in detail
   * in [this document](https://github.com/googleapis/gax-nodejs/blob/main/client-libraries.md#creating-the-client-instance).
   * The common options are:
   * @param {object} [options.credentials] - Credentials object.
   * @param {string} [options.credentials.client_email]
   * @param {string} [options.credentials.private_key]
   * @param {string} [options.email] - Account email address. Required when
   *     using a .pem or .p12 keyFilename.
   * @param {string} [options.keyFilename] - Full path to the a .json, .pem, or
   *     .p12 key downloaded from the Google Developers Console. If you provide
   *     a path to a JSON file, the projectId option below is not necessary.
   *     NOTE: .pem and .p12 require you to specify options.email as well.
   * @param {number} [options.port] - The port on which to connect to
   *     the remote host.
   * @param {string} [options.projectId] - The project ID from the Google
   *     Developer's Console, e.g. 'grape-spaceship-123'. We will also check
   *     the environment variable GCLOUD_PROJECT for your project ID. If your
   *     app is running in an environment which supports
   *     {@link https://cloud.google.com/docs/authentication/application-default-credentials Application Default Credentials},
   *     your project ID will be detected automatically.
   * @param {string} [options.apiEndpoint] - The domain name of the
   *     API remote host.
   * @param {gax.ClientConfig} [options.clientConfig] - Client configuration override.
   *     Follows the structure of {@link gapicConfig}.
   * @param {boolean} [options.fallback] - Use HTTP/1.1 REST mode.
   *     For more information, please check the
   *     {@link https://github.com/googleapis/gax-nodejs/blob/main/client-libraries.md#http11-rest-api-mode documentation}.
   * @param {gax} [gaxInstance]: loaded instance of `google-gax`. Useful if you
   *     need to avoid loading the default gRPC version and want to use the fallback
   *     HTTP implementation. Load only fallback version and pass it to the constructor:
   *     ```
   *     const gax = require('google-gax/build/src/fallback'); // avoids loading google-gax with gRPC
   *     const client = new SpannerExecutorProxyClient({fallback: true}, gax);
   *     ```
   */
  constructor(
    opts?: ClientOptions,
    gaxInstance?: typeof gax | typeof gax.fallback,
  ) {
    // Ensure that options include all the required fields.
    const staticMembers = this.constructor as typeof SpannerExecutorProxyClient;
    if (
      opts?.universe_domain &&
      opts?.universeDomain &&
      opts?.universe_domain !== opts?.universeDomain
    ) {
      throw new Error(
        'Please set either universe_domain or universeDomain, but not both.',
      );
    }
    const universeDomainEnvVar =
      typeof process === 'object' && typeof process.env === 'object'
        ? process.env['GOOGLE_CLOUD_UNIVERSE_DOMAIN']
        : undefined;
    this._universeDomain =
      opts?.universeDomain ??
      opts?.universe_domain ??
      universeDomainEnvVar ??
      'googleapis.com';
    this._servicePath = 'spanner-cloud-executor.' + this._universeDomain;
    const servicePath =
      opts?.servicePath || opts?.apiEndpoint || this._servicePath;
    this._providedCustomServicePath = !!(
      opts?.servicePath || opts?.apiEndpoint
    );
    const port = opts?.port || staticMembers.port;
    const clientConfig = opts?.clientConfig ?? {};
    const fallback =
      opts?.fallback ??
      (typeof window !== 'undefined' && typeof window?.fetch === 'function');
    opts = Object.assign({servicePath, port, clientConfig, fallback}, opts);

    // If scopes are unset in options and we're connecting to a non-default endpoint, set scopes just in case.
    if (servicePath !== this._servicePath && !('scopes' in opts)) {
      opts['scopes'] = staticMembers.scopes;
    }

    // Load google-gax module synchronously if needed
    if (!gaxInstance) {
      gaxInstance = require('google-gax') as typeof gax;
    }

    // Choose either gRPC or proto-over-HTTP implementation of google-gax.
    this._gaxModule = opts.fallback ? gaxInstance.fallback : gaxInstance;

    // Create a `gaxGrpc` object, with any grpc-specific options sent to the client.
    this._gaxGrpc = new this._gaxModule.GrpcClient(opts);

    // Save options to use in initialize() method.
    this._opts = opts;

    // Save the auth object to the client, for use by other methods.
    this.auth = this._gaxGrpc.auth as gax.GoogleAuth;

    // Set useJWTAccessWithScope on the auth object.
    this.auth.useJWTAccessWithScope = true;

    // Set defaultServicePath on the auth object.
    this.auth.defaultServicePath = this._servicePath;

    // Set the default scopes in auth client if needed.
    if (servicePath === this._servicePath) {
      this.auth.defaultScopes = staticMembers.scopes;
    }

    // Determine the client header string.
    const clientHeader = [`gax/${this._gaxModule.version}`, `gapic/${version}`];
    if (typeof process === 'object' && 'versions' in process) {
      clientHeader.push(`gl-node/${process.versions.node}`);
    } else {
      clientHeader.push(`gl-web/${this._gaxModule.version}`);
    }
    if (!opts.fallback) {
      clientHeader.push(`grpc/${this._gaxGrpc.grpcVersion}`);
    } else {
      clientHeader.push(`rest/${this._gaxGrpc.grpcVersion}`);
    }
    if (opts.libName && opts.libVersion) {
      clientHeader.push(`${opts.libName}/${opts.libVersion}`);
    }
    // Load the applicable protos.
    this._protos = this._gaxGrpc.loadProtoJSON(jsonProtos);

    // This API contains "path templates"; forward-slash-separated
    // identifiers to uniquely identify resources within the API.
    // Create useful helper objects for these.
    this.pathTemplates = {
      backupPathTemplate: new this._gaxModule.PathTemplate(
        'projects/{project}/instances/{instance}/backups/{backup}',
      ),
      backupSchedulePathTemplate: new this._gaxModule.PathTemplate(
        'projects/{project}/instances/{instance}/databases/{database}/backupSchedules/{schedule}',
      ),
      databasePathTemplate: new this._gaxModule.PathTemplate(
        'projects/{project}/instances/{instance}/databases/{database}',
      ),
      databaseRolePathTemplate: new this._gaxModule.PathTemplate(
        'projects/{project}/instances/{instance}/databases/{database}/databaseRoles/{role}',
      ),
      instancePathTemplate: new this._gaxModule.PathTemplate(
        'projects/{project}/instances/{instance}',
      ),
      instanceConfigPathTemplate: new this._gaxModule.PathTemplate(
        'projects/{project}/instanceConfigs/{instance_config}',
      ),
      instancePartitionPathTemplate: new this._gaxModule.PathTemplate(
        'projects/{project}/instances/{instance}/instancePartitions/{instance_partition}',
      ),
      sessionPathTemplate: new this._gaxModule.PathTemplate(
        'projects/{project}/instances/{instance}/databases/{database}/sessions/{session}',
      ),
    };

    // Some of the methods on this service provide streaming responses.
    // Provide descriptors for these.
    this.descriptors.stream = {
      executeActionAsync: new this._gaxModule.StreamDescriptor(
        this._gaxModule.StreamType.BIDI_STREAMING,
        !!opts.fallback,
        !!opts.gaxServerStreamingRetries,
      ),
    };

    // Put together the default options sent with requests.
    this._defaults = this._gaxGrpc.constructSettings(
      'google.spanner.executor.v1.SpannerExecutorProxy',
      gapicConfig as gax.ClientConfig,
      opts.clientConfig || {},
      {'x-goog-api-client': clientHeader.join(' ')},
    );

    // Set up a dictionary of "inner API calls"; the core implementation
    // of calling the API is handled in `google-gax`, with this code
    // merely providing the destination and request information.
    this.innerApiCalls = {};

    // Add a warn function to the client constructor so it can be easily tested.
    this.warn = this._gaxModule.warn;
  }

  /**
   * Initialize the client.
   * Performs asynchronous operations (such as authentication) and prepares the client.
   * This function will be called automatically when any class method is called for the
   * first time, but if you need to initialize it before calling an actual method,
   * feel free to call initialize() directly.
   *
   * You can await on this method if you want to make sure the client is initialized.
   *
   * @returns {Promise} A promise that resolves to an authenticated service stub.
   */
  initialize() {
    // If the client stub promise is already initialized, return immediately.
    if (this.spannerExecutorProxyStub) {
      return this.spannerExecutorProxyStub;
    }

    // Put together the "service stub" for
    // google.spanner.executor.v1.SpannerExecutorProxy.
    this.spannerExecutorProxyStub = this._gaxGrpc.createStub(
      this._opts.fallback
        ? (this._protos as protobuf.Root).lookupService(
            'google.spanner.executor.v1.SpannerExecutorProxy',
          )
        : // eslint-disable-next-line @typescript-eslint/no-explicit-any
          (this._protos as any).google.spanner.executor.v1.SpannerExecutorProxy,
      this._opts,
      this._providedCustomServicePath,
    ) as Promise<{[method: string]: Function}>;

    // Iterate over each of the methods that the service provides
    // and create an API call method for each.
    const spannerExecutorProxyStubMethods = ['executeActionAsync'];
    for (const methodName of spannerExecutorProxyStubMethods) {
      const callPromise = this.spannerExecutorProxyStub.then(
        stub =>
          (...args: Array<{}>) => {
            if (this._terminated) {
              if (methodName in this.descriptors.stream) {
                const stream = new PassThrough({objectMode: true});
                setImmediate(() => {
                  stream.emit(
                    'error',
                    new this._gaxModule.GoogleError(
                      'The client has already been closed.',
                    ),
                  );
                });
                return stream;
              }
              return Promise.reject('The client has already been closed.');
            }
            const func = stub[methodName];
            return func.apply(stub, args);
          },
        (err: Error | null | undefined) => () => {
          throw err;
        },
      );

      const descriptor = this.descriptors.stream[methodName] || undefined;
      const apiCall = this._gaxModule.createApiCall(
        callPromise,
        this._defaults[methodName],
        descriptor,
        this._opts.fallback,
      );

      this.innerApiCalls[methodName] = apiCall;
    }

    return this.spannerExecutorProxyStub;
  }

  /**
   * The DNS address for this API service.
   * @deprecated Use the apiEndpoint method of the client instance.
   * @returns {string} The DNS address for this service.
   */
  static get servicePath() {
    if (
      typeof process === 'object' &&
      typeof process.emitWarning === 'function'
    ) {
      process.emitWarning(
        'Static servicePath is deprecated, please use the instance method instead.',
        'DeprecationWarning',
      );
    }
    return 'spanner-cloud-executor.googleapis.com';
  }

  /**
   * The DNS address for this API service - same as servicePath.
   * @deprecated Use the apiEndpoint method of the client instance.
   * @returns {string} The DNS address for this service.
   */
  static get apiEndpoint() {
    if (
      typeof process === 'object' &&
      typeof process.emitWarning === 'function'
    ) {
      process.emitWarning(
        'Static apiEndpoint is deprecated, please use the instance method instead.',
        'DeprecationWarning',
      );
    }
    return 'spanner-cloud-executor.googleapis.com';
  }

  /**
   * The DNS address for this API service.
   * @returns {string} The DNS address for this service.
   */
  get apiEndpoint() {
    return this._servicePath;
  }

  get universeDomain() {
    return this._universeDomain;
  }

  /**
   * The port for this API service.
   * @returns {number} The default port for this service.
   */
  static get port() {
    return 443;
  }

  /**
   * The scopes needed to make gRPC calls for every method defined
   * in this service.
   * @returns {string[]} List of default scopes.
   */
  static get scopes() {
    return [];
  }

  getProjectId(): Promise<string>;
  getProjectId(callback: Callback<string, undefined, undefined>): void;
  /**
   * Return the project ID used by this class.
   * @returns {Promise} A promise that resolves to string containing the project ID.
   */
  getProjectId(
    callback?: Callback<string, undefined, undefined>,
  ): Promise<string> | void {
    if (callback) {
      this.auth.getProjectId(callback);
      return;
    }
    return this.auth.getProjectId();
  }

  // -------------------
  // -- Service calls --
  // -------------------

  /**
   * ExecuteActionAsync is a streaming call that starts executing a new Spanner
   * action.
   *
   * For each request, the server will reply with one or more responses, but
   * only the last response will contain status in the outcome.
   *
   * Responses can be matched to requests by action_id. It is allowed to have
   * multiple actions in flight--in that case, actions are be executed in
   * parallel.
   *
   * @param {object} [options]
   *   Call options. See {@link https://googleapis.dev/nodejs/google-gax/latest/interfaces/CallOptions.html|CallOptions} for more details.
   * @returns {Stream}
   *   An object stream which is both readable and writable. It accepts objects
   *   representing {@link protos.google.spanner.executor.v1.SpannerAsyncActionRequest|SpannerAsyncActionRequest} for write() method, and
   *   will emit objects representing {@link protos.google.spanner.executor.v1.SpannerAsyncActionResponse|SpannerAsyncActionResponse} on 'data' event asynchronously.
   *   Please see the {@link https://github.com/googleapis/gax-nodejs/blob/master/client-libraries.md#bi-directional-streaming | documentation }
   *   for more details and examples.
   * @example <caption>include:samples/generated/v1/spanner_executor_proxy.execute_action_async.js</caption>
   * region_tag:spanner-cloud-executor_v1_generated_SpannerExecutorProxy_ExecuteActionAsync_async
   */
  executeActionAsync(options?: CallOptions): gax.CancellableStream {
    this.initialize().catch(err => {
      throw err;
    });
    this._log.info('executeActionAsync stream %j', options);
    return this.innerApiCalls.executeActionAsync(null, options);
  }

  // --------------------
  // -- Path templates --
  // --------------------

  /**
   * Return a fully-qualified backup resource name string.
   *
   * @param {string} project
   * @param {string} instance
   * @param {string} backup
   * @returns {string} Resource name string.
   */
  backupPath(project: string, instance: string, backup: string) {
    return this.pathTemplates.backupPathTemplate.render({
      project: project,
      instance: instance,
      backup: backup,
    });
  }

  /**
   * Parse the project from Backup resource.
   *
   * @param {string} backupName
   *   A fully-qualified path representing Backup resource.
   * @returns {string} A string representing the project.
   */
  matchProjectFromBackupName(backupName: string) {
    return this.pathTemplates.backupPathTemplate.match(backupName).project;
  }

  /**
   * Parse the instance from Backup resource.
   *
   * @param {string} backupName
   *   A fully-qualified path representing Backup resource.
   * @returns {string} A string representing the instance.
   */
  matchInstanceFromBackupName(backupName: string) {
    return this.pathTemplates.backupPathTemplate.match(backupName).instance;
  }

  /**
   * Parse the backup from Backup resource.
   *
   * @param {string} backupName
   *   A fully-qualified path representing Backup resource.
   * @returns {string} A string representing the backup.
   */
  matchBackupFromBackupName(backupName: string) {
    return this.pathTemplates.backupPathTemplate.match(backupName).backup;
  }

  /**
   * Return a fully-qualified backupSchedule resource name string.
   *
   * @param {string} project
   * @param {string} instance
   * @param {string} database
   * @param {string} schedule
   * @returns {string} Resource name string.
   */
  backupSchedulePath(
    project: string,
    instance: string,
    database: string,
    schedule: string,
  ) {
    return this.pathTemplates.backupSchedulePathTemplate.render({
      project: project,
      instance: instance,
      database: database,
      schedule: schedule,
    });
  }

  /**
   * Parse the project from BackupSchedule resource.
   *
   * @param {string} backupScheduleName
   *   A fully-qualified path representing BackupSchedule resource.
   * @returns {string} A string representing the project.
   */
  matchProjectFromBackupScheduleName(backupScheduleName: string) {
    return this.pathTemplates.backupSchedulePathTemplate.match(
      backupScheduleName,
    ).project;
  }

  /**
   * Parse the instance from BackupSchedule resource.
   *
   * @param {string} backupScheduleName
   *   A fully-qualified path representing BackupSchedule resource.
   * @returns {string} A string representing the instance.
   */
  matchInstanceFromBackupScheduleName(backupScheduleName: string) {
    return this.pathTemplates.backupSchedulePathTemplate.match(
      backupScheduleName,
    ).instance;
  }

  /**
   * Parse the database from BackupSchedule resource.
   *
   * @param {string} backupScheduleName
   *   A fully-qualified path representing BackupSchedule resource.
   * @returns {string} A string representing the database.
   */
  matchDatabaseFromBackupScheduleName(backupScheduleName: string) {
    return this.pathTemplates.backupSchedulePathTemplate.match(
      backupScheduleName,
    ).database;
  }

  /**
   * Parse the schedule from BackupSchedule resource.
   *
   * @param {string} backupScheduleName
   *   A fully-qualified path representing BackupSchedule resource.
   * @returns {string} A string representing the schedule.
   */
  matchScheduleFromBackupScheduleName(backupScheduleName: string) {
    return this.pathTemplates.backupSchedulePathTemplate.match(
      backupScheduleName,
    ).schedule;
  }

  /**
   * Return a fully-qualified database resource name string.
   *
   * @param {string} project
   * @param {string} instance
   * @param {string} database
   * @returns {string} Resource name string.
   */
  databasePath(project: string, instance: string, database: string) {
    return this.pathTemplates.databasePathTemplate.render({
      project: project,
      instance: instance,
      database: database,
    });
  }

  /**
   * Parse the project from Database resource.
   *
   * @param {string} databaseName
   *   A fully-qualified path representing Database resource.
   * @returns {string} A string representing the project.
   */
  matchProjectFromDatabaseName(databaseName: string) {
    return this.pathTemplates.databasePathTemplate.match(databaseName).project;
  }

  /**
   * Parse the instance from Database resource.
   *
   * @param {string} databaseName
   *   A fully-qualified path representing Database resource.
   * @returns {string} A string representing the instance.
   */
  matchInstanceFromDatabaseName(databaseName: string) {
    return this.pathTemplates.databasePathTemplate.match(databaseName).instance;
  }

  /**
   * Parse the database from Database resource.
   *
   * @param {string} databaseName
   *   A fully-qualified path representing Database resource.
   * @returns {string} A string representing the database.
   */
  matchDatabaseFromDatabaseName(databaseName: string) {
    return this.pathTemplates.databasePathTemplate.match(databaseName).database;
  }

  /**
   * Return a fully-qualified databaseRole resource name string.
   *
   * @param {string} project
   * @param {string} instance
   * @param {string} database
   * @param {string} role
   * @returns {string} Resource name string.
   */
  databaseRolePath(
    project: string,
    instance: string,
    database: string,
    role: string,
  ) {
    return this.pathTemplates.databaseRolePathTemplate.render({
      project: project,
      instance: instance,
      database: database,
      role: role,
    });
  }

  /**
   * Parse the project from DatabaseRole resource.
   *
   * @param {string} databaseRoleName
   *   A fully-qualified path representing DatabaseRole resource.
   * @returns {string} A string representing the project.
   */
  matchProjectFromDatabaseRoleName(databaseRoleName: string) {
    return this.pathTemplates.databaseRolePathTemplate.match(databaseRoleName)
      .project;
  }

  /**
   * Parse the instance from DatabaseRole resource.
   *
   * @param {string} databaseRoleName
   *   A fully-qualified path representing DatabaseRole resource.
   * @returns {string} A string representing the instance.
   */
  matchInstanceFromDatabaseRoleName(databaseRoleName: string) {
    return this.pathTemplates.databaseRolePathTemplate.match(databaseRoleName)
      .instance;
  }

  /**
   * Parse the database from DatabaseRole resource.
   *
   * @param {string} databaseRoleName
   *   A fully-qualified path representing DatabaseRole resource.
   * @returns {string} A string representing the database.
   */
  matchDatabaseFromDatabaseRoleName(databaseRoleName: string) {
    return this.pathTemplates.databaseRolePathTemplate.match(databaseRoleName)
      .database;
  }

  /**
   * Parse the role from DatabaseRole resource.
   *
   * @param {string} databaseRoleName
   *   A fully-qualified path representing DatabaseRole resource.
   * @returns {string} A string representing the role.
   */
  matchRoleFromDatabaseRoleName(databaseRoleName: string) {
    return this.pathTemplates.databaseRolePathTemplate.match(databaseRoleName)
      .role;
  }

  /**
   * Return a fully-qualified instance resource name string.
   *
   * @param {string} project
   * @param {string} instance
   * @returns {string} Resource name string.
   */
  instancePath(project: string, instance: string) {
    return this.pathTemplates.instancePathTemplate.render({
      project: project,
      instance: instance,
    });
  }

  /**
   * Parse the project from Instance resource.
   *
   * @param {string} instanceName
   *   A fully-qualified path representing Instance resource.
   * @returns {string} A string representing the project.
   */
  matchProjectFromInstanceName(instanceName: string) {
    return this.pathTemplates.instancePathTemplate.match(instanceName).project;
  }

  /**
   * Parse the instance from Instance resource.
   *
   * @param {string} instanceName
   *   A fully-qualified path representing Instance resource.
   * @returns {string} A string representing the instance.
   */
  matchInstanceFromInstanceName(instanceName: string) {
    return this.pathTemplates.instancePathTemplate.match(instanceName).instance;
  }

  /**
   * Return a fully-qualified instanceConfig resource name string.
   *
   * @param {string} project
   * @param {string} instance_config
   * @returns {string} Resource name string.
   */
  instanceConfigPath(project: string, instanceConfig: string) {
    return this.pathTemplates.instanceConfigPathTemplate.render({
      project: project,
      instance_config: instanceConfig,
    });
  }

  /**
   * Parse the project from InstanceConfig resource.
   *
   * @param {string} instanceConfigName
   *   A fully-qualified path representing InstanceConfig resource.
   * @returns {string} A string representing the project.
   */
  matchProjectFromInstanceConfigName(instanceConfigName: string) {
    return this.pathTemplates.instanceConfigPathTemplate.match(
      instanceConfigName,
    ).project;
  }

  /**
   * Parse the instance_config from InstanceConfig resource.
   *
   * @param {string} instanceConfigName
   *   A fully-qualified path representing InstanceConfig resource.
   * @returns {string} A string representing the instance_config.
   */
  matchInstanceConfigFromInstanceConfigName(instanceConfigName: string) {
    return this.pathTemplates.instanceConfigPathTemplate.match(
      instanceConfigName,
    ).instance_config;
  }

  /**
   * Return a fully-qualified instancePartition resource name string.
   *
   * @param {string} project
   * @param {string} instance
   * @param {string} instance_partition
   * @returns {string} Resource name string.
   */
  instancePartitionPath(
    project: string,
    instance: string,
    instancePartition: string,
  ) {
    return this.pathTemplates.instancePartitionPathTemplate.render({
      project: project,
      instance: instance,
      instance_partition: instancePartition,
    });
  }

  /**
   * Parse the project from InstancePartition resource.
   *
   * @param {string} instancePartitionName
   *   A fully-qualified path representing InstancePartition resource.
   * @returns {string} A string representing the project.
   */
  matchProjectFromInstancePartitionName(instancePartitionName: string) {
    return this.pathTemplates.instancePartitionPathTemplate.match(
      instancePartitionName,
    ).project;
  }

  /**
   * Parse the instance from InstancePartition resource.
   *
   * @param {string} instancePartitionName
   *   A fully-qualified path representing InstancePartition resource.
   * @returns {string} A string representing the instance.
   */
  matchInstanceFromInstancePartitionName(instancePartitionName: string) {
    return this.pathTemplates.instancePartitionPathTemplate.match(
      instancePartitionName,
    ).instance;
  }

  /**
   * Parse the instance_partition from InstancePartition resource.
   *
   * @param {string} instancePartitionName
   *   A fully-qualified path representing InstancePartition resource.
   * @returns {string} A string representing the instance_partition.
   */
  matchInstancePartitionFromInstancePartitionName(
    instancePartitionName: string,
  ) {
    return this.pathTemplates.instancePartitionPathTemplate.match(
      instancePartitionName,
    ).instance_partition;
  }

  /**
   * Return a fully-qualified session resource name string.
   *
   * @param {string} project
   * @param {string} instance
   * @param {string} database
   * @param {string} session
   * @returns {string} Resource name string.
   */
  sessionPath(
    project: string,
    instance: string,
    database: string,
    session: string,
  ) {
    return this.pathTemplates.sessionPathTemplate.render({
      project: project,
      instance: instance,
      database: database,
      session: session,
    });
  }

  /**
   * Parse the project from Session resource.
   *
   * @param {string} sessionName
   *   A fully-qualified path representing Session resource.
   * @returns {string} A string representing the project.
   */
  matchProjectFromSessionName(sessionName: string) {
    return this.pathTemplates.sessionPathTemplate.match(sessionName).project;
  }

  /**
   * Parse the instance from Session resource.
   *
   * @param {string} sessionName
   *   A fully-qualified path representing Session resource.
   * @returns {string} A string representing the instance.
   */
  matchInstanceFromSessionName(sessionName: string) {
    return this.pathTemplates.sessionPathTemplate.match(sessionName).instance;
  }

  /**
   * Parse the database from Session resource.
   *
   * @param {string} sessionName
   *   A fully-qualified path representing Session resource.
   * @returns {string} A string representing the database.
   */
  matchDatabaseFromSessionName(sessionName: string) {
    return this.pathTemplates.sessionPathTemplate.match(sessionName).database;
  }

  /**
   * Parse the session from Session resource.
   *
   * @param {string} sessionName
   *   A fully-qualified path representing Session resource.
   * @returns {string} A string representing the session.
   */
  matchSessionFromSessionName(sessionName: string) {
    return this.pathTemplates.sessionPathTemplate.match(sessionName).session;
  }

  /**
   * Terminate the gRPC channel and close the client.
   *
   * The client will no longer be usable and all future behavior is undefined.
   * @returns {Promise} A promise that resolves when the client is closed.
   */
  close(): Promise<void> {
    if (this.spannerExecutorProxyStub && !this._terminated) {
      return this.spannerExecutorProxyStub.then(stub => {
        this._log.info('ending gRPC channel');
        this._terminated = true;
        stub.close();
      });
    }
    return Promise.resolve();
  }
}
