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

17 11
/*!
18 11
 * @module spanner/session
19 11
 */
20 11

21 11
import {GrpcServiceObject} from './common-grpc/service-object';
22 11
import {promisifyAll} from '@google-cloud/promisify';
23 11
import * as extend from 'extend';
24 11
import * as r from 'teeny-request';
25 11
import {
26 11
  Snapshot,
27 11
  Transaction,
28 11
  PartitionedDml,
29 11
  TimestampBounds,
30 11
} from './transaction';
31 11
import {google} from '../protos/protos';
32 11
import {
33 11
  Database,
34 11
  CreateSessionCallback,
35 11
  CreateSessionOptions,
36 11
} from './database';
37 11
import {ServiceObjectConfig, DeleteCallback} from '@google-cloud/common';
38 11
import {NormalCallback} from './common';
39 11
import {ServiceError} from 'grpc';
40 11

41 11
export type GetSessionResponse = [Session, r.Response];
42 11

43 11
/**
44 11
 * enum to capture the possible session types
45 11
 */
46 11
export const enum types {
47 11
  ReadOnly = 'readonly',
48 11
  ReadWrite = 'readwrite',
49 11
}
50 11

51 11
export type GetSessionMetadataCallback = NormalCallback<
52 11
  google.spanner.v1.ISession
53 11
>;
54 11
export type GetSessionMetadataResponse = [google.spanner.v1.ISession];
55 11

56 11
export type KeepAliveCallback = NormalCallback<google.spanner.v1.IResultSet>;
57 11
export type KeepAliveResponse = [google.spanner.v1.IResultSet];
58 11
export type DeleteResponse = [r.Response];
59 11
/**
60 11
 * Create a Session object to interact with a Cloud Spanner session.
61 11
 *
62 11
 * **It is unlikely you will need to interact with sessions directly. By
63 11
 * default, sessions are created and utilized for maximum performance
64 11
 * automatically.**
65 11
 *
66 11
 * @class
67 11
 * @param {Database} database Parent {@link Database} instance.
68 11
 * @param {string} [name] The name of the session. If not provided, it is
69 11
 *     assumed you are going to create it.
70 11
 *
71 11
 * @example
72 11
 * const {Spanner} = require('@google-cloud/spanner');
73 11
 * const spanner = new Spanner();
74 11
 *
75 11
 * const instance = spanner.instance('my-instance');
76 11
 * const database = instance.database('my-database');
77 11
 *
78 11
 * //-
79 11
 * // To create a session manually, don't provide a name.
80 11
 * //-
81 11
 * const session = database.session();
82 11
 *
83 11
 * session.create(function(err) {
84 11
 *   if (err) {
85 11
 *     // Error handling omitted.
86 11
 *   }
87 11
 *
88 11
 *   // Session created successfully.
89 11
 *   // `session.id` = The name of the session.
90 11
 * });
91 11
 *
92 11
 * //-
93 11
 * // To access a previously-created session, provide a name.
94 11
 * //-
95 11
 * const session = database.session('session-name');
96 11
 */
97 11
export class Session extends GrpcServiceObject {
98 11
  id!: string;
99 11
  formattedName_?: string;
100 11
  type?: types;
101 11
  txn?: Transaction;
102 11
  lastUsed?: number;
103 11
  lastError?: ServiceError;
104 11
  constructor(database: Database, name?: string) {
105 11
    const methods = {
106 11
      /**
107 11
       * Create a session.
108 11
       *
109 11
       * @method Session#create
110 11
       * @param {object} [options] See {@link Database#createSession}.
111 11
       * @param {CreateSessionCallback} [callback] Callback function.
112 11
       * @returns {Promise<CreateSessionResponse>}
113 11
       *
114 11
       * @example
115 11
       * session.create(function(err, session, apiResponse) {
116 11
       *   if (err) {
117 11
       *     // Error handling omitted.
118 11
       *   }
119 11
       *
120 11
       *   // Session created successfully.
121 11
       * });
122 11
       *
123 11
       * //-
124 11
       * //Returns a Promise if the callback is omitted.
125 11
       * //-
126 11
       * session.create()
127 11
       *   .then(function(data) {
128 11
       *     const session = data[0];
129 11
       *     const apiResponse = data[1];
130 11
       *
131 11
       *     // Session created successfully.
132 11
       *   });
133 11
       */
134 11
      create: true,
135 11
      /**
136 11
       * @typedef {array} SessionExistsResponse
137 11
       * @property {boolean} 0 Whether the {@link Session} exists.
138 11
       */
139 11
      /**
140 11
       * @callback SessionExistsCallback
141 11
       * @param {?Error} err Request error, if any.
142 11
       * @param {boolean} exists Whether the {@link Session} exists.
143 11
       */
144 11
      /**
145 11
       * Check if a session exists.
146 11
       *
147 11
       * @method Session#exists
148 11
       * @param {SessionExistsCallback} [callback] Callback function.
149 11
       * @returns {Promise<SessionExistsResponse>}
150 11
       *
151 11
       * @example
152 11
       * session.exists(function(err, exists) {});
153 11
       *
154 11
       * //-
155 11
       * //Returns a Promise if the callback is omitted.
156 11
       * //-
157 11
       * session.exists().then(function(data) {
158 11
       *   const exists = data[0];
159 11
       * });
160 11
       */
161 11
      exists: true,
162 11
      /**
163 11
       * @typedef {array} GetSessionResponse
164 11
       * @property {Session} 0 The {@link Session}.
165 11
       * @property {object} 1 The full API response.
166 11
       */
167 11
      /**
168 11
       * @callback CreateSessionCallback
169 11
       * @param {?Error} err Request error, if any.
170 11
       * @param {Session} session The {@link Session}.
171 11
       * @param {object} apiResponse The full API response.
172 11
       */
173 11
      /**
174 11
       * Get a session if it exists.
175 11
       *
176 11
       * You may optionally use this to "get or create" an object by providing
177 11
       * an object with `autoCreate` set to `true`. Any extra configuration that
178 11
       * is normally required for the `create` method must be contained within
179 11
       * this object as well.
180 11
       *
181 11
       * @method Session#get
182 11
       * @param {options} [options] Configuration object.
183 11
       * @param {boolean} [options.autoCreate=false] Automatically create the
184 11
       *     object if it does not exist.
185 11
       * @param {CreateSessionCallback} [callback] Callback function.
186 11
       * @returns {Promise<GetSessionResponse>}
187 11
       *
188 11
       * @example
189 11
       * session.get(function(err, session, apiResponse) {
190 11
       *   // `session.metadata` has been populated.
191 11
       * });
192 11
       *
193 11
       * //-
194 11
       * //Returns a Promise if the callback is omitted.
195 11
       * //-
196 11
       * session.get().then(function(data) {
197 11
       *   const session = data[0];
198 11
       *   const apiResponse = data[0];
199 11
       * });
200 11
       */
201 11
      get: true,
202 11
    };
203 11
    super(({
204 11
      parent: database,
205 11
      /**
206 11
       * @name Session#id
207 11
       * @type {string}
208 11
       */
209 11
      id: name,
210 11
      methods,
211 11
      createMethod: (
212 11
        _: {},
213 11
        optionsOrCallback: CreateSessionOptions | CreateSessionCallback,
214 11
        callback: CreateSessionCallback
215 11
      ) => {
216 11
        const options =
217 11
          typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
218 11
        callback =
219 11
          typeof optionsOrCallback === 'function'
220 11
            ? optionsOrCallback
221 11
            : callback;
222 11
        return database.createSession(options, (err, session, apiResponse) => {
223 11
          if (err) {
224 11
            callback(err, null, apiResponse);
225 11
            return;
226 11
          }
227 11

228 11
          extend(this, session);
229 11
          callback(null, this, apiResponse);
230 11
        });
231 11
      },
232 11
    } as {}) as ServiceObjectConfig);
233 11

234 11
    this.request = database.request;
235 11
    this.requestStream = database.requestStream;
236 11

237 11
    if (name) {
238 11
      this.formattedName_ = Session.formatName_(database.formattedName_, name);
239 11
    }
240 11
  }
241 11
  delete(): Promise<DeleteResponse>;
242 11
  delete(callback: DeleteCallback): void;
243 11
  /**
244 11
   * Delete a session.
245 11
   *
246 11
   * Wrapper around {@link v1.SpannerClient#deleteSession}.
247 11
   *
248 11
   * @see {@link v1.SpannerClient#deleteSession}
249 11
   * @see [DeleteSession API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.DeleteSession)
250 11
   *
251 11
   * @param {BasicCallback} [callback] Callback function.
252 11
   * @returns {Promise<BasicResponse>}
253 11
   *
254 11
   * @example
255 11
   * session.delete(function(err, apiResponse) {
256 11
   *   if (err) {
257 11
   *     // Error handling omitted.
258 11
   *   }
259 11
   *
260 11
   *   // Session deleted successfully.
261 11
   * });
262 11
   *
263 11
   * //-
264 11
   * //Returns a Promise if the callback is omitted.
265 11
   * //-
266 11
   * session.delete().then(function(data) {
267 11
   *   const apiResponse = data[0];
268 11
   * });
269 11
   */
270 11
  delete(callback?: DeleteCallback): void | Promise<DeleteResponse> {
271 11
    const reqOpts = {
272 11
      name: this.formattedName_,
273 11
    };
274 11
    return this.request(
275 11
      {
276 11
        client: 'SpannerClient',
277 11
        method: 'deleteSession',
278 11
        reqOpts,
279 11
      },
280 11
      callback!
281 11
    );
282 11
  }
283 11
  getMetadata(): Promise<GetSessionMetadataResponse>;
284 11
  getMetadata(callback: GetSessionMetadataCallback): void;
285 11
  /**
286 11
   * @typedef {array} GetSessionMetadataResponse
287 11
   * @property {object} 0 The session's metadata.
288 11
   * @property {object} 1 The full API response.
289 11
   */
290 11
  /**
291 11
   * @callback GetSessionMetadataCallback
292 11
   * @param {?Error} err Request error, if any.
293 11
   * @param {object} metadata The session's metadata.
294 11
   * @param {object} apiResponse The full API response.
295 11
   */
296 11
  /**
297 11
   * Get the session's metadata.
298 11
   *
299 11
   * Wrapper around {@link v1.SpannerClient#getSession}.
300 11
   *
301 11
   * @see {@link v1.SpannerClient#getSession}
302 11
   * @see [GetSession API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.GetSession)
303 11
   *
304 11
   * @param {GetSessionMetadataCallback} [callback] Callback function.
305 11
   * @returns {Promise<GetSessionMetadataResponse>}
306 11
   *
307 11
   * @example
308 11
   * session.getMetadata(function(err, metadata, apiResponse) {});
309 11
   *
310 11
   * //-
311 11
   * //Returns a Promise if the callback is omitted.
312 11
   * //-
313 11
   * session.getMetadata().then(function(data) {
314 11
   *   const metadata = data[0];
315 11
   *   const apiResponse = data[1];
316 11
   * });
317 11
   */
318 11
  getMetadata(
319 11
    callback?: GetSessionMetadataCallback
320 11
  ): void | Promise<GetSessionMetadataResponse> {
321 11
    const reqOpts = {
322 11
      name: this.formattedName_,
323 11
    };
324 11
    return this.request(
325 11
      {
326 11
        client: 'SpannerClient',
327 11
        method: 'getSession',
328 11
        reqOpts,
329 11
      },
330 11
      callback!
331 11
    );
332 11
  }
333 11
  keepAlive(): Promise<KeepAliveResponse>;
334 11
  keepAlive(callback: KeepAliveCallback): void;
335 11
  /**
336 11
   * Ping the session with `SELECT 1` to prevent it from expiring.
337 11
   *
338 11
   * @param {BasicCallback} [callback] Callback function.
339 11
   * @returns {Promise<BasicResponse>}
340 11
   *
341 11
   * @example
342 11
   * session.keepAlive(function(err) {
343 11
   *   if (err) {
344 11
   *     // An error occurred while trying to keep this session alive.
345 11
   *   }
346 11
   * });
347 11
   */
348 11
  keepAlive(callback?: KeepAliveCallback): void | Promise<KeepAliveResponse> {
349 11
    const reqOpts = {
350 11
      session: this.formattedName_,
351 11
      sql: 'SELECT 1',
352 11
    };
353 11
    return this.request(
354 11
      {
355 11
        client: 'SpannerClient',
356 11
        method: 'executeSql',
357 11
        reqOpts,
358 11
      },
359 11
      callback!
360 11
    );
361 11
  }
362 11
  /**
363 11
   * Create a PartitionedDml transaction.
364 11
   *
365 11
   * @returns {PartitionedDml}
366 11
   *
367 11
   * @example
368 11
   * const transaction = session.partitionedDml();
369 11
   */
370 11
  partitionedDml() {
371 11
    return new PartitionedDml(this);
372 11
  }
373 11
  /**
374 11
   * Create a Snapshot transaction.
375 11
   *
376 11
   * @param {TimestampBounds} [options] The timestamp bounds.
377 11
   * @param {google.spanner.v1.ExecuteSqlRequest.IQueryOptions} [queryOptions] The default query options to use.
378 11
   * @returns {Snapshot}
379 11
   *
380 11
   * @example
381 11
   * const snapshot = session.snapshot({strong: false});
382 11
   */
383 11
  snapshot(
384 11
    options?: TimestampBounds,
385 11
    queryOptions?: google.spanner.v1.ExecuteSqlRequest.IQueryOptions
386 11
  ) {
387 11
    return new Snapshot(this, options, queryOptions);
388 11
  }
389 11
  /**
390 11
   * Create a read write Transaction.
391 11
   *
392 11
   * @param {google.spanner.v1.ExecuteSqlRequest.IQueryOptions} [queryOptions] The default query options to use.
393 11
   * @return {Transaction}
394 11
   *
395 11
   * @example
396 11
   * const transaction = session.transaction();
397 11
   */
398 11
  transaction(
399 11
    queryOptions?: google.spanner.v1.ExecuteSqlRequest.IQueryOptions
400 11
  ) {
401 11
    return new Transaction(this, undefined, queryOptions);
402 11
  }
403 11
  /**
404 11
   * Format the session name to include the parent database's name.
405 11
   *
406 11
   * @private
407 11
   *
408 11
   * @param {string} databaseName The parent database's name.
409 11
   * @param {string} name The instance name.
410 11
   * @returns {string}
411 11
   *
412 11
   * @example
413 11
   * Session.formatName_('my-database', 'my-session');
414 11
   * // 'projects/grape-spaceship-123/instances/my-instance/' +
415 11
   * // 'databases/my-database/sessions/my-session'
416 11
   */
417 11
  static formatName_(databaseName: string, name: string) {
418 11
    if (name.indexOf('/') > -1) {
419 11
      return name;
420 11
    }
421 11
    const sessionName = name.split('/').pop();
422 11
    return databaseName + '/sessions/' + sessionName;
423 11
  }
424 11
}
425 11

426 11
/*! Developer Documentation
427 11
 *
428 11
 * All async methods (except for streams) will return a Promise in the event
429 11
 * that a callback is omitted.
430 11
 */
431 11
promisifyAll(Session, {
432 11
  exclude: [
433 11
    'delete',
434 11
    'getMetadata',
435 11
    'partitionedDml',
436 11
    'snapshot',
437 11
    'transaction',
438 11
  ],
439 11
});

Read our documentation on viewing source code .

Loading