Skip to content

Commit e4c1279

Browse files
committed
Implement db.withTransaction helper
1 parent 0d662fb commit e4c1279

File tree

2 files changed

+152
-1
lines changed

2 files changed

+152
-1
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,21 @@ This driver uses semantic versioning:
5252

5353
- Added cluster rebalancing methods to `Database` (DE-583)
5454

55+
- Added `db.withTransaction` helper method for streaming transactions ([#786](https://github.com/arangodb/arangojs/discussions/786))
56+
57+
This method allows using streaming transactions without having to manually
58+
begin and commit or abort the transaction.
59+
60+
```ts
61+
const vertices = db.collection("vertices");
62+
const edges = db.collection("edges");
63+
const info = await db.withTransaction([vertices, edges], async (step) => {
64+
const start = await step(() => vertices.document("a"));
65+
const end = await step(() => vertices.document("b"));
66+
return await step(() => edges.save({ _from: start._id, _to: end._id }));
67+
});
68+
```
69+
5570
## [8.3.1] - 2023-06-05
5671

5772
### Changed

src/database.ts

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3677,7 +3677,7 @@ export class Database {
36773677
* {@link graph.GraphVertexCollection}, {@link graph.GraphEdgeCollection} as well as
36783678
* (in TypeScript) {@link collection.DocumentCollection} and {@link collection.EdgeCollection}.
36793679
*
3680-
* @param collections - A collection that can be read from and written to
3680+
* @param collection - A collection that can be read from and written to
36813681
* during the transaction.
36823682
* @param options - Options for the transaction.
36833683
*
@@ -3721,6 +3721,142 @@ export class Database {
37213721
);
37223722
}
37233723

3724+
/**
3725+
* Begins and commits a transaction using the given callback. Individual
3726+
* requests that are part of the transaction need to be wrapped in the step
3727+
* function passed into the callback. If the promise returned by the callback
3728+
* is rejected, the transaction will be aborted.
3729+
*
3730+
* Collections can be specified as collection names (strings) or objects
3731+
* implementing the {@link collection.ArangoCollection} interface: `Collection`,
3732+
* {@link graph.GraphVertexCollection}, {@link graph.GraphEdgeCollection} as
3733+
* well as (in TypeScript) {@link collection.DocumentCollection} and
3734+
* {@link collection.EdgeCollection}.
3735+
*
3736+
* @param collections - Collections involved in the transaction.
3737+
* @param callback - Callback function executing the transaction steps.
3738+
* @param options - Options for the transaction.
3739+
*
3740+
* @example
3741+
* ```js
3742+
* const vertices = db.collection("vertices");
3743+
* const edges = db.collection("edges");
3744+
* await db.withTransaction(
3745+
* {
3746+
* read: ["vertices"],
3747+
* write: [edges] // collection instances can be passed directly
3748+
* },
3749+
* async (step) => {
3750+
* const start = await step(() => vertices.document("a"));
3751+
* const end = await step(() => vertices.document("b"));
3752+
* await step(() => edges.save({ _from: start._id, _to: end._id }));
3753+
* }
3754+
* );
3755+
* ```
3756+
*/
3757+
withTransaction<T>(
3758+
collections: TransactionCollections,
3759+
callback: (step: Transaction["step"]) => Promise<T>,
3760+
options?: TransactionOptions
3761+
): Promise<T>;
3762+
/**
3763+
* Begins and commits a transaction using the given callback. Individual
3764+
* requests that are part of the transaction need to be wrapped in the step
3765+
* function passed into the callback. If the promise returned by the callback
3766+
* is rejected, the transaction will be aborted.
3767+
*
3768+
* Collections can be specified as collection names (strings) or objects
3769+
* implementing the {@link collection.ArangoCollection} interface: `Collection`,
3770+
* {@link graph.GraphVertexCollection}, {@link graph.GraphEdgeCollection} as well as
3771+
* (in TypeScript) {@link collection.DocumentCollection} and {@link collection.EdgeCollection}.
3772+
*
3773+
* @param collections - Collections that can be read from and written to
3774+
* during the transaction.
3775+
* @param callback - Callback function executing the transaction steps.
3776+
* @param options - Options for the transaction.
3777+
*
3778+
* @example
3779+
* ```js
3780+
* const vertices = db.collection("vertices");
3781+
* const edges = db.collection("edges");
3782+
* await db.withTransaction(
3783+
* [
3784+
* "vertices",
3785+
* edges, // collection instances can be passed directly
3786+
* ],
3787+
* async (step) => {
3788+
* const start = await step(() => vertices.document("a"));
3789+
* const end = await step(() => vertices.document("b"));
3790+
* await step(() => edges.save({ _from: start._id, _to: end._id }));
3791+
* }
3792+
* );
3793+
* ```
3794+
*/
3795+
withTransaction<T>(
3796+
collections: (string | ArangoCollection)[],
3797+
callback: (step: Transaction["step"]) => Promise<T>,
3798+
options?: TransactionOptions
3799+
): Promise<T>;
3800+
/**
3801+
* Begins and commits a transaction using the given callback. Individual
3802+
* requests that are part of the transaction need to be wrapped in the step
3803+
* function passed into the callback. If the promise returned by the callback
3804+
* is rejected, the transaction will be aborted.
3805+
*
3806+
* The Collection can be specified as a collection name (string) or an object
3807+
* implementing the {@link collection.ArangoCollection} interface: `Collection`,
3808+
* {@link graph.GraphVertexCollection}, {@link graph.GraphEdgeCollection} as well as
3809+
* (in TypeScript) {@link collection.DocumentCollection} and {@link collection.EdgeCollection}.
3810+
*
3811+
* @param collection - A collection that can be read from and written to
3812+
* during the transaction.
3813+
* @param callback - Callback function executing the transaction steps.
3814+
* @param options - Options for the transaction.
3815+
*
3816+
* @example
3817+
* ```js
3818+
* const vertices = db.collection("vertices");
3819+
* const start = vertices.document("a");
3820+
* const end = vertices.document("b");
3821+
* const edges = db.collection("edges");
3822+
* await db.withTransaction(
3823+
* edges, // collection instances can be passed directly
3824+
* async (step) => {
3825+
* await step(() => edges.save({ _from: start._id, _to: end._id }));
3826+
* }
3827+
* );
3828+
* ```
3829+
*/
3830+
withTransaction<T>(
3831+
collection: string | ArangoCollection,
3832+
callback: (step: Transaction["step"]) => Promise<T>,
3833+
options?: TransactionOptions
3834+
): Promise<T>;
3835+
async withTransaction<T>(
3836+
collections:
3837+
| TransactionCollections
3838+
| (string | ArangoCollection)[]
3839+
| string
3840+
| ArangoCollection,
3841+
callback: (step: Transaction["step"]) => Promise<T>,
3842+
options: TransactionOptions = {}
3843+
): Promise<T> {
3844+
const trx = await this.beginTransaction(
3845+
collections as TransactionCollections,
3846+
options
3847+
);
3848+
try {
3849+
const result = await callback((fn) => trx.step(fn));
3850+
await trx.commit();
3851+
return result;
3852+
} catch (e) {
3853+
try {
3854+
await trx.abort();
3855+
} catch {}
3856+
throw e;
3857+
}
3858+
}
3859+
37243860
/**
37253861
* Fetches all active transactions from the database and returns an array of
37263862
* transaction descriptions.

0 commit comments

Comments
 (0)