feat(product, types, modules-sdk): added event bus events for products (#4654)

what:

- adds an eventbus dependency to product module.
- emits events on product, category and collection CUD

RESOLVES CORE-1450
This commit is contained in:
Riqwan Thamir
2023-08-04 09:26:02 +00:00
committed by GitHub
parent 43f34866c8
commit 8af55aed87
16 changed files with 616 additions and 23 deletions
@@ -25,13 +25,31 @@ import {
InternalModuleDeclaration,
JoinerServiceConfig,
ProductTypes,
IEventBusModuleService,
} from "@medusajs/types"
import ProductImageService from "./product-image"
import {
ProductServiceTypes,
ProductVariantServiceTypes,
} from "../types/services"
CreateProductCategoryDTO,
ProductCategoryEventData,
ProductCategoryEvents,
UpdateProductCategoryDTO,
} from "../types/services/product-category"
import { UpdateProductVariantDTO } from "../types/services/product-variant"
import {
ProductCollectionEventData,
ProductCollectionEvents,
} from "../types/services/product-collection"
import {
ProductEventData,
ProductEvents,
UpdateProductDTO,
} from "../types/services/product"
import {
InjectManager,
InjectTransactionManager,
@@ -49,7 +67,6 @@ import {
joinerConfig,
LinkableKeys,
} from "./../joiner-config"
import { ProductCategoryServiceTypes } from "../types"
type InjectedDependencies = {
baseRepository: DAL.RepositoryService
@@ -61,6 +78,7 @@ type InjectedDependencies = {
productImageService: ProductImageService<any>
productTypeService: ProductTypeService<any>
productOptionService: ProductOptionService<any>
eventBusModuleService?: IEventBusModuleService
}
export default class ProductModuleService<
@@ -80,12 +98,16 @@ export default class ProductModuleService<
TProductVariant,
TProduct
>
// eslint-disable-next-line max-len
protected readonly productCategoryService_: ProductCategoryService<TProductCategory>
protected readonly productTagService_: ProductTagService<TProductTag>
// eslint-disable-next-line max-len
protected readonly productCollectionService_: ProductCollectionService<TProductCollection>
protected readonly productImageService_: ProductImageService<TProductImage>
protected readonly productTypeService_: ProductTypeService<TProductType>
protected readonly productOptionService_: ProductOptionService<TProductOption>
protected readonly eventBusModuleService_?: IEventBusModuleService
constructor(
{
@@ -98,6 +120,7 @@ export default class ProductModuleService<
productImageService,
productTypeService,
productOptionService,
eventBusModuleService,
}: InjectedDependencies,
protected readonly moduleDeclaration: InternalModuleDeclaration
) {
@@ -110,6 +133,7 @@ export default class ProductModuleService<
this.productImageService_ = productImageService
this.productTypeService_ = productTypeService
this.productOptionService_ = productOptionService
this.eventBusModuleService_ = eventBusModuleService
}
__joinerConfig(): JoinerServiceConfig {
@@ -499,6 +523,13 @@ export default class ProductModuleService<
sharedContext
)
await this.eventBusModuleService_?.emit<ProductCollectionEventData>(
productCollections.map(({ id }) => ({
eventName: ProductCollectionEvents.COLLECTION_CREATED,
data: { id },
}))
)
return JSON.parse(JSON.stringify(productCollections))
}
@@ -512,6 +543,13 @@ export default class ProductModuleService<
sharedContext
)
await this.eventBusModuleService_?.emit<ProductCollectionEventData>(
productCollections.map(({ id }) => ({
eventName: ProductCollectionEvents.COLLECTION_UPDATED,
data: { id },
}))
)
return JSON.parse(JSON.stringify(productCollections))
}
@@ -524,6 +562,13 @@ export default class ProductModuleService<
productCollectionIds,
sharedContext
)
await this.eventBusModuleService_?.emit<ProductCollectionEventData>(
productCollectionIds.map((id) => ({
eventName: ProductCollectionEvents.COLLECTION_DELETED,
data: { id },
}))
)
}
@InjectManager("baseRepository_")
@@ -558,7 +603,7 @@ export default class ProductModuleService<
@InjectTransactionManager(shouldForceTransaction, "baseRepository_")
async createCategory(
data: ProductCategoryServiceTypes.CreateProductCategoryDTO,
data: CreateProductCategoryDTO,
@MedusaContext() sharedContext: Context = {}
) {
const productCategory = await this.productCategoryService_.create(
@@ -566,13 +611,18 @@ export default class ProductModuleService<
sharedContext
)
await this.eventBusModuleService_?.emit<ProductCategoryEventData>(
ProductCategoryEvents.CATEGORY_CREATED,
{ id: productCategory.id }
)
return JSON.parse(JSON.stringify(productCategory))
}
@InjectTransactionManager(shouldForceTransaction, "baseRepository_")
async updateCategory(
categoryId: string,
data: ProductCategoryServiceTypes.UpdateProductCategoryDTO,
data: UpdateProductCategoryDTO,
@MedusaContext() sharedContext: Context = {}
) {
const productCategory = await this.productCategoryService_.update(
@@ -581,6 +631,11 @@ export default class ProductModuleService<
sharedContext
)
await this.eventBusModuleService_?.emit<ProductCategoryEventData>(
ProductCategoryEvents.CATEGORY_UPDATED,
{ id: productCategory.id }
)
return JSON.parse(JSON.stringify(productCategory))
}
@@ -590,6 +645,11 @@ export default class ProductModuleService<
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productCategoryService_.delete(categoryId, sharedContext)
await this.eventBusModuleService_?.emit<ProductCategoryEventData>(
ProductCategoryEvents.CATEGORY_DELETED,
{ id: categoryId }
)
}
@InjectManager("baseRepository_")
@@ -612,10 +672,20 @@ export default class ProductModuleService<
sharedContext?: Context
): Promise<ProductTypes.ProductDTO[]> {
const products = await this.create_(data, sharedContext)
return this.baseRepository_.serialize<ProductTypes.ProductDTO[]>(products, {
const createdProducts = await this.baseRepository_.serialize<
ProductTypes.ProductDTO[]
>(products, {
populate: true,
})
await this.eventBusModuleService_?.emit<ProductEventData>(
createdProducts.map(({ id }) => ({
eventName: ProductEvents.PRODUCT_CREATED,
data: { id },
}))
)
return createdProducts
}
async update(
@@ -624,9 +694,20 @@ export default class ProductModuleService<
): Promise<ProductTypes.ProductDTO[]> {
const products = await this.update_(data, sharedContext)
return this.baseRepository_.serialize<ProductTypes.ProductDTO[]>(products, {
const updatedProducts = await this.baseRepository_.serialize<
ProductTypes.ProductDTO[]
>(products, {
populate: true,
})
await this.eventBusModuleService_?.emit<ProductEventData>(
updatedProducts.map(({ id }) => ({
eventName: ProductEvents.PRODUCT_UPDATED,
data: { id },
}))
)
return updatedProducts
}
@InjectTransactionManager(shouldForceTransaction, "baseRepository_")
@@ -701,7 +782,7 @@ export default class ProductModuleService<
...option,
}
const product = productByHandleMap.get(handle)
const productId = product?.id!
const productId = product?.id
if (productId) {
productOptionsData.product_id = productId
@@ -810,7 +891,7 @@ export default class ProductModuleService<
sharedContext
)
return productData as ProductServiceTypes.UpdateProductDTO
return productData as UpdateProductDTO
})
)
@@ -905,7 +986,7 @@ export default class ProductModuleService<
promises.push(
this.productVariantService_.update(
productByIdMap.get(productId)!,
variants as unknown as ProductVariantServiceTypes.UpdateProductVariantDTO[],
variants as unknown as UpdateProductVariantDTO[],
sharedContext
)
)
@@ -937,9 +1018,13 @@ export default class ProductModuleService<
if (productData.images?.length) {
productData.images = await this.productImageService_.upsert(
productData.images.map((image) =>
isString(image) ? image : image.url
),
productData.images.map((image) => {
if (isString(image)) {
return image
} else {
return image.url
}
}),
sharedContext
)
}
@@ -977,6 +1062,13 @@ export default class ProductModuleService<
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.productService_.delete(productIds, sharedContext)
await this.eventBusModuleService_?.emit<ProductEventData>(
productIds.map((id) => ({
eventName: ProductEvents.PRODUCT_DELETED,
data: { id },
}))
)
}
async softDelete<
@@ -992,11 +1084,24 @@ export default class ProductModuleService<
},
sharedContext: Context = {}
): Promise<Record<Lowercase<keyof typeof LinkableKeys>, string[]> | void> {
let [, cascadedEntitiesMap] = await this.softDelete_(
let [products, cascadedEntitiesMap] = await this.softDelete_(
productIds,
sharedContext
)
const softDeletedProducts = await this.baseRepository_.serialize<
ProductTypes.ProductDTO[]
>(products, {
populate: true,
})
await this.eventBusModuleService_?.emit<ProductEventData>(
softDeletedProducts.map(({ id }) => ({
eventName: ProductEvents.PRODUCT_DELETED,
data: { id },
}))
)
let mappedCascadedEntitiesMap
if (returnLinkableKeys) {
mappedCascadedEntitiesMap = mapObjectTo<
+2 -2
View File
@@ -1,9 +1,9 @@
export * from "./services"
import { IEventBusService } from "@medusajs/types"
import { IEventBusModuleService } from "@medusajs/types"
export type InitializeModuleInjectableDependencies = {
eventBusService?: IEventBusService
eventBusModuleService?: IEventBusModuleService
}
export * from "./services"
@@ -1,3 +1,4 @@
export * as ProductCategoryServiceTypes from "./product-category"
export * as ProductServiceTypes from "./product"
export * as ProductVariantServiceTypes from "./product-variant"
export * as ProductCollectionServiceTypes from "./product-collection"
@@ -1,3 +1,13 @@
export type ProductCategoryEventData = {
id: string
}
export enum ProductCategoryEvents {
CATEGORY_UPDATED = "product-category.updated",
CATEGORY_CREATED = "product-category.created",
CATEGORY_DELETED = "product-category.deleted",
}
export interface CreateProductCategoryDTO {
name: string
handle?: string
@@ -0,0 +1,9 @@
export type ProductCollectionEventData = {
id: string
}
export enum ProductCollectionEvents {
COLLECTION_UPDATED = "product-collection.updated",
COLLECTION_CREATED = "product-collection.created",
COLLECTION_DELETED = "product-collection.deleted",
}
@@ -1,5 +1,15 @@
import { ProductStatus, ProductCategoryDTO } from "@medusajs/types"
export type ProductEventData = {
id: string
}
export enum ProductEvents {
PRODUCT_UPDATED = "product.updated",
PRODUCT_CREATED = "product.created",
PRODUCT_DELETED = "product.deleted",
}
export interface UpdateProductDTO {
id: string
title?: string