Heroku + MongoLab 環境に Casbah を使って MongoDB に接続する Play 2.0 で作成したアプリケーションをデプロイしようとしました。
それで Heroku 上で MONGOLAB_URI の設定値として提供される MongoDB の接続 URI を com.mongodb.casbah.MongoURI(com.mongodb.MongoURI)に食わせたらまったくもってでたらめなパースをするので自分でなんとかするコードを書きました。使い方は以下のコード内のコメント参照。MongoDB の接続 URI は conf/application.conf 内で mongodb.default.uri で設定するか、起動時に -D オプションで与えるようにしてください。
package mongodb
import play.api._
import Play.current
import com.mongodb.casbah.Imports._
/**
* MongoDB をサクッと使うためのオブジェクトです。
*/
object Mongo {
/**
* MongoDB 接続用 URI をパースするための正規表現
*/
val uriPattern = "mongodb://(?:([^:^@]+)(?::([^@]+))?@)?([^:^/]+)(?::(\\d+))?/(.+)".r
/**
* MongoDB に接続されたブロックを提供します。
* 接続 URI は mongodb.default.uri の設定値を使用します。
*
* 使い方の例
* {{{
* MongoDB.withDB { db =>
* db("employee").findAll().toSeq
* }
* }}}
*/
def withDB[A](f: MongoDB => A): A = withDB("default")(f)
/**
* MongoDB に接続されたブロックを提供します。
*
* 使い方の例
* {{{
* MongoDB.withDB("mydb") { db =>
* db("employee").findAll().toSeq
* }
* }}}
*
* @param name 設定名
*/
def withDB[A](name: String)(f: MongoDB => A): A = {
// Play を使わない場合は↓このあたりを変えるといい
val uri = Play.configuration.getString("mongodb." + name + ".uri").getOrElse("mongodb://localhost/test")
// URI のパース
val (usernameOpt, passwordOpt, host, portOpt, database) = parseURI(uri)
// MongoDB に接続
val conn = portOpt map { port =>
MongoConnection(host, port.toInt)
} getOrElse {
MongoConnection(host)
}
try {
// DB 取得
val db = conn(database)
// 必要とあれば認証処理を行う
(usernameOpt, passwordOpt) match {
case (Some(username), Some(password)) => db.authenticate(username, password)
case _ =>
}
// 引数で指定された処理を実行
f(db)
} finally {
conn.close()
}
}
/**
* MongoDB 接続 URI をパースします。
*/
def parseURI(uri: String) = {
uri match {
case uriPattern(username, password, host, port, database) =>
(Option(username), Option(password), host, Option(port), database)
}
}
}