Chaining QueryMs

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Chaining QueryMs

thatismatt
Is it possible to chain QueryMs? What I mean is that I'd like to do the following:

case class Thing(a: String, b: String)

def extractThing = (for {
    a <- lookup("a") is required("a missing")
    b <- lookup("b") is required("b missing")
} yield {
    Thing(a.get, b.get)
})

def save(t: Thing): () = println("saved")

// ...

case Params(params, _) =>
    (for {
        t <- extractThing
    } yield {
        save(t)
        Redirect("/saved")
    })(params) orFail {
        fails => BadRequest ~> Html(failurePage(fails))
    }

But on the line "t <- extractThing" t is of type QueryResult[java.lang.String,Thing] not Thing as I'd expect.

What am I doing wrong here? Is this even possible?

I'm assuming that this relates to this comment: https://github.com/n8han/Unfiltered/blob/master/library/src/main/scala/request/params.scala#L89
So is this a design decision that means that I'm doing things the wrong way?

Hope this makes some sense. Thanks,
Matt
Reply | Threaded
Open this post in threaded view
|

Re: Chaining QueryMs

n8han
Administrator
On 12/17/2010 07:09 AM, thatismatt [via Databinder] wrote:
> Is it possible to chain QueryMs? What I mean is that I'd like to do
> the following:

That would be good, but it doesn't work that way currently.

You could do this though:

def extractThing[T](block: Thing => T) = (for {
     a <- lookup("a") is required("a missing")
     b <- lookup("b") is required("b missing")
} yield {
     block(Thing(a.get, b.get) )
})

case Params(params, _) =>
     extractThing { t =>
         save(t)
         Redirect("/saved")
     }(params) orFail {
         fails => BadRequest ~> Html(failurePage(fails))
     }

Nathan
Reply | Threaded
Open this post in threaded view
|

Re: Chaining QueryMs

thatismatt
Thanks Nathan.

The only thing I don't like about the use of CPS here is that it feels like the responsibility has moved to the wrong place, and the API is less explicit.

In the end I didn't change extractThing, instead I changed the calling code:

case Params(params, _) =>
    extractThing(params) match {
        case Right(t) =>
            save(t)
            Redirect("/saved")
        case Left(fails) =>
            BadRequest ~> Html(failurePage(fails))
    }

Obviously this could be packaged in to a nice extension of QueryResult, just as orFail is currently (in QueryResultX) something like:

case class QueryResultX2[E,A](r: QueryResult[E,A]) {
  def mapOrFail[B](successHandler: A => B, failureHandler: Log[E] => B) = {
    // ...
  }
}
Reply | Threaded
Open this post in threaded view
|

Re: Chaining QueryMs

n8han
Administrator
On 12/21/2010 11:21 AM, thatismatt [via Databinder] wrote:
> Obviously this could be packaged in to a nice extension of
> QueryResult, just as orFail is currently (in QueryResultX) something
> like:

Well, I would really rather get it working with plain map, the way you
originally expected it to work. I don't want to expand the QueryM
vocabulary any more than necessary.

Speaking of vocabulary, there is a new QueryM word that we can't decide
on a name for:
https://github.com/n8han/Unfiltered/commit/afd9cf849b061188624bc3b4c231e654b80c5a06

It's not generally applicable to this problem but I think it will handle
some scenarios where you might want to map. And ultimately, we'll get
map working if at all possible; I just can't get into that code right
now. Feel free to take a crack at it yourself! :)

Nathan