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
2024-02-05 11:59:10 +00:00
committed by GitHub
parent 73fd92a1af
commit 884428a1b5
66 changed files with 1407 additions and 749 deletions
@@ -1,94 +0,0 @@
import { mergeTypeDefs } from "@graphql-tools/merge"
import { makeExecutableSchema } from "@graphql-tools/schema"
import { getFieldsAndRelations } from "../../utils"
const userModule = `
type User {
id: ID!
name: String!
blabla: WHATEVER
}
type Post {
author: User!
}
`
const postModule = `
type Post {
id: ID!
title: String!
date: String
}
type User {
posts: [Post!]!
}
type WHATEVER {
random_field: String
post: Post
}
`
const mergedSchema = mergeTypeDefs([userModule, postModule])
const schema = makeExecutableSchema({
typeDefs: mergedSchema,
})
const types = schema.getTypeMap()
describe("getFieldsAndRelations", function () {
it("Should get all fields of a given entity", async function () {
const fields = getFieldsAndRelations(types, "User")
expect(fields).toEqual(expect.arrayContaining(["id", "name"]))
})
it("Should get all fields of a given entity and a relation", async function () {
const fields = getFieldsAndRelations(types, "User", ["posts"])
expect(fields).toEqual(
expect.arrayContaining([
"id",
"name",
"posts.id",
"posts.title",
"posts.date",
])
)
})
it("Should get all fields of a given entity and many relations", async function () {
const fields = getFieldsAndRelations(types, "User", [
"posts",
"blabla",
"blabla.post",
])
expect(fields).toEqual(
expect.arrayContaining([
"id",
"name",
"posts.id",
"posts.title",
"posts.date",
"blabla.random_field",
"blabla.post.id",
"blabla.post.title",
"blabla.post.date",
])
)
})
it("Should get all fields of a given entity and many relations limited to the relations given", async function () {
const fields = getFieldsAndRelations(types, "User", ["posts", "blabla"])
expect(fields).toEqual(
expect.arrayContaining([
"id",
"name",
"posts.id",
"posts.title",
"posts.date",
"blabla.random_field",
])
)
})
})
+6 -5
View File
@@ -13,6 +13,7 @@ import {
ModuleJoinerConfig,
ModuleServiceInitializeOptions,
RemoteJoinerQuery,
RemoteQueryFunction,
} from "@medusajs/types"
import {
ContainerRegistrationKeys,
@@ -41,6 +42,7 @@ export type RunMigrationFn = (
export type MedusaModuleConfig = {
[key: string | Modules]:
| string
| boolean
| Partial<InternalModuleDeclaration | ExternalModuleDeclaration>
}
@@ -182,10 +184,7 @@ function registerCustomJoinerConfigs(servicesConfig: ModuleJoinerConfig[]) {
export type MedusaAppOutput = {
modules: Record<string, LoadedModule | LoadedModule[]>
link: RemoteLink | undefined
query: (
query: string | RemoteJoinerQuery | object,
variables?: Record<string, unknown>
) => Promise<any>
query: RemoteQueryFunction
entitiesMap?: Record<string, any>
notFound?: Record<string, Record<string, string>>
runMigrations: RunMigrationFn
@@ -201,6 +200,7 @@ export async function MedusaApp({
linkModules,
remoteFetchData,
injectedDependencies,
onApplicationStartCb,
}: {
sharedContainer?: MedusaContainer
sharedResourcesConfig?: SharedResources
@@ -212,6 +212,7 @@ export async function MedusaApp({
linkModules?: ModuleJoinerConfig | ModuleJoinerConfig[]
remoteFetchData?: RemoteFetchDataCallback
injectedDependencies?: any
onApplicationStartCb?: () => void
} = {}): Promise<{
modules: Record<string, LoadedModule | LoadedModule[]>
link: RemoteLink | undefined
@@ -355,6 +356,6 @@ export async function MedusaApp({
runMigrations,
}
} finally {
await MedusaModule.onApplicationStart()
MedusaModule.onApplicationStart(onApplicationStartCb)
}
}
+15 -4
View File
@@ -69,7 +69,8 @@ export type LinkModuleBootstrapOptions = {
}
export class MedusaModule {
private static instances_: Map<string, any> = new Map()
private static instances_: Map<string, { [key: string]: IModuleService }> =
new Map()
private static modules_: Map<string, ModuleAlias[]> = new Map()
private static loading_: Map<string, Promise<any>> = new Map()
private static joinerConfig_: Map<string, ModuleJoinerConfig> = new Map()
@@ -87,12 +88,15 @@ export class MedusaModule {
})
}
public static onApplicationStart(): void {
public static onApplicationStart(onApplicationStartCb?: () => void): void {
for (const instances of MedusaModule.instances_.values()) {
for (const instance of Object.values(instances) as IModuleService[]) {
if (instance?.__hooks) {
instance.__hooks?.onApplicationStart
?.bind(instance)()
.then(() => {
onApplicationStartCb?.()
})
.catch(() => {
// The module should handle this and log it
return void 0
@@ -217,7 +221,9 @@ export class MedusaModule {
)
if (MedusaModule.instances_.has(hashKey)) {
return MedusaModule.instances_.get(hashKey)
return MedusaModule.instances_.get(hashKey)! as {
[key: string]: T
}
}
if (MedusaModule.loading_.has(hashKey)) {
@@ -249,7 +255,12 @@ export class MedusaModule {
}
}
const container = createMedusaContainer({}, sharedContainer)
// TODO: Only do that while legacy modules sharing the manager exists then remove the ternary in favor of createMedusaContainer({}, globalContainer)
const container =
modDeclaration.scope === MODULE_SCOPE.INTERNAL &&
modDeclaration.resources === MODULE_RESOURCE_TYPE.SHARED
? sharedContainer ?? createMedusaContainer()
: createMedusaContainer({}, sharedContainer)
if (injectedDependencies) {
for (const service in injectedDependencies) {
@@ -1,37 +0,0 @@
import { GraphQLNamedType, GraphQLObjectType, isObjectType } from "graphql"
export function getFieldsAndRelations(
schemaTypeMap: { [key: string]: GraphQLNamedType },
typeName: string,
relations: string[] = []
) {
const result: string[] = []
function traverseFields(typeName, prefix) {
const type = schemaTypeMap[typeName]
if (!(type instanceof GraphQLObjectType)) {
return
}
const fields = type.getFields()
for (const fieldName in fields) {
const field = fields[fieldName]
let fieldType = field.type as any
while (fieldType.ofType) {
fieldType = fieldType.ofType
}
if (!isObjectType(fieldType)) {
result.push(`${prefix}${fieldName}`)
} else if (relations.includes(prefix + fieldName)) {
traverseFields(fieldType.name, `${prefix}${fieldName}.`)
}
}
}
traverseFields(typeName, "")
return result
}
-1
View File
@@ -1,3 +1,2 @@
export * from "./clean-graphql-schema"
export * from "./get-fields-and-relations"
export * from "./graphql-schema-to-fields"