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

@@ -12,6 +12,9 @@ export const ProductShippingProfile: ModuleJoinerConfig = {
alias: [
{
name: "product_shipping_profile",
args: {
entity: "LinkProductShippingProfile",
},
},
],
primaryKeys: ["id", "product_id", "profile_id"],
@@ -17,10 +17,13 @@ export const ProductVariantInventoryItem: ModuleJoinerConfig = {
},
alias: [
{
name: "product_variant_inventory_item",
},
{
name: "product_variant_inventory_items",
name: [
"product_variant_inventory_item",
"product_variant_inventory_items",
],
args: {
entity: "LinkProductVariantInventoryItem",
},
},
],
primaryKeys: ["id", "variant_id", "inventory_item_id"],
@@ -1,6 +1,6 @@
import { LINKS } from "../links"
import { ModuleJoinerConfig } from "@medusajs/types"
import { Modules } from "@medusajs/modules-sdk"
import { ModuleJoinerConfig } from "@medusajs/types"
import { LINKS } from "../links"
export const ProductVariantPriceSet: ModuleJoinerConfig = {
serviceName: LINKS.ProductVariantPriceSet,
@@ -11,10 +11,10 @@ export const ProductVariantPriceSet: ModuleJoinerConfig = {
},
alias: [
{
name: "product_variant_price_set",
},
{
name: "product_variant_price_sets",
name: ["product_variant_price_set", "product_variant_price_sets"],
args: {
entity: "LinkProductVariantPriceSet",
},
},
],
primaryKeys: ["id", "variant_id", "price_set_id"],
+34 -3
View File
@@ -1,4 +1,8 @@
import { InternalModuleDeclaration, MedusaModule } from "@medusajs/modules-sdk"
import {
InternalModuleDeclaration,
MedusaModule,
ModuleRegistrationName,
} from "@medusajs/modules-sdk"
import {
ExternalModuleDeclaration,
ILinkModule,
@@ -15,11 +19,16 @@ import {
ContainerRegistrationKeys,
lowerCaseFirst,
simpleHash,
toPascalCase,
} from "@medusajs/utils"
import * as linkDefinitions from "../definitions"
import { getMigration } from "../migration"
import { InitializeModuleInjectableDependencies } from "../types"
import { composeLinkName, generateGraphQLSchema } from "../utils"
import {
composeLinkName,
composeTableName,
generateGraphQLSchema,
} from "../utils"
import { getLinkModuleDefinition } from "./module-definition"
export const initialize = async (
@@ -98,7 +107,28 @@ export const initialize = async (
continue
}
definition.schema = generateGraphQLSchema(definition, primary, foreign)
const logger =
injectedDependencies?.[ContainerRegistrationKeys.LOGGER] ?? console.log
definition.schema = generateGraphQLSchema(definition, primary, foreign, {
logger,
})
definition.alias ??= []
for (const alias of definition.alias) {
alias.args ??= {}
alias.args.entity = toPascalCase(
"Link_" +
(definition.databaseConfig?.tableName ??
composeTableName(
primary.serviceName,
primary.foreignKey,
foreign.serviceName,
foreign.foreignKey
))
)
}
const moduleDefinition = getLinkModuleDefinition(
definition,
@@ -110,6 +140,7 @@ export const initialize = async (
key: serviceKey,
registrationName: serviceKey,
label: serviceKey,
dependencies: [ModuleRegistrationName.EVENT_BUS],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: injectedDependencies?.[
@@ -7,7 +7,9 @@ import {
ModuleJoinerConfig,
ModulesSdkTypes,
} from "@medusajs/types"
import { lowerCaseFirst, simpleHash, toPascalCase } from "@medusajs/utils"
import { asClass, asValue } from "awilix"
import { composeLinkName, composeTableName } from "../utils"
export function containerLoader(entity, joinerConfig: ModuleJoinerConfig) {
return async (
@@ -22,6 +24,29 @@ export function containerLoader(entity, joinerConfig: ModuleJoinerConfig) {
): Promise<void> => {
const [primary, foreign] = joinerConfig.relationships!
const serviceName = !joinerConfig.isReadOnlyLink
? lowerCaseFirst(
joinerConfig.serviceName ??
composeLinkName(
primary.serviceName,
primary.foreignKey,
foreign.serviceName,
foreign.foreignKey
)
)
: simpleHash(JSON.stringify(joinerConfig.extends))
const entityName = toPascalCase(
"Link_" +
(joinerConfig.databaseConfig?.tableName ??
composeTableName(
primary.serviceName,
primary.foreignKey,
foreign.serviceName,
foreign.foreignKey
))
)
container.register({
joinerConfig: asValue(joinerConfig),
primaryKey: asValue(primary.foreignKey.split(",")),
@@ -35,6 +60,8 @@ export function containerLoader(entity, joinerConfig: ModuleJoinerConfig) {
baseRepository: asClass(BaseRepository).singleton(),
linkRepository: asClass(getLinkRepository(entity)).singleton(),
entityName: asValue(entityName),
serviceName: asValue(serviceName),
})
}
}
@@ -2,6 +2,7 @@ import {
Context,
DAL,
FindConfig,
IEventBusModuleService,
ILinkModule,
InternalModuleDeclaration,
ModuleJoinerConfig,
@@ -9,6 +10,7 @@ import {
SoftDeleteReturn,
} from "@medusajs/types"
import {
CommonEvents,
InjectManager,
InjectTransactionManager,
MapToConfig,
@@ -24,14 +26,20 @@ import { shouldForceTransaction } from "../utils"
type InjectedDependencies = {
baseRepository: DAL.RepositoryService
linkService: LinkService<any>
eventBusModuleService?: IEventBusModuleService
primaryKey: string | string[]
foreignKey: string
extraFields: string[]
entityName: string
serviceName: string
}
export default class LinkModuleService<TLink> implements ILinkModule {
protected baseRepository_: DAL.RepositoryService
protected readonly linkService_: LinkService<TLink>
protected readonly eventBusModuleService_?: IEventBusModuleService
protected readonly entityName_: string
protected readonly serviceName_: string
protected primaryKey_: string[]
protected foreignKey_: string
protected extraFields_: string[]
@@ -40,17 +48,23 @@ export default class LinkModuleService<TLink> implements ILinkModule {
{
baseRepository,
linkService,
eventBusModuleService,
primaryKey,
foreignKey,
extraFields,
entityName,
serviceName,
}: InjectedDependencies,
readonly moduleDeclaration: InternalModuleDeclaration
) {
this.baseRepository_ = baseRepository
this.linkService_ = linkService
this.eventBusModuleService_ = eventBusModuleService
this.primaryKey_ = !Array.isArray(primaryKey) ? [primaryKey] : primaryKey
this.foreignKey_ = foreignKey
this.extraFields_ = extraFields
this.entityName_ = entityName
this.serviceName_ = serviceName
}
__joinerConfig(): ModuleJoinerConfig {
@@ -188,6 +202,21 @@ export default class LinkModuleService<TLink> implements ILinkModule {
const links = await this.linkService_.create(data, sharedContext)
await this.eventBusModuleService_?.emit<Record<string, unknown>>(
(data as { id: unknown }[]).map(({ id }) => ({
eventName: this.entityName_ + "." + CommonEvents.ATTACHED,
body: {
metadata: {
service: this.serviceName_,
action: CommonEvents.ATTACHED,
object: this.entityName_,
eventGroupId: sharedContext.eventGroupId,
},
data: { id },
},
}))
)
return await this.baseRepository_.serialize<object[]>(links)
}
@@ -224,6 +253,22 @@ export default class LinkModuleService<TLink> implements ILinkModule {
this.validateFields(data)
await this.linkService_.delete(data, sharedContext)
const allData = Array.isArray(data) ? data : [data]
await this.eventBusModuleService_?.emit<Record<string, unknown>>(
allData.map(({ id }) => ({
eventName: this.entityName_ + "." + CommonEvents.DETACHED,
body: {
metadata: {
service: this.serviceName_,
action: CommonEvents.DETACHED,
object: this.entityName_,
eventGroupId: sharedContext.eventGroupId,
},
data: { id },
},
}))
)
}
async softDelete(
@@ -233,7 +278,10 @@ export default class LinkModuleService<TLink> implements ILinkModule {
): Promise<Record<string, unknown[]> | void> {
this.validateFields(data)
let [, cascadedEntitiesMap] = await this.softDelete_(data, sharedContext)
let [deletedEntities, cascadedEntitiesMap] = await this.softDelete_(
data,
sharedContext
)
const pk = this.primaryKey_.join(",")
const entityNameToLinkableKeysMap: MapToConfig = {
@@ -256,6 +304,21 @@ export default class LinkModuleService<TLink> implements ILinkModule {
)
}
await this.eventBusModuleService_?.emit<Record<string, unknown>>(
(deletedEntities as { id: string }[]).map(({ id }) => ({
eventName: this.entityName_ + "." + CommonEvents.DETACHED,
body: {
metadata: {
service: this.serviceName_,
action: CommonEvents.DETACHED,
object: this.entityName_,
eventGroupId: sharedContext.eventGroupId,
},
data: { id },
},
}))
)
return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0
}
@@ -263,7 +326,7 @@ export default class LinkModuleService<TLink> implements ILinkModule {
protected async softDelete_(
data: any,
@MedusaContext() sharedContext: Context = {}
): Promise<[string[], Record<string, string[]>]> {
): Promise<[object[], Record<string, string[]>]> {
return await this.linkService_.softDelete(data, sharedContext)
}
@@ -274,7 +337,10 @@ export default class LinkModuleService<TLink> implements ILinkModule {
): Promise<Record<string, unknown[]> | void> {
this.validateFields(data)
let [, cascadedEntitiesMap] = await this.restore_(data, sharedContext)
let [restoredEntities, cascadedEntitiesMap] = await this.restore_(
data,
sharedContext
)
const pk = this.primaryKey_.join(",")
const entityNameToLinkableKeysMap: MapToConfig = {
@@ -297,6 +363,21 @@ export default class LinkModuleService<TLink> implements ILinkModule {
)
}
await this.eventBusModuleService_?.emit<Record<string, unknown>>(
(restoredEntities as { id: string }[]).map(({ id }) => ({
eventName: this.entityName_ + "." + CommonEvents.ATTACHED,
body: {
metadata: {
service: this.serviceName_,
action: CommonEvents.ATTACHED,
object: this.entityName_,
eventGroupId: sharedContext.eventGroupId,
},
data: { id },
},
}))
)
return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0
}
@@ -304,7 +385,7 @@ export default class LinkModuleService<TLink> implements ILinkModule {
async restore_(
data: any,
@MedusaContext() sharedContext: Context = {}
): Promise<[string[], Record<string, string[]>]> {
): Promise<[object[], Record<string, string[]>]> {
return await this.linkService_.restore(data, sharedContext)
}
}
+2 -2
View File
@@ -89,7 +89,7 @@ export default class LinkService<TEntity> {
async softDelete(
data: any,
@MedusaContext() sharedContext: Context = {}
): Promise<[string[], Record<string, string[]>]> {
): Promise<[object[], Record<string, string[]>]> {
const filter = {}
for (const key in data) {
filter[key] = { $in: Array.isArray(data[key]) ? data[key] : [data[key]] }
@@ -104,7 +104,7 @@ export default class LinkService<TEntity> {
async restore(
data: any,
@MedusaContext() sharedContext: Context = {}
): Promise<[string[], Record<string, string[]>]> {
): Promise<[object[], Record<string, string[]>]> {
const filter = {}
for (const key in data) {
filter[key] = { $in: Array.isArray(data[key]) ? data[key] : [data[key]] }