Sequelizeやexpressでハマったこととか

わざわざ1つの記事にするまでもなさそうなことをメモする。

Sequelize.jsの話

belongsToとhasManyの違い

sql - belongsTo vs hasMany in Sequelize.js - Stack Overflow

公式ページにも書いてあった気がする。

例えば、Album.belongsTo(Artist)と書くとalbum.getArtist()のようにアクセスできる。 逆に、Artist.hasMany(Album)と書くとartist.getAlbums()のようにアクセスできる。

つまり、1つを書いただけだと、片方向のアクセスしかできない。

PostgreSQLでテーブル名やカラム名をダブルクオーテーションで囲わないと見つからないというエラーになる

Sequelizeはテーブル名やカラム名をcamel caseで作るが、PostgreSQLSQLを直に書くときはこれらの識別子をダブルクオーテーションで囲わないと全て小文字に自動的に変換されてしまう。 SQLを直で書くときは、すべてダブルクオーテーションで囲んで書けば解決。

many to manyのthrough tableが生成されない

各モデルごとにUser.sync()とだけやっていたのが原因。

sequelize.sync()を実行しないといけない。

Sequelizeでサブクエリの結果が入るはずのカラムがモデルのインスタンスの変数から取得できない

要するに、普通はuser.userNameのように取得できるはずが、もともとモデルに無いカラムでは取得できないということ。

user.getValue('追加したカラム名')としたらいけた。

TypeScriptでモデルを定義したらTypeError: Class constructor Model cannot be invoked without 'new

Class constructor Model cannot be invoked without 'new' and how getter v4 work? · Issue #7840 · sequelize/sequelize · GitHub

ビルド時にクラスが関数に変換されるために発生するエラー。

@babel/preset-envtargets"node": "current"になっているのに発生した。

結局、tsconfig.jsonでのコンパイルターゲットがes5になっていたのが原因だった。es6にしたら治った。

{
  "compilerOptions": {
    "target": "es6",
   ...

node.jsやexpressなど

Cannot find module '@babel/core', Cannot find module 'babel-preset-env'

古い情報と新しい情報をごっちゃにしてやっているとどこかでこのエラーが起きた。

新しいのは@babel/core@babel/preset-envなので、そっちをちゃんとインストールして設定する。

Error: ENOSPC: System limit for number of file watchers reached, watch ' ... '

Error: ENOSPC: System limit for number of file watchers reached, watch '/home/foldername/abcrypto/static' · Issue #11406 · gatsbyjs/gatsby · GitHub

ファイルシステムのfile watcherの上限に達したということらしい。

echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -pで治った。

Jestでのテストでopen handle potentially keeping Jest from exitingというエラー

まず、expressサーバはテストのときはlistenしてはいけない

javascript - Jest detects open handle with Express app - Stack Overflow

なので、例えばまず/app.jsに共通の処理を書き、

const express = require('express');
const app = express();

app.use('/api', ...

module.exports = app

本番で起動するserver.jsでは以下のようにapp.jsを読み込む。

const app = require('./app.js')
app.listen(3000, () => console.log(`Listening on port: ${PORT}`))

そして、テストを実行するtest.jsではapp.jsを読み込む。

const app = require('./app.js')

describe('test block', () => { ...

もう1点、テストのときは最後にsequelizeのデータベースをcloseする必要がある

// 他のモジュールで, ``export const database = new Sequelize( ...``としたやつ
afterAll(async () => {
  await database.close();
})

Sequelize | Sequelize

それ以外にもasyncでテストを書くとうまく動かないみたいな報告があるが、自分の場合には該当しないようだった。

Asynchronous beforeEach / beforeAll? · Issue #1256 · facebook/jest · GitHub

(ポエム) SequelizeなどORMつらい

ちょっと複雑なクエリを書こうとすると、書き方を調べないといけないし、生成されるSQLもわかりにくくなって辛くなってくる。

結局、ORMのメリットは単純なクエリのオブジェクトへのマッピングが簡単にできることであって、やっぱり複雑なクエリを書いたりパフォーマンスを最適化したりするのには向いていないという話を聞いて納得した。

Code rant: When Should I Use An ORM?