はじめに
TypeORM、素晴らしいんですが、作成したモデルを元にmigrationを掛けると残念なことになります。
例えば、
モデル名 UserHoge
→ 作成されるテーブル名 user_hoge
プロパティ名 firstName
→ 作成されるカラム名 firstName
なんでテーブルはスネークケース、カラムはキャメルケースで連結なんだ
こうあってほしい
テーブル・カラム命名規約
Railsの規約がしっくり来るので、それ風にしたい。
- テーブル名: モデルのスネークケース複数形
user_hoges
- カラム名: スネークケース
first_name
コード
とは言っても、rubyと違って(Type|Java)Scriptの変数命名規約がキャメルケースなので、
コード上はキャメルケースで書きたい
- モデル名: キャメルケース単数
UserHoge
- プロパティ名: キャメルケース
firstName
うまい方法はないかと探した結果、上記は2通りの方法で実現できそうです。
[方法1] 個別でテーブル・カラム名を定義する
@Entityデコレーター、@Columnデコレーター共に、個別で名前を指定することができます。
@Entity('users') // これ!
export class User extends BaseEntity {
@PrimaryGeneratedColumn()
public id: number
@Column({ name: 'first_name' }) // これ!
public firstName: string = ''
}
これを元にmigrationを作成すると、指定した名前に応じたSQL文が発行されます。
これで、
「コード上はモデル名:User
カラム名: firstName
」
「DB上はテーブル名:users
カラム名: first_name
」
を実現できるわけですが、すべてのテーブル・カラムに個別に名前を付けていたのでは
ヌケモレが発生したとき大変なことになりますし、何より面倒くさいです。
[方法2] 名前付けルールを設定する
ormconfigに独自の名前付けルールを設定する事で、個別に名前を設定しなくても
自動的にORM⇔DB間でいい感じに変換してくれるようになります。
1. 設定ファイルを作成
ここではconfig/TypeOrmNamingStrategy.js
という名前で作ります。
やっていることは、公式が用意してるDefaultNamingStrategyを継承して、
ルールを書き換えただけです。(念の為、デフォルトのルールはこちら)
自分はモデルから作るテーブルの他に、多対多のリレーションの中間テーブルの名前等も変えてます。
他にもOverrideしたい場合は、適宜。
var DefaultNamingStrategy = require('typeorm').DefaultNamingStrategy
var snakeCase = require('typeorm/util/StringUtils').snakeCase
var pluralize = require('pluralize')
module.exports = class TypeOrmNamingStrategy extends DefaultNamingStrategy {
tableName(className, customName) {
return customName || pluralize(snakeCase(className))
}
columnName(propertyName, customName, embeddedPrefixes) {
return snakeCase(embeddedPrefixes.join('_')) + (customName || snakeCase(propertyName))
}
relationName(propertyName) {
return snakeCase(propertyName)
}
joinColumnName(relationName, referencedColumnName) {
return snakeCase(pluralize.singular(relationName) + '_' + referencedColumnName)
}
joinTableName(firstTableName, secondTableName, firstPropertyName, secondPropertyName) {
return snakeCase(firstTableName + '_' + secondTableName)
}
joinTableColumnName(tableName, propertyName, columnName) {
return snakeCase(pluralize.singular(tableName) + '_' + (columnName || propertyName))
}
classTableInheritanceParentColumnName(parentTableName, parentTableIdPropertyName) {
return snakeCase(pluralize.singular(parentTableName) + '_' + parentTableIdPropertyName)
}
}
2. ormconfigを編集する
先程作ったカスタム名前付けルールのクラスを読み込むようにします。
設定内でクラスをインスタンス化しているため、ormconfig.jsonでは駄目です。
json拡張子を使っている人は、ormconfig.jsに変更してください。
const TypeOrmNamingStrategy = require('./src/configs/TypeOrmNamingStrategy.js') // これ!
module.exports = {
// 色々独自の設定
type: 'postgres',
host: process.env.DB_HOSTNAME,
port: 5432,
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
...
namingStrategy: new TypeOrmNamingStrategy() // これ!!
}
3. いつも通りmigrationを当てる
カスタムルールに基づいた命名規則でmigrationが作られるようになります。