프로그래밍 & IT 정보/Etc.

[Firebase/Angular] Cloud Firestore Transaction Example

아미넴 2020. 7. 3.
반응형

Angular에서 Firebase Cloud Firestore의 Transaction 기능을 좀 더 효과적으로 활용하고자 할 때 참고 바랍니다.

 

 

import { AngularFirestore } from '@angular/fire/firestore';
import * as firebase from 'firebase';

export const dbRootPath: string = "rootPath";

// 트랜잭션 타입 정의
enum transactionType { "set", "update", "delete" };
type TransactionType = keyof typeof transactionType;

// 트랜잭션 아이템 정의
export interface TransactionItem {
    type: TransactionType,
    path: string,
    key: string,
    data?: any,
    returnKey?: boolean,
    escapeValue?: string
}

// 트랜잭션 정의
export interface Transaction {
    path: string,
    key: string,
    transactionItem: TransactionItem[],
    transactionExpandItem?: TransactionItem[]
}

export class FirebaseTransaction {
    constructor(private afs: AngularFirestore) { }

    //트랜잭션 처리 함수
    async transaction(transactionList: Transaction[]) {
        try {
            let retKeyVal: string[] = [];

            await this.afs.firestore.runTransaction(async (transaction: firebase.firestore.Transaction) => {
                let docList: firebase.firestore.DocumentSnapshot[] = [];
                let tempKey: string = null;

                for (let i = 0; i < transactionList.length; i++) {
                    docList.push(await transaction.get(this.afs.firestore.collection(dbRootPath + '/' + transactionList[i].path).doc(transactionList[i].key)))
                }

                for (let i = 0; i < transactionList.length; i++) {
                    transactionList[i].transactionItem.forEach(item => {
                        const _path = dbRootPath + '/' + item.path;
                        const _equalKey = '=';
                        let _key: string;

                        if (item.key == _equalKey) { // 직전 액션과 동일한 키 사용이 필요한 경우
                            _key = tempKey;
                        } else if (item.key && !'') {
                            _key = item.key;
                        } else {
                            _key = this.afs.createId();
                        }

                        // 기존 키 임시 저장
                        tempKey = _key;

                        if (item.type == "set") {
                            transaction.set(
                                this.afs.firestore.collection(_path).doc(_key),
                                item.data
                            );
                            // returnKey true일 경우 값 저장
                            if (item.returnKey) {
                                retKeyVal.push(_key);
                            } else {
                                retKeyVal.push(null);
                            }
                        } else if (item.type == "update") {
                            if (item.data) {
                                transaction.update(
                                    this.afs.firestore.collection(_path).doc(_key),
                                    item.data
                                );
                            }
                        } else if (item.type == "delete") {
                            transaction.delete(
                                this.afs.firestore.collection(_path).doc(_key)
                            )
                        }
                    });

                    if (transactionList[i].transactionExpandItem) {
                        transactionList[i].transactionExpandItem.forEach(item => {
                            // returnKey와 연계작업을 위한 처리
                            const _escapeValue = item.escapeValue || '?';
                            const _path = dbRootPath + '/' + item.path.replace(_escapeValue, retKeyVal[i]);
                            const _equalKey = '=';
                            let _key: string;

                            if (item.key == _equalKey) { // 동일한 키 사용이 필요한 경우 반드시 대상 신규 키(공백) 다음에 위치해야 함
                                _key = tempKey;
                            } else if (item.key && !'') {
                                _key = item.key.replace(_escapeValue, retKeyVal[i]);
                            } else {
                                _key = this.afs.createId();
                            }

                            // 기존 키 임시 저장
                            tempKey = _key;

                            //data 부분 키값 처리
                            for (let key in item.data) {
                                if (item.data[key] === _escapeValue) {
                                    item.data[key] = item.data[key].replace(_escapeValue, retKeyVal[i]);
                                }
                            }

                            if (item.type == "set") {
                                transaction.set(
                                    this.afs.firestore.collection(_path).doc(_key),
                                    item.data
                                );
                            } else if (item.type == "update") {
                                if (item.data) {
                                    transaction.update(
                                        this.afs.firestore.collection(_path).doc(_key),
                                        item.data
                                    );
                                }
                            } else if (item.type == "delete") {
                                transaction.delete(
                                    this.afs.firestore.collection(_path).doc(_key)
                                )
                            }
                        });
                    }
                }
            });
            return retKeyVal;
        } catch (error) {
            throw error;
        }
    }
}
반응형

댓글

💲 추천 글