ค้นหาเว็บไซต์

typescript - วิธีการทำให้นามธรรมของธุรกรรมฐานข้อมูลในระดับการใช้งานกรณีสำหรับ Firebase ในสถาปัตยกรรมสะอาด?


ตอนนี้ฉันกำลังสร้างโครงการโดยใช้หลักการของ Clean Architecture ร่วมกับ Firebase ฉันยังใช้ Turborepo สำหรับโครงสร้าง monorepo ของฉันด้วย

ในฐานโค้ดของฉัน ภายใต้โฟลเดอร์ packages/ มีแพ็กเกจ "core" ที่ประกอบด้วยตรรกะทางธุรกิจของฉัน ซึ่งรวมถึง Entities และ Usecases ตัวอย่างเช่น ฉันมี Entity เช่น User, Promotion และ Affiliate และ usecase เช่น "สร้างรหัส affiliate" ที่ทำงานตรรกะทางธุรกิจกับ Entity ที่เกี่ยวข้อง

export abstract class Usecase<T> {
  abstract execute(...args: any[]): Promise<T>;
}

export abstract class UserRepository {
  abstract getUser(userId: string): Promise<User>;
  abstract createUser(user: User): Promise<string>;
  // ...
}

export class CreateAffiliateCodeUsecase implements Usecase<void> {
  constructor(private userRepository: UserRepository) {}

  async execute(userId: string, code: string): Promise<void> {
    const user = await this.userRepository.getUser(userId);
    if (!user) {
      throw new Error("User not found");
    }

    if (user.affiliateCodes.includes(code)) {
      throw new Error("Code already exists");
    }
    // ...
    }
}

ในการใช้งานของฉัน ตัวสร้างวัตถุถูกฉีดด้วยอินเทอร์เฟซของที่เก็บข้อมูล

ต่อไปในระดับแอปพลิเคชันฉันจะนำมันไปใช้งานและใช้มันพร้อมกับรายละเอียดการใช้งานที่จัดเรียงเรียบร้อยแล้ว:

export abstract class RemoteStorageService {
  abstract get(path: string): Promise<any>;
  abstract update(path: string): Promise<any>;
  // and so on
}

export class UserRepositoryImpl implements core.UserRepository {
  constructor(private remoteStorageService: RemoteStorageService) {}

  getUser(userId: string): Promise<core.User> {
    return this.remoteStorageService.get(`/users/${userId}`);
  }
}

export class FirestoreStorageService extends RemoteStorageService {
  // implementation

  async get(path: string): Promise<any> {
    const doc = await this.db.doc(path).get();
    if (!doc.exists) {
      throw new Error('Document not found');
    }
    return doc.data();
  }
}

คำถามของฉันคือ: ฉันสามารถสรุปการทำธุรกรรมเมื่อเขียนลงสตอเรจในระดับกรณีการใช้งานได้อย่างไรโดยไม่ต้องรู้รายละเอียดการใช้งานธุรกรรมของ Firebase? ฉันต้องการให้มั่นใจว่ากรณีการใช้งานของฉันจะไม่ขึ้นอยู่กับ Firebase โดยตรง

ฉันอยากทำอะไรสักอย่างแบบนี้:

export class CheckAffiliateCodeUsecase implements Usecase<void> {
  constructor(
    private userRepository: UserRepository,
    private promotionRepository: PromotionRepository,
  ) {}

  async execute(// .. //) {
    // validations steps here..

    // time to make multiple writes to DB
    const promotionforNewUser = Promotion.createPromotion(//data1//);
    const promotionforOldUser = Promotion.createPromotion(//data2//);
    const user = User.getUser(//params//)
    user.upgrade(//params//)

    // transaction
    transaction {
      promitionRepository.save(promotionforNewUser)
      promitionRepository.save(promotionforOldUser)
      userRepository.updateUser(user)
    }


  }
}