2017-04-09 9 views
0

hereとして実装されたタグ付き型があります。タグ付きブール型のSlickでのブール演算

私はすべてのモデルの属性に多かれ少なかれ一般的なもの(プリミティブ、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]]であるとして、これは失敗します。私は暗黙を作成する場合:

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 Sの型が一致しないとして)。

私の質問は:これらの列に対してブール演算を実行できるようにimplicitsを提供/変更できますか?私は特に||に興味があり、を使用して&&を行うことができます。

答えて

1

それはprettiesソリューションではありませんが、それは私が思いついた最善です:基本的に

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 
    } 

、一度タグ付けされた値を持つ列がブール式として使用され、結果はにすでにタグなしになりますスリックが作業できるもの。 (野生の推測の)矛盾した暗黙のため、すべてのブール演算には&&||という名前を使用できませんでしたので、(まだ)タグ付きの列を持つ側に@を追加しました。

など。企業テーブル用に定義されたように:私ができる

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を入れずにクエリを行うことができます。