How to scale the repository pattern in Scala? - scala

We're using the repository pattern for our data access in Scala and so far we have something like this in our Repository[A] trait:
trait Repository[A] {
/**
* Create a new record in the database.
*
* #param model
* #param connection
* #return
*/
def create(model: A)(implicit connection: Connection): A
/**
* Retrieve a record from the database with the corresponding id.
*
* #param id
* #param connection
* #return
*/
def getById(id: UUID)(implicit connection: Connection): Option[A]
/**
* Update the corresponding record in the database.
*
* #param model
* #param connection
* #return The updated model, or None if it was not found
*/
def update(model: A)(implicit connection: Connection): Option[A]
/**
* Delete a record from the database with the corresponding id.
*
* #param id
* #param connection
* #return The deleted model, or None if it was not found
*/
def deleteById(id: UUID)(implicit connection: Connection): Option[A]
}
And that's fine. This issue is with the "query" methods. For example, imagine I have a method for getting all blog posts where:
the user id is X, or
the user is a guest
I also want to include the blog object. Under our current system, we would have a method like this:
def getWithBlogByUserIdOrUserGuest(userId: UUID, guest: Boolean): List[Post]
This is pretty ugly, and if you want to return a bunch of relations with an entity (that have long names) it can get out of hand quickly. It's also hard to use an trait to add some sort of consistency.
Some examples I've seen only are to use a query object:
def query(criteria: Criteria): List[A]
However, this requires coming up with some sort of DSL for defining criteria, and it also requires writing code that converts the criteria to SQL which is error prone and a lot of work, and will probably suck.
So, my question is, how do most people deal with having some sort of generalized way to write query methods in repositories?

As you've already figured it out you can implement the "Query Object".
As to not "writing code that converts the criteria to SQL which is error prone and a lot of work" you can use a framework like Slick, which will do all the SQL generation for you and allows you to treat tables as collections and do things like:
posts.filter(post => post.userId == "USER-ID-1" || post.guest)
Slick's abstract class Query has a HOF called filter, so you can pass in your custom function to it to determine whether a record should be filtered out or not.

Related

Cats Effect: Avoid calling unsafeRun on external listener of T => Unit

I am using external API which offers:
def listen(listener: ResponseType => Unit): Handle
My listener returns:
IO[Unit]
Is there a way to inject my listener without a need to call unsafeRun?
listen(msg => myListener(msg).unsafeRunSync())
IO is not only container of your listener. From cats-effect documentation:
A pure abstraction representing the intention to perform a side effect,
where the result of that side effect may be obtained synchronously (via return)
or asynchronously (via callback)
it means IO contains not the some value but intention to perform some side-effect.
Here the most usual ways to work with IO:
Add some effect to the containing of IO using flatMap (this way named composition):
val ioA: IO[A] = ??? // you have some side effect returning A
// here you can have some different side effect returning B: work with DB, read some resource or so on
def aToIOB(a: A): IO[B] = ???
val ioB: IO[B] = ioA.flatMap(aToIOB)
Launching the whole chain of your combinations side effects from 1. using unsafeRunSync or similar functions which run IO. It should be called once in your application and as a rule in the end of the universe (at the end of your program).
// this line launches execution of ioA and aToIOB and will return value of B with side-effects
val b: B = ioB.unsafeRunSync()
So when you see IO[A] you should remember that it is not the similar thing as Option[A] or List[A] and you can just execute IO to get A. You should use combination of IO while your application is not on the end of execution. If so you can run it using unsafeRunSync.
I mean you should build your application without using unsafeRunSync more than one time, and I guess, your signature
def listen(listener: ResponseType => Unit): Handle
should not use IO API, but very similar to Async[F[_]] API, take a look at function async:
/**
* Creates a simple, non-cancelable `F[A]` instance that
* executes an asynchronous process on evaluation.
*
* The given function is being injected with a side-effectful
* callback for signaling the final result of an asynchronous
* process.
*
* This operation could be derived from [[asyncF]], because:
*
* {{{
* F.async(k) <-> F.asyncF(cb => F.delay(k(cb)))
* }}}
*
* As an example of wrapping an impure async API, here's the
* implementation of [[Async.shift]]:
*
* {{{
* def shift[F[_]](ec: ExecutionContext)(implicit F: Async[F]): F[Unit] =
* F.async { cb =>
* // Scheduling an async boundary (logical thread fork)
* ec.execute(new Runnable {
* def run(): Unit = {
* // Signaling successful completion
* cb(Right(()))
* }
* })
* }
* }}}
*
* #see [[asyncF]] for the variant that can suspend side effects
* in the provided registration function.
*
* #param k is a function that should be called with a
* callback for signaling the result once it is ready
*/
def async[A](k: (Either[Throwable, A] => Unit) => Unit): F[A]
Try to concentrate that listen should do in your application and choose correct signature.
Usefull links:
cats-effect IO monad
cats-effect Async typeclass

Documenting parameters of Scala functions defined via val

When documenting parameters of methods with Scaladoc, we can write:
/** Is number even
* #param i number
* #return true if i is even, false otherwise
*/
def isEvenDef(i: Int) = i % 2 == 0
Which after generating the docs (e.g. via doc from sbt) yields nice documentation of the parameters (pointless in this example, but useful in general):
However, writing an analogous function via val and using the same documentation:
/** Is number even
* #param i number
* #return true if i is even, false otherwise
*/
val isEvenVal = (i: Int) => i % 2 == 0
The param does not seem to show in the generated documentation:
Is there a way do document the parameters for functions defined via val such that they show similarly to the parameters of methods defined via def?

Scala: Compilation error: Cannot resolve overloaded method

I have imported to Intellij a Play/Scala project with the following method that gets a compilation error for a reason which I do not understand. Any ideas what is wrong here?
I am using Java 8 and Scala 2.11.6.
def fetchUser(id: Long): Option[UserRecord] =
Cache.getAs[UserRecord](id.toString).map { user =>
Some(user)
} getOrElse {
DB.withConnection { connection =>
val sql = DSL.using(connection, SQLDialect.POSTGRES_9_4)
val user = Option(sql.selectFrom[UserRecord](USER).where(USER.ID.equal(id)).fetchOne())
user.foreach { u =>
Cache.set(u.getId.toString, u)
}
user
}
}
The compilation error is on the call to the withConnection method. The error is: Cannot resolve overloaded method 'withConnection'.
When I try to jump to the implementation of the withConnection method, the compiler suggests two possible methods in the play.api.db.DB (2.4.3) class:
/**
* Execute a block of code, providing a JDBC connection. The connection is
* automatically released.
*
* #param name The datasource name.
* #param autocommit when `true`, sets this connection to auto-commit
* #param block Code block to execute.
*/
def withConnection[A](name: String = "default", autocommit: Boolean = true)(block: Connection => A)(implicit app: Application): A =
db.database(name).withConnection(autocommit)(block)
/**
* Execute a block of code, providing a JDBC connection. The connection and all created statements are
* automatically released.
*
* #param block Code block to execute.
*/
def withConnection[A](block: Connection => A)(implicit app: Application): A =
db.database("default").withConnection(block)
The compiler should find
def withConnection[A](block: Connection => A)(implicit app: Application): A =
db.database("default").withConnection(block)
because that matches the call
DB.withConnection { ... }
which is the same as
DB.withConnection( block = { ... })
as long as it can find the implicit Application. I don't know where this implicit Application exists but since this is from a sample project to a book I assume it exists somewhere and has worked in the past.
You've posted three questions pertaining to build errors about this project. Please don't post a new question every time you run into a build error for this project. That's not the point of SO. These questions are best aimed at the maintainer of the project itself, ie. the author on the issues page of the GitHub repo.
Now it doesn't look like this project is maintained. It's an old project. You're very likely to run into issues where things are broken because of outdated versions. Consider asking ONE question about building an old play project instead.

