UNPKG

14.3 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
8
9var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
10
11var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
12
13var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
14
15var _get2 = require('babel-runtime/helpers/get');
16
17var _get3 = _interopRequireDefault(_get2);
18
19var _inherits2 = require('babel-runtime/helpers/inherits');
20
21var _inherits3 = _interopRequireDefault(_inherits2);
22
23var _promise = require('babel-runtime/core-js/promise');
24
25var _promise2 = _interopRequireDefault(_promise);
26
27var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
28
29var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
30
31var _createClass2 = require('babel-runtime/helpers/createClass');
32
33var _createClass3 = _interopRequireDefault(_createClass2);
34
35var _streamObserver = require('./internal/stream-observer');
36
37var _streamObserver2 = _interopRequireDefault(_streamObserver);
38
39var _result = require('./result');
40
41var _result2 = _interopRequireDefault(_result);
42
43var _util = require('./internal/util');
44
45var _connectionHolder = require('./internal/connection-holder');
46
47var _bookmark = require('./internal/bookmark');
48
49var _bookmark2 = _interopRequireDefault(_bookmark);
50
51function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
52
53/**
54 * Represents a transaction in the Neo4j database.
55 *
56 * @access public
57 */
58var Transaction = function () {
59 /**
60 * @constructor
61 * @param {ConnectionHolder} connectionHolder - the connection holder to get connection from.
62 * @param {function()} onClose - Function to be called when transaction is committed or rolled back.
63 * @param {function(error: Error): Error} errorTransformer callback use to transform error.
64 * @param {Bookmark} bookmark bookmark for transaction begin.
65 * @param {function(bookmark: Bookmark)} onBookmark callback invoked when new bookmark is produced.
66 */
67 function Transaction(connectionHolder, onClose, errorTransformer, bookmark, onBookmark) {
68 (0, _classCallCheck3.default)(this, Transaction);
69
70 this._connectionHolder = connectionHolder;
71 var streamObserver = new _TransactionStreamObserver(this);
72
73 this._connectionHolder.getConnection(streamObserver).then(function (conn) {
74 conn.run('BEGIN', bookmark.asBeginTransactionParameters(), streamObserver);
75 conn.pullAll(streamObserver);
76 }).catch(function (error) {
77 return streamObserver.onError(error);
78 });
79
80 this._state = _states.ACTIVE;
81 this._onClose = onClose;
82 this._errorTransformer = errorTransformer;
83 this._onBookmark = onBookmark;
84 }
85
86 /**
87 * Run Cypher statement
88 * Could be called with a statement object i.e.: <code>{text: "MATCH ...", parameters: {param: 1}}</code>
89 * or with the statement and parameters as separate arguments.
90 * @param {mixed} statement - Cypher statement to execute
91 * @param {Object} parameters - Map with parameters to use in statement
92 * @return {Result} New Result
93 */
94
95
96 (0, _createClass3.default)(Transaction, [{
97 key: 'run',
98 value: function run(statement, parameters) {
99 var _validateStatementAnd = (0, _util.validateStatementAndParameters)(statement, parameters),
100 query = _validateStatementAnd.query,
101 params = _validateStatementAnd.params;
102
103 return this._state.run(this._connectionHolder, new _TransactionStreamObserver(this), query, params);
104 }
105
106 /**
107 * Commits the transaction and returns the result.
108 *
109 * After committing the transaction can no longer be used.
110 *
111 * @returns {Result} New Result
112 */
113
114 }, {
115 key: 'commit',
116 value: function commit() {
117 var committed = this._state.commit(this._connectionHolder, new _TransactionStreamObserver(this));
118 this._state = committed.state;
119 //clean up
120 this._onClose();
121 return committed.result;
122 }
123
124 /**
125 * Rollbacks the transaction.
126 *
127 * After rolling back, the transaction can no longer be used.
128 *
129 * @returns {Result} New Result
130 */
131
132 }, {
133 key: 'rollback',
134 value: function rollback() {
135 var committed = this._state.rollback(this._connectionHolder, new _TransactionStreamObserver(this));
136 this._state = committed.state;
137 //clean up
138 this._onClose();
139 return committed.result;
140 }
141
142 /**
143 * Check if this transaction is active, which means commit and rollback did not happen.
144 * @return {boolean} <code>true</code> when not committed and not rolled back, <code>false</code> otherwise.
145 */
146
147 }, {
148 key: 'isOpen',
149 value: function isOpen() {
150 return this._state == _states.ACTIVE;
151 }
152 }, {
153 key: '_onError',
154 value: function _onError() {
155 var _this = this;
156
157 if (this.isOpen()) {
158 // attempt to rollback, useful when Transaction#run() failed
159 return this.rollback().catch(function (ignoredError) {
160 // ignore all errors because it is best effort and transaction might already be rolled back
161 }).then(function () {
162 // after rollback attempt change this transaction's state to FAILED
163 _this._state = _states.FAILED;
164 });
165 } else {
166 // error happened in in-active transaction, just to the cleanup and change state to FAILED
167 this._state = _states.FAILED;
168 this._onClose();
169 // no async actions needed - return resolved promise
170 return _promise2.default.resolve();
171 }
172 }
173 }]);
174 return Transaction;
175}();
176
177/** Internal stream observer used for transactional results*/
178/**
179 * Copyright (c) 2002-2018 Neo4j Sweden AB [http://neo4j.com]
180 *
181 * This file is part of Neo4j.
182 *
183 * Licensed under the Apache License, Version 2.0 (the "License");
184 * you may not use this file except in compliance with the License.
185 * You may obtain a copy of the License at
186 *
187 * http://www.apache.org/licenses/LICENSE-2.0
188 *
189 * Unless required by applicable law or agreed to in writing, software
190 * distributed under the License is distributed on an "AS IS" BASIS,
191 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
192 * See the License for the specific language governing permissions and
193 * limitations under the License.
194 */
195
196
197var _TransactionStreamObserver = function (_StreamObserver) {
198 (0, _inherits3.default)(_TransactionStreamObserver, _StreamObserver);
199
200 function _TransactionStreamObserver(tx) {
201 (0, _classCallCheck3.default)(this, _TransactionStreamObserver);
202
203 var _this2 = (0, _possibleConstructorReturn3.default)(this, (_TransactionStreamObserver.__proto__ || (0, _getPrototypeOf2.default)(_TransactionStreamObserver)).call(this, tx._errorTransformer || function (err) {
204 return err;
205 }));
206
207 _this2._tx = tx;
208 //this is to to avoid multiple calls to onError caused by IGNORED
209 _this2._hasFailed = false;
210 return _this2;
211 }
212
213 (0, _createClass3.default)(_TransactionStreamObserver, [{
214 key: 'onError',
215 value: function onError(error) {
216 var _this3 = this;
217
218 if (!this._hasFailed) {
219 this._tx._onError().then(function () {
220 (0, _get3.default)(_TransactionStreamObserver.prototype.__proto__ || (0, _getPrototypeOf2.default)(_TransactionStreamObserver.prototype), 'onError', _this3).call(_this3, error);
221 _this3._hasFailed = true;
222 });
223 }
224 }
225 }, {
226 key: 'onCompleted',
227 value: function onCompleted(meta) {
228 (0, _get3.default)(_TransactionStreamObserver.prototype.__proto__ || (0, _getPrototypeOf2.default)(_TransactionStreamObserver.prototype), 'onCompleted', this).call(this, meta);
229 var bookmark = new _bookmark2.default(meta.bookmark);
230 this._tx._onBookmark(bookmark);
231 }
232 }]);
233 return _TransactionStreamObserver;
234}(_streamObserver2.default);
235
236/** internal state machine of the transaction*/
237
238
239var _states = {
240 //The transaction is running with no explicit success or failure marked
241 ACTIVE: {
242 commit: function commit(connectionHolder, observer) {
243 return { result: _runPullAll("COMMIT", connectionHolder, observer),
244 state: _states.SUCCEEDED };
245 },
246 rollback: function rollback(connectionHolder, observer) {
247 return { result: _runPullAll("ROLLBACK", connectionHolder, observer), state: _states.ROLLED_BACK };
248 },
249 run: function run(connectionHolder, observer, statement, parameters) {
250 connectionHolder.getConnection(observer).then(function (conn) {
251 conn.run(statement, parameters || {}, observer);
252 conn.pullAll(observer);
253 conn.sync();
254 }).catch(function (error) {
255 return observer.onError(error);
256 });
257
258 return _newRunResult(observer, statement, parameters, function () {
259 return observer.serverMetadata();
260 });
261 }
262 },
263
264 //An error has occurred, transaction can no longer be used and no more messages will
265 // be sent for this transaction.
266 FAILED: {
267 commit: function commit(connectionHolder, observer) {
268 observer.onError({
269 error: "Cannot commit statements in this transaction, because previous statements in the " + "transaction has failed and the transaction has been rolled back. Please start a new" + " transaction to run another statement."
270 });
271 return { result: _newDummyResult(observer, "COMMIT", {}), state: _states.FAILED };
272 },
273 rollback: function rollback(connectionHolder, observer) {
274 observer.onError({ error: "Cannot rollback transaction, because previous statements in the " + "transaction has failed and the transaction has already been rolled back." });
275 return { result: _newDummyResult(observer, "ROLLBACK", {}), state: _states.FAILED };
276 },
277 run: function run(connectionHolder, observer, statement, parameters) {
278 observer.onError({ error: "Cannot run statement, because previous statements in the " + "transaction has failed and the transaction has already been rolled back." });
279 return _newDummyResult(observer, statement, parameters);
280 }
281 },
282
283 //This transaction has successfully committed
284 SUCCEEDED: {
285 commit: function commit(connectionHolder, observer) {
286 observer.onError({
287 error: "Cannot commit statements in this transaction, because commit has already been successfully called on the transaction and transaction has been closed. Please start a new" + " transaction to run another statement."
288 });
289 return { result: _newDummyResult(observer, "COMMIT", {}), state: _states.SUCCEEDED };
290 },
291 rollback: function rollback(connectionHolder, observer) {
292 observer.onError({ error: "Cannot rollback transaction, because transaction has already been successfully closed." });
293 return { result: _newDummyResult(observer, "ROLLBACK", {}), state: _states.SUCCEEDED };
294 },
295 run: function run(connectionHolder, observer, statement, parameters) {
296 observer.onError({ error: "Cannot run statement, because transaction has already been successfully closed." });
297 return _newDummyResult(observer, statement, parameters);
298 }
299 },
300
301 //This transaction has been rolled back
302 ROLLED_BACK: {
303 commit: function commit(connectionHolder, observer) {
304 observer.onError({
305 error: "Cannot commit this transaction, because it has already been rolled back."
306 });
307 return { result: _newDummyResult(observer, "COMMIT", {}), state: _states.ROLLED_BACK };
308 },
309 rollback: function rollback(connectionHolder, observer) {
310 observer.onError({ error: "Cannot rollback transaction, because transaction has already been rolled back." });
311 return { result: _newDummyResult(observer, "ROLLBACK", {}), state: _states.ROLLED_BACK };
312 },
313 run: function run(connectionHolder, observer, statement, parameters) {
314 observer.onError({ error: "Cannot run statement, because transaction has already been rolled back." });
315 return _newDummyResult(observer, statement, parameters);
316 }
317 }
318};
319
320function _runPullAll(msg, connectionHolder, observer) {
321 connectionHolder.getConnection(observer).then(function (conn) {
322 conn.run(msg, {}, observer);
323 conn.pullAll(observer);
324 conn.sync();
325 }).catch(function (error) {
326 return observer.onError(error);
327 });
328
329 // for commit & rollback we need result that uses real connection holder and notifies it when
330 // connection is not needed and can be safely released to the pool
331 return new _result2.default(observer, msg, {}, emptyMetadataSupplier, connectionHolder);
332}
333
334/**
335 * Creates a {@link Result} with empty connection holder.
336 * Should be used as a result for running cypher statements. They can result in metadata but should not
337 * influence real connection holder to release connections because single transaction can have
338 * {@link Transaction#run} called multiple times.
339 * @param {StreamObserver} observer - an observer for the created result.
340 * @param {string} statement - the cypher statement that produced the result.
341 * @param {object} parameters - the parameters for cypher statement that produced the result.
342 * @param {function} metadataSupplier - the function that returns a metadata object.
343 * @return {Result} new result.
344 * @private
345 */
346function _newRunResult(observer, statement, parameters, metadataSupplier) {
347 return new _result2.default(observer, statement, parameters, metadataSupplier, _connectionHolder.EMPTY_CONNECTION_HOLDER);
348}
349
350/**
351 * Creates a {@link Result} without metadata supplier and with empty connection holder.
352 * For cases when result represents an intermediate or failed action, does not require any metadata and does not
353 * need to influence real connection holder to release connections.
354 * @param {StreamObserver} observer - an observer for the created result.
355 * @param {string} statement - the cypher statement that produced the result.
356 * @param {object} parameters - the parameters for cypher statement that produced the result.
357 * @return {Result} new result.
358 * @private
359 */
360function _newDummyResult(observer, statement, parameters) {
361 return new _result2.default(observer, statement, parameters, emptyMetadataSupplier, _connectionHolder.EMPTY_CONNECTION_HOLDER);
362}
363
364function emptyMetadataSupplier() {
365 return {};
366}
367
368exports.default = Transaction;
\No newline at end of file