Skip to content

Commit 5320af7

Browse files
authored
feat: export singleton orm client (#82)
* feat: add singleton orm
1 parent b32d9b8 commit 5320af7

File tree

12 files changed

+211
-21
lines changed

12 files changed

+211
-21
lines changed

core/orm-decorator/src/decorator/Model.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ModelInfoUtil } from '../util/ModelInfoUtil';
33

44
export interface ModelParams {
55
tableName?: string;
6+
dataSource?: string;
67
}
78

89
export const MODEL_PROTO_IMPL_TYPE = 'MODEL_PROTO';
@@ -18,6 +19,9 @@ export function Model(param?: ModelParams) {
1819
if (param?.tableName) {
1920
ModelInfoUtil.setTableName(param.tableName, clazz);
2021
}
22+
if (param?.dataSource) {
23+
ModelInfoUtil.setDataSource(param.dataSource, clazz);
24+
}
2125
func(clazz);
2226
};
2327
}

plugin/orm/app.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import { ModelProtoHook } from './lib/ModelProtoHook';
66
import { MODEL_PROTO_IMPL_TYPE } from '@eggjs/tegg-orm-decorator';
77
import ContextModelProto from './lib/ContextModelProto';
88
import { ContextModeObject } from './lib/ContextModeObject';
9+
import { ORMLoadUnitHook } from './lib/ORMLoadUnitHook';
910

