node.jsでSequelizeを使うための準備/中編 | Inhale n’ Exhale前編では、Sequelizeをインスタンス化するために自前でdbconn
モジュールを作って、app.js
はこんな感じにシンプルに書けるようになった。
1 | var express = require( 'express' ) |
2 | , resource = require( 'express-resource' ) |
3 | , config = require( 'config' ) |
4 | , sequelize = require( 'dbconn' )(config) |
5 | , app = module.exports = express.createServer(); |
7 | app.resource( 'users' , require( './routes/users' ), { id: 'id' }); |
実際にSequelizeを使ってDBに対するCRUD操作を行うAPIの実装を書く以前に、まだDBすら存在しないのでmysql
コマンドでDBだけ作っておく。
$ mysql -u root -p
mysql> create database test;
mysql> grant all privileges on test.* to 'h2plus'@'%' identified by 'password';
mysql> \q
次にテーブルの定義をするわけだが、もうSQL文を直接書くことはない。Sequelizeのimport
メソッドを使えば、モジュールとして実装されたモデルを定義することができる。サンプルとして、以下のSQLで定義されるユーザーテーブルを作ってみよう。
create table users
(
username varchar(255),
password char(40)
);
対応するモデル定義のモジュールはこうなる。
1 | module.exports = function (sequelize, DataTypes) { |
2 | return sequelize.define( 'user' , { |
3 | username: DataTypes.STRING |
これをmodels/user.js
というファイルに保存しておく。sequelize.define()
の第一引数に指定しているモデル名は単数形になっているが、Sequelizeが実際に定義するテーブル名は複数形になる。
いま定義したUser
モデルを動的に読み込むmodels
モジュールをlibs/models/index.js
に実装していく。libs
ディレクトリは前編でdbconn
モジュールを実装するときに作ったものだ。
1 | module.exports = function (sequelize) { |
4 | , path = require( 'path' ) |
9 | fs.lstatSync(directory); |
12 | fs.mkdirSync(directory); |
17 | fs.readdirSync(directory).forEach( function (fname) { |
18 | if (/\.js$/.test(fname)) { |
19 | var name = path.basename(fname, '.js' ) |
20 | , realpath = fs.realpathSync(directory+ '/' +fname); |
22 | models.__defineGetter__(name, function () { |
23 | if (models.__cache[name] === undefined) { |
24 | models.__cache[name] = sequelize.import(realpath); |
26 | return models.__cache[name]; |
これで、models
ディレクトリにテーブル定義モジュールを作るだけで、アプリケーションにモデルを追加することができるようになる。アプリケーションで定義したモデルをDBに反映させるにはSequelizeのsync
メソッドを使う。アプリ開発中にモデルが更新されることは多いだろうから、sync
メソッドの呼び出し自体をAPI化してしておくと便利だ。
sync
メソッドを実装したAPIを用意する前に、今までapp.js
に書いてあったexpress-resource
を使ったコードや、Sequelizeを使うコードをroutes/index.js
にカプセル化してしまおう。app.js
の最終形はこうなる。
1 | var express = require( 'express' ) |
2 | , resource = require( 'express-resource' ) |
3 | , config = require( 'config' ) |
4 | , app = module.exports = express.createServer(); |
9 | app.configure( function () { |
10 | app.set( 'views' , __dirname + '/views' ); |
11 | app.set( 'view engine' , 'ejs' ); |
12 | app.use(express.bodyParser()); |
13 | app.use(express.cookieParser()); |
14 | app.use(express.methodOverride()); |
16 | app.use(express.static(__dirname + '/public' )); |
19 | app.configure( 'development' , function () { |
20 | app.use(express.errorHandler({ dumpExceptions: true , showStack: true })); |
23 | app.configure( 'production' , function () { |
24 | app.use(express.errorHandler()); |
30 | require( './routes' )(app, config); |
35 | app.listen(process.env.PORT || 3000, function () { |
36 | console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env); |
冒頭に紹介したコードでは、Sequelizeをapp.js
内でインスタンス化していたが、実際にSequelize(モデル)を使うのはroutes
の中になるので、Sequelizeのインスタンス化に必要なconfig
オブジェクトをroutes
に渡すようにしている。config
オブジェクト自体はアプリケーションの設定を保持するものであり、Sequelize以外のモジュールが必要とする設定が含まれることを考えると、app.js
内でインスタンス化するのが適切だろう。
30行目でまだ存在しないroutes
モジュールを呼び出すコードを先に書いてしまったが、routes
モジュールはroutes/index.js
で以下のように実装している。
1 | module.exports = function (app, config) { |
3 | var sequelize = require( 'dbconn' )(config) |
4 | , models = require( 'models' )(sequelize); |
6 | app.resource( 'users' , require( './users' ), { id: 'id' }); |
これでしばらくapp.js
にコーディングすることはなくなるだろう。アプリケーションロジックのメインはroutes
モジュールが請け負うことになる。
結局三部作に(笑)後編に続く…
2 コメント