UNPKG

@google-cloud/spanner

Version:
288 lines 11.1 kB
"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.Table = void 0; const promisify_1 = require("@google-cloud/promisify"); const through = require("through2"); const instrument_1 = require("./instrument"); const protos_1 = require("../protos/protos"); var IsolationLevel = protos_1.google.spanner.v1.TransactionOptions.IsolationLevel; const GOOGLE_STANDARD_SQL = 'GOOGLE_STANDARD_SQL'; const POSTGRESQL = 'POSTGRESQL'; /** * Create a Table object to interact with a table in a Cloud Spanner * database. * * @class * * @param {Database} database {@link Database} instance. * @param {string} name Name of the table. * * @example * ``` * const {Spanner} = require('@google-cloud/spanner'); * const spanner = new Spanner(); * * const instance = spanner.instance('my-instance'); * const database = instance.database('my-database'); * const table = database.table('my-table'); * ``` */ class Table { database; name; _observabilityOptions; constructor(database, name) { /** * The {@link Database} instance of this {@link Table} instance. * @name Table#database * @type {Database} */ this.database = database; /** * The name of this table. * @name Table#name * @type {string} */ this.name = name; this._observabilityOptions = database._observabilityOptions; } create(schema, gaxOptionsOrCallback, cb) { const gaxOptions = typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {}; const callback = typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb; this.database.createTable(schema, gaxOptions, callback); } getDBName() { return this.database.formattedName_; } /** * Create a readable object stream to receive rows from the database using key * lookups and scans. * * @see [StreamingRead API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.StreamingRead) * @see [ReadRequest API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.ReadRequest) * * @param {ReadRequest} query Configuration object, describing what to read from the table.. * @param {TimestampBounds} [options] [Transaction options](https://cloud.google.com/spanner/docs/timestamp-bounds). * @returns {PartialResultStream} A readable stream that emits rows. * * @example * ``` * const {Spanner} = require('@google-cloud/spanner'); * const spanner = new Spanner(); * * const instance = spanner.instance('my-instance'); * const database = instance.database('my-database'); * const table = database.table('Singers'); * * table.createReadStream({ * keys: ['1'], * columns: ['SingerId', 'name'] * }) * .on('error', function(err) {}) * .on('data', function(row) { * // row = { * // SingerId: '1', * // Name: 'Eddie Wilson' * // } * }) * .on('end', function() { * // All results retrieved. * }); * * //- * // Provide an array for `query.keys` to read with a composite key. * //- * const query = { * keys: [ * [ * 'Id1', * 'Name1' * ], * [ * 'Id2', * 'Name2' * ] * ], * // ... * }; * * //- * // If you anticipate many results, you can end a stream early to prevent * // unnecessary processing and API requests. * //- * table.createReadStream({ * keys: ['1'], * columns: ['SingerId', 'name'] * }) * .on('data', function(row) { * this.end(); * }); * ``` */ createReadStream(request, options = {}) { const proxyStream = through.obj(); this.database.getSnapshot(options, (err, snapshot) => { if (err) { proxyStream.destroy(err); return; } snapshot .createReadStream(this.name, request) .on('error', err => { proxyStream.destroy(err); snapshot.end(); }) .on('end', () => snapshot.end()) .pipe(proxyStream); }); return proxyStream; } delete(gaxOptionsOrCallback, cb) { const gaxOptions = typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {}; const callback = typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb; const [schema, table] = this.name.includes('.') ? this.name.split('.') : [null, this.name]; let dropStatement = 'DROP TABLE `' + table + '`'; const performDelete = async () => { const result = await this.database.getDatabaseDialect(gaxOptions); if (result && result.includes(POSTGRESQL)) { dropStatement = schema ? `DROP TABLE "${schema}"."${table}"` : `DROP TABLE "${table}"`; } else if (result && result.includes(GOOGLE_STANDARD_SQL)) { dropStatement = schema ? 'DROP TABLE `' + schema + '`.`' + table + '`' : dropStatement; } const updateSchemaResult = callback ? this.database.updateSchema(dropStatement, gaxOptions, callback) : this.database.updateSchema(dropStatement, gaxOptions); return updateSchemaResult; }; if (!callback) { return performDelete(); } else { void performDelete(); } } deleteRows(keys, optionsOrCallback, cb) { const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {}; const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb; return this._mutate('deleteRows', keys, options, callback); } drop(gaxOptionsOrCallback, cb) { const gaxOptions = typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {}; const callback = typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb; return this.delete(gaxOptions, callback); } insert(rows, optionsOrCallback, cb) { const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {}; const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb; this._mutate('insert', rows, options, callback); } read(request, optionsOrCallback, cb) { const rows = []; const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb; const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {}; this.createReadStream(request, options) .on('error', callback) .on('data', (row) => rows.push(row)) .on('end', () => callback(null, rows)); } replace(rows, optionsOrCallback, cb) { const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {}; const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb; this._mutate('replace', rows, options, callback); } update(rows, optionsOrCallback, cb) { const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {}; const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb; this._mutate('update', rows, options, callback); } upsert(rows, optionsOrCallback, cb) { const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {}; const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb; this._mutate('upsert', rows, options, callback); } /** * Creates a new transaction and applies the desired mutation via * {@link Transaction#commit}. * * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit) * * @private * * @param {string} method CRUD method (insert, update, etc.). * @param {object|object[]} rows A map of names to values of data to insert * into this table. * @param {function} callback The callback function. */ _mutate(method, rows, options = {}, callback) { const traceConfig = { opts: this._observabilityOptions, tableName: this.name, dbName: this.getDBName(), transactionTag: options?.requestOptions ?.transactionTag, }; (0, instrument_1.startTrace)('Table.' + method, traceConfig, span => { const requestOptions = 'requestOptions' in options ? options.requestOptions : {}; const excludeTxnFromChangeStreams = 'excludeTxnFromChangeStreams' in options ? options.excludeTxnFromChangeStreams : false; const isolationLevel = 'isolationLevel' in options ? options.isolationLevel : IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED; this.database.runTransaction({ requestOptions: requestOptions, excludeTxnFromChangeStreams: excludeTxnFromChangeStreams, isolationLevel: isolationLevel, }, (err, transaction) => { if (err) { (0, instrument_1.setSpanError)(span, err); span.end(); callback(err); return; } transaction[method](this.name, rows); transaction.commit(options, (err, resp) => { if (err) { (0, instrument_1.setSpanError)(span, err); } span.end(); callback(err, resp); }); }); }); } } exports.Table = Table; /*! Developer Documentation * * All async methods (except for streams) will return a Promise in the event * that a callback is omitted. */ (0, promisify_1.promisifyAll)(Table, { exclude: ['delete', 'drop'], }); //# sourceMappingURL=table.js.map