Transactions with DDD and Repository Pattern in TypeScript: A guide to implementation | Part 2.

João Batista da Silva
2 min readNov 13, 2023

--

Photo by Clark Van Der Beken on Unsplash

We know that a database implementation is required to use transaction scope, as this scope is specialized in ensuring the integrity of the database.

So let’s use the Drizzle ORM to get the transaction scope for our operations. We will define a drizzle connection to our database and try keep it simple. See more documentation details about Drizzle ORM here.

This is the code snippet for the connection:

Here, we import the postgres lib and the drizzle implementation for postgreSQL databases. Now we have access to drizzle operations, including transaction():

The transaction() method is simple to use, basically like this:

Pay attention to the tx parameter. We can see that it is very similar to the drizzleConnection itself and has the same update and insertion methods for example. The difference is that this update or insertion will now run in a different scope than the drizzleConnection. That is, our tx parameter is the scope of the transaction, and that is exactly what we need. But how do we provide this scope to our operations?

Well, since we are using a specific ORM, we should certainly develop the specialized repository to handle that ORM. We’ll have to change our IAccountsRepository and IBooksRepository repository interfaces a bit, and we’ll create new specialized Drizzle repositories.

This is the new interfaces:

See that now operations receive a transactionScope parameter, which will be exactly our tx.
The new repositories will be:

The transactionScope parameter is typed with DrizzleTransactionScope, this is exactly the type of the tx parameter provided by Drizzle, in version 0.28.6 it is exactly like this:

Now let’s try to modify our buyBook() method to using the transaction scope:

This guarantees that all operations will succeed or all will fail, Exactly as we want. Looks good, we did it!

No… Our buyBook() has an external dependency. This function should not know how the transaction works or implementation details, drizzleConnection should not be being imported or used here. How to solve this?

Unit of work

Using the Unit Of Work (UOW) pattern, this is the answer.

In short, a Unit of Work encapsulates one or more repositories and a list of actions to be performed that are required to successfully implement independent and consistent data changes.

This is a good summary and already explains a little about how we will use it.

We need to develop a class based on the Unit of Work concept to handle database operations, providing transaction scope without directly relying on a database implementation. But there are some important details to address before developing this class.

We will cover these details in the next part of this series.

Part 1 here!
Part 3 here!

--

--

João Batista da Silva

𝕊𝕠𝕗𝕥𝕨𝕒𝕣𝕖 𝔻𝕖𝕧𝕖𝕝𝕠𝕡𝕖𝕣 | 𝗟𝗼𝗼𝗸𝗶𝗻𝗴 𝗳𝗼𝗿 𝘁𝗵𝗲 𝗯𝗲𝘀𝘁 𝗻𝗲𝘅𝘁 𝘀𝘁𝗲𝗽 𝗮𝗻𝗱 𝘀𝗵𝗮𝗿𝗶𝗻𝗴 𝘁𝗵𝗲 𝗰𝘂𝗿𝗿𝗲𝗻𝘁 𝗼𝗻𝗲.