6月 232012
 

node.jsでSequelizeを使うための準備/中編 | Inhale n’ Exhale前編では、Sequelizeをインスタンス化するために自前でdbconnモジュールを作って、app.jsはこんな感じにシンプルに書けるようになった。

1var express = require('express')
2  , resource = require('express-resource')
3  , config = require('config')
4  , sequelize = require('dbconn')(config)
5  , app = module.exports = express.createServer();
6 
7app.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)
);

対応するモデル定義のモジュールはこうなる。

1module.exports = function(sequelize, DataTypes) {
2    return sequelize.define('user', {
3        username: DataTypes.STRING
4      , password: 'char(40)'
5    });
6};

これをmodels/user.jsというファイルに保存しておく。sequelize.define()の第一引数に指定しているモデル名は単数形になっているが、Sequelizeが実際に定義するテーブル名は複数形になる。

いま定義したUserモデルを動的に読み込むmodelsモジュールをlibs/models/index.jsに実装していく。libsディレクトリは前編dbconnモジュールを実装するときに作ったものだ。

1module.exports = function(sequelize) {
2 
3  var fs = require('fs')
4    , path = require('path')
5    , directory = 'models'
6    , models = exports;
7 
8  try {
9    fs.lstatSync(directory);
10  }
11  catch(e) {
12    fs.mkdirSync(directory);
13  }
14 
15  models.__cache = {};
16 
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);
21 
22      models.__defineGetter__(name, function() {
23        if(models.__cache[name] === undefined) {
24          models.__cache[name] = sequelize.import(realpath);
25        }
26        return models.__cache[name];
27      });
28    }
29  });
30 
31  return models;
32};

これで、modelsディレクトリにテーブル定義モジュールを作るだけで、アプリケーションにモデルを追加することができるようになる。アプリケーションで定義したモデルをDBに反映させるにはSequelizeのsyncメソッドを使う。アプリ開発中にモデルが更新されることは多いだろうから、syncメソッドの呼び出し自体をAPI化してしておくと便利だ。

syncメソッドを実装したAPIを用意する前に、今までapp.jsに書いてあったexpress-resourceを使ったコードや、Sequelizeを使うコードをroutes/index.jsにカプセル化してしまおう。app.jsの最終形はこうなる。

1var express = require('express')
2  , resource = require('express-resource')
3  , config = require('config')
4  , app = module.exports = express.createServer();
5 
6//
7// Configuration
8//
9app.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());
15  app.use(app.router);
16  app.use(express.static(__dirname + '/public'));
17});
18 
19app.configure('development', function() {
20  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
21});
22 
23app.configure('production', function() {
24  app.use(express.errorHandler());
25});
26 
27//
28// Routes
29//
30require('./routes')(app, config);
31 
32//
33// Launch
34//
35app.listen(process.env.PORT || 3000, function() {
36  console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
37});

冒頭に紹介したコードでは、Sequelizeをapp.js内でインスタンス化していたが、実際にSequelize(モデル)を使うのはroutesの中になるので、Sequelizeのインスタンス化に必要なconfigオブジェクトをroutesに渡すようにしている。configオブジェクト自体はアプリケーションの設定を保持するものであり、Sequelize以外のモジュールが必要とする設定が含まれることを考えると、app.js内でインスタンス化するのが適切だろう。

30行目でまだ存在しないroutesモジュールを呼び出すコードを先に書いてしまったが、routesモジュールはroutes/index.jsで以下のように実装している。

1module.exports = function(app, config) {
2 
3  var sequelize = require('dbconn')(config)
4    , models = require('models')(sequelize);
5 
6  app.resource('users', require('./users'), { id: 'id' });
7};

これでしばらくapp.jsにコーディングすることはなくなるだろう。アプリケーションロジックのメインはroutesモジュールが請け負うことになる。

結局三部作に(笑)後編に続く

  2 コメント

 返信する

以下のHTML タグと属性が利用できます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください