BackboneベースのORM Bokshelfのpolymorphic associationです。
$ mkdir bookshelf-polymorphic-association
$ cd bookshelf-polymorphic-association
$ vi package.json
package.json:
{
"name": "bookshelf-polymorphic-association",
"version": "0.0.0",
"main": "index.js",
"dependencies": {
"bookshelf": "~0.6.1",
"knex": "git+https://github.com/tgriesser/knex.git",
"sqlite3": "~2.1.19"
}
}
モジュールのインストール:
$ npm install
テーブルの作成
Bookshelfが利用しているknexがマイグレーションをサポートしているのでこれを使います。
設定ファイルの作成
$ mkdir db
$ vi db/config.js
db/config.js:
module.exports = {
directory: './db/migrations',
database: {
client: 'sqlite3',
connection: {
filename: './db/bookshelf-polymorphic-association.db'
}
}
};
マイグレーション作成
$ ./node_modules/.bin/knex migrate:make create -c ./db/config.js
$ vi 20131130140239_create.js
20131130140239_create.js:
exports.up = function(knex, Promise) {
return Promise.all([
knex.schema.createTable('employees', function(t) {
t.increments('id').primary();
t.string('name');
}),
knex.schema.createTable('products', function(t) {
t.increments('id').primary();
t.string('name');
}),
knex.schema.createTable('pictures', function(t) {
t.increments('id').primary();
t.string('name');
t.integer('imageable_id').notNull();
t.string('imageable_type').notNull();
})
]);
};
exports.down = function(knex, Promise) {
return Promise.all([
knex.schema.dropTable('employees'),
knex.schema.dropTable('products'),
knex.schema.dropTable('pictures')
]);
};
マイグレーション実行
$ ./node_modules/.bin/knex migrate:latest -c ./db/config.js
本題
index.js:
var config = require('./db/config').database,
Bookshelf = require('bookshelf').initialize(config);
var Employee = Bookshelf.Model.extend({
tableName: 'employees',
pictures: function() {
return this.morphMany(Picture, 'imageable');
}
});
var Product = Bookshelf.Model.extend({
tableName: 'products',
pictures: function() {
return this.morphMany(Picture, 'imageable');
}
});
var Picture = Bookshelf.Model.extend({
tableName: 'pictures',
imageable: function() {
return this.morphTo('imageable', Employee, Product);
}
});
// Employeeを作成
new Employee({ name: 'hoge' }).save()
// employeeのPictureを作成
.then(function(employee) {
var picture = new Picture({
name: 'employee\'s picture',
imageable_id: employee.id,
imageable_type: 'employees'
});
return [picture.save(), employee];
})
// employeeをPicture毎フェッチしてみる
.spread(function(picture, employee) {
return employee.fetch({ withRelated: ['pictures'] });
})
.tap(function(employee) {
console.log(employee.toJSON());
})
// 今度はProductを作成
.then(function() {
return new Product({ name: 'piyo' }).save();
})
// productのPictureを作成
.then(function(product) {
var picture = new Picture({
name: 'product\'s picture',
imageable_id: product.id,
imageable_type: 'products'
});
return [picture.save(), product];
})
// productをPicture毎フェッチしてみる
.spread(function(picture, product) {
return product.fetch({ withRelated: ['pictures'] });
})
.tap(function(employee) {
console.log(employee.toJSON());
})
.then(function() {
process.exit();
});
実行
$ node index.js