LoginSignup
2
1

More than 3 years have passed since last update.

TypeORM をシングルトンで使う

Last updated at Posted at 2020-05-29

TypeORM のメソッドそのままでDBに接続すると状態管理がごちゃっとするので、ラッパークラスを作って、そこでコネクションの管理を行うようにしていきます。

コネクション管理用のクラスを作成する

  • get()Connection が取得できる
  • get() を呼び出した時にコネクションが開いて場合は、同時に作成する
  • close()Connection を閉じる
  • close() を呼び出した時にコネクションが閉じていた場合は、何もせず、エラーも起こさない

dbconnection.ts

import {
  Connection,
  createConnection,
  EntityManager,
  getConnection,
  ConnectionOptions,
} from 'typeorm';

export class DBConnection {
  private static con?: Connection;
  static getManager = (): Promise<EntityManager> =>
    DBConnection.get().then(con => con.manager);
  static get = async (): Promise<Connection> => {
    if (DBConnection.con && DBConnection.con.isConnected)
      return DBConnection.con;
    if (DBConnection.con instanceof Connection)
      return DBConnection.con.connect();
    return DBConnection.create();
  };
  private static create = async (): Promise<Connection> => {
    DBConnection.con = await createConnection(DBConnection.options).catch(() =>
      getConnection(),
    );
    if (!DBConnection.con.isConnected) await DBConnection.con.connect();
    return DBConnection.con;
  };
  static close = async (): Promise<void> => {
    if (!DBConnection.con) return;
    if (DBConnection.con && DBConnection.con.isConnected)
      DBConnection.con.close();
    DBConnection.con = undefined;
  };
}
export namespace DBConnection {
  export const options: ConnectionOptions = {
    type: 'postgres',
    host: process.env.DB_HOST,
    port: Number.parseInt(process.env.DB_PORT!),
    username: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_DATABASE_NAME,
    synchronize: false,
    logging: process.env.NODE_ENV === 'production' ? ['error'] : 'all',
  };
}

テスト

dbconnection.spec.ts
import { Connection, EntityManager } from 'typeorm';
import { DBConnection } from 'src/infrastructure/dbconnection';

describe('DBConnection', () => {
  let connection: Connection;

  beforeEach(async () => {
    connection = await DBConnection.get();
  });
  it('should be defined', () => {
    expect(connection).toBeDefined();
  });
  it('isConnected', () => {
    expect(connection.name).toBe('default');
    expect(connection.isConnected).toBeTruthy();
  });
  it('isConnected2', () => {
    expect(connection.name).toBe('default');
    expect(connection.isConnected).toBeTruthy();
  });
  it('close', async () => {
    await DBConnection.close();
  });
  it('getManager', async () => {
    const manager = await DBConnection.getManager();
    expect(manager instanceof EntityManager).toBeTruthy();
  });
  afterEach(async () => {
    await DBConnection.close();
  });
});

使ってみる

あとは通常通り Connection をつかってなんやかんや

import { Connection } from 'typeorm';

const connection: Connection = await DBConnection.get();
const result: Promise<any> = connection.transaction(manager => {
    return manager.query(`select * from users;`);
});

最後に

TypeORM の createConnection 等のメソッドが他のところからも勝手に呼べしまうのが難点。
何か制限をかけられる方法をご存知の方がいれば教えていただきたいですm(_ _)m

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1