You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, when working with transactions in Drizzle ORM, one we need to explicitly pass the transaction object to every function that needs to participate in the transaction. This leads to verbose code and makes it challenging to manage transactions across multiple function calls, especially in complex business logic.
Example of current approach:
asyncfunctioninviteUserToOrganization(db,email,organizationId,roleName){returndb.transaction(async(trx)=>{constorganization=awaitfindOrganization(trx,organizationId);if(!organization)thrownewError("Organization not found");constmembership=awaitcreatePendingMembership(trx,email,organizationId);awaitaddRoleToMembership(trx,membership.id,roleName);returnmembership;});}asyncfunctionfindOrganization(trx,organizationId){returntrx.query.organizations.findFirst({where: eq(schema.organizations.id,organizationId),});}asyncfunctioncreatePendingMembership(trx,email,organizationId){// Implementation using trx}asyncfunctionaddRoleToMembership(trx,membershipId,roleName){// Implementation using trx}
Proposed Solution
Implement an implicit transaction context using AsyncLocalStorage or a similar mechanism. This would allow functions to access the current transaction without explicitly passing it as an argument.
Example of proposed approach:
import{createTransactionContext}from'drizzle-orm/transaction-context';const{ withTransaction, useTransaction }=createTransactionContext(db);asyncfunctioninviteUserToOrganization(email,organizationId,roleName){returnwithTransaction(async()=>{constorganization=awaitfindOrganization(organizationId);if(!organization)thrownewError("Organization not found");constmembership=awaitcreatePendingMembership(email,organizationId);awaitaddRoleToMembership(membership.id,roleName);returnmembership;});}asyncfunctionfindOrganization(organizationId){consttrx=useTransaction();returntrx.query.organizations.findFirst({where: eq(schema.organizations.id,organizationId),});}asyncfunctioncreatePendingMembership(email,organizationId){consttrx=useTransaction();// Implementation using trx}asyncfunctionaddRoleToMembership(membershipId,roleName){consttrx=useTransaction();// Implementation using trx}
Benefits
Cleaner function signatures without the need to pass transaction objects explicitly.
Easier to manage transactions across multiple function calls and nested operations.
Improved readability and maintainability of business logic.
Flexibility to use transactions implicitly or explicitly as needed.
Implementation Considerations
Use AsyncLocalStorage or a similar mechanism to store the current transaction context.
Provide helper functions like withTransaction to create transaction contexts and useTransaction to access the current transaction.
Ensure proper error handling and transaction rollback in case of exceptions.
Consider providing options for transaction isolation levels and timeouts.
Questions for Discussion
Should this be implemented as a core feature of Drizzle ORM or as an optional plugin/extension?
How can we ensure this approach doesn't introduce significant performance overhead?
Are there any potential pitfalls or edge cases we should be aware of with this approach?
How can we make this feature TypeScript-friendly and provide good type inference?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Problem Statement
Currently, when working with transactions in Drizzle ORM, one we need to explicitly pass the transaction object to every function that needs to participate in the transaction. This leads to verbose code and makes it challenging to manage transactions across multiple function calls, especially in complex business logic.
Example of current approach:
Proposed Solution
Implement an implicit transaction context using AsyncLocalStorage or a similar mechanism. This would allow functions to access the current transaction without explicitly passing it as an argument.
Example of proposed approach:
Benefits
Implementation Considerations
withTransaction
to create transaction contexts anduseTransaction
to access the current transaction.Questions for Discussion
Related Discussion
An old issue #1473 already brought up this idea and I think it has a valid point. It mentions https://www.baeldung.com/spring-transactional-propagation-isolation which could be taken as a reference for a drizzle implementation.
What are your thoughts on this? How are people rolling transaction context at the moment?
Beta Was this translation helpful? Give feedback.
All reactions