Scala光滑地比较运算符

时间:2017-02-02 11:44:46

标签: scala slick slick-3.0

我正在使用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."))

  }
}

1 个答案:

答案 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
    */

}