Commit 79f759dd authored by nanahira's avatar nanahira

use typeorm 3

parent cee4b2c6
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
"koishi-thirdeye": "^11.0.6", "koishi-thirdeye": "^11.0.6",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"pg": "^8.7.3", "pg": "^8.7.3",
"typeorm": "0.2.45" "typeorm": "^0.3.7"
}, },
"devDependencies": { "devDependencies": {
"@koishijs/plugin-console": "^4.1.1", "@koishijs/plugin-console": "^4.1.1",
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
"jest": "^27.5.1", "jest": "^27.5.1",
"prettier": "^2.5.1", "prettier": "^2.5.1",
"raw-loader": "^4.0.2", "raw-loader": "^4.0.2",
"sqlite3": "^5.0.10",
"ts-jest": "^27.1.3", "ts-jest": "^27.1.3",
"ts-loader": "^9.2.6", "ts-loader": "^9.2.6",
"ts-node": "^10.5.0", "ts-node": "^10.5.0",
......
// import 'source-map-support/register'; // import 'source-map-support/register';
import { DefineSchema, RegisterSchema } from 'koishi-thirdeye'; import { DefineSchema, RegisterSchema } from 'koishi-thirdeye';
import { ConnectionOptions, EntitySchema } from 'typeorm'; import { DataSourceOptions, EntitySchema } from 'typeorm';
import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions'; import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions';
export type TypeORMPluginConfigLike = ConnectionOptions; export type TypeORMPluginConfigLike = DataSourceOptions;
@RegisterSchema() @RegisterSchema()
export class TypeORMPluginConfig implements PostgresConnectionOptions { export class TypeORMPluginConfig implements PostgresConnectionOptions {
......
// import 'source-map-support/register'; // import 'source-map-support/register';
import { import { TypeORMEntity, TypeORMPluginConfig } from './config';
TypeORMEntity,
TypeORMPluginConfig,
} from './config';
import { import {
DefinePlugin, DefinePlugin,
StarterPlugin, StarterPlugin,
...@@ -11,13 +8,13 @@ import { ...@@ -11,13 +8,13 @@ import {
LifecycleEvents, LifecycleEvents,
PluginSchema, PluginSchema,
} from 'koishi-thirdeye'; } from 'koishi-thirdeye';
import { Connection, ConnectionOptions } from 'typeorm'; import { DataSource, DataSourceOptions } from 'typeorm';
import { Context } from 'koishi'; import { Context } from 'koishi';
export * from './config'; export * from './config';
export * from 'typeorm'; export * from 'typeorm';
interface ConnectionEntry { interface DataSourceEntry {
connection: Connection; dataSource: DataSource;
entities: TypeORMEntity[]; entities: TypeORMEntity[];
} }
...@@ -27,14 +24,13 @@ declare module 'koishi' { ...@@ -27,14 +24,13 @@ declare module 'koishi' {
} }
} }
@PluginSchema(TypeORMPluginConfig)
@Provide('typeorm', { immediate: true }) @Provide('typeorm', { immediate: true })
@DefinePlugin() @DefinePlugin()
export default class TypeORMPlugin export default class TypeORMPlugin
extends StarterPlugin(TypeORMPluginConfig) extends StarterPlugin(TypeORMPluginConfig)
implements LifecycleEvents implements LifecycleEvents
{ {
private registryMap = new Map<string, ConnectionEntry>(); private registryMap = new Map<string, DataSourceEntry>();
private entityMap = new Map<TypeORMEntity, string>(); private entityMap = new Map<TypeORMEntity, string>();
@Caller() @Caller()
...@@ -43,44 +39,44 @@ export default class TypeORMPlugin ...@@ -43,44 +39,44 @@ export default class TypeORMPlugin
async close(token: string) { async close(token: string) {
const entry = this.registryMap.get(token)!; const entry = this.registryMap.get(token)!;
if (!entry) return; if (!entry) return;
const { connection, entities } = entry; const { dataSource, entities } = entry;
await connection.close(); // await dataSource.destroy();
this.registryMap.delete(token); this.registryMap.delete(token);
for (const entity of entities) { for (const entity of entities) {
this.entityMap.delete(entity); this.entityMap.delete(entity);
} }
} }
getConnection(token: string) { getDataSource(token: string) {
return this.registryMap.get(token)?.connection; return this.registryMap.get(token)?.dataSource;
} }
getEntityManager(token: string) { getEntityManager(token: string) {
return this.getConnection(token)?.manager; return this.getDataSource(token)?.manager;
} }
getRepository<T>(entity: TypeORMEntity<T>) { getRepository<T>(entity: TypeORMEntity<T>) {
const token = this.entityMap.get(entity); const token = this.entityMap.get(entity);
if (!token) return; if (!token) return;
const connection = this.getConnection(token); const dataSource = this.getDataSource(token);
if (!connection) return; if (!dataSource) return;
return connection.getRepository(entity); return dataSource.getRepository(entity);
} }
async create( async create(
token: string, token: string,
entities: TypeORMEntity[], entities: TypeORMEntity[],
extraOptions: Partial<ConnectionOptions> = {}, extraOptions: Partial<DataSourceOptions> = {},
) { ) {
if (this.registryMap.has(token)) { if (this.registryMap.has(token)) {
return this.getConnection(token); return this.getDataSource(token);
} }
const ctx = this.caller; const ctx = this.caller;
ctx.on('dispose', () => this.close(token)); ctx.on('dispose', () => this.close(token));
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
const connectionOptions: ConnectionOptions = { const dataSourceOptions: DataSourceOptions = {
...this.config, ...this.config,
entities, entities,
entityPrefix: `koishi_${token}_`, entityPrefix: `koishi_${token}_`,
...@@ -88,12 +84,12 @@ export default class TypeORMPlugin ...@@ -88,12 +84,12 @@ export default class TypeORMPlugin
name: token, name: token,
...extraOptions, ...extraOptions,
}; };
const connection = await new Connection(connectionOptions).connect(); const dataSource = await new DataSource(dataSourceOptions).initialize();
this.registryMap.set(token, { connection, entities }); this.registryMap.set(token, { dataSource, entities });
for (const entity of entities) { for (const entity of entities) {
this.entityMap.set(entity, token); this.entityMap.set(entity, token);
} }
return connection; return DataSource;
} }
async onDisconnect() { async onDisconnect() {
......
import { Context } from 'koishi'; import { Context, Fork } from 'koishi';
import TypeORMPlugin from '../src'; import TypeORMPlugin from '../src';
import { import {
Column, Column,
Connection, DataSource,
Entity, Entity,
EntityManager, EntityManager,
ManyToOne, ManyToOne,
...@@ -10,6 +10,7 @@ import { ...@@ -10,6 +10,7 @@ import {
PrimaryGeneratedColumn, PrimaryGeneratedColumn,
Repository, Repository,
} from 'typeorm'; } from 'typeorm';
import * as os from 'os';
@Entity() @Entity()
class User { class User {
...@@ -43,26 +44,27 @@ class Magic { ...@@ -43,26 +44,27 @@ class Magic {
describe('Koishi typeorm', () => { describe('Koishi typeorm', () => {
let app: Context; let app: Context;
let pluginInstance: Fork;
beforeEach(async () => { beforeEach(async () => {
app = new Context(); app = new Context();
await app.start(); await app.start();
app.plugin(TypeORMPlugin, { pluginInstance = app.plugin(TypeORMPlugin, {
type: 'postgres', type: 'sqlite',
host: 'localhost', database: `${os.tmpdir()}/${Math.random()}.sqlite`,
port: 5432,
username: 'koishi',
password: 'koishi@114514',
database: 'test-koishi',
//dropSchema: true,
}); });
}); });
afterEach(async () => {
pluginInstance.dispose();
await app.stop();
});
it('should create connection', async () => { it('should create connection', async () => {
expect(app.typeorm).toBeTruthy(); expect(app.typeorm).toBeTruthy();
await app.typeorm.create('foo', [User, Book]); await app.typeorm.create('foo', [User, Book]);
const connection = app.typeorm.getConnection('foo'); const connection = app.typeorm.getDataSource('foo');
expect(connection).toBeInstanceOf(Connection); expect(connection).toBeInstanceOf(DataSource);
const manager = app.typeorm.getEntityManager('foo'); const manager = app.typeorm.getEntityManager('foo');
expect(manager).toBeInstanceOf(EntityManager); expect(manager).toBeInstanceOf(EntityManager);
const userRepo = app.typeorm.getRepository(User); const userRepo = app.typeorm.getRepository(User);
...@@ -78,10 +80,10 @@ describe('Koishi typeorm', () => { ...@@ -78,10 +80,10 @@ describe('Koishi typeorm', () => {
it('should able to open more than 1 connection', async () => { it('should able to open more than 1 connection', async () => {
await app.typeorm.create('fooo', [User, Book]); await app.typeorm.create('fooo', [User, Book]);
await app.typeorm.create('barr', [Magic]); await app.typeorm.create('barr', [Magic]);
const connection1 = app.typeorm.getConnection('fooo'); const connection1 = app.typeorm.getDataSource('fooo');
const connection2 = app.typeorm.getConnection('barr'); const connection2 = app.typeorm.getDataSource('barr');
expect(connection1).toBeInstanceOf(Connection); expect(connection1).toBeInstanceOf(DataSource);
expect(connection2).toBeInstanceOf(Connection); expect(connection2).toBeInstanceOf(DataSource);
const userRepo = app.typeorm.getRepository(User); const userRepo = app.typeorm.getRepository(User);
const magicRepo = app.typeorm.getRepository(Magic); const magicRepo = app.typeorm.getRepository(Magic);
expect(userRepo).toBeInstanceOf(Repository); expect(userRepo).toBeInstanceOf(Repository);
...@@ -95,38 +97,36 @@ describe('Koishi typeorm', () => { ...@@ -95,38 +97,36 @@ describe('Koishi typeorm', () => {
entityPrefix: 'fooooo_', entityPrefix: 'fooooo_',
metadataTableName: 'fooooo_metadata', metadataTableName: 'fooooo_metadata',
}); });
const connection = app.typeorm.getConnection('baz'); const connection = app.typeorm.getDataSource('baz');
expect(connection.metadataTableName).toBe('fooooo_metadata'); expect(connection.metadataTableName).toBe('fooooo_metadata');
}); });
it('should auto dispose when plugin gone', async () => { it('should auto dispose when plugin gone', async () => {
let instance: Fork;
await new Promise<void>((resolve) => { await new Promise<void>((resolve) => {
app.plugin(async (ctx) => { instance = app.plugin(async (ctx) => {
await ctx.typeorm.create('bar', [User, Book]); await ctx.typeorm.create('bar', [User, Book]);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
ctx.on('fooo', () => ctx.dispose());
resolve(); resolve();
}); });
}); });
expect(app.typeorm.getConnection('bar')).toBeInstanceOf(Connection); expect(app.typeorm.getDataSource('bar')).toBeInstanceOf(DataSource);
expect(app.typeorm.getRepository(User)).toBeInstanceOf(Repository); expect(app.typeorm.getRepository(User)).toBeInstanceOf(Repository);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
app.emit('fooo'); instance.dispose();
await new Promise<void>((resolve) => { await new Promise<void>((resolve) => {
setTimeout(resolve, 1); setTimeout(resolve, 1);
}); });
expect(app.typeorm.getConnection('bar')).toBeUndefined(); expect(app.typeorm.getDataSource('bar')).toBeUndefined();
expect(app.typeorm.getRepository(User)).toBeUndefined(); expect(app.typeorm.getRepository(User)).toBeUndefined();
}); });
it('should reload the same connection', async () => { it('should reload the same connection', async () => {
await app.typeorm.create('yuzu', [User, Book]); await app.typeorm.create('yuzu', [User, Book]);
expect(app.typeorm.getConnection('yuzu')).toBeInstanceOf(Connection); expect(app.typeorm.getDataSource('yuzu')).toBeInstanceOf(DataSource);
await app.typeorm.close('yuzu'); await app.typeorm.close('yuzu');
expect(app.typeorm.getConnection('yuzu')).toBeUndefined(); expect(app.typeorm.getDataSource('yuzu')).toBeUndefined();
await app.typeorm.create('yuzu', [User, Book]); await app.typeorm.create('yuzu', [User, Book]);
expect(app.typeorm.getConnection('yuzu')).toBeInstanceOf(Connection); expect(app.typeorm.getDataSource('yuzu')).toBeInstanceOf(DataSource);
}); });
}); });
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment