ポリミーイズム

PHPを勉強する若輩者(おっさん)。専門用語の意味はわりかし覚えていません。macOS Sierra 10.12.6

ExpressにSequelizeを導入し、PostgreSQLを使用する

目的

前回のExpressに、PostgreSQL + Sequelizeでmodel層の作成

PostgreSQLのインストール

普段はmysqlを使っているのでとりあえずHomebrewでPostgreSQLmacにインストール。

brew install postgresql

やった方がいいであろうこと(僕はやってません)

  • パスを通すこと
export PGDATA=/usr/local/var/postgres

PostgreSQLを起動・停止する際に「-D」オプションを渡す必要がなくなるので、やっておいた方がいいかもしれません。

/usr/local/var/postgres

PostgreSQLの簡易的な使い方

サーバー起動

pg_ctl start -D /usr/local/var/portgres

サーバー停止

pg_ctl stop -D /usr/local/var/postgres

データベース接続

psql -d [db_name]

別データベースに接続

\connect [db_name]

テーブル定義を確認

\d [table_name]

テーブル一覧を表示

\z

PostgresSQLから切断

\q

PostgreSQLに事前準備

PostgreSQLにデータベース作成

createdb express_sample

PostgreSQLにてユーザ作成

create user root

PostgreSQLユーザに権限付与

GRANT SELECT, UPDATE, INSERT, DELETE ON express_sample TO root;

PostgreSQLユーザー指定データベースアクセス

psql -d express_sample -Uroot

PostgreSQL, Sequelizeをpackage.jsonに書き込む

npm i -S sequelize
npm i -S pg

オプション「-S」は-save(package.json)に書き込むの略。
ちなみに「i」はinstallの略。

sequelize-cliをインストール

npm install -g sequelize-cli

コマンドラインから sequelize のmigrationを実行できる

sequelize init

Sequelize CLI [Node: 8.6.0, CLI: 3.0.0, ORM: 4.19.0]

WARNING: This version of Sequelize CLI is not fully compatible with Sequelize v4. https://github.com/sequelize/cli#sequelize-support

Created "config/config.json"
Successfully created models folder at "/User/express_test/sampleapp/models".
Successfully created migrations folder at "/Users/express_test/sampleapp/migrations".
Successfully created seeders folder at "/Users/express_test/sampleapp/seeders".

Warningが出てる。
内容としては、「このバージョンのSequelize CLIは、Sequelize v4と完全に互換性がありません。」とのことみたい。
とりあえず無視して継続。  

Expressのsequlizeのconfig設定(DB接続周り)

{
  "development": {
    "username": "root",
    "password": "xxx",
    "database": "express_sample",
    "host": "127.0.0.1",
    "dialect": "postgres"
  },
  "test": {
    "username": "root",
    "password": "xxx",
    "database": "express_sample",
    "host": "127.0.0.1",
    "dialect": "postgres"
  },
  "production": {
    "username": "root",
    "password": "xxx",
    "database": "express_sample",
    "host": "127.0.0.1",
    "dialect": "postgres"
  }
}

Sequelizeを利用したmvcの構築

movieテーブルを作成する

  • イメージ
    youtubeの動画を登録するテーブル

  • テーブル

カラム名 備考
id auto_increment
title varchar
video_id varchar
upload_date date yyyy-mm-dd
tag integer 将来tagテーブルを作成する
is_delete boolean

└ 「tag」はtag_idとかに名称を変更するべきかな。

Sequelizeにて上記テーブルのmodelを作成する

sequelize model:create --name movie --underscored --attributes title:string,video_id:string,tag:integer,upload_date:date,is_delete:boolean

オプションを設定しない場合は、自動的にid, createdAt, updatedAtが作成される。
もし、キャメルケースでcreatedAt等作成されるのがいやなら、「--underscored」オプションを追加してあげるとよい。スネークケースの「created_at」と命名される。

生成されたmigrationファイル(default値を設定)

'use strict';
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('movies', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      title: {
        type: Sequelize.STRING
      },
      video_id: {
        type: Sequelize.STRING,
        unique: true
      },
      tag: {
        type: Sequelize.INTEGER
      },
      upload_date: {
        type: Sequelize.DATE
      },
      is_delete: {
        type: Sequelize.BOOLEAN,
        defaultValue: false
      },
      created_at: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updated_at: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  down: (queryInterface, Sequelize) => {
    return queryInterface.dropTable('movies');
  }
};

└ TODO : video_idはnotNull制約が必要やったなぁ…。

db migration実行 テーブル作成

sequelize db:migrate

アプリ側のCRUDを実装する前に先にテストデータをインサート

INSERT INTO movies (title, video_id, tag, upload_date, is_delete, created_at, updated_at) VALUES 
('xxx', 'xxx1', 1, '2014-5-18', false, now(), now()),
('xxx', 'xxx2', 1, '2014-5-19', false, now(), now()),
('xxx', 'xxx3', 1, '2014-5-20', false, now(), now()),
('xxx', 'xxx4', 1, '2014-5-21', false, now(), now()),
('xxx', 'xxx5', 1, '2014-5-22', false, now(), now());

select実装

routes/index.js

const models = require('../models');

router.get('/', function(req, res, next) {
  models.movie.findAll().then(function(results) {
    res.render('index', {movies: results});
  });
});

views/index.jade

each movie in movies

.movie
  img(src='http://i.ytimg.com/vi/#{movie.video_id}/default.jpg')
  p.day #{movie.upload_date}
  a.links(href='https://youtu.be/#{movie.video_id}')
    p ##{movie.id} #{movie.title}アップロードしました。

使用法の所感

わかった。
Controllerにmodel層を読み込ませて、models.xxxで呼び出し。その処理が終わったら(then)コールバックで変数名を新たに付けて受け渡しも可能。
その処理で得た結果の名前を便宜的に使用することが可能。