Skip to content

Instantly share code, notes, and snippets.

@kryptt
Last active August 29, 2015 14:17
Show Gist options
  • Save kryptt/b2f7ef6719a252dd316c to your computer and use it in GitHub Desktop.
Save kryptt/b2f7ef6719a252dd316c to your computer and use it in GitHub Desktop.
Playing with the QueryFragment Idea
package msw.util
import doobie.imports.{Composite, Query0}
import doobie.hi.connection.{ prepareStatement, prepareQueryAnalysis, prepareQueryAnalysis0, process => cprocess }
import doobie.hi.preparedstatement.{ set, executeQuery }
import doobie.hi.resultset.{ getUnique, getOption }
import scalaz.syntax.monad._
import shapeless._
import shapeless.ops.hlist.Prepend
trait QueryFragment { self =>
type L <: HList
def query: String
def params: L
def ++[POut <: HList](other: QueryFragment)(implicit P: Prepend.Aux[self.L, other.L, POut]): QueryFragment = append(other)
def append[POut <: HList](other: QueryFragment)(implicit P: Prepend.Aux[self.L, other.L, POut]): QueryFragment = new QueryFragment {
type L = POut
val query = self.query + other.query
val params = self.params ++ other.params
}
def toQuery0[B](stackTrace: Option[StackTraceElement])(implicit CL: Composite[L], CB: Composite[B]): Query0[B] = new Query0[B] {
val sql = query
val stackFrame = stackTrace
val analysis = prepareQueryAnalysis[L, B](sql)
val process = cprocess[B](sql, set(params))
def unique = prepareStatement(query)(set(params) >> executeQuery(getUnique[B]))
def option = prepareStatement(query)(set(params) >> executeQuery(getOption[B]))
}
}
object QueryFragment {
type Aux[Out <: HList] = QueryFragment { type L = Out }
def apply[P <: HList](q: String, p: P): Aux[P] = new QueryFragment {
type L = P
val query = q
val params = p
}
}
@kryptt
Copy link
Author

kryptt commented Mar 30, 2015

revision 3 brought back my initial problem:

  def listQuery(filter: Option[String], s: Option[SortInfo], p: PageInfo, withRoles: Option[Array[String]], withoutRoles: Option[Array[String]]): Query0[User.ListUserRoles] = {
    implicit def orComposite: Composite[Option[Role]] = implicitly[Composite[Option[Role]]]
    (QueryFragment("""SELECT u.id, u.email, u.firstName, u.lastName, u.verified, core.last_login(u.id), u.active,
                      r.id, r.code, COALESCE(ur.ig_id, r.ig_id) AS ig_id, ur.period_id
               FROM core.users u LEFT JOIN core.resource_roles(u.id) ur ON true
               LEFT JOIN core.roles r ON ur.role_id = r.id """, HNil) ++
   filter.fold(QueryFragment("", HNil))(f => QueryFragment("WHERE u.email ILIKE ? OR u.firstName ILIKE ? OR u.lastName ILIKE ? ", s"%$f%" :: s"%$f%" :: s"%$f%" :: HNil)) ++
    QueryFragment(s"ORDER BY u.${s.fold("id")(_.by)} ${s.fold("ASC")(_.order)} OFFSET ? LIMIT ?", p :: HNil))
    .toQuery0[User.ListUserRoles](stackFrame)
  }

fails to compile with:

[error] /home/rhansen/workspace/msw/app/src/main/scala/core/user-queries.scala:44: type mismatch;
[error]  found   : shapeless.::[String,shapeless.::[String,shapeless.::[String,shapeless.HNil]]]
[error]  required: shapeless.HNil.type
[error]    filter.fold(QueryFragment("", HNil))(f => QueryFragment("WHERE u.email ILIKE ? OR u.firstName ILIKE ? OR u.lastName ILIKE ? ", s"%$f%" :: s"%$f%" :: s"%$f%" :: HNil)) ++
[error]                                                                                                                                           ^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment