我正在使用scala和slick开发一个安静的Web服务。我正在尝试实现过滤。我唯一无法工作的是动态设置比较操作的运算符。我想支持===,=!=,< =,> =和LIKE。
我在filteringOperator
函数中遇到了泛型问题,但我找不到它。例外情况如下:
value === is not a member of HardwareRepo.this.dbConfig.driver.api.Rep[A]
有人有想法吗?
def filtering(exp: FilterExpression): (HardwareTable) => Rep[Option[Boolean]] = {
exp.field match {
case "serialNumber" => filteringOperator(exp, _.serialNumber, exp.value)
case "online" => filteringOperator(exp, _.online, Try(exp.value.toBoolean).getOrElse(false))
case _ => throw new FilterFieldNotSupportedException(s"Filter field '${exp.field}' not supported")
}
}
def filteringOperator[A](exp: FilterExpression, x: Rep[A], y: A): Rep[Option[Boolean]] = {
exp.operator match {
case FilterExpressionOperator.Equals => x === y
...
}
}
def all(offset: Int, size: Int, filter: List[FilterExpression]): Future[List[Hardware]] = {
var q = Hardwares.to[List]
//filtering
for (exp <- filter) {
try {
q = q.filter(filtering(exp))
} catch {
case ex: FilterFieldNotSupportedException => return Future.failed(ex)
}
}
//pagination
db.run(q.drop(offset).take(size).result)
}
整个源代码:
package models
import java.sql.Timestamp
import java.util.UUID
import javax.inject.Inject
import helper.{FilterExpression, FilterExpressionOperator, SortExpression, SortExpressionOrder}
import play.api.db.slick.DatabaseConfigProvider
import helper.exceptions.{EntityAlreadyExistsException, FilterFieldNotSupportedException, SortFieldNotSupportedException}
import slick.driver.JdbcProfile
import slick.lifted.ColumnOrdered
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Try
case class Hardware(id: UUID,
createdAt: Timestamp,
serialNumber: String,
color: Int,
online: Boolean,
renterCount: Int)
class HardwareRepo @Inject()()(protected val dbConfigProvider: DatabaseConfigProvider) {
val dbConfig = dbConfigProvider.get[JdbcProfile]
val db = dbConfig.db
import dbConfig.driver.api._
private val Hardwares = TableQuery[HardwareTable]
val allowedSorting = Map( "id" -> { (hw: Hardware) => hw.id } )
private def _findById(id: UUID): DBIO[Option[Hardware]] =
Hardwares.filter(_.id === id).result.headOption
private def _findBySerialNumber(serialNumber: String): Query[HardwareTable, Hardware, List] =
Hardwares.filter(_.serialNumber === serialNumber).to[List]
def findById(id: UUID): Future[Option[Hardware]] =
db.run(_findById(id))
def findBySerialNumber(serialNumber: String): Future[List[Hardware]] =
db.run(_findBySerialNumber(serialNumber).result)
def sorting(exp: SortExpression): (HardwareTable) => ColumnOrdered[_] = {
exp.field match {
case "id" => if (exp.order == SortExpressionOrder.Asc) _.id.asc else _.id.desc
case "serialNumber" => if (exp.order == SortExpressionOrder.Asc) _.serialNumber.asc else _.serialNumber.desc
case "createdAt" => if (exp.order == SortExpressionOrder.Asc) _.createdAt.asc else _.createdAt.desc
case "color" => if (exp.order == SortExpressionOrder.Asc) _.color.asc else _.color.desc
case "online" => if (exp.order == SortExpressionOrder.Asc) _.online.asc else _.online.desc
case _ => throw new SortFieldNotSupportedException(s"Sort field '${exp.field}' not supported")
}
}
def filtering(exp: FilterExpression): (HardwareTable) => Rep[Option[Boolean]] = {
exp.field match {
case "serialNumber" => _.serialNumber === exp.value
case "online" => _.online === Try(exp.value.toBoolean).getOrElse(false)
case _ => throw new FilterFieldNotSupportedException(s"Filter field '${exp.field}' not supported")
}
}
def filteringOperator[A](exp: FilterExpression, x: Rep[A], y: A): Rep[Option[Boolean]] = {
exp.operator match {
case FilterExpressionOperator.Equals => x === y
}
}
def all(offset: Int, size: Int, sort: List[SortExpression], filter: List[FilterExpression]): Future[List[Hardware]] = {
var q = Hardwares.to[List]
//sorting
for (exp <- sort) {
try {
q = q.sortBy(sorting(exp))
} catch {
case ex: SortFieldNotSupportedException => return Future.failed(ex)
}
}
//filtering
for (exp <- filter) {
try {
q = q.filter(filtering(exp))
} catch {
case ex: FilterFieldNotSupportedException => return Future.failed(ex)
}
}
//pagination
db.run(q.drop(offset).take(size).result)
}
def exists(serialNumber: String): Future[Boolean] = {
db.run(Hardwares.filter(hw => hw.serialNumber === serialNumber).exists.result)
}
def create(serialNumber: Option[String]): Future[UUID] = {
if (serialNumber.isEmpty) {
db.run(Hardwares.map(hw => (hw.color)) returning Hardwares.map(_.id) += (0))
} else {
//check serial number
val action = (Hardwares.filter(hw => hw.serialNumber === serialNumber).exists.result.flatMap {
case true => DBIO.failed(new EntityAlreadyExistsException("Serialnumber already exists"))
case false => Hardwares.map(hw => (hw.color, hw.serialNumber)) returning Hardwares.map(_.id) += (0, serialNumber.get)
}).transactionally
db.run(action)
}
}
class HardwareTable(tag: Tag) extends Table[Hardware](tag, "hardware") {
def id = column[UUID]("id", O.PrimaryKey)
def createdAt = column[Timestamp]("created_at")
def serialNumber = column[String]("serial_number")
def color = column[Int]("color")
def online = column[Boolean]("online")
def renterCount = column[Int]("renter_count")
def * = (id, createdAt, serialNumber, color, online, renterCount) <> (Hardware.tupled, Hardware.unapply)
def ? = (id.?, createdAt.?, serialNumber.?, color.?, online.?, renterCount.?).shaped.<>({ r => import r._; _1.map(_ => Hardware.tupled((_1.get, _2.get, _3.get, _4.get, _5.get, _6.get))) }, (_: Any) => throw new Exception("Inserting into ? projection not supported."))
}
}
答案 0 :(得分:0)
解决错误
值===不是其成员 HardwareRepo.this.dbConfig.driver.api.Rep [A]
要使===
运算符工作,配置文件api必须导入并在范围内可用。我会重构课程HardwareRepo
,如下所示
class HardwareRepo @Inject() (protected val dbConfigProvider: DatabaseConfigProvider) {
with HasDatabaseConfigProvider[JdbcProfile] {
import driver.api._
/*
other repo methods
*/
}