背景
sequelizeとはnodejsでDBを便利に利用するためのORマッパーです。webpackとは、javascriptで作ったプロジェクトを束ねてくれるプログラムです。自分はtypescriptで書いた作ったプロジェクトをjavascriptへビルド(トランスパイル)する時に利用してます。
sequelizeでは検索条件としてSQLを直書きして渡せたりするのですが、webpackをproductionモードでビルドを行うと、単語の短縮化によってエラーが発生することがあります。
備忘録を兼ねて対応方法を共有します。
問題
下記の2つのモデルを例として使います。- User
DBのテーブル名はusers - Article
DBのテーブル名はarticles
user_idを持つ
この2つのテーブルに対して「Articleを2つ以上もつUserを取り出す」ためのクエリを直書きすると、こう書けます。
import { literal, Op } from "sequelize"
const users = User.where({ [Op.and]: [
literal('(select count(*) from articles as article_count \
where article_count.userId = User.id) >= 2')
}})
UnhandledPromiseRejectionWarning: SequelizeDatabaseError: Unknown column 'User.id' in 'where clause'
productionモードでwebpackのトランスパイルを動かすと、minimize機能によって単語などが短縮されます。
短縮された結果、プログラムとしてはUserのことを「p」として扱っているけれど直書きしたクエリでは「User」となっているため、「User」という文字列にに該当するものが無いためにエラーが発生しています。
対応方法
この問題に対応するにはいくつかの方法を思いつきます。- literalで直書きするSQLのモデル名にプログラムが認識している名前を適用する
- literalを使わずにsqlを組み立てる
(記事数を取得するクエリを実行した後、その値を元にユーザーを絞り込むなど) - webpackのproductionモードでminimizeを無効にする
productionモードで直書きSQLを動かしたいので、「literalで直書きするSQLのモデル名にプログラムが認識している名前を適用する」方法をここでは解説します。
短縮されたモデルの名前は .name で取れるため、下記のように記述することでproductionモードでも動くクエリになります。
(文字列をバッククーオート(`)での定義にし、「User」の箇所を「${User.name}」にしています。)
import { literal, Op } from "sequelize"
const users = User.where({ [Op.and]: [
literal(`(select count(*) from articles as article_count \
where article_count.userId = ${User.name}.id) >= 2`)
}})
この記述ならproductionモードでビルドしても動いてくれます。
0 件のコメント :
コメントを投稿