execute function only once and cache value in scala

I have a function like so
def runOnce(request: Request): Future[Result] = {
}
When I call this runOnce function, if it has not been run, I want it to run some method and return that result. If it has been run, I just want it to return the original result (the request coming in will be the same).
I can do it if I have no param like so
lazy val hydratedModel = hydrateImpl(request)
future for efficient filtering
def fetchHydratedModel(): Future[HydratedModelRequest] = {
hydratedModel
}
How to do in first case?
There's a general solution to this problem, which is function memoization; for a pure function (one that has no side-effects - it will not work for non-pure functions), the result of a function call should always be the same for the same set of argument values. Therefore, an optimization is to cache the value on the first call and to return it for subsequent calls.
You can achieve this with something like the following (a memoization class for pure functions with a single argument, updated—see comment below—to make it thread-safe):
/** Memoize a pure function `f(A): R`
*
* #constructor Create a new memoized function.
* #tparam A Type of argument passed to function.
* #tparam R Type of result received from function.
* #param f Pure function to be memoized.
*/
final class Memoize1[A, R](f: A => R) extends (A => R) {
// Cached function call results.
private val result = scala.collection.mutable.Map.empty[A, R]
/** Call memoized function.
*
* If the function has not been called with the specified argument value, then the
* function is called and the result cached; otherwise the previously cached
* result is returned.
*
* #param a Argument value to be passed to `f`.
* #return Result of `f(a)`.
*/
def apply(a: A) = synchronized(result.getOrElseUpdate(a, f(a)))
}
/** Memoization companion */
object Memoize1 {
/** Memoize a specific function.
*
* #tparam A Type of argument passed to function.
* #tparam R Type of result received from function.
* #param f Pure function to be memoized.
*/
def apply[A, R](f: A => R) = new Memoize1(f)
}
Assuming that the function you're memoizing is hydrateImpl, you can then define and use runOnce as follows (note that it becomes a val not a def):
val runOnce = Memoize1(hydrateImpl)
runOnce(someRequest) // Executed on first call with new someRequest value, cached result subsequently.
UPDATE: Regarding thread-safety.
In reply to the comment from user1913596, the answer is "no"; scala.collection.mutable.Map.getOrElseUpdate is not thread-safe. However, it's fairly trivial to synchronize access, and I have updated the original code accordingly (embedding the call within sychronized(...)).
The performance hit of locking access should be negated by the improved execution time (assuming that f is nontrivial).
There are likely better ways to do this depending on your setup, but a simple solution is to do the following
private var model: Option[Future[HydratedModelRequest]] = None
def runOnce(request: Request): Future[Request] = {
if (model.isEmpty) {
model = hydrateImpl(request)
}
model.get
}
If the request is indeed the same for each call, another option would be to require the request implicitly and hydrate lazily.
implicit val request: Request
lazy val hydratedRequest: Future[HydratedModelRequest] = hydrateImpl(request)

Extend object inside of trait in Scala

I've the following code:
trait AcceptExtractors {
/**
* Common extractors to check if a request accepts JSON, Html, etc.
* Example of use:
* {{{
* request match {
* case Accepts.Json() => Ok(toJson(value))
* case _ => Ok(views.html.show(value))
* }
* }}}
*/
object Accepts {
import play.api.http.MimeTypes
val Json = Accepting(MimeTypes.JSON)
val Html = Accepting(MimeTypes.HTML)
val Xml = Accepting(MimeTypes.XML)
val JavaScript = Accepting(MimeTypes.JAVASCRIPT)
}
}
Is there any way to extend the Accepts object?
Thank you!
Nope.
Objects are single values. If they could be extended, they would not be singletons (*). The class generated to represent them is final, so even if you knew its name (not hard to find out), you could not extend it.
(*) Objects are only truly singletons when defined at global scope or nested strictly within other objects leading back to a global one.
No, but you could make Accepts a trait which you can extend.