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