Skip to content

Commit f8592c2

Browse files
sang4lvSangLv
andauthored
feat: add getEggObjects API to fetch all instances (#189)
<!-- 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]. --> - [x] `npm test` passes - [x] tests and/or benchmarks are included - [x] 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. --> 新增 `eggObjectFactory.getEggObjects` 接口,用于获取抽象类对应的所有实现。 <!-- - any feature? - close https://github.com/eggjs/egg/ISSUE_URL --> --------- Co-authored-by: SangLv <sanglv.wl@antgroup.com>
1 parent c24ba0c commit f8592c2

File tree

6 files changed

+98
-10
lines changed

6 files changed

+98
-10
lines changed

README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -934,14 +934,35 @@ import { EggObjectFactory } from '@eggjs/tegg';
934934
export class HelloService {
935935
@Inject()
936936
private readonly eggObjectFactory: EggObjectFactory;
937-
937+
938938
async hello(): Promise<string> {
939939
const helloImpl = await this.eggObjectFactory.getEggObject(AbstractHello, HelloType.BAR);
940940
return helloImpl.hello();
941941
}
942942
}
943943
```
944944

945+
动态获取多个实现,通过 for/await 循环获得实例。
946+
947+
```ts
948+
import { EggObjectFactory } from '@eggjs/tegg';
949+
950+
@ContextProto()
951+
export class HelloService {
952+
@Inject()
953+
private readonly eggObjectFactory: EggObjectFactory;
954+
955+
async hello(): Promise<string[]> {
956+
const helloImpls = await this.eggObjectFactory.getEggObjects(AbstractHello);
957+
const messages = [];
958+
for await (const helloImpl of helloImpls) {
959+
messages.push(helloImpl.hello());
960+
}
961+
return messages;
962+
}
963+
}
964+
```
965+
945966
### 配置项目 module
946967

947968
一般情况下,无需在项目中手动声明包含了哪些 module,tegg 会自动在项目目录下进行扫描。但是会存在一些特殊的情况,tegg 无法扫描到,比如说 module 是通过 npm 包的方式来发布。因此 tegg 支持通过 `config/module.json` 的方式来声明包含了哪些 module。

core/dynamic-inject-runtime/src/EggObjectFactory.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import type { EggContainerFactory } from '@eggjs/tegg-runtime';
2-
import { EggAbstractClazz, EggObjectFactory as IEggObjectFactory, QualifierImplUtil } from '@eggjs/tegg-dynamic-inject';
32
import { AccessLevel, PrototypeUtil, QualifierValue, SingletonProto } from '@eggjs/core-decorator';
3+
import {
4+
EggAbstractClazz,
5+
EggObjectFactory as IEggObjectFactory,
6+
QualifierImplUtil,
7+
} from '@eggjs/tegg-dynamic-inject';
8+
49
import { EGG_OBJECT_FACTORY_PROTO_IMPLE_TYPE } from './EggObjectFactoryPrototype';
510

611
@SingletonProto({
@@ -23,4 +28,26 @@ export class EggObjectFactory implements IEggObjectFactory {
2328
const eggObject = await this.eggContainerFactory.getOrCreateEggObject(protoObj, protoObj.name);
2429
return eggObject.obj as T;
2530
}
31+
32+
async getEggObjects<T extends object>(abstractClazz: EggAbstractClazz<T>) {
33+
const implClazzMap = QualifierImplUtil.getQualifierImpMap(abstractClazz);
34+
const getEggObject = this.getEggObject.bind(this);
35+
const qualifierValues = Array.from(implClazzMap.keys());
36+
37+
return {
38+
[Symbol.asyncIterator]() {
39+
return {
40+
key: 0,
41+
async next() {
42+
if (this.key === qualifierValues.length) {
43+
return { done: true } as IteratorResult<T>;
44+
}
45+
46+
const value = await getEggObject(abstractClazz, qualifierValues[this.key++]);
47+
return { value, done: false } as IteratorResult<T>;
48+
},
49+
};
50+
},
51+
};
52+
}
2653
}

core/dynamic-inject-runtime/test/fixtures/modules/dynamic-inject-module/HelloService.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { ContextProto, Inject } from '@eggjs/core-decorator';
2-
import { ContextHelloType, SingletonHelloType } from './FooType';
2+
import { EggObjectFactory } from '@eggjs/tegg-dynamic-inject';
3+
34
import { AbstractContextHello } from './AbstractContextHello';
45
import { AbstractSingletonHello } from './AbstractSingletonHello';
5-
import { EggObjectFactory } from '@eggjs/tegg-dynamic-inject';
6+
import { ContextHelloType, SingletonHelloType } from './FooType';
67

78
@ContextProto()
89
export class HelloService {
@@ -19,4 +20,19 @@ export class HelloService {
1920
const msgs = helloImpls.map(helloImpl => helloImpl.hello());
2021
return msgs;
2122
}
23+
24+
async sayHelloToAll(): Promise<string[]> {
25+
const singletonHellos = await this.eggObjectFactory.getEggObjects(AbstractSingletonHello);
26+
const contextHellos = await this.eggObjectFactory.getEggObjects(AbstractContextHello);
27+
28+
const msgs: string[] = [];
29+
for await (const helloImpl of singletonHellos) {
30+
msgs.push(helloImpl.hello());
31+
}
32+
for await (const helloImpl of contextHellos) {
33+
msgs.push(helloImpl.hello());
34+
}
35+
36+
return msgs;
37+
}
2238
}

core/dynamic-inject-runtime/test/index.test.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import assert from 'assert';
12
import path from 'path';
2-
import { LoadUnitInstance, LoadUnitInstanceFactory } from '@eggjs/tegg-runtime';
3+
34
import { LoadUnitFactory } from '@eggjs/tegg-metadata';
5+
import { LoadUnitInstance, LoadUnitInstanceFactory } from '@eggjs/tegg-runtime';
6+
47
import { EggTestContext } from '../../test-util';
5-
import { HelloService } from './fixtures/modules/dynamic-inject-module/HelloService';
68
import { CoreTestHelper } from '../../test-util/CoreTestHelper';
7-
import assert from 'assert';
9+
import { HelloService } from './fixtures/modules/dynamic-inject-module/HelloService';
810

911
describe('test/dynamic-inject-runtime.test.ts', () => {
1012
let modules: Array<LoadUnitInstance>;
@@ -47,4 +49,18 @@ describe('test/dynamic-inject-runtime.test.ts', () => {
4749
]);
4850
});
4951
});
52+
53+
it('should work with getAllEggObjects', async () => {
54+
await EggTestContext.mockContext(async () => {
55+
const helloService = await CoreTestHelper.getObject(HelloService);
56+
const msgs = await helloService.sayHelloToAll();
57+
assert.deepStrictEqual(msgs, [
58+
'hello, bar(singleton:0)',
59+
'hello, foo(singleton:0)',
60+
'hello, bar(context:0)',
61+
'hello, foo(context:0)',
62+
]);
63+
});
64+
65+
});
5066
});
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import { EggAbstractClazz } from './typing';
21
import { QualifierValue } from '@eggjs/core-decorator';
32

3+
import { EggAbstractClazz } from './typing';
4+
45
export interface EggObjectFactory {
56
getEggObject<T extends object>(abstractClazz: EggAbstractClazz<T>, qualifierValue: QualifierValue): Promise<T>;
7+
getEggObjects<T extends object>(abstractClazz: EggAbstractClazz<T>): Promise<AsyncIterable<T>>;
68
}
Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { EggAbstractClazz } from './typing';
21
import { EggProtoImplClass, MetadataUtil, QualifierValue } from '@eggjs/core-decorator';
32

3+
import { EggAbstractClazz } from './typing';
4+
45
export const QUALIFIER_IMPL_MAP = Symbol.for('EggPrototype#qualifierImplMap');
56

67
export class QualifierImplUtil {
@@ -9,8 +10,13 @@ export class QualifierImplUtil {
910
implMap.set(qualifierValue, implClazz);
1011
}
1112

12-
static getQualifierImp(abstractClazz: EggAbstractClazz, qualifierValue: QualifierValue):EggProtoImplClass | undefined {
13+
static getQualifierImp(abstractClazz: EggAbstractClazz, qualifierValue: QualifierValue): EggProtoImplClass | undefined {
1314
const implMap: Map<QualifierValue, EggProtoImplClass> | undefined = MetadataUtil.getMetaData(QUALIFIER_IMPL_MAP, abstractClazz as unknown as EggProtoImplClass);
1415
return implMap?.get(qualifierValue);
1516
}
17+
18+
static getQualifierImpMap(abstractClazz: EggAbstractClazz): Map<QualifierValue, EggProtoImplClass> {
19+
const implMap: Map<QualifierValue, EggProtoImplClass> | undefined = MetadataUtil.getMetaData(QUALIFIER_IMPL_MAP, abstractClazz as unknown as EggProtoImplClass);
20+
return implMap || new Map();
21+
}
1622
}

0 commit comments

Comments
 (0)