Scala 标记布尔类型上的Slick中的布尔运算

Scala 标记布尔类型上的Slick中的布尔运算,scala,slick,Scala,Slick,我已将实现为的类型标记为 我用它们标记了模型的所有属性,这些属性或多或少都是通用原语、字符串等。当我使用Slick将模型映射到dabase时,我通常会这样定义它们: val isDeleted = column[Boolean @@ CompanyDeleted]("deleted", O.Default(false.tag)) 而类型映射器我定义为: implicit def taggedBooleanColumnType[U]: BaseColumnType[Boolean @@ U] =

我已将实现为的类型标记为

我用它们标记了模型的所有属性,这些属性或多或少都是通用原语、字符串等。当我使用Slick将模型映射到dabase时,我通常会这样定义它们:

val isDeleted = column[Boolean @@ CompanyDeleted]("deleted", O.Default(false.tag))
而类型映射器我定义为:

implicit def taggedBooleanColumnType[U]: BaseColumnType[Boolean @@ U] =
  MappedColumnType.base[Boolean @@ U, Boolean](_.untag, _.tag[U])
它允许我在模型上执行所有CRUD操作。但是,当我尝试时,例如:

def fetchById(companyId: Long @@ CompanyId): SqlAction[Option[Company], NoStream, Read] =
companies.filter(c => c.companyId === companyId && !c.isDeleted).result.headOption
这将失败,因为Rep[Boolean@@CompanyDeleted]是nethier Rep[Boolean]或Rep[Option[Boolean]]。当我创建它时:

implicit def taggedBooleanExtensionMethods[P1, U](c: slick.lifted.Rep[P1]): TaggedBooleanExtensionMethods[P1, U] =
  new TaggedBooleanExtensionMethods[P1, U](c)

implicit def taggedBooleanColumnCanBeQueryCondition[U]: CanBeQueryCondition[slick.lifted.Rep[Boolean @@ U]] =
  new CanBeQueryCondition[slick.lifted.Rep[Boolean @@ U]] {
    def apply(value: slick.lifted.Rep[Boolean @@ U]) = value
  }

class TaggedBooleanExtensionMethods[P1, U](val c: Rep[P1])
    extends AnyVal
    with ExtensionMethods[Boolean @@ U, P1] {
  protected[this] implicit def b1Type = implicitly[TypedType[Boolean @@ U]]

  import slick.lifted.FunctionSymbolExtensionMethods._

  def &&[P2, R](b: Rep[P2])(implicit om: o#arg[Boolean @@ U, P2]#to[Boolean @@ U, R]) =
    om.column(Library.And, n, b.toNode)
  def ||[P2, R](b: Rep[P2])(implicit om: o#arg[Boolean @@ U, P2]#to[Boolean @@ U, R]) =
    om.column(Library.Or, n, b.toNode)
  def unary_! = Library.Not.column[P1](n)
}
我可以_一元运算符,但不是&&或| |,因为代表的类型不匹配


我的问题是:我是否可以提供/修改隐式,以便能够对这些列执行布尔运算?我对| |特别感兴趣,因为&&可以使用链式过滤器完成。

这不是漂亮的解决方案,但它是我想到的最好的解决方案:

implicit class TaggedBooleanAsFirstOperand[P1, U](val c: Rep[P1 @@ U]) {
  private val em = new BooleanColumnExtensionMethods[P1](c.untagM)
  type o = OptionMapperDSL.arg[Boolean, P1]

  def @&&[P2, R](b: Rep[P2])(implicit om: o#arg[Boolean, P2]#to[Boolean, R]): Rep[R] = em.&&[P2, R](b)
  def @||[P2, R](b: Rep[P2])(implicit om: o#arg[Boolean, P2]#to[Boolean, R]): Rep[R] = em.||[P2, R](b)
  def unary_! : Rep[P1] = em.unary_!
}

implicit class TaggedBooleanAsSecondOperand[P1](val c: Rep[P1]) {
  private val em = new BooleanColumnExtensionMethods[P1](c)
  type o = OptionMapperDSL.arg[Boolean, P1]

  def &&@[P2, U, R](b: Rep[P2 @@ U])(implicit om: o#arg[Boolean, P2]#to[Boolean, R]): Rep[R] = em.&&[P2, R](b.untagM)
  def ||@[P2, U, R](b: Rep[P2 @@ U])(implicit om: o#arg[Boolean, P2]#to[Boolean, R]): Rep[R] = em.||[P2, R](b.untagM)
}

implicit class TaggedBooleanAsBothOperands[P1, U](val c: Rep[P1 @@ U]) {
  private val em = new BooleanColumnExtensionMethods[P1](c.untagM)
  type o = OptionMapperDSL.arg[Boolean, P1]

  def @&&@[P2, V, R](b: Rep[P2 @@ V])(implicit om: o#arg[Boolean, P2]#to[Boolean, R]): Rep[R] = em.&&[P2, R](b.untagM)
  def @||@[P2, V, R](b: Rep[P2 @@ V])(implicit om: o#arg[Boolean, P2]#to[Boolean, R]): Rep[R] = em.||[P2, R](b.untagM)
}

implicit def taggedBooleanColumnCanBeQueryCondition[U]: CanBeQueryCondition[Rep[Boolean @@ U]] =
  new CanBeQueryCondition[Rep[Boolean @@ U]] {
    def apply(value: Rep[Boolean @@ U]) = value.untagM
  }
基本上,一旦一个带有标记值的列被用作布尔表达式,结果将已经被取消标记为Slick可以处理的内容。由于猜测冲突,我不能对所有布尔运算使用name&&和| |,所以我在边上添加了@,它仍然标记了列

例如,对于定义为以下内容的公司表:

val companyId = column[Long @@ CompanyId]("companyid", O.AutoInc, O.PrimaryKey)
val isDeleted = column[Boolean @@ CompanyDeleted]("deleted", O.Default(false.tag))
我可以:

val companyId = 1L.tag[CompanyId]
// fetch deleted companies
companies.filter(_.isDeleted).result
// fetch company by id if it is deleted
// c.isDeleted is tagged, so && it requires @ on right
companies.filter(c => c.companyId === companyId &&@ c.isDeleted).result.headOption
// fetch company by id if it is NOT deleted
// ! made c.isDeleted untagged so there is no need for additional @
companies.filter(c => c.companyId === companyId && !c.isDeleted).result.headOption
我希望不必添加@,但至少我可以在不到处放置c.columnName.untagM的情况下进行查询