Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import _root_.slick.ast.Ordering
- import _root_.slick.lifted.{BaseColumnExtensionMethods, ColumnOrdered, Query, Rep}
- import cats.data.NonEmptyList
- import cats.instances.option._
- import cats.syntax.apply._
- import cats.syntax.either._
- object syntax {
- implicit class QueryOps[E, U, C[_]](val query: Query[E, U, C]) extends AnyVal {
- def applyPagination(paginationRequest: PaginationRequest)(sortingMapping: E => PartialFunction[String, Rep[_]])(
- filteringMapping: E => PartialFunction[Filtering.Filter, FilteringEquality])(
- defaultSortColumnMapping: E => Rep[_])(
- implicit ev: Option[Boolean] => Rep[Option[Boolean]]): Either[PaginationRequestErrorList, Query[E, U, C]] = {
- val defaultSorting: Query[E, U, C] = {
- query.sortBy { q =>
- ColumnOrdered(
- defaultSortColumnMapping(q),
- Ordering().copy(direction = Ordering.Asc, nulls = Ordering.NullsFirst)
- )
- }
- }
- def applySorting(query: Query[E, U, C])(
- sorting: Sorting): Either[NonEmptyList[PaginationRequestError], Query[E, U, C]] = {
- val (resQuery, sortingErrors) =
- sorting.fields.distinct.reverse.foldLeft((query, List.empty[PaginationRequestError])) {
- case ((q, errors), sf @ Sorting.Field(name, direction)) =>
- Either.catchNonFatal {
- q.sortBy { e =>
- ColumnOrdered(
- sortingMapping(e)(name),
- direction match {
- case Sorting.Direction.Asc =>
- Ordering().copy(direction = Ordering.Asc, nulls = Ordering.NullsFirst)
- case Sorting.Direction.Desc =>
- Ordering().copy(direction = Ordering.Desc, nulls = Ordering.NullsLast)
- }
- )
- }
- }.fold(_ => q -> (PaginationRequestError.SortingFieldError(sf) +: errors), res => res -> errors)
- }
- sortingErrors match {
- case Nil => Right(resQuery)
- case h :: t => Left(NonEmptyList(h, t))
- }
- }
- def applyFiltering(query: Query[E, U, C])(
- filtering: Filtering): Either[NonEmptyList[PaginationRequestError], Query[E, U, C]] = {
- val (resQuery, filteringErrors) =
- filtering.filters.distinct.foldLeft((query, List.empty[PaginationRequestError])) {
- case ((q, errors), filter) =>
- Either.catchNonFatal {
- q.filter { e =>
- filteringMapping(e)(filter) match {
- case FilteringEquality.BooleanEq(v) => ev(Some(v))
- case FilteringEquality.RepBooleanEq(v) => new BaseColumnExtensionMethods(v).?
- case FilteringEquality.RepOptionBooleanEq(v) => v
- }
- }
- }.fold(_ => q -> (PaginationRequestError.FilterError(filter) +: errors), res => res -> errors)
- }
- filteringErrors match {
- case Nil => Right(resQuery)
- case h :: t => Left(NonEmptyList(h, t).reverse)
- }
- }
- for {
- _ <- {
- val nelOpt1 = paginationRequest.sorting.map(applySorting(query)(_)).flatMap(_.left.toOption)
- val nelOpt2 = paginationRequest.filtering.map(applyFiltering(query)(_)).flatMap(_.left.toOption)
- (nelOpt1, nelOpt2).mapN { case (nel1, nel2) => nel1 ::: nel2 } match {
- case None => Right(())
- case Some(x) => Left(PaginationRequestError.ErrorList(x))
- }
- }
- q1 <- paginationRequest.sorting
- .map(applySorting(query)(_).left.map(PaginationRequestError.ErrorList))
- .getOrElse(Right(defaultSorting))
- q2 <- paginationRequest.filtering
- .map(applyFiltering(q1)(_).left.map(PaginationRequestError.ErrorList))
- .getOrElse(Right(q1))
- } yield paginationRequest.pagination.map(p => q2.drop(p.offset).take(p.limit)).getOrElse(q2)
- }
- }
- }
- sealed trait FilteringEquality extends Any
- object FilteringEquality {
- final case class BooleanEq(value: Boolean) extends AnyVal with FilteringEquality
- object BooleanEq {
- implicit def deriveBooleanEq(value: Boolean): BooleanEq = new BooleanEq(value)
- }
- final case class RepBooleanEq(value: Rep[Boolean]) extends AnyVal with FilteringEquality
- object RepBooleanEq {
- implicit def deriveRepBooleanEq(value: Rep[Boolean]): RepBooleanEq = new RepBooleanEq(value)
- }
- final case class RepOptionBooleanEq(value: Rep[Option[Boolean]]) extends AnyVal with FilteringEquality
- object RepOptionBooleanEq {
- implicit def deriveRepOptionEq(value: Rep[Option[Boolean]]): RepOptionBooleanEq =
- new RepOptionBooleanEq(value)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement