How to handle implicitly passed futures in play views - scala

In my particular case I have a menu that is rendered on all pages. The menu content is loaded from a database using slick and passed implicitly to the view. The whole thing looks like this:
Controller
class Application #Inject()(
implicit val menuContext: MenuContext
) extends Controller {
def index = Action.async {
val content: Future[Content] = getContent
content.map(c => Ok(views.html.index(c)))
}
}
MenuContext
class MenuContext {
val models: Future[List[SomeModel]] = getModelsFromDB
}
View
#(content: Content)(implicit menuContext: MenuContext)
...
#menuContext.models // how to access my actual model and not the Future?
...
How do I access List[SomeModel] in my view? Is there an Action.async equivalent in play for passing implicit parameters? Or is there maybe even a better solution for stuff that is required in (almost) all views?

Definitely not a good idea to make a template have to deal with a Future - so the question becomes the one in your comment - how to non-blockingly (?) get the content from your async content source, as well as your menu items from your other async content source?
A for-comprehension on the two Future instances does the trick:
def index = Action.async {
val fContent:Future[Content] = getContent
val fMenus:Future[List[SomeModel] = getModelsFromDB
for {
content <- fContent
menus <- fMenus
} yield(Ok(views.html.index(content)(menus))))
}
Note: You may be tempted to try and save a few lines and put the method calls (getContent, getModelsFromDB) straight into the for block.
Unfortunately, while it'll compile and work, the two tasks won't run in parallel, thereby making the exercise somewhat futile.

OK I'm adding another answer here, to specifically try to DRY up the injection of menus into your Actions.
The principal problem is that you need to inject the menus at just the right time, namely:
When you have the data ready (or at least a Future holding the data)
When you know which template is going to be rendered
When you know what status code you'll be returning
Because of these constraints, we can't use an ActionBuilder or ActionRefiner - they assume that your inner block of controller code will produce a finished Result.
So instead, we'll define a trait we can mix into our controllers:
trait MenuDecoration {
def withMenuSimple(body: Future[List[SomeModel] => Result]):Future[Result] = {
val fm = getModelsFromDB
val fb = body
for {
m <- fm
b <- fb
} yield(b(m))
}
}
This should look pretty familiar from my other answer, and it works the same way - it will start the execution of both async tasks, bringing them together once they are both done.
An Action that needs to decorate the template with a menu looks like this:
class BlahController extends Controller with MenuDecoration {
def index = Action.async {
withMenuSimple {
getContent.map { content => implicit menu =>
Ok(views.html.index(content))
}
}
}
}
Why withMenuSimple ? Because at some point you'll probably want to examine the Request - so we have this alternative:
trait MenuDecoration {
...
def withMenu(body: RequestHeader => Future[List[SomeModel] => Result])(implicit request:RequestHeader):Future[Result] = {
val fm = fMenus
val fb = body(request)
for {
m <- fm
b <- fb
} yield(b(m))
}
}
which you'd use like this:
def indexWithReq = Action.async { implicit request =>
withMenu { req =>
getContent.map { content => implicit menu =>
Ok(views.html.index(content))
}
}
}

Related

First click on button has an odd behaviour

I am working on a todo list app using
scalajs,
cats (free monads), and
scalajs-react
When I am using a simple model like the code below, everything works like expected.
class TodoModel() {
private object State {
var todos = Seq.empty[Todo]
def mod(f: Seq[Todo] => Seq[Todo]): Callback = {
val newTodos = f(todos)
Callback(todos = newTodos)
}
}
def add(t: Todo): Callback = State.mod(_ :+ t)
def todos: Seq[Todo] = State.todos
}
Once I use the free monads from cats, I have an odd behaviour. The first click always inserts two todo entries. Every click afterwards works like expected. See the pictures below.
What is wrong here?
import cats.free.Free
import cats.free.Free.liftF
import japgolly.scalajs.react._
import japgolly.scalajs.react.vdom.html_<^._
import org.scalajs.dom
case class Todo(text: String)
sealed trait TodoModelOp[A]
case class Add(todo: Todo) extends TodoModelOp[Unit]
case class Todos() extends TodoModelOp[Seq[Todo]]
object FreeTodoModelOps {
// type alias for lifted TodoModelOp
type TodoModelOpF[A] = Free[TodoModelOp, A]
def add(Todo: Todo): TodoModelOpF[Unit] = liftF[TodoModelOp, Unit](Add(Todo))
def todos: TodoModelOpF[Seq[Todo]] = liftF[TodoModelOp, Seq[Todo]](Todos())
}
object StateInterpreter {
import cats.arrow.FunctionK
import cats.{ Id, ~> }
val interpet: TodoModelOp ~> Id = new (TodoModelOp ~> Id) {
val todos = scala.collection.mutable.ArrayBuffer.empty[Todo]
def apply[A](fa: TodoModelOp[A]): Id[A] = fa match {
case Add(todo) => todos += todo; ()
case Todos() => todos.toSeq
}
}
}
class TodoModel() {
import cats.instances.list._
import cats.syntax.traverse._
import FreeTodoModelOps._
def add(t: Todo): Callback = {
def program: TodoModelOpF[Unit] = for {
_ <- FreeTodoModelOps.add(t)
} yield ()
Callback(program.foldMap(StateInterpreter.interpet))
}
def todos: Seq[Todo] = {
def program: TodoModelOpF[Seq[Todo]] = for {
n <- FreeTodoModelOps.todos
} yield n
program.foldMap(StateInterpreter.interpet)
}
}
object TodoPage {
case class Props(model: TodoModel)
case class State(todos: Seq[Todo])
class Backend($: BackendScope[Props, State]) {
val t = Todo("a new todo")
def onSubmit(e: ReactEventFromInput) =
e.preventDefaultCB >>
$.modState(s => State(s.todos :+ t)) >>
$.props.flatMap(P => P.model.add(t))
def render(S: State) =
<.div(
<.form(
^.onSubmit ==> onSubmit,
<.button("Add #", S.todos.length + 1)),
<.ul(S.todos.map(t => <.li(t.text)): _*))
}
val component = ScalaComponent.builder[Props]("Todo")
.initialStateFromProps(p => State(p.model.todos))
.renderBackend[Backend]
.build
def apply(model: TodoModel) = component(Props(model))
}
object Test {
val model = new TodoModel()
def main(args: Array[String]): Unit = {
TodoPage.apply(model).renderIntoDOM(dom.document.getElementById("mount-node"))
}
}
empty, no click on button
first click on button
second click on button
In your first snippet there's a bug:
Here you've got a variable todos (inpure) which you're accessing in a pure context:
def mod(f: Seq[Todo] => Seq[Todo]): Callback = {
val newTodos = f(todos)
Callback(todos = newTodos)
Impurity should be in Callback. Even reading a variable outside of a Callback is unsafe, so it should be:
def mod(f: Seq[Todo] => Seq[Todo]): Callback =
Callback(todos = f(todos))
(See scalajs-react's Ref.scala an example of safely working with a variable.)
Secondly, with regards to your larger snippet, scalajs-react is very FP friendly but that's very unconventional way of trying to use it, and has some significant problems:
StateInterpreter.interpet isn't referentially-transparent; there's shared global state underlying that. Fails the FP test. Stops being a lawful natural transformation.
You're tracking two sets of identical state separately: the component state and the state in TodoModel (impure, fails the FP test). Not only is this approach redundant and runs the risk of the two states getting out-of-sync, but it also makes the component less reusable; imagine you decided to draw it twice on the same screen for the same data - they're going to go out of sync. Best to keep the component stateless and pure.
If you're going to transform a free structure into a component effect, it's best to transform it into a state monad, see here for an example.
It's really, really awesome that you're learning about free monads and scalajs-react. FP will make your entire program really, really easy to reason about and prevent confusing surprises in behaviour, but you've got to not cut any corners and make sure that you keep all of your code pure. Any impurity will render the entire stack all the way up to the entrypoint impure and remove those nice dependable FP properties from those layers. I'd suggest making everything as pure as possible using the points above as starting points, and then I think you'll find that the bug just disappears, or at least is very easy to then detect. Cheers

slick returning a dictionaries object from database

I am trying to select from a few tables and put their results in an Object. I want to do this because those are dictionaries and I want all of them at startup.
This is what I have right now:
Controller:
def getDictionaries = Action.async { implicit request =>
Future.successful(Ok(Json.toJson(dictionaryService.getDictionaries)))
}
DictionaryService:
override def getDictionaries : Dictionaries = {
val currencies: Future[Seq[Currency]] = dictionaryDao.getCurrencies
val propertyTypes: Future[Seq[PropertyType]] = dictionaryDao.getPropertyTypes
Dictionaries(
currencies.result(Duration(10L, TimeUnit.SECONDS)),
propertyTypes.result(Duration(10L, TimeUnit.SECONDS))
)
}
DictionaryDAO:
override def getCurrencies: Future[Seq[Currency]] = {
db.run(slickCurrencies.result)
}
... getPropertyTypes ...
Dictionaries case class and companion object
case class Dictionaries (currencies: Seq[Currency], propertyTypes: Seq[PropertyType])
object Dictionaries {
implicit val jsonFormat = Json.format[Dictionaries]
}
I am not very proud of currencies.result(Duration(10L, TimeUnit.SECONDS)) but I am not sure what I should retrieve from this function so that I can easily transform it to JSON. Also this line of code is still not working because the compiler is telling me to use Await object instead.
Also for PropertyType I need to do the same thing as for currencies.
What is the best way to obtain the desired result?
I am in the learning phase so I don't get much of this.
LATER EDIT: the flow is: request -> getDictionaries -> dictionaryService.getDictionaries -> dictionaryDAO.getCurrencies&PropertyTypes
It seems to me that I need to get them in a synchronized way.
The purpose of this is to not create a request for each type of dictionary. If I have 10 dictionaries, I want to get all of them in one request.
Later EDIT 2
This is my working example which does not look very well:
Controller:
def getDictionaries = Action.async { implicit request =>
dictionaryService.getDictionaries.map {
dictionaries => Ok(Json.toJson(dictionaries))
}
}
DictionaryService:
override def getDictionaries : Future[Dictionaries] = {
dictionaryDao.getCurrencies.flatMap { currencies =>
dictionaryDao.getPropertyTypes.flatMap { propertyTypes =>
Future.successful(Dictionaries(
currencies,
propertyTypes
))
}
}
}
Your method getDictionaries should return Future[Dictionaries]:
override def getDictionaries : Future[Dictionaries] = {
val futureCurrencies = dictionaryDao.getCurrencies
futureCurrencies map { currencies => // currencies is here Seq[Currency]
Dictionaries(
currencies,
List(PropertyType(1, "x"))
)
}
And your controller method:
def getDictionaries = Action.async { implicit request =>
val futureDictionaries = dictionaryService.getDictionaries
futureDictionaries map { dictionaries =>
Ok(Json.toJson(dictionaries))
}
}
EXPLANATION: You have to use Futures all the way bottom up if you want your actions to be really asynchronous. You'll have to learn how to compose them with map, flatMap and for comprehensions. I didn't find any gentle and short introduction for that, you'll have to search it by yourself. Basically, when you map over Future, you are transforming it's(successful) result, and thus getting another Future. With flatMap you can have some ordering of futures, like: when f1 finishes, start f2 etc...

Slick - What if database does not contain result

I am trying to build a simple RESTful service that performs CRUD operations on a database and returns JSON. I have a service adhering to an API like this
GET mydomain.com/predictions/some%20string
I use a DAO which contains the following method that I have created to retrieve the associated prediction:
def getPrediction(rawText: String): Prediction = {
val predictionAction = predictions.filter{_.rawText === rawText}.result
val header = predictionAction.head
val f = db.run(header)
f.onComplete{case pred => pred}
throw new Exception("Oops")
}
However, this can't be right, so I started reading about Option. I changed my code accordingly:
def getPrediction(rawText: String): Option[Prediction] = {
val predictionAction = predictions.filter{_.rawText === rawText}.result
val header = predictionAction.headOption
val f = db.run(header)
f.onSuccess{case pred => pred}
None
}
This still doesn't feel quite right. What is the best way to invoke these filters, return the results, and handle any uncertainty?
I think the best way to rewrite your code is like this:
def getPrediction(rawText: String): Future[Option[Prediction]] = {
db.run(users.filter(_.rawText === rawText).result.headOption)
}
In other words, return a Future instead of the plain result. This way, the database actions will execute asynchronously, which is the preferred way for both Play and Akka.
The client code will then work with the Future. Per instance, a Play action would be like:
def prediction = Action.async {
predictionDao.getPrediction("some string").map { pred =>
Ok(views.html.predictions.show(pred))
}.recover {
case ex =>
logger.error(ex)
BadRequest()
}
}

Asynchronous wait for database-value in Playframework (2.4-M3) and Slick (3.0.0-RC3)

I'd like to keep my application as asynchronously as possible. Now I have this repository:
object LanguageRepository extends LanguageRepositoryTrait
{
private val languages = TableQuery[Languages]
private def db:Database = Database.forDataSource(DB.getDataSource())
private def filterQuery(id: Long): Query[Languages, Language, Seq] = languages.filter(_.id === id)
private def filterCode(code: String): Query[Languages, Language, Seq] = languages.filter(_.code === code)
private def all() : Query[Languages, Language, Seq] = languages
override def find(id: Long): Future[Language] =
{
try db.run(filterQuery(id).result.head)
finally db.close()
}
override def find(code: String): Future[Language] =
{
try db.run(filterCode(code).result.head)
finally db.close()
}
override def get(): Future[Seq[Language]] =
{
try db.run(all().result)
finally db.close()
}
}
When I call a url like "domain.tld/{language}" I want to check whether the given language(code) actually exists. Like, if the site isn't available in french (fr) I want to throw an exception or a 404.
Now, my problem is that this whole asynchronously thing is pretty cool and while I do think to understand the theory behind it, I'm rather baffled right now. I mean, I want this to be non-blocking (and asynchronously, which is the reason for me using Future and async ;))
In my controller I want to do something like:
def checkLanguage(language:String) = Action
{
val lang:Future[Language] = languageRepository.find(language)
lang.onComplete
{
case Success(s) = Ok("Yay")
case Failure(f) = 404("Oh no!")
}
}
Of course this can't work, but that's a schema of how I want to have things working. I want to wait or postpone the rendering of the site, until it's confirmed that the given language-code is valid or invalid.
I had a look at the Playframeworks async-documentation for 2.3.6 (https://www.playframework.com/documentation/2.3.6/ScalaAsync) but I couldn't really get this to work as intended.
Any input appreciated!
From your db query don't use .head instead use .headOption. that way ur return type will be a Future [Option [x]]
In ur controller u can do something like this
Lang.map { case Some (x) => Ok (x)
case None => 404 ( "not found ")
}
Try this,
Action.async {
val lang:Future[Option[Language]] = languageRepository.find(language)
lang.map {l => l.map{_ => Ok("Yay") }.getOrElse(NotFound("Oh no!"))
}
First of all, I am assuming that if there is a possibility that a language will not exist then languageRepository.find(language) should return an Option of Language. Change Future[Language] to Future[Result] and use Action.async instead of Action
Now for some explanation, Action takes a block whose result should be Result. However, what you get is Future[Option[Language]]. Play provides async method for Action which needs Future[Result] and it takes cares of completing the request.
So, you need to convert Future[Option[Language]] to Future[Result].
lang.map {l => l.map{_ => Ok("Yay") }.getOrElse(NotFound("Oh no!"))
We map over the lang, if the Option[Language] is not None then we convert it to Ok("yay") else we convert it to NotFound
Even, If you don't get Option[Language], the idea remains the same. Convert Future[Language] to Future[Result] and use Action.async instead of Action

Database transactions in Play framework scala applications (anorm)

I am developing an application using Play framework and scala. I am using anorm for data-access layer. And I've got a problem I could not solve.
Brief: I want to be able to have methods in data-access objects (dao) to work inside transactions as well as being called alone.
Details:
I have data-access layer consist of class with methods that only executes particular SQL over database. Traditionally they looks like:
def list() = DB.withConnection { implicit cn =>
...
}
Now I want to have some methods to be executed in a transaction scope. Like traditional select-update service methods but still be able to run them alone. So, what I have in my mind is like this:
class Service {
def fooTransacted() = {
inTransaction {
val old = dao.select(id = 2)
val newObj = old.copy(isActive = true)
dao.update(newObj)
}
}
def fooSinle() = {
dao.select(id = 2)
}
}
I tried around several ways, but could not come up with any solution.
What about
class Dao {
def foo(id: Long)(implicit connection: Connection) = {
SQL("select * from foo where id={id}").on('id->id).as(...)
}
}
class Service{
def withConnection = {
DB.withConnection {implicit connection =>
Dao.foo(1)
Dao.foo(2)
}
}
def withTransaction = {
DB.withTransaction {implicit connection =>
Dao.foo(1)
Dao.foo(2)
}
}
The solution I've seen used elsewhere (principally in Squeryl), is roughly the following:
import java.sql.Connection
object Helper {
private val conn: ThreadLocal[Connection] = new ThreadLocal
def inTransaction[X](f: Connection => X) = {
conn.get() match {
case null =>
DB.withConnection { newConn =>
conn.set(newConn)
try f(newConn)
finally conn.set(null)
}
case c => f(c)
}
}
}
This way, the inTransaction method is re-entrant, so there's no harm in calling it redundantly inside dao.select.
If you prefer, you can expose conn via a public method, and change the signature of f to => X - you lose some compile-time safety, but the API is a little cleaner.
One pitfall with this approach is that connections are tied to threads, which may cause problems if you're using futures or actors, and a process can resume on a different thread (this is a tricky area anyway, but one you should be aware of).
You might want to look into Squeryl too - it may already do what you need.