@decaf-ts/transactional-decorators 0.3.5 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,6 +6,14 @@ A comprehensive TypeScript library providing transaction management capabilities
6
6
 
7
7
  > Release docs refreshed on 2025-11-26. See [workdocs/reports/RELEASE_NOTES.md](./workdocs/reports/RELEASE_NOTES.md) for ticket summaries.
8
8
 
9
+ ### Core Concepts
10
+
11
+ * **`@transactional`**: A method decorator that wraps a method in a transaction, ensuring that it is executed atomically.
12
+ * **`Transaction` Class**: The core class for managing transaction lifecycle, including creation, execution, and cleanup.
13
+ * **Locks**: The library provides different lock implementations to control concurrency.
14
+ * **`SynchronousLock`**: A simple lock that allows only one transaction to execute at a time.
15
+ * **`MultiLock`**: A more advanced lock that allows multiple transactions to execute concurrently, with a configurable limit.
16
+
9
17
 
10
18
  ![Licence](https://img.shields.io/github/license/decaf-ts/transactional-decorators.svg?style=plastic)
11
19
  ![GitHub language count](https://img.shields.io/github/languages/count/decaf-ts/transactional-decorators?style=plastic)
@@ -60,226 +68,67 @@ The Transactional Decorators library is a standalone module that provides a robu
60
68
  This library is ideal for applications that need to ensure data consistency and handle concurrent operations safely, such as database applications, financial systems, or any application where atomic operations are important.
61
69
 
62
70
 
63
- ### How to Use
64
-
65
- - [Initial Setup](./tutorials/For%20Developers.md#_initial-setup_)
66
- - [Installation](./tutorials/For%20Developers.md#installation)
71
+ # How to Use
67
72
 
68
- #### Using the @transactional Decorator
73
+ This guide provides examples of how to use the main features of the `@decaf-ts/transactional-decorators` library.
69
74
 
70
- The `@transactional` decorator is the simplest way to add transactional behavior to your methods.
75
+ ## Transactional Decorator
71
76
 
72
- **Description**: Add transactional behavior to a class method, ensuring that the method executes within a transaction context.
77
+ The `@transactional` decorator ensures that a method is executed within a transaction.
73
78
 
74
79
  ```typescript
75
80
  import { transactional } from '@decaf-ts/transactional-decorators';
76
81
 
77
- class UserService {
82
+ class MyService {
78
83
  @transactional()
79
- async createUser(userData: any): Promise<any> {
80
- // This method will be executed within a transaction
81
- // If an error occurs, the transaction will be released with the error
82
- const user = await this.userRepository.save(userData);
83
- return user;
84
- }
85
-
86
- @transactional(['custom', 'metadata'])
87
- async updateUser(userId: string, userData: any): Promise<any> {
88
- // You can pass custom metadata to the transaction
89
- const user = await this.userRepository.findById(userId);
90
- Object.assign(user, userData);
91
- return await this.userRepository.save(user);
84
+ async myTransactionalMethod() {
85
+ // This method will be executed within a transaction.
92
86
  }
93
87
  }
94
-
95
- // Using the transactional method
96
- const userService = new UserService();
97
- const newUser = await userService.createUser({ name: 'John Doe' });
98
88
  ```
99
89
 
100
- #### Using the Transaction Class Directly
101
-
102
- For more control over the transaction lifecycle, you can use the Transaction class directly.
103
-
104
- **Description**: Create and manage transactions manually for complex scenarios or when you need fine-grained control.
105
-
106
- ```typescript
107
- import { Transaction } from '@decaf-ts/transactional-decorators';
108
-
109
- // Creating a transaction
110
- const transaction = new Transaction(
111
- 'UserService', // Source
112
- 'createUser', // Method name
113
- async () => {
114
- // Transaction logic here
115
- const user = await userRepository.save({ name: 'John Doe' });
116
- return user;
117
- }
118
- );
119
-
120
- // Submitting the transaction for execution
121
- await Transaction.submit(transaction);
122
-
123
- // Using the Transaction.push method for callback-style APIs
124
- Transaction.push(
125
- userService, // The object instance
126
- userService.createUserWithCallback, // The method to call
127
- { name: 'John Doe' }, // Arguments
128
- (err, user) => {
129
- if (err) {
130
- console.error('Error creating user:', err);
131
- return;
132
- }
133
- console.log('User created:', user);
134
- }
135
- );
136
- ```
90
+ ## Locks
137
91
 
138
- #### Handling Super Calls in Transactional Methods
92
+ The library provides different lock implementations to control concurrency.
139
93
 
140
- When extending a class with transactional methods, you can use the `transactionalSuperCall` utility to ensure transaction continuity.
94
+ ### SynchronousLock
141
95
 
142
- **Description**: Maintain transaction context when calling a superclass method that is also transactional.
96
+ The `SynchronousLock` allows only one transaction to execute at a time. This is the default lock.
143
97
 
144
98
  ```typescript
145
- import { transactional, transactionalSuperCall } from '@decaf-ts/transactional-decorators';
146
-
147
- class BaseRepository {
148
- @transactional()
149
- async save(entity: any): Promise<any> {
150
- // Base save implementation
151
- return entity;
152
- }
153
- }
99
+ import { Transaction, SynchronousLock } from '@decaf-ts/transactional-decorators';
154
100
 
155
- class UserRepository extends BaseRepository {
156
- @transactional()
157
- async save(user: any): Promise<any> {
158
- // Pre-processing
159
- user.updatedAt = new Date();
160
-
161
- // Call the super method with transaction context
162
- const result = await transactionalSuperCall(super.save.bind(this), user);
163
-
164
- // Post-processing
165
- console.log('User saved:', result);
166
- return result;
167
- }
168
- }
101
+ Transaction.setLock(new SynchronousLock());
169
102
  ```
170
103
 
171
- #### Customizing the Transaction Lock
172
-
173
- You can implement your own TransactionLock to customize how transactions are processed.
104
+ ### MultiLock
174
105
 
175
- **Description**: Create a custom transaction lock implementation for specialized concurrency control.
106
+ The `MultiLock` allows multiple transactions to execute concurrently, with a configurable limit.
176
107
 
177
108
  ```typescript
178
- import { TransactionLock, Transaction } from '@decaf-ts/transactional-decorators';
179
-
180
- // Custom transaction lock that logs transactions
181
- class LoggingTransactionLock implements TransactionLock {
182
- currentTransaction?: Transaction;
183
- private pendingTransactions: Transaction[] = [];
184
-
185
- submit(transaction: Transaction): void {
186
- console.log(`Submitting transaction: ${transaction.toString()}`);
187
-
188
- if (this.currentTransaction) {
189
- this.pendingTransactions.push(transaction);
190
- console.log(`Transaction queued. Queue length: ${this.pendingTransactions.length}`);
191
- } else {
192
- this.currentTransaction = transaction;
193
- console.log(`Executing transaction immediately`);
194
- transaction.fire();
195
- }
196
- }
197
-
198
- async release(err?: Error): Promise<void> {
199
- if (err) {
200
- console.error(`Transaction error: ${err.message}`);
201
- } else {
202
- console.log(`Transaction completed successfully`);
203
- }
204
-
205
- this.currentTransaction = undefined;
109
+ import { Transaction, MultiLock } from '@decaf-ts/transactional-decorators';
206
110
 
207
- if (this.pendingTransactions.length > 0) {
208
- const nextTransaction = this.pendingTransactions.shift()!;
209
- console.log(`Processing next transaction: ${nextTransaction.toString()}`);
210
- this.currentTransaction = nextTransaction;
211
- nextTransaction.fire();
212
- }
213
-
214
- return Promise.resolve();
215
- }
216
- }
217
-
218
- // Set the custom lock as the default
219
- Transaction.setLock(new LoggingTransactionLock());
111
+ // Allow up to 5 transactions to execute concurrently
112
+ Transaction.setLock(new MultiLock(5));
220
113
  ```
221
114
 
222
- #### Using the Lock Class
223
-
224
- The Lock class provides a basic locking mechanism that you can use independently of the transaction system.
115
+ ## Manual Transaction Management
225
116
 
226
- **Description**: Use the Lock class for simple concurrency control in non-transactional contexts.
117
+ You can also manage transactions manually using the `Transaction` class.
227
118
 
228
119
  ```typescript
229
- import { Lock } from '@decaf-ts/transactional-decorators';
230
-
231
- // Create a lock for a shared resource
232
- const resourceLock = new Lock();
233
-
234
- // Execute a function with exclusive access to the resource
235
- async function accessSharedResource() {
236
- const result = await resourceLock.execute(async () => {
237
- // This code will run with exclusive access to the resource
238
- const data = await fetchDataFromDatabase();
239
- const processedData = processData(data);
240
- await saveDataToDatabase(processedData);
241
- return processedData;
242
- });
243
-
244
- return result;
245
- }
120
+ import { Transaction } from '@decaf-ts/transactional-decorators';
246
121
 
247
- // Alternatively, you can manually acquire and release the lock
248
- async function manualLockHandling() {
249
- await resourceLock.acquire();
250
- try {
251
- // Critical section with exclusive access
252
- const data = await fetchDataFromDatabase();
253
- const processedData = processData(data);
254
- await saveDataToDatabase(processedData);
255
- return processedData;
256
- } finally {
257
- // Always release the lock, even if an error occurs
258
- resourceLock.release();
122
+ const myTransaction = new Transaction(
123
+ 'MyManualTransaction',
124
+ 'myAction',
125
+ async () => {
126
+ // Transaction logic here
259
127
  }
260
- }
261
- ```
262
-
128
+ );
263
129
 
264
- ## Coding Principles
265
-
266
- - group similar functionality in folders (analog to namespaces but without any namespace declaration)
267
- - one class per file;
268
- - one interface per file (unless interface is just used as a type);
269
- - group types as other interfaces in a types.ts file per folder;
270
- - group constants or enums in a constants.ts file per folder;
271
- - group decorators in a decorators.ts file per folder;
272
- - always import from the specific file, never from a folder or index file (exceptions for dependencies on other packages);
273
- - prefer the usage of established design patters where applicable:
274
- - Singleton (can be an anti-pattern. use with care);
275
- - factory;
276
- - observer;
277
- - strategy;
278
- - builder;
279
- - etc;
280
-
281
- ## Release Documentation Hooks
282
- Stay aligned with the automated release pipeline by reviewing [Release Notes](./workdocs/reports/RELEASE_NOTES.md) and [Dependencies](./workdocs/reports/DEPENDENCIES.md) after trying these recipes (updated on 2025-11-26).
130
+ Transaction.submit(myTransaction);
131
+ ```
283
132
 
284
133
 
285
134
  ### Related
@@ -17,5 +17,5 @@ export * from "./types";
17
17
  * @const VERSION
18
18
  * @memberOf module:transactions
19
19
  */
20
- export declare const VERSION = "0.3.4";
20
+ export declare const VERSION = "0.3.5";
21
21
  export declare const PACKAGE_NAME = "@decaf-ts/transactional-decorators";
package/lib/esm/index.js CHANGED
@@ -18,7 +18,7 @@ export * from "./types.js";
18
18
  * @const VERSION
19
19
  * @memberOf module:transactions
20
20
  */
21
- export const VERSION = "0.3.4";
21
+ export const VERSION = "0.3.5";
22
22
  export const PACKAGE_NAME = "@decaf-ts/transactional-decorators";
23
23
  Metadata.registerLibrary(PACKAGE_NAME, VERSION);
24
24
  //# sourceMappingURL=index.js.map
package/lib/index.cjs CHANGED
@@ -35,7 +35,7 @@ __exportStar(require("./types.cjs"), exports);
35
35
  * @const VERSION
36
36
  * @memberOf module:transactions
37
37
  */
38
- exports.VERSION = "0.3.4";
38
+ exports.VERSION = "0.3.5";
39
39
  exports.PACKAGE_NAME = "@decaf-ts/transactional-decorators";
40
40
  decoration_1.Metadata.registerLibrary(exports.PACKAGE_NAME, exports.VERSION);
41
41
  //# sourceMappingURL=index.js.map
package/lib/index.d.ts CHANGED
@@ -17,5 +17,5 @@ export * from "./types";
17
17
  * @const VERSION
18
18
  * @memberOf module:transactions
19
19
  */
20
- export declare const VERSION = "0.3.4";
20
+ export declare const VERSION = "0.3.5";
21
21
  export declare const PACKAGE_NAME = "@decaf-ts/transactional-decorators";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decaf-ts/transactional-decorators",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Locking and transactions",
5
5
  "type": "module",
6
6
  "exports": {