2017-04-09 2 views
0

here으로 구현 된 태그 유형이 있습니다.태그 부울 유형의 Slick에서 부울 연산

나는 내 모델의 모든 속성에 다소 일반적인 (기본, String 등) 태그를 붙입니다. 나는 dabase에 매핑 모델 슬릭 사용할 때 나는 그들은 일반적으로 다음과 같이 정의되어 있습니다

val isDeleted = column[Boolean @@ CompanyDeleted]("deleted", O.Default(false.tag)) 

유형 매퍼 동안은 정의 : 그것은 나를 모델에 모든 CRUD 작업을 수행 할 수 있습니다

implicit def taggedBooleanColumnType[U]: BaseColumnType[Boolean @@ U] = 
    MappedColumnType.base[Boolean @@ U, Boolean](_.untag, _.tag[U]) 

. 그러나 나는 예컨대하려고 할 때 : Rep[Boolean @@ CompanyDeleted]이 nethier Rep[Boolean]Rep[Option[Boolean]] 같이

def fetchById(companyId: Long @@ CompanyId): SqlAction[Option[Company], NoStream, Read] = 
companies.filter(c => c.companyId === companyId && !c.isDeleted).result.headOption 

이 실패합니다. 내가 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를 제공하거나 수정할 수 있습니까? 특히 ||에 관심이 있으니 을 사용하여 &&을 사용할 수 있습니다.

답변

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 
    } 

, 한 번에 태그 값을 가진 열이 부울 표현으로 사용되며, 그 결과로 이미 태그가없는 것 슬릭이 작업 할 수있는 어떤 것. 모든 부울 연산에 대해 &&||이라는 이름을 사용할 수 없기 때문에 (여전히) 태그가 지정된 열이있는쪽에 @을 추가했습니다.

예. 회사 테이블에 대해 정의 된 : 내가 할 수있는

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을주지 않고 쿼리를 할 수 있습니다.