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

17 5
import {promisifyAll} from '@google-cloud/promisify';
18 5
import * as through from 'through2';
19 5
import {Operation as GaxOperation, CallOptions} from 'google-gax';
20 5
import {Database, UpdateSchemaCallback, UpdateSchemaResponse} from './database';
21 5
import {PartialResultStream, Row} from './partial-result-stream';
22 5
import {
23 5
  ReadRequest,
24 5
  TimestampBounds,
25 5
  CommitResponse,
26 5
  ReadResponse,
27 5
  ReadCallback,
28 5
  CommitCallback,
29 5
} from './transaction';
30 5
import {google as databaseAdmin} from '../protos/protos';
31 5
import {Schema, LongRunningCallback} from './common';
32 5

33 5
export type Key = string | string[];
34 5

35 5
export type CreateTableResponse = [
36 5
  Table,
37 5
  GaxOperation,
38 5
  databaseAdmin.longrunning.IOperation
39 5
];
40 5
export type CreateTableCallback = LongRunningCallback<Table>;
41 5

42 5
export type DropTableResponse = UpdateSchemaResponse;
43 5
export type DropTableCallback = UpdateSchemaCallback;
44 5

45 5
export type DeleteRowsCallback = CommitCallback;
46 5
export type DeleteRowsResponse = CommitResponse;
47 5

48 5
export type InsertRowsCallback = CommitCallback;
49 5
export type InsertRowsResponse = CommitResponse;
50 5

51 5
export type ReplaceRowsCallback = CommitCallback;
52 5
export type ReplaceRowsResponse = CommitResponse;
53 5

54 5
export type UpdateRowsCallback = CommitCallback;
55 5
export type UpdateRowsResponse = CommitResponse;
56 5

57 5
export type UpsertRowsCallback = CommitCallback;
58 5
export type UpsertRowsResponse = CommitResponse;
59 5
/**
60 5
 * Create a Table object to interact with a table in a Cloud Spanner
61 5
 * database.
62 5
 *
63 5
 * @class
64 5
 *
65 5
 * @param {Database} database {@link Database} instance.
66 5
 * @param {string} name Name of the table.
67 5
 *
68 5
 * @example
69 5
 * const {Spanner} = require('@google-cloud/spanner');
70 5
 * const spanner = new Spanner();
71 5
 *
72 5
 * const instance = spanner.instance('my-instance');
73 5
 * const database = instance.database('my-database');
74 5
 * const table = database.table('my-table');
75 5
 */
76 5
class Table {
77 5
  database: Database;
78 5
  name: string;
79 5
  constructor(database: Database, name: string) {
80 5
    /**
81 5
     * The {@link Database} instance of this {@link Table} instance.
82 5
     * @name Table#database
83 5
     * @type {Database}
84 5
     */
85 5
    this.database = database;
86 5
    /**
87 5
     * The name of this table.
88 5
     * @name Table#name
89 5
     * @type {string}
90 5
     */
91 5
    this.name = name;
92 5
  }
93 5
  create(
94 5
    schema: Schema,
95 5
    gaxOptions?: CallOptions
96 5
  ): Promise<CreateTableResponse>;
97 5
  create(schema: Schema, callback: CreateTableCallback): void;
98 5
  create(
99 5
    schema: Schema,
100 5
    gaxOptions: CallOptions,
101 5
    callback: CreateTableCallback
102 5
  ): void;
103 5
  /**
104 5
   * Create a table.
105 5
   *
106 5
   * @param {string} schema See {@link Database#createTable}.
107 5
   * @param {CreateTableCallback} [callback] Callback function.
108 5
   * @returns {Promise<CreateTableResponse>}
109 5
   *
110 5
   * @example
111 5
   * const {Spanner} = require('@google-cloud/spanner');
112 5
   * const spanner = new Spanner();
113 5
   *
114 5
   * const instance = spanner.instance('my-instance');
115 5
   * const database = instance.database('my-database');
116 5
   * const table = database.table('Singers');
117 5
   *
118 5
   * const schema =
119 5
   *   'CREATE TABLE Singers (' +
120 5
   *   '  SingerId INT64 NOT NULL,' +
121 5
   *   '  FirstName STRING(1024),' +
122 5
   *   '  LastName STRING(1024),' +
123 5
   *   '  SingerInfo BYTES(MAX),' +
124 5
   *   ') PRIMARY KEY(SingerId)';
125 5
   *
126 5
   * table.create(schema, function(err, table, operation, apiResponse) {
127 5
   *   if (err) {
128 5
   *     // Error handling omitted.
129 5
   *   }
130 5
   *
131 5
   *   operation
132 5
   *     .on('error', function(err) {})
133 5
   *     .on('complete', function() {
134 5
   *       // Table created successfully.
135 5
   *     });
136 5
   * });
137 5
   *
138 5
   * //-
139 5
   * // If the callback is omitted, we'll return a Promise.
140 5
   * //-
141 5
   * table.create(schema)
142 5
   *   .then(function(data) {
143 5
   *     const table = data[0];
144 5
   *     const operation = data[1];
145 5
   *
146 5
   *     return operation.promise();
147 5
   *   })
148 5
   *   .then(function() {
149 5
   *     // Table created successfully.
150 5
   *   });
151 5
   */
152 5
  create(
153 5
    schema: Schema,
154 5
    gaxOptionsOrCallback?: CallOptions | CreateTableCallback,
155 5
    cb?: CreateTableCallback
156 5
  ): Promise<CreateTableResponse> | void {
157 5
    const gaxOptions =
158 5
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
159 5
    const callback =
160 5
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
161 5

162 5
    this.database.createTable(schema, gaxOptions, callback!);
163 5
  }
164 5
  /**
165 5
   * Create a readable object stream to receive rows from the database using key
166 5
   * lookups and scans.
167 5
   *
168 5
   * @see [StreamingRead API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.StreamingRead)
169 5
   * @see [ReadRequest API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.ReadRequest)
170 5
   *
171 5
   * @param {ReadRequest} query Configuration object. See official
172 5
   *     [`ReadRequest`](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.ReadRequest).
173 5
   *     API documentation.
174 5
   * @param {TimestampBounds} [options] [Transaction options](https://cloud.google.com/spanner/docs/timestamp-bounds).
175 5
   * @returns {ReadableStream}
176 5
   *
177 5
   * @example
178 5
   * const {Spanner} = require('@google-cloud/spanner');
179 5
   * const spanner = new Spanner();
180 5
   *
181 5
   * const instance = spanner.instance('my-instance');
182 5
   * const database = instance.database('my-database');
183 5
   * const table = database.table('Singers');
184 5
   *
185 5
   * table.createReadStream({
186 5
   *     keys: ['1'],
187 5
   *     columns: ['SingerId', 'name']
188 5
   *   })
189 5
   *   .on('error', function(err) {})
190 5
   *   .on('data', function(row) {
191 5
   *     // row = {
192 5
   *     //   SingerId: '1',
193 5
   *     //   Name: 'Eddie Wilson'
194 5
   *     // }
195 5
   *   })
196 5
   *   .on('end', function() {
197 5
   *     // All results retrieved.
198 5
   *   });
199 5
   *
200 5
   * //-
201 5
   * // Provide an array for `query.keys` to read with a composite key.
202 5
   * //-
203 5
   * const query = {
204 5
   *   keys: [
205 5
   *     [
206 5
   *       'Id1',
207 5
   *       'Name1'
208 5
   *     ],
209 5
   *     [
210 5
   *       'Id2',
211 5
   *       'Name2'
212 5
   *     ]
213 5
   *   ],
214 5
   *   // ...
215 5
   * };
216 5
   *
217 5
   * //-
218 5
   * // If you anticipate many results, you can end a stream early to prevent
219 5
   * // unnecessary processing and API requests.
220 5
   * //-
221 5
   * table.createReadStream({
222 5
   *     keys: ['1'],
223 5
   *     columns: ['SingerId', 'name']
224 5
   *   })
225 5
   *   .on('data', function(row) {
226 5
   *     this.end();
227 5
   *   });
228 5
   */
229 5
  createReadStream(
230 5
    request: ReadRequest,
231 5
    options: TimestampBounds = {}
232 5
  ): PartialResultStream {
233 5
    const proxyStream = through.obj();
234 5

235 5
    this.database.getSnapshot(options, (err, snapshot) => {
236 5
      if (err) {
237 5
        proxyStream.destroy(err);
238 5
        return;
239 5
      }
240 5

241 5
      snapshot!
242 5
        .createReadStream(this.name, request)
243 5
        .on('error', err => {
244 5
          proxyStream.destroy(err);
245 5
          snapshot!.end();
246 5
        })
247 5
        .on('end', () => snapshot!.end())
248 5
        .pipe(proxyStream);
249 5
    });
250 5

251 5
    return proxyStream as PartialResultStream;
252 5
  }
253 5
  delete(gaxOptions?: CallOptions): Promise<DropTableResponse>;
254 5
  delete(callback: DropTableCallback): void;
255 5
  delete(gaxOptions: CallOptions, callback: DropTableCallback): void;
256 5
  /**
257 5
   * Delete the table. Not to be confused with {@link Table#deleteRows}.
258 5
   *
259 5
   * Wrapper around {@link Database#updateSchema}.
260 5
   *
261 5
   * @see {@link Database#updateSchema}
262 5
   *
263 5
   * @throws {TypeError} If any arguments are passed in.
264 5
   * @param {object} [gaxOptions] Request configuration options, outlined here:
265 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
266 5
   * @param {LongRunningOperationCallback} [callback] Callback function.
267 5
   * @returns {Promise<LongRunningOperationResponse>}
268 5
   *
269 5
   * @example
270 5
   * const {Spanner} = require('@google-cloud/spanner');
271 5
   * const spanner = new Spanner();
272 5
   *
273 5
   * const instance = spanner.instance('my-instance');
274 5
   * const database = instance.database('my-database');
275 5
   * const table = database.table('Singers');
276 5
   *
277 5
   * table.delete(function(err, operation, apiResponse) {
278 5
   *   if (err) {
279 5
   *     // Error handling omitted.
280 5
   *   }
281 5
   *
282 5
   *   operation
283 5
   *     .on('error', function(err) {})
284 5
   *     .on('complete', function() {
285 5
   *       // Table deleted successfully.
286 5
   *     });
287 5
   * });
288 5
   *
289 5
   * //-
290 5
   * // If the callback is omitted, we'll return a Promise.
291 5
   * //-
292 5
   * table.delete()
293 5
   *   .then(function(data) {
294 5
   *     const operation = data[0];
295 5
   *     return operation.promise();
296 5
   *   })
297 5
   *   .then(function() {
298 5
   *     // Table deleted successfully.
299 5
   *   });
300 5
   */
301 5
  delete(
302 5
    gaxOptionsOrCallback?: CallOptions | DropTableCallback,
303 5
    cb?: DropTableCallback
304 5
  ): Promise<DropTableResponse> | void {
305 5
    const gaxOptions =
306 5
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
307 5
    const callback =
308 5
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
309 5

310 5
    return this.database.updateSchema(
311 5
      'DROP TABLE `' + this.name + '`',
312 5
      gaxOptions,
313 5
      callback!
314 5
    );
315 5
  }
316 5
  deleteRows(
317 5
    keys: Key[],
318 5
    gaxOptions?: CallOptions
319 5
  ): Promise<DeleteRowsResponse>;
320 5
  deleteRows(keys: Key[], callback: DeleteRowsCallback): void;
321 5
  deleteRows(
322 5
    keys: Key[],
323 5
    gaxOptions: CallOptions,
324 5
    callback: DeleteRowsCallback
325 5
  ): void;
326 5
  /**
327 5
   * Delete rows from this table.
328 5
   *
329 5
   * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit)
330 5
   *
331 5
   * @param {array} keys The keys for the rows to delete. If using a
332 5
   *     composite key, provide an array within this array. See the example
333 5
   * below.
334 5
   * @param {object} [gaxOptions] Request configuration options, outlined here:
335 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
336 5
   * @param {BasicCallback} [callback] Callback function.
337 5
   * @returns {Promise<BasicResponse>}
338 5
   *
339 5
   * @example
340 5
   * const {Spanner} = require('@google-cloud/spanner');
341 5
   * const spanner = new Spanner();
342 5
   *
343 5
   * const instance = spanner.instance('my-instance');
344 5
   * const database = instance.database('my-database');
345 5
   * const table = database.table('Singers');
346 5
   *
347 5
   * const keys = ['Id1', 'Id2', 'Id3'];
348 5
   *
349 5
   * table.deleteRows(keys, function(err, apiResponse) {});
350 5
   *
351 5
   * //-
352 5
   * // Provide an array for `keys` to delete rows with a composite key.
353 5
   * //-
354 5
   * const keys = [
355 5
   *   [
356 5
   *     'Id1',
357 5
   *     'Name1'
358 5
   *   ],
359 5
   *   [
360 5
   *     'Id2',
361 5
   *     'Name2'
362 5
   *   ]
363 5
   * ];
364 5
   *
365 5
   * //-
366 5
   * // If the callback is omitted, we'll return a Promise.
367 5
   * //-
368 5
   * table.deleteRows(keys)
369 5
   *   .then(function(data) {
370 5
   *     const apiResponse = data[0];
371 5
   *   });
372 5
   */
373 5
  deleteRows(
374 5
    keys: Key[],
375 5
    gaxOptionsOrCallback?: CallOptions | DeleteRowsCallback,
376 5
    cb?: DeleteRowsCallback
377 5
  ): Promise<DeleteRowsResponse> | void {
378 5
    const gaxOptions =
379 5
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
380 5
    const callback =
381 5
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
382 5

383 5
    return this._mutate('deleteRows', keys, gaxOptions, callback!);
384 5
  }
385 5
  drop(gaxOptions?: CallOptions): Promise<DropTableResponse>;
386 5
  drop(callback: DropTableCallback): void;
387 5
  drop(gaxOptions: CallOptions, callback: DropTableCallback): void;
388 5
  /**
389 5
   * Drop the table.
390 5
   *
391 5
   * @see {@link Table#delete}
392 5
   * @see {@link Database#updateSchema}
393 5
   *
394 5
   * @param {object} [gaxOptions] Request configuration options, outlined here:
395 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
396 5
   * @param {LongRunningOperationCallback} [callback] Callback function.
397 5
   * @returns {Promise<LongRunningOperationResponse>}
398 5
   *
399 5
   * @example
400 5
   * const {Spanner} = require('@google-cloud/spanner');
401 5
   * const spanner = new Spanner();
402 5
   *
403 5
   * const instance = spanner.instance('my-instance');
404 5
   * const database = instance.database('my-database');
405 5
   * const table = database.table('Singers');
406 5
   *
407 5
   * table.drop(function(err, operation, apiResponse) {
408 5
   *   if (err) {
409 5
   *     // Error handling omitted.
410 5
   *   }
411 5
   *
412 5
   *   operation
413 5
   *     .on('error', function(err) {})
414 5
   *     .on('complete', function() {
415 5
   *       // Table dropped successfully.
416 5
   *     });
417 5
   * });
418 5
   *
419 5
   * //-
420 5
   * // If the callback is omitted, we'll return a Promise.
421 5
   * //-
422 5
   * table.drop()
423 5
   *   .then(function(data) {
424 5
   *     const operation = data[0];
425 5
   *     return operation.promise();
426 5
   *   })
427 5
   *   .then(function() {
428 5
   *     // Table dropped successfully.
429 5
   *   });
430 5
   */
431 5
  drop(
432 5
    gaxOptionsOrCallback?: CallOptions | DropTableCallback,
433 5
    cb?: DropTableCallback
434 5
  ): Promise<DropTableResponse> | void {
435 5
    const gaxOptions =
436 5
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
437 5
    const callback =
438 5
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
439 5

440 5
    return this.delete(gaxOptions, callback!);
441 5
  }
442 5
  insert(
443 5
    rows: object | object[],
444 5
    gaxOptions?: CallOptions
445 5
  ): Promise<InsertRowsResponse>;
446 5
  insert(rows: object | object[], callback: InsertRowsCallback): void;
447 5
  insert(
448 5
    rows: object | object[],
449 5
    gaxOptions: CallOptions,
450 5
    callback: InsertRowsCallback
451 5
  ): void;
452 5
  /**
453 5
   * Insert rows of data into this table.
454 5
   *
455 5
   * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit)
456 5
   *
457 5
   * @param {object|object[]} rows A map of names to values of data to insert
458 5
   *     into this table.
459 5
   * @param {object} [gaxOptions] Request configuration options, outlined here:
460 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
461 5
   * @param {BasicCallback} [callback] Callback function.
462 5
   * @returns {Promise<BasicResponse>}
463 5
   *
464 5
   * @example
465 5
   * const {Spanner} = require('@google-cloud/spanner');
466 5
   * const spanner = new Spanner();
467 5
   *
468 5
   * const instance = spanner.instance('my-instance');
469 5
   * const database = instance.database('my-database');
470 5
   * const table = database.table('Singers');
471 5
   *
472 5
   * const row = {
473 5
   *   SingerId: 'Id3',
474 5
   *   Name: 'Eddie Wilson'
475 5
   * };
476 5
   *
477 5
   * table.insert(row, function(err, apiResponse) {
478 5
   *   if (err) {
479 5
   *     // Error handling omitted.
480 5
   *   }
481 5
   *
482 5
   *   // Rows inserted successfully.
483 5
   * });
484 5
   *
485 5
   * //-
486 5
   * // Multiple rows can be inserted at once.
487 5
   * //-
488 5
   * const row2 = {
489 5
   *   SingerId: 'Id3b',
490 5
   *   Name: 'Joe West'
491 5
   * };
492 5
   *
493 5
   * table.insert([
494 5
   *   row,
495 5
   *   row2
496 5
   * ], function(err, apiResponse) {});
497 5
   *
498 5
   * //-
499 5
   * // If the callback is omitted, we'll return a Promise.
500 5
   * //-
501 5
   * table.insert(row)
502 5
   *   .then(function(data) {
503 5
   *     const apiResponse = data[0];
504 5
   *   });
505 5
   *
506 5
   * @example <caption>include:samples/crud.js</caption>
507 5
   * region_tag:spanner_insert_data
508 5
   * Full example:
509 5
   */
510 5
  insert(
511 5
    rows: object | object[],
512 5
    gaxOptionsOrCallback?: CallOptions | InsertRowsCallback,
513 5
    cb?: InsertRowsCallback
514 5
  ): Promise<InsertRowsResponse> | void {
515 5
    const gaxOptions =
516 5
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
517 5
    const callback =
518 5
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
519 5

520 5
    this._mutate('insert', rows, gaxOptions, callback!);
521 5
  }
522 5
  read(request: ReadRequest, options?: TimestampBounds): Promise<ReadResponse>;
523 5
  read(request: ReadRequest, callback: ReadCallback): void;
524 5
  read(
525 5
    request: ReadRequest,
526 5
    options: TimestampBounds,
527 5
    callback: ReadCallback
528 5
  ): void;
529 5
  /**
530 5
   * Configuration object, describing what to read from the table.
531 5
   *
532 5
   * @typedef {object} TableReadRequestOptions
533 5
   * @property {string[]} columns The columns of the table to be returned for each
534 5
   *     row matching this query.
535 5
   * @property {string[]|string[][]} keys The primary keys of the rows in this table to be
536 5
   *     yielded. If using a composite key, provide an array within this array.
537 5
   *     See the example below.
538 5
   * @property {string} [index] The name of an index on the table.
539 5
   * @property {boolean} [json=false] Receive the rows as serialized objects. This
540 5
   *     is the equivalent of calling `toJSON()` on each row.
541 5
   * @property {object} [jsonOptions] Configuration options for the serialized
542 5
   *     objects.
543 5
   * @property {boolean} [jsonOptions.wrapNumbers=false] Protect large integer
544 5
   *     values outside of the range of JavaScript Number.
545 5
   * @property {object} [keySet] Defines a collection of keys and/or key ranges to
546 5
   *     read.
547 5
   * @property {number} [limit] The number of rows to yield.
548 5
   */
549 5
  /**
550 5
   * @typedef {array} TableReadResponse
551 5
   * @property {array[]} 1 Rows are returned as an array of object arrays. Each
552 5
   *     object has a `name` and `value` property. To get a serialized object,
553 5
   *     call `toJSON()`. Optionally, provide an options object to `toJSON()`
554 5
   *     specifying `wrapNumbers: true` to protect large integer values outside
555 5
   * of the range of JavaScript Number. If set, FLOAT64 values will be returned
556 5
   *     as {@link Spanner.Float} objects and INT64 values as {@link
557 5
   * Spanner.Int}.
558 5
   */
559 5
  /**
560 5
   * @callback TableReadCallback
561 5
   * @param {?Error} err Request error, if any.
562 5
   * @param {array[]} rows Rows are returned as an array of object arrays. Each
563 5
   *     object has a `name` and `value` property. To get a serialized object,
564 5
   *     call `toJSON()`. Optionally, provide an options object to `toJSON()`
565 5
   *     specifying `wrapNumbers: true` to protect large integer values outside
566 5
   * of the range of JavaScript Number. If set, FLOAT64 values will be returned
567 5
   *     as {@link Spanner.Float} objects and INT64 values as {@link
568 5
   * Spanner.Int}.
569 5
   */
570 5
  /**
571 5
   * Receive rows from the database using key lookups and scans.
572 5
   *
573 5
   * **Performance Considerations:**
574 5
   *
575 5
   * This method wraps the streaming method,
576 5
   * {@link Table#createReadStream} for your convenience. All rows will
577 5
   * be stored in memory before being released to your callback. If you intend
578 5
   * on receiving a lot of results from your query, consider using the streaming
579 5
   * method, so you can free each result from memory after consuming it.
580 5
   *
581 5
   * @param {ReadRequest} query Configuration object, describing
582 5
   *     what to read from the table.
583 5
   * @param {TimestampBounds} options [Transaction options](https://cloud.google.com/spanner/docs/timestamp-bounds).
584 5
   * @param {TableReadCallback} [callback] Callback function.
585 5
   * @returns {Promise<TableReadResponse>}
586 5
   *
587 5
   * @example
588 5
   * const {Spanner} = require('@google-cloud/spanner');
589 5
   * const spanner = new Spanner();
590 5
   *
591 5
   * const instance = spanner.instance('my-instance');
592 5
   * const database = instance.database('my-database');
593 5
   * const table = database.table('Singers');
594 5
   *
595 5
   * const query = {
596 5
   *   keys: ['1'],
597 5
   *   columns: ['SingerId', 'name']
598 5
   * };
599 5
   *
600 5
   * table.read(query, function(err, rows) {
601 5
   *   if (err) {
602 5
   *     // Error handling omitted.
603 5
   *   }
604 5
   *
605 5
   *   const firstRow = rows[0];
606 5
   *
607 5
   *   // firstRow = [
608 5
   *   //   {
609 5
   *   //     name: 'SingerId',
610 5
   *   //     value: '1'
611 5
   *   //   },
612 5
   *   //   {
613 5
   *   //     name: 'Name',
614 5
   *   //     value: 'Eddie Wilson'
615 5
   *   //   }
616 5
   *   // ]
617 5
   * });
618 5
   *
619 5
   * //-
620 5
   * // Provide an array for `query.keys` to read with a composite key.
621 5
   * //-
622 5
   * const query = {
623 5
   *   keys: [
624 5
   *     [
625 5
   *       'Id1',
626 5
   *       'Name1'
627 5
   *     ],
628 5
   *     [
629 5
   *       'Id2',
630 5
   *       'Name2'
631 5
   *     ]
632 5
   *   ],
633 5
   *   // ...
634 5
   * };
635 5
   *
636 5
   * //-
637 5
   * // Rows are returned as an array of object arrays. Each object has a `name`
638 5
   * // and `value` property. To get a serialized object, call `toJSON()`.
639 5
   * //
640 5
   * // Alternatively, set `query.json` to `true`, and this step will be
641 5
   * performed
642 5
   * // automatically.
643 5
   * //-
644 5
   * table.read(query, function(err, rows) {
645 5
   *   if (err) {
646 5
   *     // Error handling omitted.
647 5
   *   }
648 5
   *
649 5
   *   const firstRow = rows[0];
650 5
   *
651 5
   *   // firstRow.toJSON() = {
652 5
   *   //   SingerId: '1',
653 5
   *   //   Name: 'Eddie Wilson'
654 5
   *   // }
655 5
   * });
656 5
   *
657 5
   * //-
658 5
   * // If the callback is omitted, we'll return a Promise.
659 5
   * //-
660 5
   * table.read(query)
661 5
   *   .then(function(data) {
662 5
   *     const rows = data[0];
663 5
   *   });
664 5
   *
665 5
   * @example <caption>include:samples/crud.js</caption>
666 5
   * region_tag:spanner_read_data
667 5
   * Full example:
668 5
   *
669 5
   * @example <caption>include:samples/crud.js</caption>
670 5
   * region_tag:spanner_read_stale_data
671 5
   * Reading stale data:
672 5
   *
673 5
   * @example <caption>include:samples/indexing.js</caption>
674 5
   * region_tag:spanner_read_data_with_index
675 5
   * Reading data using an index:
676 5
   *
677 5
   * @example <caption>include:samples/indexing.js</caption>
678 5
   * region_tag:spanner_read_data_with_storing_index
679 5
   * Reading data using a storing index:
680 5
   */
681 5
  read(
682 5
    request: ReadRequest,
683 5
    optionsOrCallback?: TimestampBounds | ReadCallback,
684 5
    cb?: ReadCallback
685 5
  ): Promise<ReadResponse> | void {
686 5
    const rows: Row[] = [];
687 5

688 5
    const callback =
689 5
      typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
690 5
    const options =
691 5
      typeof optionsOrCallback === 'object'
692 5
        ? (optionsOrCallback as TimestampBounds)
693 5
        : {};
694 5

695 5
    this.createReadStream(request, options)
696 5
      .on('error', callback!)
697 5
      .on('data', (row: Row) => rows.push(row))
698 5
      .on('end', () => callback!(null, rows));
699 5
  }
700 5
  replace(
701 5
    rows: object | object[],
702 5
    gaxOptions?: CallOptions
703 5
  ): Promise<ReplaceRowsResponse>;
704 5
  replace(rows: object | object[], callback: ReplaceRowsCallback): void;
705 5
  replace(
706 5
    rows: object | object[],
707 5
    gaxOptions: CallOptions,
708 5
    callback: ReplaceRowsCallback
709 5
  ): void;
710 5
  /**
711 5
   * Replace rows of data within this table.
712 5
   *
713 5
   * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit)
714 5
   *
715 5
   * @param {object|object[]} rows A map of names to values of data to insert
716 5
   *     into this table.
717 5
   * @param {object} [gaxOptions] Request configuration options, outlined here:
718 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
719 5
   * @param {BasicCallback} [callback] Callback function.
720 5
   * @returns {Promise<BasicResponse>}
721 5
   *
722 5
   * @example
723 5
   * const {Spanner} = require('@google-cloud/spanner');
724 5
   * const spanner = new Spanner();
725 5
   *
726 5
   * const instance = spanner.instance('my-instance');
727 5
   * const database = instance.database('my-database');
728 5
   * const table = database.table('Singers');
729 5
   *
730 5
   * const row = {
731 5
   *   SingerId: 'Id3',
732 5
   *   Name: 'Joe West'
733 5
   * };
734 5
   *
735 5
   * table.replace(row, function(err, apiResponse) {
736 5
   *   if (err) {
737 5
   *     // Error handling omitted.
738 5
   *   }
739 5
   *
740 5
   *   // Row replaced successfully.
741 5
   * });
742 5
   *
743 5
   * //-
744 5
   * // If the callback is omitted, we'll return a Promise.
745 5
   * //-
746 5
   * table.replace(row)
747 5
   *   .then(function(data) {
748 5
   *     const apiResponse = data[0];
749 5
   *   });
750 5
   */
751 5
  replace(
752 5
    rows: object | object[],
753 5
    gaxOptionsOrCallback?: CallOptions | ReplaceRowsCallback,
754 5
    cb?: ReplaceRowsCallback
755 5
  ): Promise<ReplaceRowsResponse> | void {
756 5
    const gaxOptions =
757 5
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
758 5
    const callback =
759 5
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
760 5

761 5
    this._mutate('replace', rows, gaxOptions, callback!);
762 5
  }
763 5
  update(
764 5
    rows: object | object[],
765 5
    gaxOptions?: CallOptions
766 5
  ): Promise<UpdateRowsResponse>;
767 5
  update(rows: object | object[], callback: UpdateRowsCallback): void;
768 5
  update(
769 5
    rows: object | object[],
770 5
    gaxOptions: CallOptions,
771 5
    callback: UpdateRowsCallback
772 5
  ): void;
773 5
  /**
774 5
   * Update rows of data within this table.
775 5
   *
776 5
   * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit)
777 5
   *
778 5
   * @param {object|object[]} rows A map of names to values of data to insert
779 5
   *     into this table.
780 5
   * @param {object} [gaxOptions] Request configuration options, outlined here:
781 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
782 5
   * @param {BasicCallback} [callback] Callback function.
783 5
   * @returns {Promise<BasicResponse>}
784 5
   *
785 5
   * @example
786 5
   * const {Spanner} = require('@google-cloud/spanner');
787 5
   * const spanner = new Spanner();
788 5
   *
789 5
   * const instance = spanner.instance('my-instance');
790 5
   * const database = instance.database('my-database');
791 5
   * const table = database.table('Singers');
792 5
   *
793 5
   * const row = {
794 5
   *   SingerId: 'Id3',
795 5
   *   Name: 'Joe West'
796 5
   * };
797 5
   *
798 5
   * table.update(row, function(err, apiResponse) {
799 5
   *   if (err) {
800 5
   *     // Error handling omitted.
801 5
   *   }
802 5
   *
803 5
   *   // Row updated successfully.
804 5
   * });
805 5
   *
806 5
   * //-
807 5
   * // If the callback is omitted, we'll return a Promise.
808 5
   * //-
809 5
   * table.update(row)
810 5
   *   .then(function(data) {
811 5
   *     const apiResponse = data[0];
812 5
   *   });
813 5
   *
814 5
   * @example <caption>include:samples/crud.js</caption>
815 5
   * region_tag:spanner_update_data
816 5
   * Full example:
817 5
   */
818 5
  update(
819 5
    rows: object | object[],
820 5
    gaxOptionsOrCallback?: CallOptions | UpdateRowsCallback,
821 5
    cb?: UpdateRowsCallback
822 5
  ): Promise<UpdateRowsResponse> | void {
823 5
    const gaxOptions =
824 5
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
825 5
    const callback =
826 5
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
827 5

828 5
    this._mutate('update', rows, gaxOptions, callback!);
829 5
  }
830 5
  upsert(
831 5
    rows: object | object[],
832 5
    gaxOptions?: CallOptions
833 5
  ): Promise<UpsertRowsResponse>;
834 5
  upsert(rows: object | object[], callback: UpsertRowsCallback): void;
835 5
  upsert(
836 5
    rows: object | object[],
837 5
    gaxOptions: CallOptions,
838 5
    callback: UpsertRowsCallback
839 5
  ): void;
840 5
  /**
841 5
   * Insert or update rows of data within this table.
842 5
   *
843 5
   * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit)
844 5
   *
845 5
   * @param {object|object[]} rows A map of names to values of data to insert
846 5
   *     into this table.
847 5
   *
848 5
   * @param {object} [gaxOptions] Request configuration options, outlined here:
849 5
   *     https://googleapis.github.io/gax-nodejs/classes/CallSettings.html.
850 5
   * @param {BasicCallback} [callback] Callback function.
851 5
   * @returns {Promise<BasicResponse>}
852 5
   *
853 5
   * @example
854 5
   * const {Spanner} = require('@google-cloud/spanner');
855 5
   * const spanner = new Spanner();
856 5
   *
857 5
   * const instance = spanner.instance('my-instance');
858 5
   * const database = instance.database('my-database');
859 5
   * const table = database.table('Singers');
860 5
   *
861 5
   * const row = {
862 5
   *   SingerId: 'Id3',
863 5
   *   Name: 'Joe West'
864 5
   * };
865 5
   *
866 5
   * table.upsert(row, function(err, apiResponse) {
867 5
   *   if (err) {
868 5
   *     // Error handling omitted.
869 5
   *   }
870 5
   *
871 5
   *   // Row inserted or updated successfully.
872 5
   * });
873 5
   *
874 5
   * //-
875 5
   * // If the callback is omitted, we'll return a Promise.
876 5
   * //-
877 5
   * table.upsert(row)
878 5
   *   .then(function(data) {
879 5
   *     const apiResponse = data[0];
880 5
   *   });
881 5
   */
882 5
  upsert(
883 5
    rows: object | object[],
884 5
    gaxOptionsOrCallback?: CallOptions | UpsertRowsCallback,
885 5
    cb?: UpsertRowsCallback
886 5
  ): Promise<UpsertRowsResponse> | void {
887 5
    const gaxOptions =
888 5
      typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
889 5
    const callback =
890 5
      typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb!;
891 5

892 5
    this._mutate('upsert', rows, gaxOptions, callback!);
893 5
  }
894 5
  /**
895 5
   * Creates a new transaction and applies the desired mutation via
896 5
   * {@link Transaction#commit}.
897 5
   *
898 5
   * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit)
899 5
   *
900 5
   * @private
901 5
   *
902 5
   * @param {string} method CRUD method (insert, update, etc.).
903 5
   * @param {object|object[]} rows A map of names to values of data to insert
904 5
   *     into this table.
905 5
   * @param {function} callback The callback function.
906 5
   */
907 5
  private _mutate(
908 5
    method: 'deleteRows' | 'insert' | 'replace' | 'update' | 'upsert',
909 5
    rows: object | object[],
910 5
    gaxOptions: CallOptions = {},
911 5
    callback: CommitCallback
912 5
  ): void {
913 5
    this.database.runTransaction((err, transaction) => {
914 5
      if (err) {
915 5
        callback(err);
916 5
        return;
917 5
      }
918 5

919 5
      transaction![method](this.name, rows as Key[]);
920 5
      transaction!.commit(gaxOptions, callback);
921 5
    });
922 5
  }
923 5
}
924 5

925 5
/*! Developer Documentation
926 5
 *
927 5
 * All async methods (except for streams) will return a Promise in the event
928 5
 * that a callback is omitted.
929 5
 */
930 5
promisifyAll(Table, {
931 5
  exclude: ['delete', 'drop'],
932 5
});
933 5

934 5
/**
935 5
 * Reference to the {@link Table} class.
936 5
 * @name module:@google-cloud/spanner.Table
937 5
 * @see Table
938 5
 */
939 5
export {Table};

Read our documentation on viewing source code .

Loading