Skip to content

Commit ed365bd

Browse files
bigmontzrobsdedude
andauthored
Deprecate .commit(), .rollback() or .close() managed transactions (#890)
Allowing self-manage managed transactions could causing unexpected behaviours in the user code depends on how the different possible code paths in the transaction work. Co-authored-by: Robsdedude <[email protected]>
1 parent 4080b19 commit ed365bd

File tree

14 files changed

+381
-6
lines changed

14 files changed

+381
-6
lines changed

packages/core/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ import ConnectionProvider from './connection-provider'
7070
import Connection from './connection'
7171
import Transaction from './transaction'
7272
import TransactionPromise from './transaction-promise'
73+
import ManagedTransaction from './transaction-managed'
7374
import Session, { TransactionConfig } from './session'
7475
import Driver, * as driver from './driver'
7576
import auth from './auth'
@@ -136,6 +137,7 @@ const forExport = {
136137
Result,
137138
Transaction,
138139
TransactionPromise,
140+
ManagedTransaction,
139141
Session,
140142
Driver,
141143
Connection,
@@ -194,6 +196,7 @@ export {
194196
Connection,
195197
Transaction,
196198
TransactionPromise,
199+
ManagedTransaction,
197200
Session,
198201
Driver,
199202
types,

packages/core/src/session.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ import { Query, SessionMode } from './types'
3232
import Connection from './connection'
3333
import { NumberOrInteger } from './graph-types'
3434
import TransactionPromise from './transaction-promise'
35+
import ManagedTransaction from './transaction-managed'
3536

3637
type ConnectionConsumer = (connection: Connection | void) => any | undefined
37-
type TransactionWork<T> = (tx: Transaction) => Promise<T> | T
38+
type TransactionWork<T> = (tx: ManagedTransaction) => Promise<T> | T
3839

3940
interface TransactionConfig {
4041
timeout?: NumberOrInteger
@@ -336,7 +337,7 @@ class Session {
336337
* delay of 1 second and maximum retry time of 30 seconds. Maximum retry time is configurable via driver config's
337338
* `maxTransactionRetryTime` property in milliseconds.
338339
*
339-
* @param {function(tx: Transaction): Promise} transactionWork - Callback that executes operations against
340+
* @param {function(tx: ManagedTransaction): Promise} transactionWork - Callback that executes operations against
340341
* a given {@link Transaction}.
341342
* @param {TransactionConfig} [transactionConfig] - Configuration for all transactions started to execute the unit of work.
342343
* @return {Promise} Resolved promise as returned by the given function or rejected promise when given
@@ -358,7 +359,7 @@ class Session {
358359
* delay of 1 second and maximum retry time of 30 seconds. Maximum retry time is configurable via driver config's
359360
* `maxTransactionRetryTime` property in milliseconds.
360361
*
361-
* @param {function(tx: Transaction): Promise} transactionWork - Callback that executes operations against
362+
* @param {function(tx: ManagedTransaction): Promise} transactionWork - Callback that executes operations against
362363
* a given {@link Transaction}.
363364
* @param {TransactionConfig} [transactionConfig] - Configuration for all transactions started to execute the unit of work.
364365
* @return {Promise} Resolved promise as returned by the given function or rejected promise when given
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import Transaction from './transaction'
21+
22+
/**
23+
* Represents a transaction that is managed by the transaction executor.
24+
*
25+
* @public
26+
*/
27+
class ManagedTransaction extends Transaction {
28+
29+
/**
30+
* Commits the transaction and returns the result.
31+
*
32+
* After committing the transaction can no longer be used.
33+
*
34+
* @deprecated Commit should be done by returning from the transaction work.
35+
*
36+
* @returns {Promise<void>} An empty promise if committed successfully or error if any error happened during commit.
37+
*/
38+
commit(): Promise<void> {
39+
return super.commit()
40+
}
41+
42+
/**
43+
* Rollbacks the transaction.
44+
*
45+
* After rolling back, the transaction can no longer be used.
46+
*
47+
* @deprecated Rollback should be done by throwing or returning a rejected promise from the transaction work.
48+
*
49+
* @returns {Promise<void>} An empty promise if rolled back successfully or error if any error happened during
50+
* rollback.
51+
*/
52+
rollback(): Promise<void> {
53+
return super.rollback()
54+
}
55+
56+
/**
57+
* Closes the transaction
58+
*
59+
* This method will roll back the transaction if it is not already committed or rolled back.
60+
*
61+
* @deprecated Closure should not be done in transaction work. See {@link ManagedTransaction#commit} and {@link ManagedTransaction#rollback}
62+
*
63+
* @returns {Promise<void>} An empty promise if closed successfully or error if any error happened during
64+
*/
65+
close(): Promise<void> {
66+
return super.close()
67+
}
68+
}
69+
70+
export default ManagedTransaction

packages/core/src/transaction-promise.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ class TransactionPromise extends Transaction implements Promise<Transaction>{
170170

171171
/**
172172
* @access private
173+
* @returns {void}
173174
*/
174175
private _onBeginError(error: Error): void {
175176
this._beginError = error;
@@ -180,6 +181,7 @@ class TransactionPromise extends Transaction implements Promise<Transaction>{
180181

181182
/**
182183
* @access private
184+
* @returns {void}
183185
*/
184186
private _onBeginMetadata(metadata: any): void {
185187
this._beginMetadata = metadata || {};

packages/core/test/transaction.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ import { ConnectionProvider, newError, Transaction, TransactionPromise } from ".
2121
import { Bookmarks } from "../src/internal/bookmarks";
2222
import { ConnectionHolder } from "../src/internal/connection-holder";
2323
import { TxConfig } from "../src/internal/tx-config";
24+
import ManagedTransaction from "../src/transaction-managed";
2425
import FakeConnection from "./utils/connection.fake";
2526

2627

2728
testTx('Transaction', newRegularTransaction)
29+
testTx('ManagedTransaction', newManagedTransaction)
2830

2931
testTx('TransactionPromise', newTransactionPromise, () => {
3032
describe('Promise', () => {
@@ -498,6 +500,39 @@ function newRegularTransaction({
498500
return transaction
499501
}
500502

503+
function newManagedTransaction({
504+
connection,
505+
fetchSize = 1000,
506+
highRecordWatermark = 700,
507+
lowRecordWatermark = 300
508+
}: {
509+
connection: FakeConnection
510+
fetchSize?: number
511+
highRecordWatermark?: number,
512+
lowRecordWatermark?: number
513+
}): ManagedTransaction {
514+
const connectionProvider = new ConnectionProvider()
515+
connectionProvider.acquireConnection = () => Promise.resolve(connection)
516+
connectionProvider.close = () => Promise.resolve()
517+
518+
const connectionHolder = new ConnectionHolder({ connectionProvider })
519+
connectionHolder.initializeConnection()
520+
521+
const transaction = new ManagedTransaction({
522+
connectionHolder,
523+
onClose: () => { },
524+
onBookmarks: (_: Bookmarks) => { },
525+
onConnection: () => { },
526+
reactive: false,
527+
fetchSize,
528+
impersonatedUser: "",
529+
highRecordWatermark,
530+
lowRecordWatermark
531+
})
532+
533+
return transaction
534+
}
535+
501536
function newFakeConnection(): FakeConnection {
502537
return new FakeConnection()
503538
}

packages/neo4j-driver-lite/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import {
6363
Session,
6464
Transaction,
6565
TransactionPromise,
66+
ManagedTransaction,
6667
ServerInfo,
6768
Connection,
6869
driver as coreDriver,
@@ -427,6 +428,7 @@ const forExport = {
427428
Session,
428429
Transaction,
429430
TransactionPromise,
431+
ManagedTransaction,
430432
Point,
431433
Duration,
432434
LocalTime,
@@ -476,6 +478,7 @@ export {
476478
Session,
477479
Transaction,
478480
TransactionPromise,
481+
ManagedTransaction,
479482
Point,
480483
Duration,
481484
LocalTime,

packages/neo4j-driver/src/session-rx.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { flatMap, catchError, concat } from 'rxjs/operators'
2121
import RxResult from './result-rx'
2222
import { Session, internal } from 'neo4j-driver-core'
2323
import RxTransaction from './transaction-rx'
24+
import RxManagedTransaction from './transaction-managed-rx'
2425
import RxRetryLogic from './internal/retry-logic-rx'
2526

2627
const {
@@ -84,7 +85,7 @@ export default class RxSession {
8485
* Executes the provided unit of work in a {@link READ} reactive transaction which is created with the provided
8586
* transaction configuration.
8687
* @public
87-
* @param {function(txc: RxTransaction): Observable} work - A unit of work to be executed.
88+
* @param {function(txc: RxManagedTransaction): Observable} work - A unit of work to be executed.
8889
* @param {TransactionConfig} transactionConfig - Configuration for the enclosing transaction created by the driver.
8990
* @returns {Observable} - A reactive stream returned by the unit of work.
9091
*/
@@ -96,7 +97,7 @@ export default class RxSession {
9697
* Executes the provided unit of work in a {@link WRITE} reactive transaction which is created with the provided
9798
* transaction configuration.
9899
* @public
99-
* @param {function(txc: RxTransaction): Observable} work - A unit of work to be executed.
100+
* @param {function(txc: RxManagedTransaction): Observable} work - A unit of work to be executed.
100101
* @param {TransactionConfig} transactionConfig - Configuration for the enclosing transaction created by the driver.
101102
* @returns {Observable} - A reactive stream returned by the unit of work.
102103
*/
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import RxTransaction from './transaction-rx'
21+
22+
/**
23+
* Represents a RX transaction that is managed by the transaction executor.
24+
*
25+
* @public
26+
*/
27+
class RxManagedTransaction extends RxTransaction {
28+
/**
29+
* Commits the transaction.
30+
*
31+
* @public
32+
* @deprecated Commit should be done by returning from the transaction work.
33+
* @returns {Observable} - An empty observable
34+
*/
35+
commit () {
36+
return super.commit()
37+
}
38+
39+
/**
40+
* Rolls back the transaction.
41+
*
42+
* @public
43+
* @deprecated Rollback should be done by throwing or returning a rejected promise from the transaction work.
44+
* @returns {Observable} - An empty observable
45+
*/
46+
rollback () {
47+
return super.rollback()
48+
}
49+
50+
/**
51+
* Closes the transaction
52+
*
53+
* This method will roll back the transaction if it is not already committed or rolled back.
54+
* @deprecated Closure should not be done in transaction work. See {@link RxManagedTransaction#commit} and {@link RxManagedTransaction#rollback}
55+
* @returns {Observable} - An empty observable
56+
*/
57+
close () {
58+
return super.close()
59+
}
60+
}
61+
62+
export default RxManagedTransaction

0 commit comments

Comments
 (0)