UNPKG

@google-cloud/spanner

Version:
1,347 lines 63 kB
/*! * 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. */ import { PreciseDate } from '@google-cloud/precise-date'; import Long = require('long'); import { EventEmitter } from 'events'; import { grpc, CallOptions } from 'google-gax'; import { common as p } from 'protobufjs'; import { Readable } from 'stream'; import { Json, JSONOptions, Type, Value } from './codec'; import { PartialResultStream, ResumeToken, Row } from './partial-result-stream'; import { Session } from './session'; import { Key } from './table'; import { google as spannerClient } from '../protos/protos'; import { NormalCallback } from './common'; import { google } from '../protos/protos'; import IQueryOptions = google.spanner.v1.ExecuteSqlRequest.IQueryOptions; import IRequestOptions = google.spanner.v1.IRequestOptions; import { Spanner } from '.'; import { ObservabilityOptions, traceConfig } from './instrument'; import { RunTransactionOptions } from './transaction-runner'; export type Rows = Array<Row | Json>; export interface TimestampBounds { strong?: boolean; minReadTimestamp?: PreciseDate | spannerClient.protobuf.ITimestamp; maxStaleness?: number | spannerClient.protobuf.IDuration; readTimestamp?: PreciseDate | spannerClient.protobuf.ITimestamp; exactStaleness?: number | spannerClient.protobuf.IDuration; returnReadTimestamp?: boolean; } export interface BatchWriteOptions { requestOptions?: Pick<IRequestOptions, 'priority' | 'transactionTag'>; gaxOptions?: CallOptions; excludeTxnFromChangeStreams?: boolean; } export interface RequestOptions { json?: boolean; jsonOptions?: JSONOptions; gaxOptions?: CallOptions; maxResumeRetries?: number; /** * An object where column names as keys and custom objects as corresponding * values for deserialization. This is only needed for proto columns * where deserialization logic is on user-specific code. When provided, * the custom object enables deserialization of backend-received column data. * If not provided, data remains serialized as buffer for Proto Messages and * integer for Proto Enums. * * @example * To obtain Proto Messages and Proto Enums as JSON objects, you must supply * additional metadata. This metadata should include the protobufjs-cli * generated proto message function and enum object. It encompasses the essential * logic for proper data deserialization. * * Eg: To read data from Proto Columns in json format using DQL, you should pass * columnsMetadata where key is the name of the column and value is the protobufjs-cli * generated proto message function and enum object. * * const query = { * sql: `SELECT SingerId, * FirstName, * LastName, * SingerInfo, * SingerGenre, * SingerInfoArray, * SingerGenreArray * FROM Singers * WHERE SingerId = 6`, * columnsMetadata: { * SingerInfo: music.SingerInfo, * SingerInfoArray: music.SingerInfo, * SingerGenre: music.Genre, * SingerGenreArray: music.Genre, * }, * }; */ columnsMetadata?: object; } export interface CommitOptions { requestOptions?: Pick<IRequestOptions, 'priority'>; returnCommitStats?: boolean; maxCommitDelay?: spannerClient.protobuf.IDuration; gaxOptions?: CallOptions; } export interface Statement { sql: string; params?: { [param: string]: Value; }; types?: Type | { [param: string]: Value; }; paramTypes?: { [k: string]: google.spanner.v1.Type; } | null; } export interface ExecuteSqlRequest extends Statement, RequestOptions { resumeToken?: ResumeToken; queryMode?: spannerClient.spanner.v1.ExecuteSqlRequest.QueryMode; partitionToken?: Uint8Array | string; seqno?: number; queryOptions?: IQueryOptions; requestOptions?: Omit<IRequestOptions, 'transactionTag'>; dataBoostEnabled?: boolean | null; directedReadOptions?: google.spanner.v1.IDirectedReadOptions; } export interface KeyRange { startClosed?: Value[]; startOpen?: Value[]; endClosed?: Value[]; endOpen?: Value[]; } export interface ReadRequest extends RequestOptions { table?: string; index?: string; columns?: string[] | null; keys?: string[] | string[][]; ranges?: KeyRange[]; keySet?: spannerClient.spanner.v1.IKeySet | null; limit?: number | Long | string | null; resumeToken?: Uint8Array | null; partitionToken?: Uint8Array | null; requestOptions?: Omit<IRequestOptions, 'transactionTag'>; dataBoostEnabled?: boolean | null; directedReadOptions?: google.spanner.v1.IDirectedReadOptions; } export interface BatchUpdateError extends grpc.ServiceError { rowCounts: number[]; } export type CommitRequest = spannerClient.spanner.v1.ICommitRequest; export type BatchUpdateResponse = [ number[], spannerClient.spanner.v1.ExecuteBatchDmlResponse ]; export type BeginResponse = [spannerClient.spanner.v1.ITransaction]; export type BeginTransactionCallback = NormalCallback<spannerClient.spanner.v1.ITransaction>; export type CommitResponse = [spannerClient.spanner.v1.ICommitResponse]; export type ReadResponse = [Rows]; export type RunResponse = [ Rows, spannerClient.spanner.v1.ResultSetStats, spannerClient.spanner.v1.ResultSetMetadata ]; export type RunUpdateResponse = [number]; export interface BatchUpdateOptions { requestOptions?: Omit<IRequestOptions, 'transactionTag'>; gaxOptions?: CallOptions; } export interface BatchUpdateCallback { (err: null | BatchUpdateError, rowCounts: number[], response?: spannerClient.spanner.v1.ExecuteBatchDmlResponse): void; } export interface BatchUpdateOptions { requestOptions?: Omit<IRequestOptions, 'transactionTag'>; gaxOptions?: CallOptions; } export type ReadCallback = NormalCallback<Rows>; export interface RunCallback { (err: null | grpc.ServiceError, rows: Rows, stats: spannerClient.spanner.v1.ResultSetStats, metadata?: spannerClient.spanner.v1.ResultSetMetadata): void; } export interface RunUpdateCallback { (err: null | grpc.ServiceError, rowCount: number): void; } export type CommitCallback = NormalCallback<spannerClient.spanner.v1.ICommitResponse>; /** * @typedef {object} TimestampBounds * @property {boolean} [strong=true] Read at a timestamp where all previously * committed transactions are visible. * @property {external:PreciseDate|google.protobuf.Timestamp} [minReadTimestamp] * Executes all reads at a `timestamp >= minReadTimestamp`. * @property {number|google.protobuf.Timestamp} [maxStaleness] Read data at a * `timestamp >= NOW - maxStaleness` (milliseconds). * @property {external:PreciseDate|google.protobuf.Timestamp} [readTimestamp] * Executes all reads at the given timestamp. * @property {number|google.protobuf.Timestamp} [exactStaleness] Executes all * reads at a timestamp that is `exactStaleness` (milliseconds) old. * @property {boolean} [returnReadTimestamp=true] When true, * {@link Snapshot#readTimestamp} will be populated after * {@link Snapshot#begin} is called. */ /** * This transaction type provides guaranteed consistency across several reads, * but does not allow writes. Snapshot read-only transactions can be configured * to read at timestamps in the past. * * When finished with the Snapshot, call {@link Snapshot#end} to * release the underlying {@link Session}. Failure to do so can result in a * Session leak. * * **This object is created and returned from {@link Database#getSnapshot}.** * * @class * @hideconstructor * * @see [Timestamp Bounds API Documentation](https://cloud.google.com/spanner/docs/timestamp-bounds) * * @example * ``` * const {Spanner} = require('@google-cloud/spanner'); * const spanner = new Spanner(); * * const instance = spanner.instance('my-instance'); * const database = instance.database('my-database'); * * const timestampBounds = { * strong: true * }; * * database.getSnapshot(timestampBounds, (err, transaction) => { * if (err) { * // Error handling omitted. * } * * // It should be called when the snapshot finishes. * transaction.end(); * }); * ``` */ export declare class Snapshot extends EventEmitter { protected _options: spannerClient.spanner.v1.ITransactionOptions; protected _seqno: number; protected _waitingRequests: Array<() => void>; protected _inlineBeginStarted: any; protected _useInRunner: boolean; id?: Uint8Array | string; ended: boolean; metadata?: spannerClient.spanner.v1.ITransaction; readTimestamp?: PreciseDate; readTimestampProto?: spannerClient.protobuf.ITimestamp; request: (config: {}, callback: Function) => void; requestStream: (config: {}) => Readable; session: Session; queryOptions?: IQueryOptions; commonHeaders_: { [k: string]: string; }; requestOptions?: Pick<IRequestOptions, 'transactionTag'>; _observabilityOptions?: ObservabilityOptions; _traceConfig: traceConfig; protected _dbName?: string; /** * The transaction ID. * * @name Snapshot#id * @type {?(string|Buffer)} */ /** * Whether or not the transaction has ended. If true, make no further * requests, and discard the transaction. * * @name Snapshot#ended * @type {boolean} */ /** * The raw transaction response object. It is populated after * {@link Snapshot#begin} is called. * * @name Snapshot#metadata * @type {?TransactionResponse} */ /** * **Snapshot only** * The timestamp at which all reads are performed. * * @name Snapshot#readTimestamp * @type {?external:PreciseDate} */ /** * **Snapshot only** * The protobuf version of {@link Snapshot#readTimestamp}. This is useful if * you require microsecond precision. * * @name Snapshot#readTimestampProto * @type {?google.protobuf.Timestamp} */ /** * @constructor * * @param {Session} session The parent Session object. * @param {TimestampBounds} [options] Snapshot timestamp bounds. * @param {QueryOptions} [queryOptions] Default query options to use when none * are specified for a query. */ constructor(session: Session, options?: TimestampBounds, queryOptions?: IQueryOptions); /** * @typedef {object} TransactionResponse * @property {string|Buffer} id The transaction ID. * @property {?google.protobuf.Timestamp} readTimestamp For snapshot read-only * transactions, the read timestamp chosen for the transaction. */ /** * @typedef {array} TransactionBeginResponse * @property {TransactionResponse} 0 The raw transaction object. */ /** * @callback TransactionBeginCallback * @param {?Error} err Request error, if any. * @param {TransactionResponse} apiResponse The raw transaction object. */ /** * Begin a new transaction. Typically, you need not call this unless * manually creating transactions via {@link Session} objects. * * @see [BeginTransaction API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.BeginTransaction) * * @param {object} [gaxOptions] Request configuration options, * See {@link https://googleapis.dev/nodejs/google-gax/latest/interfaces/CallOptions.html|CallOptions} * for more details. * @param {TransactionBeginCallback} [callback] Callback function. * @returns {Promise<TransactionBeginResponse>} * * @example * ``` * transaction.begin(function(err) { * if (!err) { * // transaction began successfully. * } * }); * * ``` * @example If the callback is omitted, the function returns a Promise * ``` * transaction.begin() * .then(function(data) { * const apiResponse = data[0]; * }); * ``` */ begin(gaxOptions?: CallOptions): Promise<BeginResponse>; begin(callback: BeginTransactionCallback): void; begin(gaxOptions: CallOptions, callback: BeginTransactionCallback): void; /** * A KeyRange represents a range of rows in a table or index. * * A range has a start key and an end key. These keys can be open or closed, * indicating if the range includes rows with that key. * * Keys are represented by an array of strings where the nth value in the list * corresponds to the nth component of the table or index primary key. * * @typedef {object} KeyRange * @property {string[]} [startClosed] If the start is closed, then the range * includes all rows whose first key columns exactly match. * @property {string[]} [startOpen] If the start is open, then the range * excludes rows whose first key columns exactly match. * @property {string[]} [endClosed] If the end is closed, then the range * includes all rows whose first key columns exactly match. * @property {string[]} [endOpen] If the end is open, then the range excludes * rows whose first key columns exactly match. */ /** * Read request options. This includes all standard ReadRequest options as * well as several convenience properties. * * @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) * * @typedef {object} ReadRequest * @property {string} table The name of the table in the database to be read. * @property {string[]} columns The columns of the table to be returned for each * row matching this query. * @property {string[]|string[][]} keys The primary or index keys of the rows in this table to be * yielded. If using a composite key, provide an array within this array. * See the example below. * @property {KeyRange[]} [ranges] An alternative to the keys property; this can * be used to define a range of keys to be yielded. * @property {string} [index] The name of an index on the table if a * different index than the primary key should be used to determine which rows to return. * @property {boolean} [json=false] Receive the rows as serialized objects. This * is the equivalent of calling `toJSON()` on each row. * @property {JSONOptions} [jsonOptions] Configuration options for the serialized * objects. * @property {object} [keySet] Defines a collection of keys and/or key ranges to * read. * @property {number} [limit] The number of rows to yield. * @property {Buffer} [partitionToken] * If present, results will be restricted to the specified partition * previously created using PartitionRead(). There must be an exact * match for the values of fields common to this message and the * PartitionReadRequest message used to create this partition_token. * @property {google.spanner.v1.RequestOptions} [requestOptions] * Common options for this request. * @property {google.spanner.v1.IDirectedReadOptions} [directedReadOptions] * Indicates which replicas or regions should be used for non-transactional reads or queries. * @property {object} [gaxOptions] * Call options. See {@link https://googleapis.dev/nodejs/google-gax/latest/interfaces/CallOptions.html|CallOptions} * for more details. */ /** * Create a readable object stream to receive rows from the database using key * lookups and scans. * * Wrapper around {@link v1.SpannerClient#streamingRead}. * * @see {@link v1.SpannerClient#streamingRead} * @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) * * @fires PartialResultStream#response * @fires PartialResultStream#stats * * @param {string} table The table to read from. * @param {ReadRequest} query Configuration object. See official * [`ReadRequest`](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.ReadRequest). * API documentation. * @returns {ReadableStream} A readable stream that emits rows. * * @example * ``` * transaction.createReadStream('Singers', { * keys: ['1'], * columns: ['SingerId', 'name'] * }) * .on('error', function(err) {}) * .on('data', function(row) { * // row = [ * // { * // name: 'SingerId', * // value: '1' * // }, * // { * // name: 'Name', * // value: 'Eddie Wilson' * // } * // ] * }) * .on('end', function() { * // All results retrieved. * }); * * ``` * @example Provide an array for `query.keys` to read with a * composite key. * ``` * const query = { * keys: [ * [ * 'Id1', * 'Name1' * ], * [ * 'Id2', * 'Name2' * ] * ], * // ... * }; * ``` * * @example Rows are returned as an array of object arrays. Each * object has a `name` and `value` property. To get a serialized object, call * `toJSON()`. * ``` * transaction.createReadStream('Singers', { * keys: ['1'], * columns: ['SingerId', 'name'] * }) * .on('error', function(err) {}) * .on('data', function(row) { * // row.toJSON() = { * // SingerId: '1', * // Name: 'Eddie Wilson' * // } * }) * .on('end', function() { * // All results retrieved. * }); * ``` * * @example Alternatively, set `query.json` to `true`, and this step * will perform automatically. * ``` * transaction.createReadStream('Singers', { * keys: ['1'], * columns: ['SingerId', 'name'], * json: true, * }) * .on('error', function(err) {}) * .on('data', function(row) { * // row = { * // SingerId: '1', * // Name: 'Eddie Wilson' * // } * }) * .on('end', function() { * // All results retrieved. * }); * ``` * * @example If you anticipate many results, you can end a stream * early to prevent unnecessary processing and API requests. * ``` * transaction.createReadStream('Singers', { * keys: ['1'], * columns: ['SingerId', 'name'] * }) * .on('data', function(row) { * this.end(); * }); * ``` */ createReadStream(table: string, request?: ReadRequest): PartialResultStream; /** * Let the client know you're done with a particular transaction. This should * mainly be called for {@link Snapshot} objects, however in certain cases * you may want to call them for {@link Transaction} objects as well. * * @example Calling `end` on a read only snapshot * ``` * database.getSnapshot((err, transaction) => { * if (err) { * // Error handling omitted. * } * * transaction.run('SELECT * FROM Singers', (err, rows) => { * if (err) { * // Error handling omitted. * } * * // End the snapshot. * transaction.end(); * }); * }); * ``` * * @example Calling `end` on a read/write transaction * ``` * database.runTransaction((err, transaction) => { * if (err) { * // Error handling omitted. * } * * const query = 'UPDATE Account SET Balance = 1000 WHERE Key = 1'; * * transaction.runUpdate(query, err => { * if (err) { * // In the event of an error, there would be nothing to rollback, * so * // instead of continuing, discard the * transaction. transaction.end(); return; * } * * transaction.commit(err => {}); * }); * }); * ``` */ end(): void; /** * @typedef {array} ReadResponse * @property {array[]} 0 Rows are returned as an array of object arrays. Each * object has a `name` and `value` property. To get a serialized object, * call `toJSON()`. Optionally, provide an options object to `toJSON()` * specifying `wrapNumbers: true` to protect large integer values outside * of the range of JavaScript Number. If set, FLOAT64 values are returned * as {@link Spanner.Float} objects and INT64 values as {@link * Spanner.Int}. */ /** * @callback ReadCallback * @param {?Error} err Request error, if any. * @param {array[]} rows Rows are returned as an array of object arrays. Each * object has a `name` and `value` property. To get a serialized object, * call `toJSON()`. Optionally, provide an options object to `toJSON()` * specifying `wrapNumbers: true` to protect large integer values outside * of the range of JavaScript Number. If set, FLOAT64 values are returned * as {@link Spanner.Float} objects and INT64 values as {@link * Spanner.Int}. */ /** * Performs a read request against the specified Table. * * Wrapper around {@link v1.SpannerClient#read}. * * @see {@link v1.SpannerClient#read} * * @param {string} table The table to read from. * @param {ReadRequest} query Configuration object. See official * [`ReadRequest`](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.ReadRequest). * API documentation. * @param {ReadCallback} [callback] Callback function. * @returns {Promise<ReadResponse>} * * @example * ``` * const query = { * keys: ['1'], * columns: ['SingerId', 'name'] * }; * * transaction.read('Singers', query, function(err, rows) { * if (err) { * // Error handling omitted. * } * * const firstRow = rows[0]; * * // firstRow = [ * // { * // name: 'SingerId', * // value: '1' * // }, * // { * // name: 'Name', * // value: 'Eddie Wilson' * // } * // ] * }); * * ``` * @example Provide an array for `query.keys` to read with a * composite key. * ``` * const query = { * keys: [ * [ * 'Id1', * 'Name1' * ], * [ * 'Id2', * 'Name2' * ] * ], * // ... * }; * ``` * * @example Rows are returned as an array of object arrays. Each * object has a `name` and `value` property. To get a serialized object, call * `toJSON()`. * ``` * transaction.read('Singers', query, function(err, rows) { * if (err) { * // Error handling omitted. * } * * const firstRow = rows[0]; * * // firstRow.toJSON() = { * // SingerId: '1', * // Name: 'Eddie Wilson' * // } * }); * ``` * * @example Alternatively, set `query.json` to `true`, and this step * will perform automatically. * ``` * query.json = true; * * transaction.read('Singers', query, function(err, rows) { * if (err) { * // Error handling omitted. * } * * const firstRow = rows[0]; * * // firstRow = { * // SingerId: '1', * // Name: 'Eddie Wilson' * // } * }); * ``` */ read(table: string, request: ReadRequest): Promise<ReadResponse>; read(table: string, callback: ReadCallback): void; read(table: string, request: ReadRequest, callback: ReadCallback): void; /** * Execute a SQL statement on this database inside of a transaction. * * **Performance Considerations:** * * This method wraps the streaming method, * {@link Snapshot#run} for your convenience. All rows are stored in memory * before releasing to your callback. If you intend to receive a lot of * results from your query, consider using the streaming method, * so you can free each result from memory after consuming it. * * Wrapper around {@link v1.SpannerClient#executeStreamingSql}. * * @see {@link v1.SpannerClient#executeStreamingSql} * @see [ExecuteStreamingSql API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.ExecuteStreamingSql) * @see [ExecuteSqlRequest API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.ExecuteSqlRequest) * * @param {string|ExecuteSqlRequest} query A SQL query or * {@link ExecuteSqlRequest} object. * @param {RunCallback} [callback] Callback function. * @returns {Promise<RunResponse>} * * @example * ``` * transaction.run(query, function(err, rows) { * if (err) { * // Error handling omitted. * } * * // rows = [ * // { * // SingerId: '1', * // Name: 'Eddie Wilson' * // } * // ] * }); * * ``` * @example The SQL query string can contain parameter placeholders. * A parameter placeholder consists of '@' followed by the parameter name. * ``` * const query = { * sql: 'SELECT * FROM Singers WHERE name = @name', * params: { * name: 'Eddie Wilson' * } * }; * * transaction.run(query, function(err, rows) { * if (err) { * // Error handling omitted. * } * }); * ``` * * @example If you need to enforce a specific param type, a types map * can be provided. This is typically useful if your param value can be null. * ``` * const query = { * sql: 'SELECT * FROM Singers WHERE name = @name AND id = @id', * params: { * id: spanner.int(8), * name: null * }, * types: { * id: 'int64', * name: 'string' * } * }; * * transaction.run(query, function(err, rows) { * if (err) { * // Error handling omitted. * } * }); * ``` */ run(query: string | ExecuteSqlRequest): Promise<RunResponse>; run(query: string | ExecuteSqlRequest, callback: RunCallback): void; /** * ExecuteSql request options. This includes all standard ExecuteSqlRequest * options as well as several convenience properties. * * @see [Query Syntax](https://cloud.google.com/spanner/docs/query-syntax) * @see [ExecuteSql API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.ExecuteSql) * * @typedef {object} ExecuteSqlRequest * @property {string} resumeToken The token used to resume getting results. * @property {google.spanner.v1.ExecuteSqlRequest.QueryMode} queryMode Query plan and * execution statistics for the SQL statement that * produced this result set. * @property {string} partitionToken The partition token. * @property {number} seqno The Sequence number. This option is used internally and will be overridden. * @property {string} sql The SQL string. * @property {google.spanner.v1.ExecuteSqlRequest.IQueryOptions} [queryOptions] * Default query options to use with the database. These options will be * overridden by any query options set in environment variables or that * are specified on a per-query basis. * @property {google.spanner.v1.IRequestOptions} requestOptions The request options to include * with the commit request. * @property {Object.<string, *>} [params] A map of parameter names to values. * @property {Object.<string, (string|ParamType)>} [types] A map of parameter * names to types. If omitted the client will attempt to guess for all * non-null values. * @property {boolean} [json=false] Receive the rows as serialized objects. This * is the equivalent of calling `toJSON()` on each row. * @property {JSONOptions} [jsonOptions] Configuration options for the * serialized objects. * @property {object} [gaxOptions] Request configuration options, * See {@link https://googleapis.dev/nodejs/google-gax/latest/interfaces/CallOptions.html|CallOptions} * for more details. * @property {number} [maxResumeRetries] The maximum number of times that the * stream will retry to push data downstream, when the downstream indicates * that it is not ready for any more data. Increase this value if you * experience 'Stream is still not ready to receive data' errors as a * result of a slow writer in your receiving stream. * @property {object} [directedReadOptions] * Indicates which replicas or regions should be used for non-transactional reads or queries. */ /** * Create a readable object stream to receive resulting rows from a SQL * statement. * * Wrapper around {@link v1.SpannerClient#executeStreamingSql}. * * @see {@link v1.SpannerClient#executeStreamingSql} * @see [ExecuteStreamingSql API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.ExecuteStreamingSql) * @see [ExecuteSqlRequest API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.ExecuteSqlRequest) * * @fires PartialResultStream#response * @fires PartialResultStream#stats * * @param {string|ExecuteSqlRequest} query A SQL query or * {@link ExecuteSqlRequest} object. * @returns {ReadableStream} * * @example * ``` * const query = 'SELECT * FROM Singers'; * * transaction.runStream(query) * .on('error', function(err) {}) * .on('data', function(row) { * // row = { * // SingerId: '1', * // Name: 'Eddie Wilson' * // } * }) * .on('end', function() { * // All results retrieved. * }); * * ``` * @example The SQL query string can contain parameter placeholders. * A parameter placeholder consists of '@' followed by the parameter name. * ``` * const query = { * sql: 'SELECT * FROM Singers WHERE name = @name', * params: { * name: 'Eddie Wilson' * } * }; * * transaction.runStream(query) * .on('error', function(err) {}) * .on('data', function(row) {}) * .on('end', function() {}); * ``` * * @example If you anticipate many results, you can end a stream * early to prevent unnecessary processing and API requests. * ``` * transaction.runStream(query) * .on('data', function(row) { * this.end(); * }); * ``` */ runStream(query: string | ExecuteSqlRequest): PartialResultStream; /** * * @private */ configureTagOptions(singleUse?: boolean, transactionTag?: string, requestOptions?: {}): IRequestOptions | null; /** * Transforms convenience options `keys` and `ranges` into a KeySet object. * * @private * @static * * @param {ReadRequest} request The read request. * @returns {object} */ static encodeKeySet(request: ReadRequest): spannerClient.spanner.v1.IKeySet; /** * Formats timestamp options into proto format. * * @private * @static * * @param {TimestampBounds} options The user supplied options. * @returns {object} */ static encodeTimestampBounds(options: TimestampBounds): spannerClient.spanner.v1.TransactionOptions.IReadOnly; /** * Encodes convenience options `param` and `types` into the proto formatted. * * @private * @static * * @param {ExecuteSqlRequest} request The SQL request. * @returns {object} */ static encodeParams(request: ExecuteSqlRequest): { params: p.IStruct; paramTypes: { [field: string]: spannerClient.spanner.v1.Type; }; }; /** * Get directed read options * @private * @param {google.spanner.v1.IDirectedReadOptions} directedReadOptions Request directedReadOptions object. */ protected _getDirectedReadOptions(directedReadOptions: google.spanner.v1.IDirectedReadOptions | null | undefined): spannerClient.spanner.v1.IDirectedReadOptions | null | undefined; /** * Update transaction properties from the response. * * @private * * @param {spannerClient.spanner.v1.ITransaction} resp Response object. */ protected _update(resp: spannerClient.spanner.v1.ITransaction): void; /** * Wrap `makeRequest` function with the lock to make sure the inline begin * transaction can happen only once. * * @param makeRequest * @private */ private _wrapWithIdWaiter; _releaseWaitingRequests(): void; /** * Gets the Spanner object * * @private * * @returns {Spanner} */ protected _getSpanner(): Spanner; } /** * Never use DML class directly. Instead, it should be extended upon * if a class requires DML capabilities. * * @private * @class */ export declare class Dml extends Snapshot { /** * @typedef {array} RunUpdateResponse * @property {number} 0 Affected row count. */ /** * @callback RunUpdateCallback * @param {?Error} err Request error, if any. * @param {number} rowCount Affected row count. */ /** * Execute a DML statement and get the affected row count. * * @private * * @see {@link Transaction#run} * * @param {string|object} query A DML statement or * [`ExecuteSqlRequest`](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.ExecuteSqlRequest) * object. * @param {object} [query.params] A map of parameter name to values. * @param {object} [query.types] A map of parameter types. * @param {RunUpdateCallback} [callback] Callback function. * @returns {Promise<RunUpdateResponse>} */ runUpdate(query: string | ExecuteSqlRequest): Promise<RunUpdateResponse>; runUpdate(query: string | ExecuteSqlRequest, callback: RunUpdateCallback): void; } /** * This type of transaction is the only way to write data into Cloud Spanner. * These transactions rely on pessimistic locking and, if necessary, two-phase * commit. Locking read-write transactions may abort, requiring the application * to retry. * * Calling either {@link Transaction#commit} or {@link Transaction#rollback} * signals that the transaction is finished and no further requests will be * made. If for some reason you decide not to call one of the aformentioned * methods, call {@link Transaction#end} to release the underlying * {@link Session}. * * Running a transaction via {@link Database#runTransaction} or * {@link Database#runTransactionAsync} automatically re-runs the * transaction on `ABORTED` errors. * * {@link Database#getTransaction} returns a plain {@link Transaction} * object, requiring the user to retry manually. * * @class * @extends Snapshot * * @param {Session} session The parent Session object. * * @example * ``` * const {Spanner} = require('@google-cloud/spanner'); * const spanner = new Spanner(); * * const instance = spanner.instance('my-instance'); * const database = instance.database('my-database'); * * database.runTransaction(function(err, transaction) { * // The `transaction` object is ready for use. * }); * * ``` * @example To manually control retrying the transaction, use the * `getTransaction` method. * ``` * database.getTransaction(function(err, transaction) { * // The `transaction` object is ready for use. * }); * ``` */ export declare class Transaction extends Dml { commitTimestamp?: PreciseDate; commitTimestampProto?: spannerClient.protobuf.ITimestamp; private _queuedMutations; /** * Timestamp at which the transaction was committed. Will be populated once * {@link Transaction#commit} is called. * * @name Transaction#commitTimestamp * @type {?external:PreciseDate} */ /** * The protobuf version of {@link Transaction#commitTimestamp}. This is useful * if you require microsecond precision. * * @name Transaction#commitTimestampProto * @type {?google.protobuf.Timestamp} */ /** * Execute a DML statement and get the affected row count. * * @name Transaction#runUpdate * * @see {@link Transaction#run} * * @param {string|object} query A DML statement or * [`ExecuteSqlRequest`](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.ExecuteSqlRequest) * object. * @param {object} [query.params] A map of parameter name to values. * @param {object} [query.types] A map of parameter types. * @param {RunUpdateCallback} [callback] Callback function. * @returns {Promise<RunUpdateResponse>} * * @example * ``` * const query = 'UPDATE Account SET Balance = 1000 WHERE Key = 1'; * * transaction.runUpdate(query, (err, rowCount) => { * if (err) { * // Error handling omitted. * } * }); * ``` */ constructor(session: Session, options?: spannerClient.spanner.v1.TransactionOptions.ReadWrite, queryOptions?: IQueryOptions, requestOptions?: Pick<IRequestOptions, 'transactionTag'>); /** * @typedef {error} BatchUpdateError * @property {number} code gRPC status code. * @property {?object} metadata gRPC metadata. * @property {number[]} rowCounts The affected row counts for any DML * statements that were executed successfully before this error occurred. */ /** * @typedef {object} BatchUpdateOptions * @property {object} [gaxOptions] Request configuration options, * See {@link https://googleapis.dev/nodejs/google-gax/latest/interfaces/CallOptions.html|CallOptions} * for more details. * @property {google.spanner.v1.IRequestOptions} [requestOptions] The request options to include * with the commit request. */ /** * @typedef {array} BatchUpdateResponse * @property {number[]} 0 Affected row counts. * @property {object} 1 The full API response. */ /** * @callback BatchUpdateCallback * @param {?BatchUpdateError} err Request error, if any. * @param {number[]} rowCounts Affected row counts. * @param {object} apiResponse The full API response. */ /** * Execute a series of DML statements and get the affected row counts. * * If any of the DML statements fail, the returned error will contain a list * of results for all successfully executed statements. * * @param {string[]|object[]} query A DML statement or * [`ExecuteSqlRequest`](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.ExecuteSqlRequest) * object. * @param {object} [query.params] A map of parameter name to values. * @param {object} [query.types] A map of parameter types. * @param {object} [gaxOptions] Request configuration options, * See {@link https://googleapis.dev/nodejs/google-gax/latest/interfaces/CallOptions.html|CallOptions} * for more details. * @param {BatchUpdateOptions} [options] Options for configuring the request. * @param {RunUpdateCallback} [callback] Callback function. * @returns {Promise<RunUpdateResponse>} * * @example * ``` * const queries = [ * { * sql: 'INSERT INTO MyTable (Key, Value) VALUES (@key, @value)', * params: {key: 'my-key', value: 'my-value'}, * }, * { * sql: 'UPDATE MyTable t SET t.Value = @value WHERE t.KEY = @key', * params: {key: 'my-other-key', value: 'my-other-value'} * } * ]; * * transaction.batchUpdate(queries, (err, rowCounts, apiResponse) => { * if (err) { * // Error handling omitted. * } * }); * * ``` * @example If the callback is omitted, we'll return a Promise. * ``` * const [rowCounts, apiResponse] = await transaction.batchUpdate(queries); * ``` */ batchUpdate(queries: Array<string | Statement>, options?: BatchUpdateOptions | CallOptions): Promise<BatchUpdateResponse>; batchUpdate(queries: Array<string | Statement>, callback: BatchUpdateCallback): void; batchUpdate(queries: Array<string | Statement>, options: BatchUpdateOptions | CallOptions, callback: BatchUpdateCallback): void; private static extractKnownMetadata; /** * This method updates the _queuedMutations property of the transaction. * * @public * * @param {spannerClient.spanner.v1.Mutation[]} [mutation] */ setQueuedMutations(mutation: spannerClient.spanner.v1.Mutation[]): void; /** * @typedef {object} CommitOptions * @property {google.spanner.v1.IRequestOptions} requestOptions The request options to include * with the commit request. * @property {boolean} returnCommitStats Include statistics related to the * transaction in the {@link CommitResponse}. * @property {spannerClient.proto.IDuration} maxCommitDelay Maximum amount * of delay the commit is willing to incur in order to improve * throughput. Value should be between 0ms and 500ms. * @property {object} [gaxOptions] The request configuration options, * See {@link https://googleapis.dev/nodejs/google-gax/latest/interfaces/CallOptions.html|CallOptions} * for more details. */ /** * @typedef {object} CommitResponse * @property {google.protobuf.Timestamp} commitTimestamp The transaction * commit timestamp. * @property {google.spanner.v1.CommitResponse.ICommitStats|null} commitStats * The statistics about this commit. Only populated if requested in * {@link CommitOptions}. */ /** * @typedef {array} CommitPromiseResponse * @property {CommitResponse} 0 The commit response. */ /** * @callback CommitCallback * @param {?Error} error Request error, if any. * @param {CommitResponse} apiResponse The full API response. */ /** * Commit the transaction. * * Wrapper around {@link v1.SpannerClient#commit}. * * @see {@link v1.SpannerClient#commit} * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit) * * @param {CommitOptions} [options] Options for configuring the request. * @param {CommitCallback} [callback] Callback function. * @returns {Promise<CommitPromiseResponse>} * * @example * ``` * database.runTransaction(function(err, transaction) { * if (err) { * // Error handling omitted. * } * * // Queue a mutation (note that there is no callback passed to `insert`). * transaction.insert('Singers', { * SingerId: 'Id3b', * Name: 'Joe West' * }); * * // Commit the transaction. * transaction.commit(function(err, apiResponse) { * if (!err) { * // Get the commit timestamp on successful commits. * const {commitTimestamp} = apiResponse; * } * }); * }); * ``` */ commit(options?: CommitOptions | CallOptions): Promise<CommitResponse>; commit(callback: CommitCallback): void; commit(options: CommitOptions | CallOptions, callback: CommitCallback): void; /** * Decorates an error returned by a commit with additional information for * specific known errors. * @param err the error to check and decorate with additional information if possible * @param mutations the mutations included in the commit request * @private */ private static decorateCommitError; /** * Decorates an error returned by a commit with additional information if the * error was returned because the application tried to insert an array of * objects into a JSON column. An array of objects will by default be encoded * as ARRAY<JSON>, but can also be interpreted as JSON. An application must * specify a top-level array of objects that should be inserted into a JSON * column as a string instead of as an array of objects. * @param err the error returned by the commit RPC * @param mutations the mutations included in the commit request * @private */ private static decoratePossibleJsonMismatchError; /** * Delete rows from a table. * * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit) * * @param {string} table The name of the table. * @param {array} keys The keys for the rows to delete. If using a * composite key, provide an array within this array. See the example * below. * * @example * ``` * const keys = ['Id1', 'Id2', 'Id3']; * * database.runTransaction(function(err, transaction) { * if (err) { * // Error handling omitted. * } * * // Queue this mutation until later calling `commit`. * // Note that a callback is not passed to `deleteRows`. * transaction.deleteRows('Singers', keys); * * // Commit the transaction. * transaction.commit(function(err) { * if (!err) { * // The rows were deleted successfully. * } * }); * }); * * ``` * @example Provide an array for `keys` to delete rows with a * composite key. * ``` * const keys = [ * [ * 'Id1', * 'Name1' * ], * [ * 'Id2', * 'Name2' * ] * ]; * ``` */ deleteRows(table: string, keys: Key[]): void; /** * Insert rows of data into this table. * * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit) * * @param {string} table The name of the table. * @param {object|object[]} rows A map of names to values of data to insert * into this table. * * @example * ``` * const row = { * SingerId: 'Id3', * Name: 'Eddie Wilson' * }; * * database.runTransaction(function(err, transaction) { * if (err) { * // Error handling omitted. * } * * // Queue this mutation until later calling `commit`. * // Note that a callback is not passed to `insert`. * transaction.insert('Singers', row); * * // Commit the transaction. * transaction.commit(function(err) { * if (!err) { * // The row was inserted successfully. * } * }); * }); * * ``` * @example Multiple rows can be inserted at once. * ``` * const row2 = { * SingerId: 'Id3b', * Name: 'Joe West' * }; * * database.runTransaction(function(err, transaction) { * if (err) { * // Error handling omitted. * } * * // Queue multiple mutations until later calling `commit`. * // Note that a callback is not passed to `insert`. * transaction.insert('Singers', [ * row, * row2 * ]); * * // Commit the transaction. * transaction.commit(function(err) { * if (!err) { * // The rows were inserted successfully. * } * }); * }); * ``` */ insert(table: string, rows: object | object[]): void; /** * Replace rows of data within a table. * * @see [Commit API Documentation](https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.Commit) * * @param {string} table The table to read from. * @param {object|object[]} rows A map of names to values of data to insert * into this table. * * @example * ``` * const row