6月 232012
 

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

var express = require('express')
  , resource = require('express-resource')
  , config = require('config')
  , sequelize = require('dbconn')(config)
  , app = module.exports = express.createServer();

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)
);

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

module.exports = function(sequelize, DataTypes) {
    return sequelize.define('user', {
        username: DataTypes.STRING
      , password: 'char(40)'
    });
};

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

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

module.exports = function(sequelize) {

  var fs = require('fs')
    , path = require('path')
    , directory = 'models'
    , models = exports;

  try {
    fs.lstatSync(directory);
  }
  catch(e) {
    fs.mkdirSync(directory);
  }

  models.__cache = {};

  fs.readdirSync(directory).forEach(function(fname) {
    if(/\.js$/.test(fname)) {
      var name = path.basename(fname, '.js')
        , realpath = fs.realpathSync(directory+'/'+fname);

      models.__defineGetter__(name, function() {
        if(models.__cache[name] === undefined) {
          models.__cache[name] = sequelize.import(realpath);
        }
        return models.__cache[name];
      });
    }
  });

  return models;
};

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

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

var express = require('express')
  , resource = require('express-resource')
  , config = require('config')
  , app = module.exports = express.createServer();

//
// Configuration
//
app.configure(function() {
  app.set('views', __dirname + '/views');
  app.set('view engine', 'ejs');
  app.use(express.bodyParser());
  app.use(express.cookieParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function() {
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function() {
  app.use(express.errorHandler());
});

//
// Routes
//
require('./routes')(app, config);

//
// Launch
//
app.listen(process.env.PORT || 3000, function() {
  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で以下のように実装している。

module.exports = function(app, config) {

  var sequelize = require('dbconn')(config)
    , models = require('models')(sequelize);

  app.resource('users', require('./users'), { id: 'id' });
};

これでしばらく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 を使っています。コメントデータの処理方法の詳細はこちらをご覧ください