Scala - how to get data from IO[HttpResponse] in Hammock? - scala

I have a simple methods:
def retrieveRepositories(url: String, params: String): IO[HttpResponse] = Hammock.getWithOpts(uri"$url", createOpts).exec[IO]
Which is a http client. and json decoder:
implicit def decodeResponseEntity(response: HttpResponse): Either[CodecException, List[GitRepository]] = Decoder[List[GitRepository]].decode(response.entity)
Now I want to call this client like this:
def getRepos(organization: String, params: String): F[Either[CodecException, List[GitRepository]]] = for {
res <- retrieveRepositories(organization, params)
result <- Sync[F].delay(decodeResponseEntity(res))
} yield result
But, there is a problem with result <- Sync[F].delay(decodeResponseEntity(res)) line, because I got an error: Type mismatch. Reguired: IO[B_] but found F[Either[CodecException, List[GitRepository]]]. When I add unsafeRunSync() method to retrieveRepositories(organization, params) then it works ok, but I should call this method in the end and not here. How should I fix it?

If you can, you may want to change the definition of retrieveRepositories and parameterize on the effect type (F) instead of using the concrete IO type.
If you can't change retrieveRepositories, add a implicit LiftIO constraint in getRepos. You will be able to use liftIO method to lift concrete IO values into F. An alternative would be use the Async typeclass, which inherits from both Sync and LiftIO.
See documentation for liftIO: https://typelevel.org/cats-effect/typeclasses/liftio.html

Related

Scala: Calling function dynamically

I am very new to scala.
I am using rscala to integrate with R functions.
For example, I am using the following method to call an R function and retreive a String value.
Method Signature:
def invokeS0(function: Reference, args: Any*): String
Method Implementation
val v= rc.invokeS0("doPred","lemmas"->"Communicate,Design,Java,","frequency"->"3,3,1")
My Problem
However, rc.invokeS0 can call ANY function and thus have ANY number of arguments.
I'm thinking of building a wrapper method that takes the function name as a String and arguments as a Map. Perhaps something like this:
private def invokeRStringFunction(functionName: String = "testFunction", args: Map[String,String]): Unit =
{
/**Iterate through map to generate following code*/
val v= rc.invokeS0(functionName,mapKey1->mapValue1,mapKey2->mapValue2 etc etc)
}
But I am not sure how to write the code given that the number of arguments is dynamic. Frankly, I am not sure if it is possible, but thought I would check, just in case.
Any hints would be greatly appreciated.
Convert the Map[String, String] into a Seq[(String, String)] with args.toSeq, and then use the _* ascription to pass it as a sequence of arguments instead of just one.
def invokeRStringFunction(functionName: String, args: Map[String, String]): Unit
= rc.invokeS0(functionName, args.toSeq: _*)

Building a generic DAO for slick

I was tired of always doing something like the following in order to do database access using slick for each of my domain entities.
database withSession {
implicit session =>
val entities = TableQuery[EntityTable]
val id = //Some ID
val q = for {
e <- entities if e.id === id
} yield (e)
val entity = q.first
}
(Note: EntityTable was defined like described here)
So I decided that I want a generic database access object that handles this for me. The usage should look something like
[...]
val entityDAO = new GenericDAO[Entity, EntityTable, String]()
[...]
database withSession { implicit session =>
val id = // Some ID
val entity = entityDAO.get(id)
}
My try of the implementation of the GenericDAO looks like this
class GenericDAO[T, TB, PK](implicit session: Session) {
val entities = TableQuery[TB] // Line 1
def get(id: PK): T = {
val q = for {
e <- entities
} yield (e)
val res: T = q.first
res
}
}
But line 1 leaves me with a compiler error stating that something is wrong with the TB argument.
Multiple markers at this line
- type arguments [TB] conform to the bounds of none of the overloaded alternatives of value apply: [E <:
scala.slick.lifted.AbstractTable[]]=>
scala.slick.lifted.TableQuery[E,E#TableElementType] [E <:
scala.slick.lifted.AbstractTable[]](cons: scala.slick.lifted.Tag =>
E)scala.slick.lifted.TableQuery[E,E#TableElementType]
- wrong number of type parameters for overloaded method value apply with alternatives: [E <: scala.slick.lifted.AbstractTable[]]=>
scala.slick.lifted.TableQuery[E,E#TableElementType] [E <:
scala.slick.lifted.AbstractTable[]](cons: scala.slick.lifted.Tag =>
E)scala.slick.lifted.TableQuery[E,E#TableElementType]
Any suggesions on this issue? Or maybe I am wrong and it is supposed to be implemented in another way. I am open for any solution. Thanks!
First of all, you could write
val entities = TableQuery[EntityTable] // put in a central place for re-use
and then
database.withSession(
(for {
e <- entities if e.id === /*Some ID*/
} yield e).first()(_)
)
or this
database.withSession(entities.filter(_.id === /*Some ID*/).first()(_))
or this
val get = entities.findBy(_.id) // <- reuse this
database.withSession(get(/*Some ID*/).first()(_))
for brevity. This probably makes your whole DAO unnecessary (which is great :)!).
Regarding the error message you got. TableQuery[TB]is a macro, which is a short-hand for TableQuery(tag => new TB(tag)), TB must be a Table and support object creation. You cannot just use the TableQuery macro on an unconstrained type parameter your got from a DAO wrapper. You could constraint TB <: Table[_] but it still wouldn't support object creation, which you cannot constraint in Scala. You could only provide a factory to your DAO (a common pattern is to fetch one as an implicit argument), but that all does not make sense, when you can just write your TableQuery once and store it in a globally accessible place.
Update:
The shortcut works for all of these methods the same way. It's plain Scala. You just turn the method into a function and pass it to the higher-order function withSession, which requires a function from session to anything. Just be aware, that some Slick methods have an empty argument list, which requires ()(_) to turn them into a function and some only have the implicit argument list, which requires only (_). E.g. database.withSession(entities.filter(_.id === /*Some ID*/).delete(_)).
If you wonder about the _. Scala distinguishes methods from functions. def foo(a: A, b: B, ...): R is a method but can be turned into a function of type (A,B,C) => R using foo _. This conversion is called eta expansion and googling for it will turn up more info. Sometimes when a function expected, but you provide a method, the Scala compiler infers the _ and you don't have to write it explicitly. You can also provide some parameters and use _ in place of the parameters you don't want to apply yet. In that case you partially apply the method and get a function back. This is what we do here. We use _ in the place where the methods usually expect a session and get a function back that takes a session. When exactly you have to use _ or (_) or ()(_) has to do with the method signatures and the details interplay between implicit argument lists, nullary methods, methods with empty argument lists, which is general Scala knowledge worth researching at some point.
This was a huge help to me. A complete working generic dao https://gist.github.com/lshoo/9785645

Scala Type Error with Traits and Generics

I've recently returned to scala after a long hiatus in python and trying to wrap my mind around the type system again. I'm trying to make a very simple web URL dispatcher to get familiar with the language again. So far I have:
trait Executable {
def execute(request: HttpRequest, response: HttpResponse): Future[HttpResponse]
}
class HelloWorldHandler extends Executable {
override def execute(request: HttpRequest, response: HttpResponse) = {
Future.value(response)
}
}
What I think I have here is the scala equivalent of an interface Executable and a class that implements that interface. Now I'd like to create a mapping of URLs to handlers like so:
val mapping: Map[String, _ <: Executable] = {
"/hello" -> new HelloWorldHandler()
}
When I compile this, I get the following error:
type mismatch;
found : (java.lang.String, pollcaster.handlers.HelloWorldHandler)
required: Map[String,pollcaster.Executable]
"/" -> new HelloWorldHandler()
^
I'm not sure where I went wrong in my understanding here but would appreciate any help in understanding how can I put a bunch of different classes that have the trait of Executable into a map object?
TIA
Scala doesn't have a map literal like that. The following should work, though:
val mapping: Map[String, _ <: Executable] = Map(
"/hello" -> new HelloWorldHandler(),
"/something" -> new SomeOtherHandler()
)
This is just using the Map object's apply method to create a new map.
You can create a Map from a generic Seq of Tuples2 but there is no automatic conversion from Tuple2 to Map. That makes perfectly sense: why would you create a map with a single key and a single value?

Why do I need a curried function to be able to pass function literals with short placeholder syntax?

Given this definition:
class Foo(var x: String) {}
object Helper {
def model[T](get: ⇒ T, set: T ⇒ Unit) : Model[T] = new Model[T] {
override def getObject(): T = get
override def setObject(obj: T) { set(obj) }
}
}
I try to call model like this:
val f = new Foo("initial")
val stringModel = model(f.x, f.x = _)
But that doesn't work, the compiler gives me this, complaining about the underscore:
missing parameter type for expanded function ((x$1) => f.x = x$1)
If I change the definition of model to use two parameter lists like this:
def model[T](get: ⇒ T)(set: T ⇒ Unit) // rest is unchanged
Then I can call it like this:
model(f.x)(f.x = _)
Which I find nice and concise. I don't really mind doing it like this, though it makes method overloading harder. I would like to understand, however, why the second variant works and the first one doesn't?
The second variant works because Scala refines its types parameter-block by parameter-block. If you don't specify the type of your input parameter for the function, it's possible that it would change the type T that it has inferred based on the first parameter. If you push it to a separate parameter block, Scala's already decided what T must be by the time it hits that block, so it fills in the only possible value for the function argument type.

How can I combine fluent interfaces with a functional style in Scala?

I've been reading about the OO 'fluent interface' approach in Java, JavaScript and Scala and I like the look of it, but have been struggling to see how to reconcile it with a more type-based/functional approach in Scala.
To give a very specific example of what I mean: I've written an API client which can be invoked like this:
val response = MyTargetApi.get("orders", 24)
The return value from get() is a Tuple3 type called RestfulResponse, as defined in my package object:
// 1. Return code
// 2. Response headers
// 2. Response body (Option)
type RestfulResponse = (Int, List[String], Option[String])
This works fine - and I don't really want to sacrifice the functional simplicity of a tuple return value - but I would like to extend the library with various 'fluent' method calls, perhaps something like this:
val response = MyTargetApi.get("customers", 55).throwIfError()
// Or perhaps:
MyTargetApi.get("orders", 24).debugPrint(verbose=true)
How can I combine the functional simplicity of get() returning a typed tuple (or similar) with the ability to add more 'fluent' capabilities to my API?
It seems you are dealing with a client side API of a rest style communication. Your get method seems to be what triggers the actual request/response cycle. It looks like you'd have to deal with this:
properties of the transport (like credentials, debug level, error handling)
providing data for the input (your id and type of record (order or customer)
doing something with the results
I think for the properties of the transport, you can put some of it into the constructor of the MyTargetApi object, but you can also create a query object that will store those for a single query and can be set in a fluent way using a query() method:
MyTargetApi.query().debugPrint(verbose=true).throwIfError()
This would return some stateful Query object that stores the value for log level, error handling. For providing the data for the input, you can also use the query object to set those values but instead of returning your response return a QueryResult:
class Query {
def debugPrint(verbose: Boolean): this.type = { _verbose = verbose; this }
def throwIfError(): this.type = { ... }
def get(tpe: String, id: Int): QueryResult[RestfulResponse] =
new QueryResult[RestfulResponse] {
def run(): RestfulResponse = // code to make rest call goes here
}
}
trait QueryResult[A] { self =>
def map[B](f: (A) => B): QueryResult[B] = new QueryResult[B] {
def run(): B = f(self.run())
}
def flatMap[B](f: (A) => QueryResult[B]) = new QueryResult[B] {
def run(): B = f(self.run()).run()
}
def run(): A
}
Then to eventually get the results you call run. So at the end of the day you can call it like this:
MyTargetApi.query()
.debugPrint(verbose=true)
.throwIfError()
.get("customers", 22)
.map(resp => resp._3.map(_.length)) // body
.run()
Which should be a verbose request that will error out on issue, retrieve the customers with id 22, keep the body and get its length as an Option[Int].
The idea is that you can use map to define computations on a result you do not yet have. If we add flatMap to it, then you could also combine two computations from two different queries.
To be honest, I think it sounds like you need to feel your way around a little more because the example is not obviously functional, nor particularly fluent. It seems you might be mixing up fluency with not-idempotent in the sense that your debugPrint method is presumably performing I/O and the throwIfError is throwing exceptions. Is that what you mean?
If you are referring to whether a stateful builder is functional, the answer is "not in the purest sense". However, note that a builder does not have to be stateful.
case class Person(name: String, age: Int)
Firstly; this can be created using named parameters:
Person(name="Oxbow", age=36)
Or, a stateless builder:
object Person {
def withName(name: String)
= new { def andAge(age: Int) = new Person(name, age) }
}
Hey presto:
scala> Person withName "Oxbow" andAge 36
As to your use of untyped strings to define the query you are making; this is poor form in a statically-typed language. What is more, there is no need:
sealed trait Query
case object orders extends Query
def get(query: Query): Result
Hey presto:
api get orders
Although, I think this is a bad idea - you shouldn't have a single method which can give you back notionally completely different types of results
To conclude: I personally think there is no reason whatsoever that fluency and functional cannot mix, since functional just indicates the lack of mutable state and the strong preference for idempotent functions to perform your logic in.
Here's one for you:
args.map(_.toInt)
args map toInt
I would argue that the second is more fluent. It's possible if you define:
val toInt = (_ : String).toInt
That is; if you define a function. I find functions and fluency mix very well in Scala.
You could try having get() return a wrapper object that might look something like this
type RestfulResponse = (Int, List[String], Option[String])
class ResponseWrapper(private rr: RestfulResponse /* and maybe some flags as additional arguments, or something? */) {
def get : RestfulResponse = rr
def throwIfError : RestfulResponse = {
// Throw your exception if you detect an error
rr // And return the response if you didn't detect an error
}
def debugPrint(verbose: Boolean, /* whatever other parameters you had in mind */) {
// All of your debugging printing logic
}
// Any and all other methods that you want this API response to be able to execute
}
Basically, this allows you to put your response into a contain that has all of these nice methods that you want, and, if you simply want to get the wrapped response, you can just call the wrapper's get() method.
Of course, the downside of this is that you will need to change your API a bit, if that's worrisome to you at all. Well... you could probably avoid needing to change your API, actually, if you, instead, created an implicit conversion from RestfulResponse to ResponseWrapper and vice versa. That's something worth considering.