1 | ;
|
2 | /*!
|
3 | * Copyright 2014 Google LLC.
|
4 | *
|
5 | * Licensed under the Apache License, Version 2.0 (the "License");
|
6 | * you may not use this file except in compliance with the License.
|
7 | * You may obtain a copy of the License at
|
8 | *
|
9 | * http://www.apache.org/licenses/LICENSE-2.0
|
10 | *
|
11 | * Unless required by applicable law or agreed to in writing, software
|
12 | * distributed under the License is distributed on an "AS IS" BASIS,
|
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14 | * See the License for the specific language governing permissions and
|
15 | * limitations under the License.
|
16 | */
|
17 | var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
18 | if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
19 | if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
20 | return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
21 | };
|
22 | var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
23 | if (kind === "m") throw new TypeError("Private method is not writable");
|
24 | if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
25 | if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
26 | return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
27 | };
|
28 | var _Transaction_instances, _Transaction_mutex, _Transaction_state, _Transaction_runCommit, _Transaction_processBeginResults, _Transaction_parseRunSuccess, _Transaction_beginTransactionAsync, _Transaction_withBeginTransaction;
|
29 | Object.defineProperty(exports, "__esModule", { value: true });
|
30 | exports.Transaction = void 0;
|
31 | const promisify_1 = require("@google-cloud/promisify");
|
32 | const arrify = require("arrify");
|
33 | const _1 = require(".");
|
34 | const entity_1 = require("./entity");
|
35 | const request_1 = require("./request");
|
36 | const async_mutex_1 = require("async-mutex");
|
37 | var TransactionState;
|
38 | (function (TransactionState) {
|
39 | TransactionState[TransactionState["NOT_STARTED"] = 0] = "NOT_STARTED";
|
40 | TransactionState[TransactionState["IN_PROGRESS"] = 1] = "IN_PROGRESS";
|
41 | })(TransactionState || (TransactionState = {}));
|
42 | /**
|
43 | * A transaction is a set of Datastore operations on one or more entities. Each
|
44 | * transaction is guaranteed to be atomic, which means that transactions are
|
45 | * never partially applied. Either all of the operations in the transaction are
|
46 | * applied, or none of them are applied.
|
47 | *
|
48 | * @see {@link https://cloud.google.com/datastore/docs/concepts/transactions| Transactions Reference}
|
49 | *
|
50 | * @class
|
51 | * @extends {Request}
|
52 | * @param {Datastore} datastore A Datastore instance.
|
53 | * @mixes module:datastore/request
|
54 | *
|
55 | * @example
|
56 | * ```
|
57 | * const {Datastore} = require('@google-cloud/datastore');
|
58 | * const datastore = new Datastore();
|
59 | * const transaction = datastore.transaction();
|
60 | * ```
|
61 | */
|
62 | class Transaction extends request_1.DatastoreRequest {
|
63 | constructor(datastore, options) {
|
64 | super();
|
65 | _Transaction_instances.add(this);
|
66 | _Transaction_mutex.set(this, new async_mutex_1.Mutex());
|
67 | _Transaction_state.set(this, TransactionState.NOT_STARTED);
|
68 | /**
|
69 | * @name Transaction#datastore
|
70 | * @type {Datastore}
|
71 | */
|
72 | this.datastore = datastore;
|
73 | /**
|
74 | * @name Transaction#namespace
|
75 | * @type {string}
|
76 | */
|
77 | this.namespace = datastore.namespace;
|
78 | options = options || {};
|
79 | this.id = options.id;
|
80 | this.readOnly = options.readOnly === true;
|
81 | this.request = datastore.request_.bind(datastore);
|
82 | // A queue for entity modifications made during the transaction.
|
83 | this.modifiedEntities_ = [];
|
84 | // Queue the callbacks that process the API responses.
|
85 | this.requestCallbacks_ = [];
|
86 | // Queue the requests to make when we send the transactional commit.
|
87 | this.requests_ = [];
|
88 | }
|
89 | commit(gaxOptionsOrCallback, cb) {
|
90 | const callback = typeof gaxOptionsOrCallback === 'function'
|
91 | ? gaxOptionsOrCallback
|
92 | : typeof cb === 'function'
|
93 | ? cb
|
94 | : () => { };
|
95 | const gaxOptions = typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
|
96 | // This ensures that the transaction is started before calling runCommit
|
97 | __classPrivateFieldGet(this, _Transaction_instances, "m", _Transaction_withBeginTransaction).call(this, gaxOptions, () => {
|
98 | __classPrivateFieldGet(this, _Transaction_instances, "m", _Transaction_runCommit).call(this, gaxOptions, callback);
|
99 | }, callback);
|
100 | }
|
101 | createQuery(namespaceOrKind, kind) {
|
102 | return this.datastore.createQuery.call(this, namespaceOrKind, kind);
|
103 | }
|
104 | /**
|
105 | * Create an aggregation query from the query specified. See {module:datastore/query} for all
|
106 | * of the available methods.
|
107 | *
|
108 | */
|
109 | createAggregationQuery(query) {
|
110 | return this.datastore.createAggregationQuery.call(this, query);
|
111 | }
|
112 | /**
|
113 | * Delete all entities identified with the specified key(s) in the current
|
114 | * transaction.
|
115 | *
|
116 | * @param {Key|Key[]} key Datastore key object(s).
|
117 | *
|
118 | * @example
|
119 | * ```
|
120 | * const {Datastore} = require('@google-cloud/datastore');
|
121 | * const datastore = new Datastore();
|
122 | * const transaction = datastore.transaction();
|
123 | *
|
124 | * transaction.run((err) => {
|
125 | * if (err) {
|
126 | * // Error handling omitted.
|
127 | * }
|
128 | *
|
129 | * // Delete a single entity.
|
130 | * transaction.delete(datastore.key(['Company', 123]));
|
131 | *
|
132 | * // Delete multiple entities at once.
|
133 | * transaction.delete([
|
134 | * datastore.key(['Company', 123]),
|
135 | * datastore.key(['Product', 'Computer'])
|
136 | * ]);
|
137 | *
|
138 | * transaction.commit((err) => {
|
139 | * if (!err) {
|
140 | * // Transaction committed successfully.
|
141 | * }
|
142 | * });
|
143 | * });
|
144 | * ```
|
145 | */
|
146 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
147 | delete(entities) {
|
148 | arrify(entities).forEach((ent) => {
|
149 | this.modifiedEntities_.push({
|
150 | entity: {
|
151 | key: ent,
|
152 | },
|
153 | method: 'delete',
|
154 | args: [ent],
|
155 | });
|
156 | });
|
157 | }
|
158 | get(keys, optionsOrCallback, cb) {
|
159 | const options = typeof optionsOrCallback === 'object' && optionsOrCallback
|
160 | ? optionsOrCallback
|
161 | : {};
|
162 | const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
|
163 | // This ensures that the transaction is started before calling get
|
164 | __classPrivateFieldGet(this, _Transaction_instances, "m", _Transaction_withBeginTransaction).call(this, options.gaxOptions, () => {
|
165 | super.get(keys, options, callback);
|
166 | }, callback);
|
167 | }
|
168 | /**
|
169 | * Maps to {@link https://cloud.google.com/nodejs/docs/reference/datastore/latest/datastore/transaction#_google_cloud_datastore_Transaction_save_member_1_|Datastore#save}, forcing the method to be `insert`.
|
170 | *
|
171 | * @param {object|object[]} entities Datastore key object(s).
|
172 | * @param {Key} entities.key Datastore key object.
|
173 | * @param {string[]} [entities.excludeFromIndexes] Exclude properties from
|
174 | * indexing using a simple JSON path notation. See the examples in
|
175 | * {@link Datastore#save} to see how to target properties at different
|
176 | * levels of nesting within your entity.
|
177 | * @param {object} entities.data Data to save with the provided key.
|
178 | */
|
179 | insert(entities) {
|
180 | entities = arrify(entities)
|
181 | .map(request_1.DatastoreRequest.prepareEntityObject_)
|
182 | .map((x) => {
|
183 | x.method = 'insert';
|
184 | return x;
|
185 | });
|
186 | this.save(entities);
|
187 | }
|
188 | rollback(gaxOptionsOrCallback, cb) {
|
189 | const gaxOptions = typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
|
190 | const callback = typeof gaxOptionsOrCallback === 'function' ? gaxOptionsOrCallback : cb;
|
191 | this.request_({
|
192 | client: 'DatastoreClient',
|
193 | method: 'rollback',
|
194 | gaxOpts: gaxOptions || {},
|
195 | }, (err, resp) => {
|
196 | this.skipCommit = true;
|
197 | callback(err || null, resp);
|
198 | });
|
199 | }
|
200 | run(optionsOrCallback, cb) {
|
201 | const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
|
202 | const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
|
203 | __classPrivateFieldGet(this, _Transaction_mutex, "f").runExclusive(async () => {
|
204 | if (__classPrivateFieldGet(this, _Transaction_state, "f") === TransactionState.NOT_STARTED) {
|
205 | const runResults = await __classPrivateFieldGet(this, _Transaction_instances, "m", _Transaction_beginTransactionAsync).call(this, options);
|
206 | __classPrivateFieldGet(this, _Transaction_instances, "m", _Transaction_processBeginResults).call(this, runResults, callback);
|
207 | }
|
208 | else {
|
209 | process.emitWarning('run has already been called and should not be called again.');
|
210 | callback(null, this, { transaction: this.id });
|
211 | }
|
212 | });
|
213 | }
|
214 | runAggregationQuery(query, optionsOrCallback, cb) {
|
215 | const options = typeof optionsOrCallback === 'object' && optionsOrCallback
|
216 | ? optionsOrCallback
|
217 | : {};
|
218 | const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
|
219 | // This ensures that the transaction is started before calling runAggregationQuery
|
220 | __classPrivateFieldGet(this, _Transaction_instances, "m", _Transaction_withBeginTransaction).call(this, options.gaxOptions, () => {
|
221 | super.runAggregationQuery(query, options, callback);
|
222 | }, callback);
|
223 | }
|
224 | runQuery(query, optionsOrCallback, cb) {
|
225 | const options = typeof optionsOrCallback === 'object' && optionsOrCallback
|
226 | ? optionsOrCallback
|
227 | : {};
|
228 | const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
|
229 | // This ensures that the transaction is started before calling runQuery
|
230 | __classPrivateFieldGet(this, _Transaction_instances, "m", _Transaction_withBeginTransaction).call(this, options.gaxOptions, () => {
|
231 | super.runQuery(query, options, callback);
|
232 | }, callback);
|
233 | }
|
234 | /**
|
235 | * Insert or update the specified object(s) in the current transaction. If a
|
236 | * key is incomplete, its associated object is inserted and the original Key
|
237 | * object is updated to contain the generated ID.
|
238 | *
|
239 | * This method will determine the correct Datastore method to execute
|
240 | * (`upsert`, `insert`, or `update`) by using the key(s) provided. For
|
241 | * example, if you provide an incomplete key (one without an ID), the request
|
242 | * will create a new entity and have its ID automatically assigned. If you
|
243 | * provide a complete key, the entity will be updated with the data specified.
|
244 | *
|
245 | * By default, all properties are indexed. To prevent a property from being
|
246 | * included in *all* indexes, you must supply an `excludeFromIndexes` array.
|
247 | * See below for an example.
|
248 | *
|
249 | * @param {object|object[]} entities Datastore key object(s).
|
250 | * @param {Key} entities.key Datastore key object.
|
251 | * @param {string[]} [entities.excludeFromIndexes] Exclude properties from
|
252 | * indexing using a simple JSON path notation. See the example below to
|
253 | * see how to target properties at different levels of nesting within your
|
254 | * entity.
|
255 | * @param {object} entities.data Data to save with the provided key.
|
256 | *
|
257 | * @example
|
258 | * ```
|
259 | * <caption>Save a single entity.</caption>
|
260 | * const {Datastore} = require('@google-cloud/datastore');
|
261 | * const datastore = new Datastore();
|
262 | * const transaction = datastore.transaction();
|
263 | *
|
264 | * // Notice that we are providing an incomplete key. After the transaction is
|
265 | * // committed, the Key object held by the `key` variable will be populated
|
266 | * // with a path containing its generated ID.
|
267 | * //-
|
268 | * const key = datastore.key('Company');
|
269 | *
|
270 | * transaction.run((err) => {
|
271 | * if (err) {
|
272 | * // Error handling omitted.
|
273 | * }
|
274 | *
|
275 | * transaction.save({
|
276 | * key: key,
|
277 | * data: {
|
278 | * rating: '10'
|
279 | * }
|
280 | * });
|
281 | *
|
282 | * transaction.commit((err) => {
|
283 | * if (!err) {
|
284 | * // Data saved successfully.
|
285 | * }
|
286 | * });
|
287 | * });
|
288 | *
|
289 | * ```
|
290 | * @example
|
291 | * ```
|
292 | * const {Datastore} = require('@google-cloud/datastore');
|
293 | * const datastore = new Datastore();
|
294 | * const transaction = datastore.transaction();
|
295 | *
|
296 | * // Use an array, `excludeFromIndexes`, to exclude properties from indexing.
|
297 | * // This will allow storing string values larger than 1500 bytes.
|
298 | *
|
299 | * transaction.run((err) => {
|
300 | * if (err) {
|
301 | * // Error handling omitted.
|
302 | * }
|
303 | *
|
304 | * transaction.save({
|
305 | * key: key,
|
306 | * excludeFromIndexes: [
|
307 | * 'description',
|
308 | * 'embeddedEntity.description',
|
309 | * 'arrayValue[].description'
|
310 | * ],
|
311 | * data: {
|
312 | * description: 'Long string (...)',
|
313 | * embeddedEntity: {
|
314 | * description: 'Long string (...)'
|
315 | * },
|
316 | * arrayValue: [
|
317 | * {
|
318 | * description: 'Long string (...)'
|
319 | * }
|
320 | * ]
|
321 | * }
|
322 | * });
|
323 | *
|
324 | * transaction.commit((err) => {
|
325 | * if (!err) {
|
326 | * // Data saved successfully.
|
327 | * }
|
328 | * });
|
329 | * });
|
330 | *
|
331 | * ```
|
332 | * @example
|
333 | * ```
|
334 | * <caption>Save multiple entities at once.</caption>
|
335 | * const {Datastore} = require('@google-cloud/datastore');
|
336 | * const datastore = new Datastore();
|
337 | * const transaction = datastore.transaction();
|
338 | * const companyKey = datastore.key(['Company', 123]);
|
339 | * const productKey = datastore.key(['Product', 'Computer']);
|
340 | *
|
341 | * transaction.run((err) => {
|
342 | * if (err) {
|
343 | * // Error handling omitted.
|
344 | * }
|
345 | *
|
346 | * transaction.save([
|
347 | * {
|
348 | * key: companyKey,
|
349 | * data: {
|
350 | * HQ: 'Dallas, TX'
|
351 | * }
|
352 | * },
|
353 | * {
|
354 | * key: productKey,
|
355 | * data: {
|
356 | * vendor: 'Dell'
|
357 | * }
|
358 | * }
|
359 | * ]);
|
360 | *
|
361 | * transaction.commit((err) => {
|
362 | * if (!err) {
|
363 | * // Data saved successfully.
|
364 | * }
|
365 | * });
|
366 | * });
|
367 | * ```
|
368 | */
|
369 | save(entities) {
|
370 | arrify(entities).forEach((ent) => {
|
371 | this.modifiedEntities_.push({
|
372 | entity: {
|
373 | key: ent.key,
|
374 | },
|
375 | method: 'save',
|
376 | args: [ent],
|
377 | });
|
378 | });
|
379 | }
|
380 | /**
|
381 | * Maps to {@link https://cloud.google.com/nodejs/docs/reference/datastore/latest/datastore/transaction#_google_cloud_datastore_Transaction_save_member_1_|Datastore#save}, forcing the method to be `update`.
|
382 | *
|
383 | * @param {object|object[]} entities Datastore key object(s).
|
384 | * @param {Key} entities.key Datastore key object.
|
385 | * @param {string[]} [entities.excludeFromIndexes] Exclude properties from
|
386 | * indexing using a simple JSON path notation. See the examples in
|
387 | * {@link Datastore#save} to see how to target properties at different
|
388 | * levels of nesting within your entity.
|
389 | * @param {object} entities.data Data to save with the provided key.
|
390 | */
|
391 | update(entities) {
|
392 | entities = arrify(entities)
|
393 | .map(request_1.DatastoreRequest.prepareEntityObject_)
|
394 | .map((x) => {
|
395 | x.method = 'update';
|
396 | return x;
|
397 | });
|
398 | this.save(entities);
|
399 | }
|
400 | /**
|
401 | * Maps to {@link https://cloud.google.com/nodejs/docs/reference/datastore/latest/datastore/transaction#_google_cloud_datastore_Transaction_save_member_1_|Datastore#save}, forcing the method to be `upsert`.
|
402 | *
|
403 | * @param {object|object[]} entities Datastore key object(s).
|
404 | * @param {Key} entities.key Datastore key object.
|
405 | * @param {string[]} [entities.excludeFromIndexes] Exclude properties from
|
406 | * indexing using a simple JSON path notation. See the examples in
|
407 | * {@link Datastore#save} to see how to target properties at different
|
408 | * levels of nesting within your entity.
|
409 | * @param {object} entities.data Data to save with the provided key.
|
410 | */
|
411 | upsert(entities) {
|
412 | entities = arrify(entities)
|
413 | .map(request_1.DatastoreRequest.prepareEntityObject_)
|
414 | .map((x) => {
|
415 | x.method = 'upsert';
|
416 | return x;
|
417 | });
|
418 | this.save(entities);
|
419 | }
|
420 | }
|
421 | exports.Transaction = Transaction;
|
422 | _Transaction_mutex = new WeakMap(), _Transaction_state = new WeakMap(), _Transaction_instances = new WeakSet(), _Transaction_runCommit = function _Transaction_runCommit(gaxOptions, callback) {
|
423 | if (this.skipCommit) {
|
424 | setImmediate(callback);
|
425 | return;
|
426 | }
|
427 | const keys = {};
|
428 | this.modifiedEntities_
|
429 | // Reverse the order of the queue to respect the "last queued request
|
430 | // wins" behavior.
|
431 | .reverse()
|
432 | // Limit the operations we're going to send through to only the most
|
433 | // recently queued operations. E.g., if a user tries to save with the
|
434 | // same key they just asked to be deleted, the delete request will be
|
435 | // ignored, giving preference to the save operation.
|
436 | .filter((modifiedEntity) => {
|
437 | const key = modifiedEntity.entity.key;
|
438 | if (!entity_1.entity.isKeyComplete(key))
|
439 | return true;
|
440 | const stringifiedKey = JSON.stringify(modifiedEntity.entity.key);
|
441 | if (!keys[stringifiedKey]) {
|
442 | keys[stringifiedKey] = true;
|
443 | return true;
|
444 | }
|
445 | return false;
|
446 | })
|
447 | // Group entities together by method: `save` mutations, then `delete`.
|
448 | // Note: `save` mutations being first is required to maintain order when
|
449 | // assigning IDs to incomplete keys.
|
450 | .sort((a, b) => {
|
451 | return a.method < b.method ? 1 : a.method > b.method ? -1 : 0;
|
452 | })
|
453 | // Group arguments together so that we only make one call to each
|
454 | // method. This is important for `DatastoreRequest.save`, especially, as
|
455 | // that method handles assigning auto-generated IDs to the original keys
|
456 | // passed in. When we eventually execute the `save` method's API
|
457 | // callback, having all the keys together is necessary to maintain
|
458 | // order.
|
459 | .reduce((acc, entityObject) => {
|
460 | const lastEntityObject = acc[acc.length - 1];
|
461 | const sameMethod = lastEntityObject && entityObject.method === lastEntityObject.method;
|
462 | if (!lastEntityObject || !sameMethod) {
|
463 | acc.push(entityObject);
|
464 | }
|
465 | else {
|
466 | lastEntityObject.args = lastEntityObject.args.concat(entityObject.args);
|
467 | }
|
468 | return acc;
|
469 | }, [])
|
470 | // Call each of the mutational methods (DatastoreRequest[save,delete])
|
471 | // to build up a `req` array on this instance. This will also build up a
|
472 | // `callbacks` array, that is the same callback that would run if we
|
473 | // were using `save` and `delete` outside of a transaction, to process
|
474 | // the response from the API.
|
475 | .forEach((modifiedEntity) => {
|
476 | const method = modifiedEntity.method;
|
477 | const args = modifiedEntity.args.reverse();
|
478 | _1.Datastore.prototype[method].call(this, args, () => { });
|
479 | });
|
480 | // Take the `req` array built previously, and merge them into one request to
|
481 | // send as the final transactional commit.
|
482 | const reqOpts = {
|
483 | mutations: this.requests_
|
484 | .map((x) => x.mutations)
|
485 | .reduce((a, b) => a.concat(b), []),
|
486 | };
|
487 | this.request_({
|
488 | client: 'DatastoreClient',
|
489 | method: 'commit',
|
490 | reqOpts,
|
491 | gaxOpts: gaxOptions || {},
|
492 | }, (err, resp) => {
|
493 | if (err) {
|
494 | // Rollback automatically for the user.
|
495 | this.rollback(() => {
|
496 | // Provide the error & API response from the failed commit to the
|
497 | // user. Even a failed rollback should be transparent. RE:
|
498 | // https://github.com/GoogleCloudPlatform/google-cloud-node/pull/1369#discussion_r66833976
|
499 | callback(err, resp);
|
500 | });
|
501 | return;
|
502 | }
|
503 | // The `callbacks` array was built previously. These are the callbacks
|
504 | // that handle the API response normally when using the
|
505 | // DatastoreRequest.save and .delete methods.
|
506 | this.requestCallbacks_.forEach((cb) => {
|
507 | cb(null, resp);
|
508 | });
|
509 | callback(null, resp);
|
510 | });
|
511 | }, _Transaction_processBeginResults = function _Transaction_processBeginResults(runResults, callback) {
|
512 | const err = runResults.err;
|
513 | const resp = runResults.resp;
|
514 | if (err) {
|
515 | callback(err, null, resp);
|
516 | }
|
517 | else {
|
518 | __classPrivateFieldGet(this, _Transaction_instances, "m", _Transaction_parseRunSuccess).call(this, runResults);
|
519 | callback(null, this, resp);
|
520 | }
|
521 | }, _Transaction_parseRunSuccess = function _Transaction_parseRunSuccess(runResults) {
|
522 | const resp = runResults.resp;
|
523 | this.id = resp.transaction;
|
524 | __classPrivateFieldSet(this, _Transaction_state, TransactionState.IN_PROGRESS, "f");
|
525 | }, _Transaction_beginTransactionAsync =
|
526 | /**
|
527 | * This async function makes a beginTransaction call and returns a promise with
|
528 | * the information returned from the call that was made.
|
529 | *
|
530 | * @param {RunOptions} options The options used for a beginTransaction call.
|
531 | * @returns {Promise<RequestPromiseReturnType>}
|
532 | *
|
533 | *
|
534 | **/
|
535 | async function _Transaction_beginTransactionAsync(options) {
|
536 | const reqOpts = {
|
537 | transactionOptions: {},
|
538 | };
|
539 | if (options.readOnly || this.readOnly) {
|
540 | reqOpts.transactionOptions.readOnly = {};
|
541 | }
|
542 | if (options.transactionId || this.id) {
|
543 | reqOpts.transactionOptions.readWrite = {
|
544 | previousTransaction: options.transactionId || this.id,
|
545 | };
|
546 | }
|
547 | if (options.transactionOptions) {
|
548 | reqOpts.transactionOptions = options.transactionOptions;
|
549 | }
|
550 | return new Promise((resolve) => {
|
551 | this.request_({
|
552 | client: 'DatastoreClient',
|
553 | method: 'beginTransaction',
|
554 | reqOpts,
|
555 | gaxOpts: options.gaxOptions,
|
556 | },
|
557 | // Always use resolve because then this function can return both the error and the response
|
558 | (err, resp) => {
|
559 | resolve({
|
560 | err,
|
561 | resp,
|
562 | });
|
563 | });
|
564 | });
|
565 | }, _Transaction_withBeginTransaction = function _Transaction_withBeginTransaction(gaxOptions, fn, callback) {
|
566 | (async () => {
|
567 | if (__classPrivateFieldGet(this, _Transaction_state, "f") === TransactionState.NOT_STARTED) {
|
568 | try {
|
569 | await __classPrivateFieldGet(this, _Transaction_mutex, "f").runExclusive(async () => {
|
570 | if (__classPrivateFieldGet(this, _Transaction_state, "f") === TransactionState.NOT_STARTED) {
|
571 | // This sends an rpc call to get the transaction id
|
572 | const runResults = await __classPrivateFieldGet(this, _Transaction_instances, "m", _Transaction_beginTransactionAsync).call(this, {
|
573 | gaxOptions,
|
574 | });
|
575 | if (runResults.err) {
|
576 | // The rpc getting the id was unsuccessful.
|
577 | // Do not call the wrapped function.
|
578 | throw runResults.err;
|
579 | }
|
580 | __classPrivateFieldGet(this, _Transaction_instances, "m", _Transaction_parseRunSuccess).call(this, runResults);
|
581 | // The rpc saving the transaction id was successful.
|
582 | // Now the wrapped function fn will be called.
|
583 | }
|
584 | });
|
585 | }
|
586 | catch (err) {
|
587 | // Handle an error produced by the beginTransactionAsync call
|
588 | return callback(err);
|
589 | }
|
590 | }
|
591 | return fn();
|
592 | })();
|
593 | };
|
594 | /*! Developer Documentation
|
595 | *
|
596 | * All async methods (except for streams) will return a Promise in the event
|
597 | * that a callback is omitted.
|
598 | */
|
599 | (0, promisify_1.promisifyAll)(Transaction, {
|
600 | exclude: [
|
601 | 'createAggregationQuery',
|
602 | 'createQuery',
|
603 | 'delete',
|
604 | 'insert',
|
605 | '#runAsync',
|
606 | 'save',
|
607 | 'update',
|
608 | 'upsert',
|
609 | ],
|
610 | });
|
611 | //# sourceMappingURL=transaction.js.map |
\ | No newline at end of file |