Skip to content

Commit

Permalink
fix: fix merge qualifier (#250)
Browse files Browse the repository at this point in the history
<!--
Thank you for your pull request. Please review below requirements.
Bug fixes and new features should include tests and possibly benchmarks.
Contributors guide:
https://github.com/eggjs/egg/blob/master/CONTRIBUTING.md

感谢您贡献代码。请确认下列 checklist 的完成情况。
Bug 修复和新功能必须包含测试,必要时请附上性能测试。
Contributors guide:
https://github.com/eggjs/egg/blob/master/CONTRIBUTING.md
-->

##### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to
[x]. -->

- [ ] `npm test` passes
- [ ] tests and/or benchmarks are included
- [ ] documentation is changed or added
- [ ] commit message follows commit guidelines

##### Affected core subsystem(s)
<!-- Provide affected core subsystem(s). -->


##### Description of change
<!-- Provide a description of the change below this comment. -->

<!--
- any feature?
- close https://github.com/eggjs/egg/ISSUE_URL
-->
  • Loading branch information
killagu authored Oct 14, 2024
1 parent 8acbcc4 commit d5a8a93
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 53 deletions.
8 changes: 4 additions & 4 deletions core/aop-runtime/src/PointCutGraphHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ function findPointCutAdvice(globalGraph: GlobalGraph, protoNode: GraphNode<Proto
const injectProto = globalGraph.findDependencyProtoNode(protoNode.val.proto, {
objName: property.name,
refName: property.name,
qualifiers: [
...property?.qualifiers ?? [],
...QualifierUtil.getProtoQualifiers(clazz),
],
qualifiers: QualifierUtil.mergeQualifiers(
property?.qualifiers ?? [],
QualifierUtil.getProtoQualifiers(clazz),
),
});
if (injectProto) {
result.add(injectProto);
Expand Down
17 changes: 17 additions & 0 deletions core/core-decorator/src/util/QualifierUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,21 @@ export class QualifierUtil {
if (clazzQualifiers.length !== requestQualifiers.length) return false;
return QualifierUtil.matchQualifiers(clazzQualifiers, requestQualifiers);
}

static mergeQualifiers(...qualifiers: QualifierInfo[][]): QualifierInfo[] {
const result: QualifierInfo[] = [];
const temp: Record<QualifierAttribute, QualifierValue> = {};
for (const qualifierList of qualifiers) {
for (const { attribute, value } of qualifierList) {
temp[attribute] = value;
}
}
for (const key of Reflect.ownKeys(temp)) {
result.push({
attribute: key,
value: temp[key],
});
}
return result;
}
}
8 changes: 4 additions & 4 deletions core/dynamic-inject-runtime/src/EggObjectFactoryPrototype.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ export class EggObjectFactoryPrototype implements EggPrototype {

constructor(clazz: EggProtoImplClass<EggObjectFactory>, loadUnit: LoadUnit, prototypeInfo: EggPrototypeInfo) {
this.clazz = clazz;
this.qualifiers = [
...QualifierUtil.getProtoQualifiers(clazz),
...(prototypeInfo.qualifiers ?? []),
];
this.qualifiers = QualifierUtil.mergeQualifiers(
QualifierUtil.getProtoQualifiers(clazz),
(prototypeInfo.qualifiers ?? []),
);
this.id = IdenticalUtil.createProtoId(loadUnit.id, NameUtil.getClassName(this.clazz));
this.initType = prototypeInfo.initType;
this.accessLevel = prototypeInfo.accessLevel;
Expand Down
40 changes: 20 additions & 20 deletions core/metadata/src/impl/EggPrototypeBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ export class EggPrototypeBuilder {
builder.injectType = PrototypeUtil.getInjectType(clazz);
builder.injectObjects = PrototypeUtil.getInjectObjects(clazz) || [];
builder.loadUnit = loadUnit;
builder.qualifiers = [
...QualifierUtil.getProtoQualifiers(clazz),
...(ctx.prototypeInfo.qualifiers ?? []),
];
builder.qualifiers = QualifierUtil.mergeQualifiers(
QualifierUtil.getProtoQualifiers(clazz),
(ctx.prototypeInfo.qualifiers ?? []),
);
builder.properQualifiers = ctx.prototypeInfo.properQualifiers ?? {};
builder.multiInstanceConstructorIndex = PrototypeUtil.getMultiInstanceConstructorIndex(clazz);
builder.multiInstanceConstructorAttributes = PrototypeUtil.getMultiInstanceConstructorAttributes(clazz);
Expand All @@ -66,36 +66,36 @@ export class EggPrototypeBuilder {
private tryFindDefaultPrototype(injectObject: InjectObject): EggPrototype {
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,
]);
return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, QualifierUtil.mergeQualifiers(
propertyQualifiers,
multiInstancePropertyQualifiers,
));
}

private tryFindContextPrototype(injectObject: InjectObject): EggPrototype {
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,
{
return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, QualifierUtil.mergeQualifiers(
propertyQualifiers,
multiInstancePropertyQualifiers,
[{
attribute: InitTypeQualifierAttribute,
value: ObjectInitType.CONTEXT,
},
]);
}],
));
}

