Skip to content

Instantly share code, notes, and snippets.

@tlync
Last active February 8, 2018 06:36
Show Gist options
  • Save tlync/7913967 to your computer and use it in GitHub Desktop.
Save tlync/7913967 to your computer and use it in GitHub Desktop.
Scala Advent Calendar 2013 12/11 の記事で利用した Transparent IO Context パターンのコード
// Transparent IO Context pattern using implicit parameter
// ---
// domain
// ---
// base (サンプルなのでほぼただの Marker Trait)
trait Entity
// 永続化に利用するセッションを保持するただのコンテナ
case class IoContext[S](session: S)
// IoContext を各レイヤから透過的に扱える様にする為の trait
trait TransparentIoContext[S] {
implicit def wrapContext(implicit session: S) = IoContext(session)
implicit def unwrapContext(implicit ctx: IoContext[S]) = ctx.session
}
trait Repository[S] extends TransparentIoContext[S]
case class User(id: Int, name: String) extends Entity
trait Users[S] extends Repository[S] {
// Repository の各インターフェースは抽象的な IoContext に依存するだけ
def find(id: Int)(implicit ctx: IoContext[S]): Option[User]
}
// ---
// infra
// ---
import scalikejdbc._
import SQLInterpolation._
class ScalikeJdbcBasedUsers extends Users[DBSession] {
private def rsToEntity(rs: WrappedResultSet) = {
User(rs.int("id"), rs.string("name"))
}
def find(id: Int)(implicit ctx: IoContext[DBSession]): Option[User] = {
// TransparentIoContext#unwrapContext が評価され暗黙的に DBSession が渡される
// もちろん ctx が渡ってきているので明示的に使うこともできる
sql"select * from users where $id".map(rsToEntity).single().apply()
}
}
// ---
// app
// ---
class SomeService extends TransparentIoContext[DBSession] {
val users = new ScalikeJdbcBasedUsers // 実際には DI 使う
// UserRepo 以外も色々扱って処理するなにか
def doSomething() = {
DB localTx { implicit session =>
// この implicit session は TransparentIoContext により、
// IoContext[DBSession] に変換されて、Users#find に暗黙パラメータとして渡される
val u = users.find(1)
// ...
println(u) // -> Some(User(1,scalachan))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment