我们使用两个数据库:主数据库和副本数据库。
用例:
我们希望提供一个可用于运行 DBIOAction (s) 的对象,并能够根据平滑效果推断要使用哪个数据库。读取 => 副本。写入 => 主要。
我还希望允许程序员将主数据库固定为读取,而不是复制到写入。如果有人试图将副本固定到读取操作,我想得到一个编译错误。
我有以下代码:
import scala.concurrent.Future
import slick.jdbc.MySQLProfile.api._
import Effect._
import scala.annotation.implicitNotFound
object DatabaseModule {
// Used to create a constraint on what Role can an effect have.
trait Role[E <: Effect]
type ReplicaRole = Role[Read]
type PrimaryRole = Role[Write] with ReplicaRole
// database configuration depends on the role.
sealed trait DatabaseConfiguration[R <: Role[_]] {
def createDatabase(): Database
}
object DatabaseConfiguration {
object Primary extends DatabaseConfiguration[PrimaryRole] {
def createDatabase(): Database = Database.forConfig("slick.mysql.write")
}
object Replica extends DatabaseConfiguration[ReplicaRole] {
def createDatabase(): Database = Database.forConfig("slick.mysql.read")
}
}
class DB[R <: Role[_]](databaseConfiguration: DatabaseConfiguration[R]){
val underlyingDatabase = databaseConfiguration.createDatabase()
}
object DB {
// this error will be returned if the implicit is not found.
@implicitNotFound("'${R}' database is not privileged to to perform effect '${E}'.")
trait HasPrivilege[R <: Role[E], E <: Effect]
// phantom types safe to assign null, used to enforce typing.
implicit val replicaCanRead: ReplicaRole HasPrivilege Read = _
implicit val primaryCanWrite: PrimaryRole HasPrivilege Write = _
implicit val primaryCanRead: PrimaryRole HasPrivilege Read = _
// primary and replica databases.
implicit lazy val dbPrimary: DB[PrimaryRole] = new DB(DatabaseConfiguration.Primary)
implicit lazy val dbReplica: DB[ReplicaRole] = new DB(DatabaseConfiguration.Replica)
// this function should infer which configuration to use (primary for writes, replica for reads)
def run[A, E <: Effect](a: DBIOAction[A, NoStream, E])(implicit defaultDb: DB[Role[E]], p: Role[E] HasPrivilege E)
: Future[A] = defaultDb.underlyingDatabase.run(a)
// If we want to pin to replica, use this as follow DB.run(dbioAction)(dbMaster)
def run[A, E <: Effect](a: DBIOAction[A, NoStream, E])(db: Database)(implicit p: Role[E] HasPrivilege E)
: Future[A] = db.run(a)
}
}
但是这不起作用,当我尝试使用它时,我收到以下 sbt 错误
[error] [A, E <: slick.jdbc.MySQLProfile.api.Effect](a: slick.jdbc.MySQLProfile.api.DBIOAction[A,slick.jdbc.MySQLProfile.api.NoStream,E])(db: slick.jdbc.MySQLProfile.api.Database)(implicit p: com.hautelook.support.db.mysql.DatabaseModule.DB.HasPrivilege[com.hautelook.support.db.mysql.DatabaseModule.Role[E],E])scala.concurrent.Future[A] <and>
[error] [A, E <: slick.jdbc.MySQLProfile.api.Effect](a: slick.jdbc.MySQLProfile.api.DBIOAction[A,slick.jdbc.MySQLProfile.api.NoStream,E])(implicit defaultDb: com.hautelook.support.db.mysql.DatabaseModule.DB[com.hautelook.support.db.mysql.DatabaseModule.Role[E]], implicit p: com.hautelook.support.db.mysql.DatabaseModule.DB.HasPrivilege[com.hautelook.support.db.mysql.DatabaseModule.Role[E],E])scala.concurrent.Future[A]
[error] cannot be applied to (slick.dbio.DBIOAction[Int,Any,slick.jdbc.MySQLProfile.api.Effect.Write])
任何人都知道如何正确解决这些类型?