node.js + typescript で typeorm を使おうとするといろいろハマったのでメモを残しておきます

Webアプリ開発

環境

  • OS: Windows 10 Pro
  • WSL2
    • ディストリビューション: Ubuntu20.04
  • node.js と npm はインストール済み
    • node.js: v16.15.1
    • npm: 8.12.1
  • npm にて以下をグローバルインストール済み
    • yarn
    • typescript
    • sqlite3

やろうとしていること

sqlite に対してORマッパーを適用しようと思い、Typescript では typeorm というライブラリがアツいということがわかったので、それを導入しようとしました。

とりあえずチュートリアル的に、以下を実行しようとしました。

  1. データベースに接続し、
  2. テーブルを作成し、
  3. 適当にレコードを書いて、
  4. 書いたレコードを読み込む

起きたこと

上記の動作が、なかなかうまくいきませんでした。

使用したライブりのバージョン

  • sqlite3: 5.0.8
  • typeorm: 0.3.6
  • typescript: 4.7.4

ディレクトリ構成

データベース周りを抜粋すると以下のような感じです。

- hoge
    |─ src
    |   |─databse
    |   |   └─ ormconfig.ts
    |   |   └─ testRepository.ts
    |   └─ entity
    |       └─ Test.ts
    |─ pacakge.json
    └─ test.db

参考にしたドキュメント

TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.

こちらをみてトライしてみました。

うまくいかなかったソース

以下、関連場所のみ抜粋

// Test.ts
import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity()
export default class Test {
  @PrimaryGeneratedColumn()
  readonly id: number;

  @Column('text', { nullable: false })
  text: string;

  @CreateDateColumn()
  readonly created_at?: Date;

  @UpdateDateColumn()
  readonly updated_at?: Date;

  constructor(text: string) {
    this.text = text;
  }
}
// ormconfig.ts
import { DataSource } from 'typeorm';
import path from 'path'

const dataSource = new DataSource({
    type: 'sqlite',
    database: path.join(process.cwd(), 'test.db'),
    entities: [{__dirname} + "../entity/*.{js,ts}"],
    synchronize: true
})

export default dataSource
// testRepository.ts
import { DataSource } from "typeorm";
import Test from "@/entity/Test";
import dataSource from './ormconfig';

export default class testRepository {

    public async add(text: string) {
        dataSource.initialize()
            .then(async () => {
                console.log("Data Source has been initialized!")
                const manager = dataSource.manager;
                const test = new Test(text);
                await manager.save(test);
                console.log("Saved a new test with text: " + test.text);

                console.log("Loading tests from the database...");
                const tests = await manager.find(Test);
                console.log("Loaded tests: ", tests);
            })
            .catch(err => {
                console.error("Error during Data Source initialization", err)
            });
    }
}

実行結果

上記で実行すると以下のようになりました。

$ npm run start
Data Source has been initialized!
Error during Data Source initialization EntityMetadataNotFoundError: No metadata for "Test" was found.
    at DataSource.getMetadata (/home/tashima/separate_vue_express/backend/node_modules/src/data-source/DataSource.ts:422:30)
    at /home/tashima/separate_vue_express/backend/node_modules/src/persistence/EntityPersistExecutor.ts:84:56
    at Array.forEach (<anonymous>)
    at /home/tashima/separate_vue_express/backend/node_modules/src/persistence/EntityPersistExecutor.ts:77:30
    at Array.map (<anonymous>)
    at EntityPersistExecutor.execute (/home/tashima/separate_vue_express/backend/node_modules/src/persistence/EntityPersistExecutor.ts:73:34)
    at async /home/tashima/separate_vue_express/backend/src/database/testRepository.ts:16:17

このエラー、そこそこ発生しているらしく、ググったらたくさん症例が出ています。
しかし、どの解決策を試しても自分の環境ではうまくいきませんでした・・・

解決方法

手さぐりでしたが、以下のように ormconfig.ts を変更すると解決しました。

import { DataSource } from 'typeorm';
import path from 'path'
+ import Test from "../entity/Test";

const dataSource = new DataSource({
    type: 'sqlite',
    database: path.join(process.cwd(), 'test.db'),
-    entities: [{ __dirname } + "../entity/*.{js,ts}"],
+    entities: [Test],
    synchronize: true
})

export default dataSource

結構きつかった・・・

コメント

タイトルとURLをコピーしました