@google-cloud/spanner
Version:
Cloud Spanner Client Library for Node.js
362 lines • 12.7 kB
JavaScript
"use strict";
/*!
* Copyright 2016 Google Inc. All Rights Reserved.
*
* 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
*
* http://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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Session = void 0;
/*!
* @module spanner/session
*/
// eslint-disable-next-line @typescript-eslint/no-var-requires
const common = require('./common-grpc/service-object');
const promisify_1 = require("@google-cloud/promisify");
const extend = require("extend");
const transaction_1 = require("./transaction");
const common_1 = require("./common");
const request_id_header_1 = require("./request_id_header");
/**
* Create a Session object to interact with a Cloud Spanner session.
*
* **It is unlikely you will need to interact with sessions directly. By
* default, sessions are created and utilized for maximum performance
* automatically.**
*
* @class
* @param {Database} database Parent {@link Database} instance.
* @param {string} [name] The name of the session. If not provided, it is
* assumed you are going to create it.
*
* @example
* ```
* const {Spanner} = require('@google-cloud/spanner');
* const spanner = new Spanner();
*
* const instance = spanner.instance('my-instance');
* const database = instance.database('my-database');
*
* //-
* // To create a session manually, don't provide a name.
* //-
* const session = database.session();
*
* session.create(function(err) {
* if (err) {
* // Error handling omitted.
* }
*
* // Session created successfully.
* // `session.id` = The name of the session.
* });
*
* //-
* // To access a previously-created session, provide a name.
* //-
* const session = database.session('session-name');
* ```
*/
class Session extends common.GrpcServiceObject {
formattedName_;
txn;
lastUsed;
lastError;
commonHeaders_;
_observabilityOptions;
constructor(database, name) {
const methods = {
/**
* Create a session.
*
* @method Session#create
* @param {object} [options] See {@link Database#createSession}.
* @param {CreateSessionCallback} [callback] Callback function.
* @returns {Promise<CreateSessionResponse>}
*
* @example
* ```
* session.create(function(err, session, apiResponse) {
* if (err) {
* // Error handling omitted.
* }
*
* // Session created successfully.
* });
*
* //-
* //Returns a Promise if the callback is omitted.
* //-
* session.create()
* .then(function(data) {
* const session = data[0];
* const apiResponse = data[1];
*
* // Session created successfully.
* });
* ```
*/
create: true,
/**
* @typedef {array} SessionExistsResponse
* @property {boolean} 0 Whether the {@link Session} exists.
*/
/**
* @callback SessionExistsCallback
* @param {?Error} err Request error, if any.
* @param {boolean} exists Whether the {@link Session} exists.
*/
/**
* Check if a session exists.
*
* @method Session#exists
* @param {SessionExistsCallback} [callback] Callback function.
* @returns {Promise<SessionExistsResponse>}
*
* @example
* ```
* session.exists(function(err, exists) {});
*
* //-
* //Returns a Promise if the callback is omitted.
* //-
* session.exists().then(function(data) {
* const exists = data[0];
* });
* ```
*/
exists: true,
/**
* @typedef {array} GetSessionResponse
* @property {Session} 0 The {@link Session}.
* @property {object} 1 The full API response.
*/
/**
* @callback CreateSessionCallback
* @param {?Error} err Request error, if any.
* @param {Session} session The {@link Session}.
* @param {object} apiResponse The full API response.
*/
/**
* Get a session if it exists.
*
* You may optionally use this to "get or create" an object by providing
* an object with `autoCreate` set to `true`. Any extra configuration that
* is normally required for the `create` method must be contained within
* this object as well.
*
* @method Session#get
* @param {options} [options] Configuration object.
* @param {boolean} [options.autoCreate=false] Automatically create the
* object if it does not exist.
* @param {CreateSessionCallback} [callback] Callback function.
* @returns {Promise<GetSessionResponse>}
*
* @example
* ```
* session.get(function(err, session, apiResponse) {
* // `session.metadata` has been populated.
* });
*
* //-
* //Returns a Promise if the callback is omitted.
* //-
* session.get().then(function(data) {
* const session = data[0];
* const apiResponse = data[0];
* });
* ```
*/
get: true,
};
super({
parent: database,
/**
* @name Session#id
* @type {string}
*/
id: name,
methods,
createMethod: (_, optionsOrCallback, callback) => {
const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
callback =
typeof optionsOrCallback === 'function'
? optionsOrCallback
: callback;
this.labels = options.labels || null;
this.databaseRole =
options.databaseRole || database.databaseRole || null;
return database.createSession(options, (err, session, apiResponse) => {
if (err) {
callback(err, null, apiResponse);
return;
}
extend(this, session);
callback(null, this, apiResponse);
});
},
});
this._observabilityOptions = database._observabilityOptions;
this.commonHeaders_ = (0, common_1.getCommonHeaders)(this.parent.formattedName_, this._observabilityOptions?.enableEndToEndTracing);
this.request = database.request;
this.requestStream = database.requestStream;
if (name) {
this.formattedName_ = Session.formatName_(database.formattedName_, name);
}
}
delete(optionsOrCallback, cb) {
const gaxOpts = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
const reqOpts = {
name: this.formattedName_,
};
const database = this.parent;
return this.request({
client: 'SpannerClient',
method: 'deleteSession',
reqOpts,
gaxOpts,
headers: (0, request_id_header_1.injectRequestIDIntoHeaders)(this.commonHeaders_, this, (0, request_id_header_1.nextNthRequest)(database), 1),
}, callback);
}
getMetadata(optionsOrCallback, cb) {
const gaxOpts = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
const reqOpts = {
name: this.formattedName_,
};
const headers = this.commonHeaders_;
if (this._getSpanner().routeToLeaderEnabled) {
(0, common_1.addLeaderAwareRoutingHeader)(headers);
}
const database = this.parent;
return this.request({
client: 'SpannerClient',
method: 'getSession',
reqOpts,
gaxOpts,
headers: (0, request_id_header_1.injectRequestIDIntoHeaders)(headers, this.session, (0, request_id_header_1.nextNthRequest)(database), 1),
}, (err, resp) => {
if (resp) {
resp.databaseRole = resp.creatorRole;
delete resp.creatorRole;
this.metadata = resp;
}
callback(err, resp);
});
}
keepAlive(optionsOrCallback, cb) {
const gaxOpts = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
const reqOpts = {
session: this.formattedName_,
sql: 'SELECT 1',
};
const database = this.parent;
return this.request({
client: 'SpannerClient',
method: 'executeSql',
reqOpts,
gaxOpts,
headers: (0, request_id_header_1.injectRequestIDIntoHeaders)(this.commonHeaders_, this, (0, request_id_header_1.nextNthRequest)(database), 1),
}, callback);
}
/**
* Create a PartitionedDml transaction.
*
* @returns {PartitionedDml}
*
* @example
* ```
* const transaction = session.partitionedDml();
* ```
*/
partitionedDml() {
return new transaction_1.PartitionedDml(this);
}
/**
* Create a Snapshot transaction.
*
* @param {TimestampBounds} [options] The timestamp bounds.
* @param {google.spanner.v1.ExecuteSqlRequest.IQueryOptions} [queryOptions] The default query options to use.
* @returns {Snapshot}
*
* @example
* ```
* const snapshot = session.snapshot({strong: false});
* ```
*/
snapshot(options, queryOptions) {
return new transaction_1.Snapshot(this, options, queryOptions);
}
/**
* Create a read write Transaction.
*
* @param {google.spanner.v1.ExecuteSqlRequest.IQueryOptions} [queryOptions] The default query options to use.
* @return {Transaction}
*
* @example
* ```
* const transaction = session.transaction();
* ```
*/
transaction(queryOptions, requestOptions) {
return new transaction_1.Transaction(this, undefined, queryOptions, requestOptions);
}
/**
* Format the session name to include the parent database's name.
*
* @private
*
* @param {string} databaseName The parent database's name.
* @param {string} name The instance name.
* @returns {string}
*
* @example
* ```
* Session.formatName_('my-database', 'my-session');
* // 'projects/grape-spaceship-123/instances/my-instance/' +
* // 'databases/my-database/sessions/my-session'
* ```
*/
static formatName_(databaseName, name) {
if (name.indexOf('/') > -1) {
return name;
}
const sessionName = name.split('/').pop();
return databaseName + '/sessions/' + sessionName;
}
/**
* Gets the Spanner object
*
* @private
*
* @returns {Spanner}
*/
_getSpanner() {
return this.parent.parent.parent;
}
channelId() {
// The Node.js client does not use a gRPC channel pool, so this always returns 1.
return 1;
}
}
exports.Session = Session;
/*! Developer Documentation
*
* All async methods (except for streams) will return a Promise in the event
* that a callback is omitted.
*/
(0, promisify_1.promisifyAll)(Session, {
exclude: ['delete', 'partitionedDml', 'snapshot', 'transaction'],
});
//# sourceMappingURL=session.js.map