diff --git a/.changeset/gold-fireants-look.md b/.changeset/gold-fireants-look.md new file mode 100644 index 0000000000..09d8c22b3a --- /dev/null +++ b/.changeset/gold-fireants-look.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +feat(medusa): Add event emitter to ProductCollectionService diff --git a/packages/medusa/src/services/__tests__/product-collection.js b/packages/medusa/src/services/__tests__/product-collection.js index 1aa6f1c9fa..e80ede717e 100644 --- a/packages/medusa/src/services/__tests__/product-collection.js +++ b/packages/medusa/src/services/__tests__/product-collection.js @@ -1,5 +1,6 @@ import { IdMap, MockRepository, MockManager } from "medusa-test-utils" import ProductCollectionService from "../product-collection" +import { EventBusServiceMock } from "../__mocks__/event-bus" describe("ProductCollectionService", () => { describe("retrieve", () => { @@ -15,6 +16,7 @@ describe("ProductCollectionService", () => { const productCollectionService = new ProductCollectionService({ manager: MockManager, productCollectionRepository, + eventBusService: EventBusServiceMock, }) beforeEach(async () => { @@ -48,11 +50,13 @@ describe("ProductCollectionService", () => { describe("create", () => { const productCollectionRepository = MockRepository({ findOne: query => Promise.resolve({ id: IdMap.getId("bathrobe") }), + create: query => Promise.resolve({ id: IdMap.getId("bathrobe") }), }) const productCollectionService = new ProductCollectionService({ manager: MockManager, productCollectionRepository, + eventBusService: EventBusServiceMock, }) beforeEach(async () => { @@ -60,12 +64,19 @@ describe("ProductCollectionService", () => { }) it("successfully creates a product collection", async () => { - await productCollectionService.create({ title: "bathrobe" }) + const entity = await productCollectionService.create({ title: "bathrobe" }) expect(productCollectionRepository.create).toHaveBeenCalledTimes(1) expect(productCollectionRepository.create).toHaveBeenCalledWith({ title: "bathrobe", }) + + expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) + expect(EventBusServiceMock.emit).toHaveBeenCalledWith( + ProductCollectionService.Events.CREATED, { + id: entity.id, + } + ) }) }) @@ -82,6 +93,7 @@ describe("ProductCollectionService", () => { const productCollectionService = new ProductCollectionService({ manager: MockManager, productCollectionRepository, + eventBusService: EventBusServiceMock, }) beforeEach(async () => { @@ -98,6 +110,13 @@ describe("ProductCollectionService", () => { id: IdMap.getId("bathrobe"), title: "bathrobes", }) + + expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) + expect(EventBusServiceMock.emit).toHaveBeenCalledWith( + ProductCollectionService.Events.UPDATED, { + id: IdMap.getId("bathrobe"), + } + ) }) it("fails on non-existing product collection", async () => { @@ -126,6 +145,7 @@ describe("ProductCollectionService", () => { const productCollectionService = new ProductCollectionService({ manager: MockManager, productCollectionRepository, + eventBusService: EventBusServiceMock, }) beforeEach(async () => { @@ -139,6 +159,13 @@ describe("ProductCollectionService", () => { expect(productCollectionRepository.softRemove).toHaveBeenCalledWith({ id: IdMap.getId("bathrobe"), }) + + expect(EventBusServiceMock.emit).toHaveBeenCalledTimes(1) + expect(EventBusServiceMock.emit).toHaveBeenCalledWith( + ProductCollectionService.Events.DELETED, { + id: IdMap.getId("bathrobe"), + } + ) }) it("succeeds idempotently", async () => { diff --git a/packages/medusa/src/services/product-collection.ts b/packages/medusa/src/services/product-collection.ts index 7a730e29eb..4ca80995f0 100644 --- a/packages/medusa/src/services/product-collection.ts +++ b/packages/medusa/src/services/product-collection.ts @@ -38,6 +38,14 @@ class ProductCollectionService extends TransactionBaseService { protected readonly productCollectionRepository_: typeof ProductCollectionRepository protected readonly productRepository_: typeof ProductRepository + static readonly Events = { + CREATED: "product-collection.created", + UPDATED: "product-collection.updated", + DELETED: "product-collection.deleted", + PRODUCTS_ADDED: "product-collection.products_added", + PRODUCTS_REMOVED: "product-collection.products_removed", + } + constructor({ productCollectionRepository, productRepository, @@ -124,9 +132,16 @@ class ProductCollectionService extends TransactionBaseService { const collectionRepo = manager.withRepository( this.productCollectionRepository_ ) + let productCollection = collectionRepo.create(collection) + productCollection = await collectionRepo.save(productCollection); - const productCollection = collectionRepo.create(collection) - return await collectionRepo.save(productCollection) + await this.eventBus_ + .withTransaction(manager) + .emit(ProductCollectionService.Events.CREATED, { + id: productCollection.id, + }) + + return productCollection }) } @@ -145,19 +160,27 @@ class ProductCollectionService extends TransactionBaseService { this.productCollectionRepository_ ) - const collection = await this.retrieve(collectionId) + let productCollection = await this.retrieve(collectionId) const { metadata, ...rest } = update if (metadata) { - collection.metadata = setMetadata(collection, metadata) + productCollection.metadata = setMetadata(productCollection, metadata) } for (const [key, value] of Object.entries(rest)) { - collection[key] = value + productCollection[key] = value } - return collectionRepo.save(collection) + productCollection = await collectionRepo.save(productCollection) + + await this.eventBus_ + .withTransaction(manager) + .emit(ProductCollectionService.Events.UPDATED, { + id: productCollection.id, + }) + + return productCollection }) } @@ -172,13 +195,19 @@ class ProductCollectionService extends TransactionBaseService { this.productCollectionRepository_ ) - const collection = await this.retrieve(collectionId) + const productCollection = await this.retrieve(collectionId) - if (!collection) { + if (!productCollection) { return Promise.resolve() } - await productCollectionRepo.softRemove(collection) + await productCollectionRepo.softRemove(productCollection) + + await this.eventBus_ + .withTransaction(manager) + .emit(ProductCollectionService.Events.DELETED, { + id: productCollection.id, + }) return Promise.resolve() }) @@ -195,9 +224,18 @@ class ProductCollectionService extends TransactionBaseService { await productRepo.bulkAddToCollection(productIds, id) - return await this.retrieve(id, { + const productCollection = await this.retrieve(id, { relations: ["products"], }) + + await this.eventBus_ + .withTransaction(manager) + .emit(ProductCollectionService.Events.PRODUCTS_ADDED, { + productCollection: productCollection, + productIds: productIds, + }) + + return productCollection }) } @@ -212,6 +250,17 @@ class ProductCollectionService extends TransactionBaseService { await productRepo.bulkRemoveFromCollection(productIds, id) + const productCollection = await this.retrieve(id, { + relations: ["products"], + }) + + await this.eventBus_ + .withTransaction(manager) + .emit(ProductCollectionService.Events.PRODUCTS_REMOVED, { + productCollection: productCollection, + productIds: productIds, + }) + return Promise.resolve() }) }