firebase / firebase/firebase-js-sdk
FR: API for making the transaction object globally accessible
- Dominant language
- TypeScript
- Stars
- 5.1k
- Forks
- 1k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 37
Description
### Operating System
N/A
### Browser Version
N/A
### Firebase SDK Version
N/A
### Firebase SDK Product:
Firestore
### Describe your project's tooling
N/A
### Describe the problem
## Feature request
Would it be possible to provide an API for begginning/commiting a transaction without having to perform all the transaction operantions within a single closure?
Also it would be extremely helpful to not have to use another set of functions to manipulate the data when using a transaction and when not. When inside a transaction, operations have to be done through the `transaction` object (`transaction.set`) and when there is no transaction they are done through the firestore modular functions (`setDoc`).
## Problem description
The fact that firebase only provides the `runTransaction()` api is very limiting for architecturing an app using different architectural patterns and abstracting functionality as the application scales.
### For instance
In the case of implementing a service/repository pattern, where the service handles all the business logic and the repositories encapsulates all the database queries, the issue is clearly visible when I need to start a transaction from the service and call multiple repositories involved in the operation.
Now I'm forced to:
* Create a new layer of abstraction for sharing the `transaction` object between the service and the repositories.
* Inject this new layer in all my services for initializing transactions.
* Inject this new layer in all my repositories for accessing the `transaction` object in each operation.
* Duplicate the code in each operation for checking if I'm inside a transaction or not.
* This is because the code is different depending if there is a transaction or not, and the repositories should still work event if they are not inside a transaction.
* For example `setDoc` vs `transaction.set`
### Code example
```typescript
// TransactionManager
import { runTransaction as fsRunTransaction } from 'firebase/firestore'
let openTransaction: Transaction | null = null
const transactionManager = {
const db = getFirestore(getFirebaseApp())
const runTransaction = (updateFn) => {
return fsRunTransaction(
db,
async (transaction) => {
// Keep a reference to the open transaction so I can make different operations across different repositories.
openTransaction = transaction
await updateFn(transaction)
openTransaction = null
}
)
}
return { transaction: openTransaction, runTransaction }
```
```typescript
// Service
const create = async (snapshot) => {
transactionManager.runTransaction(async () => {
const account = await accountsRepository.get(snapshot.accountId)
if (!account) throw new Error('Account not found')
await snapshotsRepository.create(snapshot)
await accountsRepository.update({ ...account, balance: snapshot.balance })
})
}
```
```typescript
// Repository
const create = async (snapshot) => {
const snapshotsRef = collection(db, 'accounts', snapshot.accountId, 'snapshots')
const snapshotRef = doc(snapshotsRef)
if (transactionManager.transaction) {
transactionManager.transaction.set(snapshotRef, snapshot)
} else {
await setDoc(snapshotRef, snapshot)
}
}
```
### Steps and code to reproduce issue
N/A
Contributor guide
Assessment
This issue has not been assessed yet.