feat: event aggregator (#6218)

What:
- Event Aggregator Util
- Preparation for normalizing event in a new format (backward compatible with the current format)
- GQL Schema to joiner config and some Entities configured
- Link modules emmiting events
This commit is contained in:
Carlos R. L. Rodrigues authored and GitHub committed 2024-02-05 11:59:10 +00:00
1 parent 73fd92a1af
commit 884428a1b5
66 files changed
+1407 -749

No files matched your search

@@ -1,19 +1,27 @@
import {
EmitData,
EventBusTypes,
IEventBusModuleService,
Message,
Subscriber,
} from "@medusajs/types"
export class EventBusService implements IEventBusModuleService {
async emit<T>(
emit<T>(
eventName: string,
data: T,
options: Record<string, unknown>
options?: Record<string, unknown>
): Promise<void>
emit<T>(data: EmitData<T>[]): Promise<void>
emit<T>(data: Message<T>[]): Promise<void>
async emit<T>(data: EventBusTypes.EmitData<T>[]): Promise<void>
async emit<T, TInput extends string | EventBusTypes.EmitData<T>[] = string>(
async emit<
T,
TInput extends
| string
| EventBusTypes.EmitData<T>[]
| EventBusTypes.Message<T>[] = string
>(
eventOrData: TInput,
data?: T,
options: Record<string, unknown> = {}
@@ -2,6 +2,7 @@ import { MedusaModule, Modules } from "@medusajs/modules-sdk"
import { IProductModuleService } from "@medusajs/types"
import { kebabCase } from "@medusajs/utils"
import { knex } from "knex"
import { initModules } from "medusa-test-utils"
import * as CustomRepositories from "../__fixtures__/module"
import {
buildProductAndRelationsData,
@@ -9,7 +10,6 @@ import {
} from "../__fixtures__/product"
import { productsData } from "../__fixtures__/product/data"
import { DB_URL, TestDatabase } from "../utils"
import { initModules } from "medusa-test-utils"
import { getInitModuleConfig } from "../utils/get-init-module-config"
const sharedPgConnection = knex<any, any>({
@@ -238,7 +238,23 @@ describe("Product module", function () {
thumbnail: images[0],
})
const products = await module.create([data])
const productsCreated = await module.create([data])
const products = await module.list(
{ id: productsCreated[0].id },
{
relations: [
"images",
"categories",
"variants",
"variants.options",
"options",
"options.values",
"tags",
"type",
],
}
)
expect(products).toHaveLength(1)
@@ -1,12 +1,12 @@
import { MedusaModule, Modules } from "@medusajs/modules-sdk"
import { IProductModuleService, ProductTypes } from "@medusajs/types"
import { Product, ProductCategory } from "@models"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { getInitModuleConfig, TestDatabase } from "../../../utils"
import { Product, ProductCategory } from "@models"
import { initModules } from "medusa-test-utils"
import { EventBusService } from "../../../__fixtures__/event-bus"
import { createProductCategories } from "../../../__fixtures__/product-category"
import { productCategoriesRankData } from "../../../__fixtures__/product-category/data"
import { EventBusService } from "../../../__fixtures__/event-bus"
import { MedusaModule, Modules } from "@medusajs/modules-sdk"
import { initModules } from "medusa-test-utils/dist"
import { TestDatabase, getInitModuleConfig } from "../../../utils"
describe("ProductModuleService product categories", () => {
let service: IProductModuleService
@@ -1,9 +1,9 @@
import { getInitModuleConfig, TestDatabase } from "../../../utils"
import { IProductModuleService, ProductTypes } from "@medusajs/types"
import { Product, ProductTag } from "@models"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { MedusaModule, Modules } from "@medusajs/modules-sdk"
import { initModules } from "medusa-test-utils/dist"
import { IProductModuleService, ProductTypes } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { Product, ProductTag } from "@models"
import { initModules } from "medusa-test-utils"
import { TestDatabase, getInitModuleConfig } from "../../../utils"
describe("ProductModuleService product tags", () => {
let service: IProductModuleService
@@ -1,9 +1,9 @@
import { getInitModuleConfig, TestDatabase } from "../../../utils"
import { IProductModuleService } from "@medusajs/types"
import { ProductType } from "@models"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { MedusaModule, Modules } from "@medusajs/modules-sdk"
import { initModules } from "medusa-test-utils/dist"
import { IProductModuleService } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { ProductType } from "@models"
import { initModules } from "medusa-test-utils"
import { getInitModuleConfig, TestDatabase } from "../../../utils"
describe("ProductModuleService product types", () => {
let service: IProductModuleService
@@ -1,9 +1,9 @@
import { getInitModuleConfig, TestDatabase } from "../../../utils"
import { IProductModuleService, ProductTypes } from "@medusajs/types"
import { Product, ProductVariant } from "@models"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { MedusaModule, Modules } from "@medusajs/modules-sdk"
import { initModules } from "medusa-test-utils/dist"
import { IProductModuleService, ProductTypes } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { Product, ProductVariant } from "@models"
import { initModules } from "medusa-test-utils"
import { getInitModuleConfig, TestDatabase } from "../../../utils"
describe("ProductModuleService product variants", () => {
let service: IProductModuleService
@@ -13,13 +13,13 @@ import {
ProductVariant,
} from "@models"
import { initModules } from "medusa-test-utils"
import { initialize } from "../../../../src"
import { EventBusService } from "../../../__fixtures__/event-bus"
import { createCollections, createTypes } from "../../../__fixtures__/product"
import { createProductCategories } from "../../../__fixtures__/product-category"
import { buildProductAndRelationsData } from "../../../__fixtures__/product/data/create-product"
import { DB_URL, getInitModuleConfig, TestDatabase } from "../../../utils"
import { initModules } from "medusa-test-utils"
import { DB_URL, TestDatabase, getInitModuleConfig } from "../../../utils"
const beforeEach_ = async () => {
await TestDatabase.setupDatabase()
@@ -584,7 +584,23 @@ describe("ProductModuleService products", function () {
thumbnail: images[0],
})
const products = await module.create([data])
const productsCreated = await module.create([data])
const products = await module.list(
{ id: productsCreated[0].id },
{
relations: [
"images",
"categories",
"variants",
"variants.options",
"options",
"options.values",
"tags",
"type",
],
}
)
expect(products).toHaveLength(1)
expect(products[0].images).toHaveLength(1)
+20 -55
View File
@@ -43,92 +43,57 @@ export const joinerConfig: ModuleJoinerConfig = {
schema: moduleSchema,
alias: [
{
name: "product",
},
{
name: "products",
},
{
name: "variant",
name: ["product", "products"],
args: {
entity: "Product",
},
},
{
name: ["variant", "variants"],
args: {
entity: "ProductVariant",
methodSuffix: "Variants",
},
},
{
name: "variants",
args: {
methodSuffix: "Variants",
},
},
{
name: "product_option",
name: ["product_option", "product_options"],
args: {
entity: "ProductOption",
methodSuffix: "Options",
},
},
{
name: "product_options",
args: {
methodSuffix: "Options",
},
},
{
name: "product_type",
name: ["product_type", "product_types"],
args: {
entity: "ProductType",
methodSuffix: "Types",
},
},
{
name: "product_types",
args: {
methodSuffix: "Types",
},
},
{
name: "product_image",
name: ["product_image", "product_images"],
args: {
entity: "ProductImage",
methodSuffix: "Images",
},
},
{
name: "product_images",
args: {
methodSuffix: "Images",
},
},
{
name: "product_tag",
name: ["product_tag", "product_tags"],
args: {
entity: "ProductTag",
methodSuffix: "Tags",
},
},
{
name: "product_tags",
args: {
methodSuffix: "Tags",
},
},
{
name: "product_collection",
name: ["product_collection", "product_collections"],
args: {
entity: "ProductCollection",
methodSuffix: "Collections",
},
},
{
name: "product_collections",
args: {
methodSuffix: "Collections",
},
},
{
name: "product_category",
args: {
methodSuffix: "Categories",
},
},
{
name: "product_categories",
name: ["product_category", "product_categories"],
args: {
entity: "ProductCategory",
methodSuffix: "Categories",
},
},
@@ -7,6 +7,7 @@ import {
Index,
ManyToMany,
ManyToOne,
OnInit,
OneToMany,
OptionalProps,
PrimaryKey,
@@ -14,8 +15,8 @@ import {
Unique,
} from "@mikro-orm/core"
import Product from "./product"
import { DAL } from "@medusajs/types"
import Product from "./product"
type OptionalFields = DAL.SoftDeletableEntityDateColumns
@@ -85,6 +86,11 @@ class ProductCategory {
@ManyToMany(() => Product, (product) => product.categories)
products = new Collection<Product>(this)
@OnInit()
async onInit() {
this.id = generateEntityId(this.id, "pcat")
}
@BeforeCreate()
async onCreate(args: EventArgs<ProductCategory>) {
this.id = generateEntityId(this.id, "pcat")
@@ -4,6 +4,7 @@ import {
Entity,
Filter,
Index,
OnInit,
OneToMany,
OptionalProps,
PrimaryKey,
@@ -11,9 +12,9 @@ import {
Unique,
} from "@mikro-orm/core"
import { DAL } from "@medusajs/types"
import { DALUtils, generateEntityId, kebabCase } from "@medusajs/utils"
import Product from "./product"
import { DAL } from "@medusajs/types"
type OptionalRelations = "products"
type OptionalFields = DAL.SoftDeletableEntityDateColumns
@@ -61,6 +62,11 @@ class ProductCollection {
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "pcol")
}
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "pcol")
+7 -1
View File
@@ -5,14 +5,15 @@ import {
Filter,
Index,
ManyToMany,
OnInit,
OptionalProps,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import { DAL } from "@medusajs/types"
import { DALUtils, generateEntityId } from "@medusajs/utils"
import Product from "./product"
import { DAL } from "@medusajs/types"
type OptionalRelations = "products"
type OptionalFields = DAL.SoftDeletableEntityDateColumns
@@ -54,6 +55,11 @@ class ProductImage {
@ManyToMany(() => Product, (product) => product.images)
products = new Collection<Product>(this)
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "img")
}
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "img")
@@ -1,16 +1,17 @@
import { DAL } from "@medusajs/types"
import { DALUtils, generateEntityId } from "@medusajs/utils"
import {
BeforeCreate,
Entity,
Filter,
Index,
ManyToOne,
OnInit,
OptionalProps,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import { ProductOption, ProductVariant } from "./index"
import { DALUtils, generateEntityId } from "@medusajs/utils"
import { DAL } from "@medusajs/types"
type OptionalFields =
| "allow_backorder"
@@ -72,6 +73,11 @@ class ProductOptionValue {
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "optval")
}
@BeforeCreate()
beforeCreate() {
this.id = generateEntityId(this.id, "optval")
@@ -8,6 +8,7 @@ import {
Filter,
Index,
ManyToOne,
OnInit,
OneToMany,
OptionalProps,
PrimaryKey,
@@ -70,6 +71,11 @@ class ProductOption {
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "opt")
}
@BeforeCreate()
beforeCreate() {
this.id = generateEntityId(this.id, "opt")
+7 -1
View File
@@ -5,14 +5,15 @@ import {
Filter,
Index,
ManyToMany,
OnInit,
OptionalProps,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import { DAL } from "@medusajs/types"
import { DALUtils, generateEntityId } from "@medusajs/utils"
import Product from "./product"
import { DAL } from "@medusajs/types"
type OptionalRelations = "products"
type OptionalFields = DAL.SoftDeletableEntityDateColumns
@@ -53,6 +54,11 @@ class ProductTag {
@ManyToMany(() => Product, (product) => product.tags)
products = new Collection<Product>(this)
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "ptag")
}
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "ptag")
+7 -1
View File
@@ -3,13 +3,14 @@ import {
Entity,
Filter,
Index,
OnInit,
OptionalProps,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import { DALUtils, generateEntityId } from "@medusajs/utils"
import { DAL } from "@medusajs/types"
import { DALUtils, generateEntityId } from "@medusajs/utils"
type OptionalFields = DAL.SoftDeletableEntityDateColumns
@@ -46,6 +47,11 @@ class ProductType {
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "ptyp")
}
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "ptyp")
@@ -1,3 +1,4 @@
import { DAL } from "@medusajs/types"
import {
DALUtils,
generateEntityId,
@@ -11,6 +12,7 @@ import {
Filter,
Index,
ManyToOne,
OnInit,
OneToMany,
OptionalProps,
PrimaryKey,
@@ -19,7 +21,6 @@ import {
} from "@mikro-orm/core"
import { Product } from "@models"
import ProductOptionValue from "./product-option-value"
import { DAL } from "@medusajs/types"
type OptionalFields =
| "allow_backorder"
@@ -152,6 +153,11 @@ class ProductVariant {
})
options = new Collection<ProductOptionValue>(this)
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "variant")
}
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "variant")
+8 -2
View File
@@ -8,12 +8,14 @@ import {
ManyToMany,
ManyToOne,
OneToMany,
OnInit,
OptionalProps,
PrimaryKey,
Property,
Unique,
} from "@mikro-orm/core"
import { DAL } from "@medusajs/types"
import {
DALUtils,
generateEntityId,
@@ -22,12 +24,11 @@ import {
} from "@medusajs/utils"
import ProductCategory from "./product-category"
import ProductCollection from "./product-collection"
import ProductImage from "./product-image"
import ProductOption from "./product-option"
import ProductTag from "./product-tag"
import ProductType from "./product-type"
import ProductVariant from "./product-variant"
import ProductImage from "./product-image"
import { DAL } from "@medusajs/types"
type OptionalRelations = "collection" | "type"
type OptionalFields =
@@ -176,6 +177,11 @@ class Product {
@Property({ columnType: "jsonb", nullable: true })
metadata?: Record<string, unknown> | null
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "prod")
}
@BeforeCreate()
beforeCreate() {
this.id = generateEntityId(this.id, "prod")
@@ -42,12 +42,6 @@ import {
ModulesSdkUtils,
promiseAll,
} from "@medusajs/utils"
import { entityNameToLinkableKeysMap, joinerConfig } from "./../joiner-config"
import { ProductEventData, ProductEvents } from "../types/services/product"
import {
ProductCategoryEventData,
ProductCategoryEvents,
} from "../types/services/product-category"
import {
ProductCategoryServiceTypes,
ProductCollectionServiceTypes,
@@ -55,6 +49,12 @@ import {
ProductServiceTypes,
ProductVariantServiceTypes,
} from "@types"
import { ProductEventData, ProductEvents } from "../types/services/product"
import {
ProductCategoryEventData,
ProductCategoryEvents,
} from "../types/services/product-category"
import { entityNameToLinkableKeysMap, joinerConfig } from "./../joiner-config"
type InjectedDependencies = {
baseRepository: DAL.RepositoryService
@@ -371,52 +371,56 @@ export default class ProductModuleService<
async createTags(
data: ProductTypes.CreateProductTagDTO[],
@MedusaContext() sharedContext: Context = {}
) {
): Promise<ProductTypes.ProductTagDTO[]> {
const productTags = await this.productTagService_.create(
data,
sharedContext
)
return JSON.parse(JSON.stringify(productTags))
return await this.baseRepository_.serialize(productTags, { populate: true })
}
@InjectTransactionManager("baseRepository_")
async updateTags(
data: ProductTypes.UpdateProductTagDTO[],
@MedusaContext() sharedContext: Context = {}
) {
): Promise<ProductTypes.ProductTagDTO[]> {
const productTags = await this.productTagService_.update(
data,
sharedContext
)
return JSON.parse(JSON.stringify(productTags))
return await this.baseRepository_.serialize(productTags, { populate: true })
}
@InjectTransactionManager("baseRepository_")
async createTypes(
data: ProductTypes.CreateProductTypeDTO[],
@MedusaContext() sharedContext: Context = {}
) {
): Promise<ProductTypes.ProductTypeDTO[]> {
const productTypes = await this.productTypeService_.create(
data,
sharedContext
)
return JSON.parse(JSON.stringify(productTypes))
return await this.baseRepository_.serialize(productTypes, {
populate: true,
})
}
@InjectTransactionManager("baseRepository_")
async updateTypes(
data: ProductTypes.UpdateProductTypeDTO[],
@MedusaContext() sharedContext: Context = {}
) {
): Promise<ProductTypes.ProductTypeDTO[]> {
const productTypes = await this.productTypeService_.update(
data,
sharedContext
)
return JSON.parse(JSON.stringify(productTypes))
return await this.baseRepository_.serialize(productTypes, {
populate: true,
})
}
@InjectTransactionManager("baseRepository_")
@@ -476,7 +480,7 @@ export default class ProductModuleService<
async updateCollections(
data: ProductTypes.UpdateProductCollectionDTO[],
@MedusaContext() sharedContext: Context = {}
) {
): Promise<ProductTypes.ProductCollectionDTO[]> {
const productCollections = await this.productCollectionService_.update(
data,
sharedContext
@@ -492,14 +496,16 @@ export default class ProductModuleService<
}))
)
return JSON.parse(JSON.stringify(productCollections))
return await this.baseRepository_.serialize(productCollections, {
populate: true,
})
}
@InjectTransactionManager("baseRepository_")
async createCategory(
data: ProductCategoryServiceTypes.CreateProductCategoryDTO,
@MedusaContext() sharedContext: Context = {}
) {
): Promise<ProductTypes.ProductCategoryDTO> {
const productCategory = await this.productCategoryService_.create(
data,
sharedContext
@@ -510,7 +516,9 @@ export default class ProductModuleService<
{ id: productCategory.id }
)
return JSON.parse(JSON.stringify(productCategory))
return await this.baseRepository_.serialize(productCategory, {
populate: true,
})
}
@InjectTransactionManager("baseRepository_")
@@ -518,7 +526,7 @@ export default class ProductModuleService<
categoryId: string,
data: ProductCategoryServiceTypes.UpdateProductCategoryDTO,
@MedusaContext() sharedContext: Context = {}
) {
): Promise<ProductTypes.ProductCategoryDTO> {
const productCategory = await this.productCategoryService_.update(
categoryId,
data,
@@ -530,7 +538,9 @@ export default class ProductModuleService<
{ id: productCategory.id }
)
return JSON.parse(JSON.stringify(productCategory))
return await this.baseRepository_.serialize(productCategory, {
populate: true,
})
}
@InjectManager("baseRepository_")