From ceddce943528e393e0576c9bb4a330a90cb8fe9a Mon Sep 17 00:00:00 2001 From: killagu Date: Mon, 30 Sep 2024 02:40:21 +0800 Subject: [PATCH] fix: fix miss MultiInstance proper qualifiers --- core/core-decorator/src/util/PrototypeUtil.ts | 21 +++- .../src/factory/EggPrototypeCreatorFactory.ts | 19 ++- core/metadata/src/impl/EggPrototypeBuilder.ts | 28 +++-- core/metadata/src/impl/ModuleLoadUnit.ts | 109 ++++++------------ core/metadata/src/model/AppGraph.ts | 35 +++--- .../app/modules/app/module.yml | 6 +- .../app/modules/app2/App.ts | 5 +- .../app/modules/bar/BizManager.ts | 7 +- .../app/modules/foo/Secret.ts | 17 +-- .../core-decorator/model/EggPrototypeInfo.ts | 2 +- .../app/modules/bar/BizManager.ts | 2 +- 11 files changed, 130 insertions(+), 121 deletions(-) diff --git a/core/core-decorator/src/util/PrototypeUtil.ts b/core/core-decorator/src/util/PrototypeUtil.ts index fbba59df6..fb30a4ad9 100644 --- a/core/core-decorator/src/util/PrototypeUtil.ts +++ b/core/core-decorator/src/util/PrototypeUtil.ts @@ -3,10 +3,10 @@ import { EggMultiInstancePrototypeInfo, EggProtoImplClass, EggPrototypeInfo, - EggPrototypeName, + EggPrototypeName, InitTypeQualifierAttribute, InjectConstructorInfo, InjectObjectInfo, - InjectType, + InjectType, LoadUnitNameQualifierAttribute, MultiInstancePrototypeGetObjectsContext, QualifierAttribute, } from '@eggjs/tegg-types'; import { MetadataUtil } from './MetadataUtil'; @@ -141,9 +141,24 @@ export class PrototypeUtil { } const callBackMetadata = MetadataUtil.getMetaData(PrototypeUtil.MULTI_INSTANCE_PROTOTYPE_CALLBACK_PROPERTY, clazz); if (callBackMetadata) { + const objects = callBackMetadata.getObjects(ctx); + const defaultQualifier = [{ + attribute: InitTypeQualifierAttribute, + value: callBackMetadata.initType, + }, { + attribute: LoadUnitNameQualifierAttribute, + value: ctx.moduleName, + }]; + for (const object of objects) { + defaultQualifier.forEach(qualifier => { + if (!object.qualifiers.find(t => t.attribute === qualifier.attribute)) { + object.qualifiers.push(qualifier); + } + }); + } return { ...callBackMetadata, - objects: callBackMetadata.getObjects(ctx), + objects, }; } } diff --git a/core/metadata/src/factory/EggPrototypeCreatorFactory.ts b/core/metadata/src/factory/EggPrototypeCreatorFactory.ts index 5ec9f7526..d09dc6793 100644 --- a/core/metadata/src/factory/EggPrototypeCreatorFactory.ts +++ b/core/metadata/src/factory/EggPrototypeCreatorFactory.ts @@ -1,4 +1,4 @@ -import { PrototypeUtil } from '@eggjs/core-decorator'; +import { InitTypeQualifierAttribute, LoadUnitNameQualifierAttribute, PrototypeUtil } from '@eggjs/core-decorator'; import type { EggProtoImplClass, EggPrototypeInfo, @@ -28,12 +28,29 @@ export class EggPrototypeCreatorFactory { moduleName: loadUnit.name, })!; for (const obj of multiInstanceProtoInfo.objects) { + const defaultQualifier = [{ + attribute: InitTypeQualifierAttribute, + value: PrototypeUtil.getInitType(clazz, { + unitPath: loadUnit.unitPath, + moduleName: loadUnit.name, + })!, + }, { + attribute: LoadUnitNameQualifierAttribute, + value: loadUnit.name, + }]; + defaultQualifier.forEach(qualifier => { + if (!obj.qualifiers.find(t => t.attribute === qualifier.attribute)) { + obj.qualifiers.push(qualifier); + } + }); + properties.push({ name: obj.name, protoImplType: multiInstanceProtoInfo.protoImplType, initType: multiInstanceProtoInfo.initType, accessLevel: multiInstanceProtoInfo.accessLevel, qualifiers: obj.qualifiers, + properQualifiers: obj.properQualifiers, className: multiInstanceProtoInfo.className, }); } diff --git a/core/metadata/src/impl/EggPrototypeBuilder.ts b/core/metadata/src/impl/EggPrototypeBuilder.ts index cda7fadbf..1f43b3005 100644 --- a/core/metadata/src/impl/EggPrototypeBuilder.ts +++ b/core/metadata/src/impl/EggPrototypeBuilder.ts @@ -34,6 +34,7 @@ export class EggPrototypeBuilder { private injectObjects: Array = []; private loadUnit: LoadUnit; private qualifiers: QualifierInfo[] = []; + private properQualifiers: Record = {}; private className?: string; private multiInstanceConstructorIndex?: number; private multiInstanceConstructorAttributes?: QualifierAttribute[]; @@ -56,6 +57,8 @@ export class EggPrototypeBuilder { ...QualifierUtil.getProtoQualifiers(clazz), ...(ctx.prototypeInfo.qualifiers ?? []), ]; + console.log('proto: ', ctx.prototypeInfo.properQualifiers); + builder.properQualifiers = ctx.prototypeInfo.properQualifiers ?? {}; builder.multiInstanceConstructorIndex = PrototypeUtil.getMultiInstanceConstructorIndex(clazz); builder.multiInstanceConstructorAttributes = PrototypeUtil.getMultiInstanceConstructorAttributes(clazz); return builder.build(); @@ -63,31 +66,38 @@ export class EggPrototypeBuilder { private tryFindDefaultPrototype(injectObject: InjectObject): EggPrototype { const propertyQualifiers = QualifierUtil.getProperQualifiers(this.clazz, injectObject.refName); - return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, propertyQualifiers); + const multiInstancePropertyQualifiers = this.properQualifiers[injectObject.refName as string] ?? []; + console.log('multi instance: ', this.properQualifiers, injectObject.refName); + return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, [ + ...propertyQualifiers, + ...multiInstancePropertyQualifiers, + ]); } private tryFindContextPrototype(injectObject: InjectObject): EggPrototype { - let propertyQualifiers = QualifierUtil.getProperQualifiers(this.clazz, injectObject.refName); - propertyQualifiers = [ + const propertyQualifiers = QualifierUtil.getProperQualifiers(this.clazz, injectObject.refName); + const multiInstancePropertyQualifiers = this.properQualifiers[injectObject.refName as string] ?? []; + return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, [ ...propertyQualifiers, + ...multiInstancePropertyQualifiers, { attribute: InitTypeQualifierAttribute, value: ObjectInitType.CONTEXT, }, - ]; - return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, propertyQualifiers); + ]); } private tryFindSelfInitTypePrototype(injectObject: InjectObject): EggPrototype { - let propertyQualifiers = QualifierUtil.getProperQualifiers(this.clazz, injectObject.refName); - propertyQualifiers = [ + const propertyQualifiers = QualifierUtil.getProperQualifiers(this.clazz, injectObject.refName); + const multiInstancePropertyQualifiers = this.properQualifiers[injectObject.refName as string] ?? []; + return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, [ ...propertyQualifiers, + ...multiInstancePropertyQualifiers, { attribute: InitTypeQualifierAttribute, value: this.initType, }, - ]; - return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, propertyQualifiers); + ]); } private findInjectObjectPrototype(injectObject: InjectObject): EggPrototype { diff --git a/core/metadata/src/impl/ModuleLoadUnit.ts b/core/metadata/src/impl/ModuleLoadUnit.ts index e3d334390..bf861894c 100644 --- a/core/metadata/src/impl/ModuleLoadUnit.ts +++ b/core/metadata/src/impl/ModuleLoadUnit.ts @@ -35,15 +35,17 @@ class ProtoNode implements GraphNodeObj { readonly qualifiers: QualifierInfo[]; readonly initType: ObjectInitTypeLike; - constructor(clazz: EggProtoImplClass, objName: EggPrototypeName, unitPath: string, moduleName: string) { + constructor( + clazz: EggProtoImplClass, + objName: EggPrototypeName, + initType: ObjectInitTypeLike, + qualifiers: QualifierInfo[], + ) { this.name = objName; this.id = '' + (id++); this.clazz = clazz; - this.qualifiers = QualifierUtil.getProtoQualifiers(clazz); - this.initType = PrototypeUtil.getInitType(clazz, { - unitPath, - moduleName, - })!; + this.qualifiers = qualifiers; + this.initType = initType; } verifyQualifiers(qualifiers: QualifierInfo[]): boolean { @@ -65,77 +67,21 @@ class ProtoNode implements GraphNodeObj { } } -class MultiInstanceProtoNode implements GraphNodeObj { - readonly clazz: EggProtoImplClass; - readonly name: EggPrototypeName; - readonly id: string; - readonly qualifiers: QualifierInfo[]; - readonly initType: ObjectInitTypeLike; - readonly unitPath: string; - readonly moduleName: string; - - constructor(clazz: EggProtoImplClass, objName: EggPrototypeName, unitPath: string, moduleName: string) { - this.name = objName; - this.id = '' + (id++); - this.clazz = clazz; - this.qualifiers = QualifierUtil.getProtoQualifiers(clazz); - this.initType = PrototypeUtil.getInitType(clazz, { - unitPath, - moduleName, - })!; - this.unitPath = unitPath; - this.moduleName = moduleName; - } - - verifyQualifiers(qualifiers: QualifierInfo[]): boolean { - const property = PrototypeUtil.getMultiInstanceProperty(this.clazz, { - unitPath: this.unitPath, - moduleName: this.moduleName, - }); - if (!property) { - return false; - } - for (const obj of property.objects) { - const selfQualifiers = [ - ...this.qualifiers, - ...obj.qualifiers, - ]; - if (this.verifyInstanceQualifiers(selfQualifiers, qualifiers)) { - return true; - } - } - return false; - } - - verifyInstanceQualifiers(selfQualifiers: QualifierInfo[], qualifiers: QualifierInfo[]): boolean { - for (const qualifier of qualifiers) { - if (!selfQualifiers.find(t => t.attribute === qualifier.attribute && t.value === qualifier.value)) { - return false; - } - } - return true; - } - - toString(): string { - return `${this.clazz.name}@${PrototypeUtil.getFilePath(this.clazz)}`; - } -} - export class ModuleGraph { - private graph: Graph; + private graph: Graph; clazzList: EggProtoImplClass[]; readonly unitPath: string; readonly name: string; constructor(clazzList: EggProtoImplClass[], unitPath: string, name: string) { this.clazzList = clazzList; - this.graph = new Graph(); + this.graph = new Graph(); this.unitPath = unitPath; this.name = name; this.build(); } - private findInjectNode(objName: EggPrototypeName, qualifiers: QualifierInfo[], parentInitTye: ObjectInitTypeLike): GraphNode | undefined { + private findInjectNode(objName: EggPrototypeName, qualifiers: QualifierInfo[], parentInitTye: ObjectInitTypeLike): GraphNode | undefined { let nodes = Array.from(this.graph.nodes.values()) .filter(t => t.val.name === objName) .filter(t => t.val.verifyQualifiers(qualifiers)); @@ -156,7 +102,7 @@ export class ModuleGraph { return nodes[0]; } - const temp: Map> = new Map(); + const temp: Map> = new Map(); for (const node of nodes) { temp.set(node.val.clazz, node); } @@ -170,17 +116,28 @@ export class ModuleGraph { } private build() { - const protoGraphNodes: GraphNode[] = []; + const protoGraphNodes: GraphNode[] = []; for (const clazz of this.clazzList) { - const objNames = PrototypeUtil.getObjNames(clazz, { - unitPath: this.unitPath, - moduleName: this.name, - }); - for (const objName of objNames) { - if (PrototypeUtil.isEggMultiInstancePrototype(clazz)) { - protoGraphNodes.push(new GraphNode(new MultiInstanceProtoNode(clazz, objName, this.unitPath, this.name))); - } else { - protoGraphNodes.push(new GraphNode(new ProtoNode(clazz, objName, this.unitPath, this.name))); + if (PrototypeUtil.isEggMultiInstancePrototype(clazz)) { + const properties = PrototypeUtil.getMultiInstanceProperty(clazz, { + unitPath: this.unitPath, + moduleName: this.name, + }); + if (properties) { + const qualifiers = QualifierUtil.getProtoQualifiers(clazz); + for (const obj of properties.objects || []) { + const instanceQualifiers = [ + ...qualifiers, + ...obj.qualifiers, + ]; + protoGraphNodes.push(new GraphNode(new ProtoNode(clazz, obj.name, properties.initType, instanceQualifiers))); + } + } + } else { + const qualifiers = QualifierUtil.getProtoQualifiers(clazz); + const property = PrototypeUtil.getProperty(clazz); + if (property) { + protoGraphNodes.push(new GraphNode(new ProtoNode(clazz, property.name, property.initType, qualifiers))); } } } diff --git a/core/metadata/src/model/AppGraph.ts b/core/metadata/src/model/AppGraph.ts index 89cfade9e..ec05becd1 100644 --- a/core/metadata/src/model/AppGraph.ts +++ b/core/metadata/src/model/AppGraph.ts @@ -55,6 +55,10 @@ export class ClazzMap { }); assert(property, `multi instance property not found for ${clazz.name}`); for (const info of property.objects) { + const instanceQualifiers = [ + ...qualifiers, + ...info.qualifiers, + ]; clazzMap[info.name] = clazzMap[info.name] || []; clazzMap[info.name].push({ name: info.name, @@ -62,10 +66,7 @@ export class ClazzMap { unitPath: instanceNode.val.moduleConfig.path, moduleName: instanceNode.val.moduleConfig.name, }) as AccessLevel, - qualifiers: [ - ...qualifiers, - ...info.qualifiers, - ], + qualifiers: instanceQualifiers, properQualifiers: info.properQualifiers || {}, instanceModule: instanceNode, ownerModule: ownerNode, @@ -179,18 +180,20 @@ export class ModuleNode implements GraphNodeObj { if (!this.clazzList.includes(clazz)) { this.clazzList.push(clazz); } - const defaultQualifier = [{ - attribute: InitTypeQualifierAttribute, - value: PrototypeUtil.getInitType(clazz, { - unitPath: this.moduleConfig.path, - moduleName: this.moduleConfig.name, - })!, - }, { - attribute: LoadUnitNameQualifierAttribute, - value: this.name, - }]; - for (const qualifier of defaultQualifier) { - QualifierUtil.addProtoQualifier(clazz, qualifier.attribute, qualifier.value); + if (!PrototypeUtil.isEggMultiInstancePrototype(clazz)) { + const defaultQualifier = [{ + attribute: InitTypeQualifierAttribute, + value: PrototypeUtil.getInitType(clazz, { + unitPath: this.moduleConfig.path, + moduleName: this.moduleConfig.name, + })!, + }, { + attribute: LoadUnitNameQualifierAttribute, + value: this.name, + }]; + for (const qualifier of defaultQualifier) { + QualifierUtil.addProtoQualifier(clazz, qualifier.attribute, qualifier.value); + } } } diff --git a/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/app/module.yml b/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/app/module.yml index 34e00088b..1922f3623 100644 --- a/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/app/module.yml +++ b/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/app/module.yml @@ -1,7 +1,9 @@ BizManager: clients: - foo: {} - bar: {} + foo: + secret: '1' + bar: + secret: '2' secret: keys: diff --git a/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/app2/App.ts b/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/app2/App.ts index 06c1e1c6a..09aaa2592 100644 --- a/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/app2/App.ts +++ b/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/app2/App.ts @@ -1,9 +1,10 @@ -import { Inject, SingletonProto } from '@eggjs/core-decorator'; +import { Inject, ModuleQualifier, SingletonProto } from '@eggjs/core-decorator'; import { Secret, SecretQualifier } from '../foo/Secret'; @SingletonProto() export class App2 { @Inject() - @SecretQualifier('app2') + @ModuleQualifier('app2') + @SecretQualifier('1') secret: Secret; } diff --git a/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/bar/BizManager.ts b/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/bar/BizManager.ts index 82f9bc5c8..f4199efc9 100644 --- a/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/bar/BizManager.ts +++ b/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/bar/BizManager.ts @@ -8,10 +8,10 @@ import { MultiInstanceInfo, } from '@eggjs/tegg'; import { ModuleConfigUtil } from '@eggjs/tegg-common-util'; -import { EggProtoImplClass, QualifierUtil } from '@eggjs/core-decorator'; +import { EggProtoImplClass, LoadUnitNameQualifierAttribute, QualifierUtil } from '@eggjs/core-decorator'; import { Secret, SecretQualifierAttribute } from '../foo/Secret'; -export const BizManagerQualifierAttribute = Symbol.for('Qualifier.ChatModel'); +export const BizManagerQualifierAttribute = Symbol.for('Qualifier.BizManager'); export const BizManagerInjectName = 'bizManager'; export function BizManagerQualifier(chatModelName: string) { @@ -41,6 +41,9 @@ export function BizManagerQualifier(chatModelName: string) { properQualifiers: { secret: [{ attribute: SecretQualifierAttribute, + value: clients[clientName].secret, + }, { + attribute: LoadUnitNameQualifierAttribute, value: name, }], }, diff --git a/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/foo/Secret.ts b/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/foo/Secret.ts index 8dfa7d1c5..96bf51f02 100644 --- a/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/foo/Secret.ts +++ b/core/metadata/test/fixtures/modules/app-multi-inject-multi/app/modules/foo/Secret.ts @@ -25,14 +25,15 @@ export function SecretQualifier(chatModelName: string) { const config = ModuleConfigUtil.loadModuleConfigSync(ctx.unitPath) as any; const keys = config?.secret?.keys; if (!keys || keys.length === 0) return []; - const name = ModuleConfigUtil.readModuleNameSync(ctx.unitPath); - return [{ - name: SecretInjectName, - qualifiers: [{ - attribute: SecretQualifierAttribute, - value: name, - }], - }]; + return keys.map(t => { + return { + name: SecretInjectName, + qualifiers: [{ + attribute: SecretQualifierAttribute, + value: t, + }], + }; + }); }, }) export class Secret { diff --git a/core/types/core-decorator/model/EggPrototypeInfo.ts b/core/types/core-decorator/model/EggPrototypeInfo.ts index a886a7730..a193aa35e 100644 --- a/core/types/core-decorator/model/EggPrototypeInfo.ts +++ b/core/types/core-decorator/model/EggPrototypeInfo.ts @@ -33,5 +33,5 @@ export interface EggPrototypeInfo { /** * EggPrototype properties qualifiers */ - properQualifiers?: QualifierInfo[]; + properQualifiers?: Record; } diff --git a/plugin/tegg/test/fixtures/apps/app-multi-inject-multi/app/modules/bar/BizManager.ts b/plugin/tegg/test/fixtures/apps/app-multi-inject-multi/app/modules/bar/BizManager.ts index 317454edf..ad7c28b1a 100644 --- a/plugin/tegg/test/fixtures/apps/app-multi-inject-multi/app/modules/bar/BizManager.ts +++ b/plugin/tegg/test/fixtures/apps/app-multi-inject-multi/app/modules/bar/BizManager.ts @@ -11,7 +11,7 @@ import { ModuleConfigUtil } from '@eggjs/tegg-common-util'; import { EggProtoImplClass, QualifierUtil } from '@eggjs/core-decorator'; import { Secret, SecretQualifierAttribute } from '../foo/Secret'; -export const BizManagerQualifierAttribute = Symbol.for('Qualifier.ChatModel'); +export const BizManagerQualifierAttribute = Symbol.for('Qualifier.BizManager'); export const BizManagerInjectName = 'bizManager'; export function BizManagerQualifier(chatModelName: string) {