2017-04-09 86 views
0

我已经标记类型实现为here布尔运算在Slick on tagged布尔类型

与他们我标记所有我的模型的属性是或多或少通用(原语,String等)。当我用油滑的映射模型到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]]这会失败。当我创建implicits:

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) 
} 

我可以!_unary运营商,而不是&&也不||(作为类型的Rep■不要匹配)。

我的问题是:我可以提供/修改implicits以便能够对这些列执行布尔操作吗?我对||特别感兴趣,因为&&可以使用链接filter s完成。

回答

1

这不是美眉的解决方案,但它是我想出了最好的:

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可以使用的东西。由于(疯狂猜测)矛盾implicits我不能使用名称&&||所有布尔操作,所以我加了@侧,它仍然(仍然)标记列。

E.g.对于公司表定义为:

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无处不在。