private tryFindSelfInitTypePrototype(injectObject: InjectObject): EggPrototype {
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,
{
return EggPrototypeFactory.instance.getPrototype(injectObject.objName, this.loadUnit, QualifierUtil.mergeQualifiers(
propertyQualifiers,
multiInstancePropertyQualifiers,
[{
attribute: InitTypeQualifierAttribute,
value: this.initType,
},
]);
}],
));
}

private findInjectObjectPrototype(injectObject: InjectObject): EggPrototype {
Expand Down
16 changes: 8 additions & 8 deletions core/metadata/src/model/ProtoDescriptorHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,21 @@ export class ProtoDescriptorHelper {
const res: ProtoDescriptor[] = [];

for (const obj of instanceProperty.objects) {
let qualifiers = [
...QualifierUtil.getProtoQualifiers(clazz),
...obj.qualifiers,
];
let qualifiers = QualifierUtil.mergeQualifiers(
QualifierUtil.getProtoQualifiers(clazz),
obj.qualifiers,
);
qualifiers = ProtoDescriptorHelper.addDefaultQualifier(qualifiers, instanceProperty.initType, options.instanceModuleName);
const injectObjects: InjectObjectDescriptor[] = PrototypeUtil.getInjectObjects(clazz)
.map(t => {
const qualifiers = QualifierUtil.getProperQualifiers(clazz, t.refName);
const instanceQualifier = obj.properQualifiers?.[t.refName] ?? [];
return {
...t,
qualifiers: [
...qualifiers,
...instanceQualifier,
],
qualifiers: QualifierUtil.mergeQualifiers(
qualifiers,
instanceQualifier,
),
};
});
res.push(new ClassProtoDescriptor({
Expand Down
19 changes: 10 additions & 9 deletions core/metadata/src/model/graph/GlobalGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { FrameworkErrorFormater } from 'egg-errors';
import { EggPrototypeNotFound, MultiPrototypeFound } from '../../errors';
import { GlobalModuleNodeBuilder } from './GlobalModuleNodeBuilder';
import { ModuleDescriptor } from '../ModuleDescriptor';
import { QualifierUtil } from '@eggjs/core-decorator';

export interface GlobalGraphOptions {
// TODO next major version refactor to force strict
Expand Down Expand Up @@ -145,10 +146,10 @@ export class GlobalGraph {
for (const node of this.protoGraph.nodes.values()) {
if (node.val.selectProto({
name: injectObject.objName,
qualifiers: [
...injectObject.qualifiers,
...qualifiers,
],
qualifiers: QualifierUtil.mergeQualifiers(
injectObject.qualifiers,
qualifiers,
),
moduleName: proto.instanceModuleName,
})) {
result.push(node);
Expand Down Expand Up @@ -189,13 +190,13 @@ export class GlobalGraph {
if (!loadUnitQualifier) {
return this.findDependencyProtoNode(proto, {
...injectObject,
qualifiers: [
...injectObject.qualifiers,
{
qualifiers: QualifierUtil.mergeQualifiers(
injectObject.qualifiers,
[{
attribute: LoadUnitNameQualifierAttribute,
value: proto.instanceModuleName,
},
],
}],
),
});
}
throw FrameworkErrorFormater.formatError(new MultiPrototypeFound(injectObject.objName, injectObject.qualifiers));
Expand Down
6 changes: 5 additions & 1 deletion core/runtime/src/impl/EggObjectUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ export class EggObjectUtil {
return target[p];
}
const obj = getObj();
return obj[p];
const val = obj[p];
if (typeof val === 'function') {
return val.bind(obj);
}
return val;
},
getOwnPropertyDescriptor(_target: {}, p: string | symbol): PropertyDescriptor | undefined {
const obj = getObj();
Expand Down
5 changes: 3 additions & 2 deletions plugin/dal/lib/TransactionalAOP.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Advice, AdviceContext, IAdvice } from '@eggjs/tegg/aop';
import { AccessLevel, EggProtoImplClass, ObjectInitType } from '@eggjs/tegg';
import { PropagationType } from '@eggjs/tegg/transaction';
import assert from 'node:assert';
import { MysqlDataSource } from '@eggjs/dal-runtime';

export interface TransactionalParams {
Expand All @@ -17,7 +16,9 @@ export class TransactionalAOP implements IAdvice<EggProtoImplClass, Transactiona
public async around(ctx: AdviceContext<EggProtoImplClass, TransactionalParams>, next: () => Promise<any>): Promise<void> {
const { propagation, dataSourceGetter } = ctx.adviceParams!;
const dataSource = dataSourceGetter();
assert(propagation === PropagationType.REQUIRED, '事务注解目前只支持 REQUIRED 机制');
if (propagation === PropagationType.ALWAYS_NEW) {
return await dataSource.beginTransactionScope(next);
}
return await dataSource.beginTransactionScope(next);
}
}
8 changes: 4 additions & 4 deletions plugin/tegg/lib/EggCompatibleProtoImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ export class EggCompatibleProtoImpl implements EggPrototype {
const name = ctx.prototypeInfo.name;
const id = IdenticalUtil.createProtoId(loadUnit.id, name);
const proto = new EggCompatibleProtoImpl(
id, name, clazz, ctx.prototypeInfo.initType, loadUnit.id, [
...QualifierUtil.getProtoQualifiers(clazz),
...(ctx.prototypeInfo.qualifiers ?? []),
],
id, name, clazz, ctx.prototypeInfo.initType, loadUnit.id, QualifierUtil.mergeQualifiers(
QualifierUtil.getProtoQualifiers(clazz),
(ctx.prototypeInfo.qualifiers ?? []),
),
);
return proto;
}
Expand Down
6 changes: 6 additions & 0 deletions plugin/tegg/test/ConstructorModuleConfig.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import mm from 'egg-mock';
import assert from 'assert';
import path from 'path';
import { Foo } from './fixtures/apps/constructor-module-config/modules/module-with-config/foo';

describe('plugin/tegg/test/ModuleConfig.test.ts', () => {
let app;
Expand Down Expand Up @@ -37,4 +38,9 @@ describe('plugin/tegg/test/ModuleConfig.test.ts', () => {
});
});
});

it('construct proxy should work', async () => {
const foo: Foo = await app.getEggObject(Foo);
foo.log();
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AccessLevel, Inject, SingletonProto } from '@eggjs/tegg';
import { EggLogger } from 'egg-logger';

@SingletonProto({
accessLevel: AccessLevel.PUBLIC,
Expand All @@ -7,8 +8,15 @@ export class Foo {
readonly foo: string;
readonly bar: string;

constructor(@Inject() moduleConfig: Record<string, any>) {
constructor(
@Inject() moduleConfig: Record<string, any>,
@Inject() readonly logger: EggLogger,
) {
this.foo = moduleConfig.features.dynamic.foo;
this.bar = moduleConfig.features.dynamic.bar;
}

log() {
this.logger.info('foo');
}
}

0 comments on commit d5a8a93

Please sign in to comment.