Skip to content

Instantly share code, notes, and snippets.

Created July 2, 2012 07:03
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save nafg/3031581 to your computer and use it in GitHub Desktop.
Extensible data processors
Given some Q[A] (Q might be ScalaQuery's query, A might be the first column of the table),
there should be a function that can return an object that has a Q[B] (B might be the first two columns
of the table), and a way to go from a B to an A (e.g. from (Int, String) to Int). We need to have a
collection of such objects (not sure if List or HList).
The purpose is this:
Suppose for instance I want to develop a very pluggable issue tracker. Its core implementation might
only support a ticket id and a description. Other extensions might add support for various other fields,
yet those fields might exist in the database on the same table.
Even if not, the number of queries to the database should not need to increase along with the number of
extensions. They should be able to enhance the query.
These objects would also be able to render the data. So the second might know how to render a B, (or a
String), while the first might be able to render only an A (or Int).
That's why the types need to be able to go from Q[A] to Q[B] as well as from B to A.
So for building up the query you go down the list of extensions, adding more to the query, and for
rendering you go up the list: each extension renders its data and passes the remaining (earlier) part
of the data up the list.
case class Item[A, B](get: A => B)(val apply: B => String => String)
class DataExtending[A] {
def hlist =
Item((_: A) => 73)(x => _ + " " + x) ::
Item((_: A) => "hello")(x => _ + " " + x) ::
Item((_: A) => false)(x => _ + " " + x) ::
object combine extends Poly2 {
implicit def x[L <: HList, B] = at[A => L, Item[A, B]]((aggFunc: A => L, item: Item[A, B]) => { a: A => item.get(a) :: aggFunc(a) })
object apply extends Poly1 {
implicit def default[T] = at[(Item[A, T], T)]{ case (i, t) => i apply t }
object combine2 extends Poly2 {
implicit def x = at[String => String, String => String]{ _ andThen _ }
def run(a: A) = {
val items = hlist
type ItemA[B] = Item[A, B]
def m[L <: HList: *->*[ItemA]#λ](l: L) = null
val f1 = items.foldLeft((_: A) => HNil: HNil)(combine)
val res = f1(a)
val zipped = items zip res.reverse
val applied = zipped map apply
applied.foldLeft({ x: String => x })(combine2)
object Test extends App {
val de = new DataExtending[Double]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment