Our app has a service layer on top of a storage layer - a service layer method will create a new database session (we're using Slick on top of MySql) and passes the session as an implicit parameter to the storage layer methods
trait Service1 {
def serviceLayerMethod(params) = {
db withSession {
implicit session: Session =>
storageLayerMethod1(params)
storageLayerMethod2(params)
}}}
object DAO1 {
def storageLayerMethod1(params)(implicit session: Session)
}
object DAO2 {
def storageLayerMethod2(params)(implicit session: Session)
}
We'd like to be able to inject different method implementations from the service layer to the storage layer, for example we have a multiGet
method that retrieves multiple records, and we'd like to have different implementations of this method e.g. one that does the multiGet
in parallel and another that attempts to retrieve data from the Redis cache before pulling it from the database. I could pass these methods around as implicit parameters, but I was hoping that there was a way to do this with less boilerplate.
trait MultiGet {
def multiGet(params)(implicit session: Session)
}
object MultiGetDefault extends MultiGet
object MultiGetParallel extends MultiGet
object MultiGetCached extends Multiget
trait Servic1 {
def serviceLayerMethod1(params) = {
db withSession {
implicit session: Session =>
storageLayerMethod1(params)(MultiGetDefault)
}}
def serviceLayerMethod2(params) = {
db withSession {
implicit session: Session =>
storageLayerMethod1(params)(MultiGetParallel)
}}}
object DAO1 {
def storageLayerMethod1(params)(implicit session: Session, multiGetImpl: MultiGet) {
multiGetImpl.multiGet(params)
}}
Most of the storage layer methods are in singleton objects, so I'm not able to mixin different MultiGet
implementations without a significant refactor. The service layer traits are being instantiated/injected at the controller layer via the cake pattern.