Advertisement
Guest User

Untitled

a guest
Mar 26th, 2019
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.65 KB | None | 0 0
  1. import _root_.slick.ast.Ordering
  2. import _root_.slick.lifted.{BaseColumnExtensionMethods, ColumnOrdered, Query, Rep}
  3. import cats.data.NonEmptyList
  4. import cats.instances.option._
  5. import cats.syntax.apply._
  6. import cats.syntax.either._
  7.  
  8. object syntax {
  9.  
  10. implicit class QueryOps[E, U, C[_]](val query: Query[E, U, C]) extends AnyVal {
  11.  
  12. def applyPagination(paginationRequest: PaginationRequest)(sortingMapping: E => PartialFunction[String, Rep[_]])(
  13. filteringMapping: E => PartialFunction[Filtering.Filter, FilteringEquality])(
  14. defaultSortColumnMapping: E => Rep[_])(
  15. implicit ev: Option[Boolean] => Rep[Option[Boolean]]): Either[PaginationRequestErrorList, Query[E, U, C]] = {
  16.  
  17. val defaultSorting: Query[E, U, C] = {
  18. query.sortBy { q =>
  19. ColumnOrdered(
  20. defaultSortColumnMapping(q),
  21. Ordering().copy(direction = Ordering.Asc, nulls = Ordering.NullsFirst)
  22. )
  23. }
  24. }
  25.  
  26. def applySorting(query: Query[E, U, C])(
  27. sorting: Sorting): Either[NonEmptyList[PaginationRequestError], Query[E, U, C]] = {
  28. val (resQuery, sortingErrors) =
  29. sorting.fields.distinct.reverse.foldLeft((query, List.empty[PaginationRequestError])) {
  30. case ((q, errors), sf @ Sorting.Field(name, direction)) =>
  31. Either.catchNonFatal {
  32. q.sortBy { e =>
  33. ColumnOrdered(
  34. sortingMapping(e)(name),
  35. direction match {
  36. case Sorting.Direction.Asc =>
  37. Ordering().copy(direction = Ordering.Asc, nulls = Ordering.NullsFirst)
  38. case Sorting.Direction.Desc =>
  39. Ordering().copy(direction = Ordering.Desc, nulls = Ordering.NullsLast)
  40. }
  41. )
  42. }
  43. }.fold(_ => q -> (PaginationRequestError.SortingFieldError(sf) +: errors), res => res -> errors)
  44. }
  45.  
  46. sortingErrors match {
  47. case Nil => Right(resQuery)
  48. case h :: t => Left(NonEmptyList(h, t))
  49. }
  50. }
  51.  
  52. def applyFiltering(query: Query[E, U, C])(
  53. filtering: Filtering): Either[NonEmptyList[PaginationRequestError], Query[E, U, C]] = {
  54. val (resQuery, filteringErrors) =
  55. filtering.filters.distinct.foldLeft((query, List.empty[PaginationRequestError])) {
  56. case ((q, errors), filter) =>
  57. Either.catchNonFatal {
  58. q.filter { e =>
  59. filteringMapping(e)(filter) match {
  60. case FilteringEquality.BooleanEq(v) => ev(Some(v))
  61. case FilteringEquality.RepBooleanEq(v) => new BaseColumnExtensionMethods(v).?
  62. case FilteringEquality.RepOptionBooleanEq(v) => v
  63. }
  64. }
  65. }.fold(_ => q -> (PaginationRequestError.FilterError(filter) +: errors), res => res -> errors)
  66. }
  67.  
  68. filteringErrors match {
  69. case Nil => Right(resQuery)
  70. case h :: t => Left(NonEmptyList(h, t).reverse)
  71. }
  72. }
  73.  
  74. for {
  75. _ <- {
  76. val nelOpt1 = paginationRequest.sorting.map(applySorting(query)(_)).flatMap(_.left.toOption)
  77. val nelOpt2 = paginationRequest.filtering.map(applyFiltering(query)(_)).flatMap(_.left.toOption)
  78.  
  79. (nelOpt1, nelOpt2).mapN { case (nel1, nel2) => nel1 ::: nel2 } match {
  80. case None => Right(())
  81. case Some(x) => Left(PaginationRequestError.ErrorList(x))
  82. }
  83. }
  84. q1 <- paginationRequest.sorting
  85. .map(applySorting(query)(_).left.map(PaginationRequestError.ErrorList))
  86. .getOrElse(Right(defaultSorting))
  87. q2 <- paginationRequest.filtering
  88. .map(applyFiltering(q1)(_).left.map(PaginationRequestError.ErrorList))
  89. .getOrElse(Right(q1))
  90. } yield paginationRequest.pagination.map(p => q2.drop(p.offset).take(p.limit)).getOrElse(q2)
  91. }
  92. }
  93. }
  94.  
  95. sealed trait FilteringEquality extends Any
  96.  
  97. object FilteringEquality {
  98. final case class BooleanEq(value: Boolean) extends AnyVal with FilteringEquality
  99. object BooleanEq {
  100. implicit def deriveBooleanEq(value: Boolean): BooleanEq = new BooleanEq(value)
  101. }
  102.  
  103. final case class RepBooleanEq(value: Rep[Boolean]) extends AnyVal with FilteringEquality
  104. object RepBooleanEq {
  105. implicit def deriveRepBooleanEq(value: Rep[Boolean]): RepBooleanEq = new RepBooleanEq(value)
  106. }
  107.  
  108. final case class RepOptionBooleanEq(value: Rep[Option[Boolean]]) extends AnyVal with FilteringEquality
  109. object RepOptionBooleanEq {
  110. implicit def deriveRepOptionEq(value: Rep[Option[Boolean]]): RepOptionBooleanEq =
  111. new RepOptionBooleanEq(value)
  112. }
  113. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement