Skip to content

Instantly share code, notes, and snippets.

@Bastianowicz
Created February 7, 2023 19:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Bastianowicz/5fd606db75708fd557d27b23feed1f4a to your computer and use it in GitHub Desktop.
Save Bastianowicz/5fd606db75708fd557d27b23feed1f4a to your computer and use it in GitHub Desktop.
Nest.js Setup for decoupled Firestore Transactions
export class FirebaseTransactionAdapter implements TransactionProviderPort {
private readonly logger = new Logger(FirebaseTransactionAdapter.name);
constructor(
@Inject(Firestore.prototype.runTransaction)
private readonly runTransaction: TransactionRunner,
) {
}
async executeTransaction(
callback: () => Promise<void>
): Promise<Result<void, DeleteErrorTypes>> {
try {
// transcations triggered down the stream will now all run via the same transaction workload
const result = await this.runTransaction(callback);
return ok(result);
} catch (e) {
const msg = "Error executing transaction";
this.logger.error(msg, e);
return err(new WriteError(msg));
}
}
}
const adminApp = admin.initializeApp();
let transaction: Transaction | undefined;
export type TransactionLambda = (transaction: Transaction) => Promise<void>;
export type TransactionRunner = (callback: TransactionLambda) => Promise<void>;
@Global()
@Module({
providers: [
{
provide: Firestore,
useValue: (() => {
// must be value and not factory so that settings is only being called once
const firestore = adminApp.firestore();
firestore.settings({ignoreUndefinedProperties: true,});
return firestore;
}
)()
},
{
provide: Firestore.prototype.runTransaction,
inject: [Firestore],
useFactory: (firestore: Firestore) => {
return async (updateFunction: TransactionLambda) => {
if(transaction) {
// if a transaction has already been triggered, just execute the lambda with existing transaction
await updateFunction(transaction);
} else {
// if this is the start of a transaction, start a new one...
await firestore.runTransaction(async (t) => {
// ... reference the transaction object
transaction = t;
// execute the lambda
await updateFunction(transaction);
// unset the transaction reference
transaction = undefined;
});
}
};
}
}
],
exports: [
Firestore.prototype.runTransaction,
Firestore,
]
})
export class UtilModule {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment