2009-10-07
JavaScript 版の SQL::Abstract ぽいのを作った
WebDatabase で SQLite 使うんで、JavaScript で SQL 生成するのに作った。Ruby の ActiveRecord の SQL 生成方法より、SQL::Abstract のほうがしっくりくるんだよなー。S2JDBC のような Fluent Interface ぽいのも作ってみたけどしっくりこなく、結局 SQL::Abstract が単純明快で個人的にはわかりやすいんだよな。
WebDatabase の executeSql は引数に SQL 文と、プレースホルダーに bind する配列をとるので、Perl の SQL::Abstract とほぼ同じ引数、戻り値になっている。
where 句作る
var sql = new SQLAbstract;
var res = sql.where(['user = ? AND status = ?', 'nadeko', 'completed']);
// res[0] #=> 'WHERE user = ? AND status = ?'
// res[1] #=> ['nadeko', 'completed']
名前つきプレースホルダーも使える
res = sql.where(['user = :user AND status = :status', {
user: 'nadeko',
status: 'completed'
}]);
// res[0] #=> 'WHERE user = ? AND status = ?'
// res[1] #=> ['nadeko', 'completed']
Hash を引数にとれる
res = sql.where({
user: 'nadeko',
status: 'completed'
});
// res[0] #=> 'WHERE user = ? AND status = ?'
// res[1] #=> ['nadeko', 'completed']
select。limit/offset/group などもかける
res = sql.select('table', '*', {
user: null,
status: 'completed'
}, {
limit: 20,
offset: 10
});
// res[0] => 'select * from table WHERE user IS NULL AND status = ? LIMIT ? OFFSET ?'
// res[1] => ['completed', 20, 10]
insert/update/delete
res = sql.insert('table', {
user: 'nadeko',
status: 'completed'
});
// res[0] => 'insert into table (user, status) values (?, ?)'
// res[1] => ['nadeko', 'completed']
res = sql.update('table', {
user: 'nadeko',
status: 'completed'
});
// res[0] => 'update table3 SET user = ?, status = ?'
// res[1] => ['nadeko', 'completed']
res = sql.update('table', {
user: 'nadeko',
status: 'completed'
});
// res[0] => 'update table3 SET user = ?, status = ?'
// res[1] => ['nadeko', 'completed']
res = sql.deleteSql('table', {
id: 3
});
// res[0] => 'delete from table WHERE id = ?'
// res[1] => [3]
その他いろいろは test/test.js をみてください。テストは、Safari4 などの openDatabase の実装があるなら、それを使って Syntax チェックもします。
Deferred.prototype.e
JSDeferred 使っていて、非同期時の例外をきちんと error() でキャッチするのではなく、ログに表示したいとき
Deferred.prototype.e = function() {
this.error(function(e) {
console.log('catch deferred error: ' + e);
return e;
});
};
とか定義しておくと
d.next(foo).e();
とするだけで便利、と思ったけどいっそ以下のようにしちゃって、問答無用で表示の方が開発時は便利だな。
Deferred.prototype._fire = function (okng, value) {
var next = "ok";
try {
value = this.callback[okng].call(this, value);
} catch (e) {
next = "ng";
if (Deferred.debug) console.log('DeferredError: ' + e);
value = e;
}
if (value instanceof Deferred) {
value._next = this._next;
} else {
if (this._next) this._next._fire(next, value);
}
return this;
}
Deferred.debug = true;