1011
export default class OrmAppBootHook {
1112
private readonly app: Application;
1213
private readonly dataSourceManager: DataSourceManager;
1314
private readonly leoricRegister: LeoricRegister;
1415
private readonly modelProtoManager: ModelProtoManager;
1516
private readonly modelProtoHook: ModelProtoHook;
17+
private readonly ormLoadUnitHook: ORMLoadUnitHook;
1618

1719
constructor(app) {
1820
this.app = app;
@@ -22,11 +24,13 @@ export default class OrmAppBootHook {
2224
this.modelProtoHook = new ModelProtoHook(this.modelProtoManager);
2325
this.app.eggPrototypeCreatorFactory.registerPrototypeCreator(MODEL_PROTO_IMPL_TYPE, ContextModelProto.createProto);
2426
this.app.leoricRegister = this.leoricRegister;
27+
this.ormLoadUnitHook = new ORMLoadUnitHook();
2528
}
2629

2730
configWillLoad() {
2831
this.app.eggPrototypeLifecycleUtil.registerLifecycle(this.modelProtoHook);
2932
this.app.eggObjectFactory.registerEggObjectCreateMethod(ContextModelProto, ContextModeObject.createObject);
33+
this.app.loadUnitLifecycleUtil.registerLifecycle(this.ormLoadUnitHook);
3034
}
3135

3236
configDidLoad() {

plugin/orm/lib/LeoricRegister.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,35 @@ export class LeoricRegister extends Base {
1717
this.realmMap = new Map();
1818
}
1919

20-
getOrCreateRealm(datasource: string | undefined): any {
20+
getConfig(datasource?: string) {
2121
let config: OrmConfig | undefined;
2222
if (!datasource) {
2323
config = this.dataSourceManager.getDefaultConfig();
2424
} else {
2525
config = this.dataSourceManager.getConfig(datasource);
2626
}
27-
if (!config) {
28-
throw new Error(`not found datasource for ${datasource}`);
27+
return config;
28+
}
29+
30+
getRealm(config: OrmConfig | undefined): Realm | undefined {
31+
if (!config?.database) {
32+
return undefined;
2933
}
30-
let realm = this.realmMap.get(config.database);
31-
if (realm) {
32-
return realm;
34+
const realm = this.realmMap.get(config.database);
35+
return realm;
36+
}
37+
38+
getOrCreateRealm(datasource: string | undefined): any {
39+
const config = this.getConfig(datasource);
40+
let realm: Realm | undefined;
41+
if (config) {
42+
realm = this.getRealm(config);
43+
if (realm) {
44+
return realm;
45+
}
3346
}
3447
realm = new (Realm as any)({ ...config });
35-
this.realmMap.set(config.database, realm);
48+
this.realmMap.set(config!.database, realm);
3649
return realm;
3750
}
3851

plugin/orm/lib/ORMLoadUnitHook.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { LifecycleHook } from '@eggjs/tegg';
2+
import {
3+
EggLoadUnitType,
4+
EggPrototypeCreatorFactory,
5+
EggPrototypeFactory,
6+
LoadUnit,
7+
LoadUnitLifecycleContext,
8+
} from '@eggjs/tegg-metadata';
9+
import { Orm } from './SingletonORM';
10+
11+
const REGISTER_CLAZZ = [
12+
Orm,
13+
];
14+
15+
export class ORMLoadUnitHook implements LifecycleHook<LoadUnitLifecycleContext, LoadUnit> {
16+
async postCreate(_ctx: LoadUnitLifecycleContext, loadUnit: LoadUnit): Promise<void> {
17+
if (loadUnit.type === EggLoadUnitType.APP) {
18+
for (const clazz of REGISTER_CLAZZ) {
19+
const proto = await EggPrototypeCreatorFactory.createProto(clazz, loadUnit);
20+
EggPrototypeFactory.instance.registerPrototype(proto, loadUnit);
21+
}
22+
}
23+
}
24+
}

plugin/orm/lib/SingletonORM.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {
2+
AccessLevel,
3+
Inject,
4+
SingletonProto,
5+
} from '@eggjs/tegg';
6+
import { LeoricRegister } from './LeoricRegister';
7+
import Realm from 'leoric';
8+
9+
@SingletonProto({
10+
accessLevel: AccessLevel.PUBLIC,
11+
})
12+
export class Orm {
13+
@Inject()
14+
private leoricRegister: LeoricRegister;
15+
16+
// default dataSource
17+
get client(): Realm {
18+
const defaultConfig = this.leoricRegister.getConfig();
19+
return this.leoricRegister.getRealm(defaultConfig)!;
20+
}
21+
22+
getClient(datasource: string): Realm {
23+
const config = this.leoricRegister.getConfig(datasource);
24+
if (!config) {
25+
throw new Error(`not found ${datasource} datasource`);
26+
}
27+
return this.leoricRegister.getOrCreateRealm(config.database)!;
28+
}
29+
30+
}

plugin/orm/test/fixtures/apps/orm-app/config/config.default.js

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
module.exports = function() {
3+
module.exports = function () {
44
const config = {
55
keys: 'test key',
66
security: {
@@ -9,19 +9,53 @@ module.exports = function() {
99
},
1010
},
1111
orm: {
12-
client: 'mysql',
13-
database: 'test',
14-
host: '127.0.0.1',
15-
port: 3306,
16-
user: 'root',
12+
datasources: [
13+
{
14+
client: 'mysql',
15+
database: 'test',
16+
host: '127.0.0.1',
17+
port: 3306,
18+
user: 'root',
1719

18-
delegate: 'model',
19-
baseDir: 'model',
20-
migrations: 'database',
20+
delegate: 'model',
21+
baseDir: 'model',
22+
migrations: 'database',
2123

22-
define: {
23-
underscored: true,
24-
},
24+
define: {
25+
underscored: true,
26+
},
27+
},
28+
{
29+
client: 'mysql',
30+
database: 'apple',
31+
host: '127.0.0.1',
32+
port: 3306,
33+
user: 'root',
34+
35+
delegate: 'model',
36+
baseDir: 'model',
37+
migrations: 'database',
38+
39+
define: {
40+
underscored: true,
41+
},
42+
},
43+
{
44+
client: 'mysql',
45+
database: 'banana',
46+
host: '127.0.0.1',
47+
port: 3306,
48+
user: 'root',
49+
50+
delegate: 'model',
51+
baseDir: 'model',
52+
migrations: 'database',
53+
54+
define: {
55+
underscored: true,
56+
},
57+
},
58+
],
2559
},
2660
};
2761
return config;

plugin/orm/test/fixtures/apps/orm-app/modules/orm-module/AppService.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import { ContextProto, Inject } from '@eggjs/tegg';
2+
import { Orm } from '@eggjs/tegg-orm-plugin/lib/SingletonORM';
23
import { App } from './model/App';
34

45
@ContextProto()
56
export class AppService {
67
@Inject()
78
App: typeof App;
89

10+
@Inject()
11+
private readonly orm: Orm;
12+
913
async createApp(data: {
1014
name: string;
1115
desc: string;
@@ -18,4 +22,17 @@ export class AppService {
1822
const app = await this.App.findOne({ name });
1923
return app as App;
2024
}
25+
26+
async rawQuery(dataSource: string, sql: string, values?: any[]) {
27+
return await this.orm.getClient(dataSource).query(sql, values);
28+
}
29+
30+
async getClient(name: string) {
31+
return this.orm.getClient(name);
32+
}
33+
34+
async getDefaultClient() {
35+
return this.orm.client;
36+
}
37+
2138
}

plugin/orm/test/fixtures/apps/orm-app/modules/orm-module/model/App.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Attribute, Model } from '@eggjs/tegg-orm-decorator';
22
import { DataTypes, Bone } from 'leoric';
33

4-
@Model()
4+
@Model({
5+
dataSource: 'test',
6+
})
57
export class App extends Bone {
68
@Attribute(DataTypes.STRING)
79
name: string;

plugin/orm/test/fixtures/apps/orm-app/modules/orm-module/model/Pkg.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Attribute, Model } from '@eggjs/tegg-orm-decorator';
22
import { DataTypes, Bone } from 'leoric';
33

4-
@Model()
4+
@Model({
5+
dataSource: 'test',
6+
})
57
export class Pkg extends Bone {
68
@Attribute(DataTypes.STRING)
79
name: string;

plugin/orm/test/fixtures/prepare.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ async function query(sql) {
3333
async function init() {
3434
await query('DROP DATABASE IF EXISTS `test`;');
3535
await query('CREATE DATABASE test;');
36+
await query('DROP DATABASE IF EXISTS `apple`;');
37+
await query('CREATE DATABASE apple;');
38+
await query('DROP DATABASE IF EXISTS `banana`;');
39+
await query('CREATE DATABASE banana;');
3640
await query('use test;');
3741
await query('CREATE TABLE `apps` (\n' +
3842
' `id` bigint unsigned NOT NULL AUTO_INCREMENT,\n' +

0 commit comments

Comments
 (0)