I see codes like this:
trait LoginInfoRepoImpl extends LoginInfoRepo {
def loginInfoRepository = new LoginInfoRepository {
private val loginInfoTable = TableQuery[LoginInfoTable]
// return a LoginID
def save(userLoginInfo: userLoginInfo): Future[userLoginID] = Future {
val newRecord = DB.withSession { implicit session =>
loginInfoTable.filter(
l => l.userID === userLoginInfo.userID &&
(l.deviceID === userLoginInfo.deviceID || (l.deviceID.isEmpty && userLoginInfo.userID.isEmpty))).list.headOption.fold {
val newSubID = loginInfoTable.filter(l => l.userID === userLoginInfo.userID).sortBy(_.subID.desc).take(1).map(_.subID).list.headOption.getOrElse(0) + 1
(loginInfoTable returning loginInfoTable) += LoginInfoRecord(userLoginInfo.userID, newSubID, userLoginInfo.deviceID, userLoginInfo.userAgent, getCurrentTime)
} { l =>
// to do : update time
val q = for (l <- loginInfoTable if l.userID === userLoginInfo.userID && ((l.deviceID === userLoginInfo.deviceID)
|| (l.deviceID.isEmpty && userLoginInfo.userID.isEmpty)))
yield l.lastLoginTime
q.updateReturning(loginInfoTable.map(identity), getCurrentTime).head
}
}
userLoginID(newRecord.userID, newRecord.subID.toString)
}
}
}
This looks a little monstrous for me. I found many things are crowded into one line. Also, I found l.deviceID is of type Column[Option[String]], while userLoginInfo.deviceID is of typeOption[String], they don't equal if both of them is None. Thus a l.device.isEmpty looks necessary..
Does anyone have suggestions about how to refactor these codes? Thanks!
First of all: Better indentation and breaking up long lines.
Slick-specific: pull queries out of the withSession block and reuse them for shared logic. Use firstOption instead of .list.headOption.
Side-note: Since you are generating IDs based on old ones, you may want to use a transaction or use a more efficient means provided by your DB.
trait LoginInfoRepoImpl extends LoginInfoRepo {
def loginInfoRepository = new LoginInfoRepository {
private val loginInfoTable = TableQuery[LoginInfoTable]
// return a LoginID
def save(userLoginInfo: userLoginInfo): Future[userLoginID] = Future {
val userLoginInfoQuery = loginInfoTable.filter(l => l.userID === userLoginInfo.userID)
val deviceLoginInfoQuery = userLoginInfoQuery.filter(
l =>
l.deviceID === userLoginInfo.deviceID ||
(
l.deviceID.isEmpty && userLoginInfo.userID.isEmpty
)
)
val subIdQuery = userLoginInfoQuery.sortBy(_.subID.desc).map(_.subID)
val newRecord = DB.withTransaction{ implicit session =>
deviceLoginInfoQuery
.firstOption
.fold {
val newSubID = subIdQuery.firstOption.getOrElse(0) + 1
val newLoginInfo = LoginInfoRecord(userLoginInfo.userID, newSubID, userLoginInfo.deviceID, userLoginInfo.userAgent, getCurrentTime)
(loginInfoTable returning loginInfoTable) += newLoginInfo
}( _ =>
// to do : update time
deviceLoginInfoQuery
.map(_.lastLoginTime)
.updateReturning(loginInfoTable.map(identity), getCurrentTime)
.head
)
}
userLoginID(newRecord.userID, newRecord.subID.toString)
}
}
}
Related
I am new to Play Scala. Below code snippet I am trying to use to expose an API. Its failing with the below error.
type mismatch;
found : scala.concurrent.Future[String]
required: String
API source:
def getStrategy(date: String) = Action.async {
val currentDate:String = toString(DateTime.now.minusDays(1))
getDecision(date, currentDate).map(lastError => Ok("No Strategy found:%s".format(lastError)))
}
def getDecision(reqestedDate:String, currentDate:String): Future[String] = {
getForecastPrice(reqestedDate).map(forecastPrice =>
getCurrentPrice(currentDate).map(currentPrice =>
getCall(currentPrice, forecastPrice)
)
)
}
def getForecastPrice(requestedDate:String): Future[Option[Double]] = {
predictionRepo.getPrediction(requestedDate).map( maybePrediction =>
maybePrediction.map ( fPrice => fPrice.price )
)
}
def getCurrentPrice(currentDate:String): Future[Option[Double]] = {
priceRepo.getPrice(currentDate).map ( maybePrice =>
maybePrice.map ( cPrice => cPrice.price )
)
}
def getCall(currentPrice:Option[Double], forcastPrice:Option[Double]): String = {
var decision = ""
println("currentPrice:" + currentPrice)
println("forcastPrice:" + forcastPrice)
if(currentPrice.isDefined && forcastPrice.isDefined) {
var currentPriceValue = currentPrice.get.toDouble
var forcastPriceValue = forcastPrice.get.toDouble
if((currentPriceValue*5/100) < (currentPriceValue - forcastPriceValue)) {
decision = "BUY"
} else if((currentPriceValue*5/100) > (currentPriceValue - forcastPriceValue)) {
decision = "SELL"
} else {
decision = "HOLD"
}
}
return decision
}
Error in the above code is shwon at the below location.
getCurrentPrice(currentDate).map(currentPrice =>
Could you please help me to find the reason for this issue?
Can you change the first map in getDecision to flatMap:
def getDecision(reqestedDate:String, currentDate:String): Future[String] = {
getForecastPrice(reqestedDate).flatMap(forecastPrice =>
getCurrentPrice(currentDate).map(currentPrice =>
getCall(currentPrice, forecastPrice)
)
)
}
With the current code the result type would Future[Future[String]]
You can use for comprehension rather than using a map inside another map. The sample code would be something like this.
for(
getForecastPriceResult <- getForecastPrice(requestedDate);
getCurrentPriceResult <- getCurrentPrice(currentDate)
) yield(getCall(getForecastPriceResult,getCurrentPriceResult))
Trying to execute a function in a given time frame, but if computation fails by TimeOut get a partial result instead of an empty exception.
The attached code solves it.
The timedRun function is from Computation with time limit
Any better approach?.
package ga
object Ga extends App {
//this is the ugly...
var bestResult = "best result";
try {
val result = timedRun(150)(bestEffort())
} catch {
case e: Exception =>
print ("timed at = ")
}
println(bestResult)
//dummy function
def bestEffort(): String = {
var res = 0
for (i <- 0 until 100000) {
res = i
bestResult = s" $res"
}
" " + res
}
//This is the elegant part from stackoverflow gruenewa
#throws(classOf[java.util.concurrent.TimeoutException])
def timedRun[F](timeout: Long)(f: => F): F = {
import java.util.concurrent.{ Callable, FutureTask, TimeUnit }
val task = new FutureTask(new Callable[F]() {
def call() = f
})
new Thread(task).start()
task.get(timeout, TimeUnit.MILLISECONDS)
}
}
I would introduce a small intermediate class for more explicitly communicating the partial results between threads. That way you don't have to modify non-local state in any surprising ways. Then you can also just catch the exception within the timedRun method:
class Result[A](var result: A)
val result = timedRun(150)("best result")(bestEffort)
println(result)
//dummy function
def bestEffort(r: Result[String]): Unit = {
var res = 0
for (i <- 0 until 100000) {
res = i
r.result = s" $res"
}
r.result = " " + res
}
def timedRun[A](timeout: Long)(initial: A)(f: Result[A] => _): A = {
import java.util.concurrent.{ Callable, FutureTask, TimeUnit }
val result = new Result(initial)
val task = new FutureTask(new Callable[A]() {
def call() = { f(result); result.result }
})
new Thread(task).start()
try {
task.get(timeout, TimeUnit.MILLISECONDS)
} catch {
case e: java.util.concurrent.TimeoutException => result.result
}
}
It's admittedly a bit awkward since you don't usually have the "return value" of a function passed in as a parameter. But I think it's the least-radical modification of your code that makes sense. You could also consider modeling your computation as something that returns a Stream or Iterator of partial results, and then essentially do .takeWhile(notTimedOut).last. But how feasible that is really depends on the actual computation.
First, you need to use one of the solution to recover after the future timed out which are unfortunately not built-in in Scala:
See: Scala Futures - built in timeout?
For example:
def withTimeout[T](fut:Future[T])(implicit ec:ExecutionContext, after:Duration) = {
val prom = Promise[T]()
val timeout = TimeoutScheduler.scheduleTimeout(prom, after)
val combinedFut = Future.firstCompletedOf(List(fut, prom.future))
fut onComplete{case result => timeout.cancel()}
combinedFut
}
Then it is easy:
var bestResult = "best result"
val expensiveFunction = Future {
var res = 0
for (i <- 0 until 10000) {
Thread.sleep(10)
res = i
bestResult = s" $res"
}
" " + res
}
val timeoutFuture = withTimeout(expensiveFunction) recover {
case _: TimeoutException => bestResult
}
println(Await.result(timeoutFuture, 1 seconds))
In the following function, I am passing an Option. Depending on whether the Option is Some or None, I need to call the a specific API but the rest of the code is the same for both Some and None. I don't know how to remove the code duplication though. How could I re-write the code in functional-programming style?
def getRowsByPartitionKeyId(id:I, pagingStateOption:Option[PagingState]):Tuple2[Option[List[M]],Option[PagingState]] = {
pagingStateOption match {
case Some(pagingState:PagingState) => {
val resultSet = session.execute(whereClause
.setFetchSize(1)
.setPagingState(pagingState)) //THIS IS THE ONLY DIFFERENCE IN THE TWO CODE LEGS
val it = resultSet.iterator();//resultSet is an iterator
val newPagingState:PagingState = resultSet.getExecutionInfo.getPagingState
if(it.hasNext){
val resultSetAsList:List[Row] = asScalaIterator(it).toList
val resultSetAsModelList = rowToModel(resultSetAsList.head)
Tuple2(Some(List(resultSetAsModelList)),Some(pagingState))
}
else {
Tuple2(None, None)
}
}
case None =>{
val resultSet = session.execute(whereClause
.setFetchSize(1)) //get one row from ResultSet. Cassandra might return more or less though
val it = resultSet.iterator();//resultSet is an iterator
val pagingState:PagingState = resultSet.getExecutionInfo.getPagingState
if(it.hasNext){
val resultSetAsList:List[Row] = asScalaIterator(it).toList
val resultSetAsModelList = rowToModel(resultSetAsList.head)
Tuple2(Some(List(resultSetAsModelList)),Some(pagingState))
}
else {
Tuple2(None, None)
}
}
}
def getRowsByPartitionKeyId(
id:I,
pagingStateOption:Option[PagingState]
): (Option[List[M]], Option[PagingState]) = {
val resultSet = session.execute(pagingStateOption match {
case Some(pagingState: PagingState) =>
whereClause.setFetchSize(1).setPagingState(pagingState)
case None =>
whereClause.setFetchSize(1)
})
val it = resultSet.iterator();//resultSet is an iterator
val newPagingState:PagingState = resultSet.getExecutionInfo.getPagingState
if (it.hasNext) {
val resultSetAsList:List[Row] = asScalaIterator(it).toList
val resultSetAsModelList = rowToModel(resultSetAsList.head)
Tuple2(Some(List(resultSetAsModelList)),Some(pagingState))
} else {
Tuple2(None, None)
}
}
Got it. I forgot that everything in Scala returns a value, even match, so I can do this
val resultSet = pagingStateOption match {
case Some(pagingState: PagingState) => {
println("got paging state:" +pagingState)
session.execute(whereClause
.setFetchSize(1)
.setPagingState(pagingState)) //get one row from ResultSet. Cassandra might return more or less though
}
case None => {
session.execute(whereClause
.setFetchSize(1)) //get one row from ResultSet. Cassandra might return more or less though
}
}
I got the error
found : scala.concurrent.Future[Option[models.ProcessTemplatesModel]]
required: Option[models.ProcessTemplatesModel]
My function is below
def createCopyOfProcessTemplate(processTemplateId: Int): Future[Option[ProcessTemplatesModel]] = {
val action = processTemplates.filter(_.id === processTemplateId).result.map(_.headOption)
val result: Future[Option[ProcessTemplatesModel]] = db.run(action)
result.map { case (result) =>
result match {
case Some(r) => {
var copy = (processTemplates returning processTemplates.map(_.id)) += ProcessTemplatesModel(None, "[Copy of] " + r.title, r.version, r.createdat, r.updatedat, r.deadline, r.status, r.comment, Some(false), r.checkedat, Some(false), r.approvedat, false, r.approveprocess, r.trainingsprocess)
val composedAction = copy.flatMap { id =>
processTemplates.filter(_.id === id).result.headOption
}
db.run(composedAction)
}
}
}
}
what is my problem in this case?
edit:
my controller function looks like this:
def createCopyOfProcessTemplate(processTemplateId: Int) = Action.async {
processTemplateDTO.createCopyOfProcessTemplate(processTemplateId).map { process =>
Ok(Json.toJson(process))
}
}
Is there my failure?
According to the your code - there are the following issues:
You use two db.run which return futures, but inner future will
not complete. For resolving it you should compose futures with
flatMap or for-comprehension.
You use only one partial-function case Some(_) => for pattern matching
and don't handle another value None.
You can use only one db.run and actions composition.
Your code can be like as:
def createCopyOfProcessTemplate(processTemplateId: Int): Future[Option[ProcessTemplatesModel]] = {
val action = processTemplates.filter(...).result.map(_.headOption)
val composedAction = action.flatMap {
case Some(r) =>
val copyAction = (processTemplates returning processTemplates...)
copyAction.flatMap { id =>
processTemplates.filter(_.id === id).result.headOption
}
case _ =>
DBIO.successful(None) // issue #2 has been resolved here
}
db.run(composedAction) // issue #3 has been resolved here
}
We get rid of issue #1 (because we use actions composition).
Given two scala play enumerators A and B that each provide sorted integers, is there a way to derive an enumerator of integers that exist in B that don't exist in A?
For example:
val A: Enumerator[Int] = Enumerator(1,3,5,9,11,13)
and
val B: Enumerator[Int] = Enumerator(1,3,5,7,9,11,13)
I would somehow get:
val C: Enumerator[Int] // This enumerator will output 7
Doing it in a reactive way with enumerators/iteratees/enumeratees is preferred.
One solution I've thought of is to interleave the enumerators and somehow use Iteratee.fold to maintain a buffer to compare the two streams but that seems like it should be unnecessary.
I had somewhat similar question
How to merge 2 Enumerators in one, based on merge rule
I modified given answer, to fit your needs
object Disjunction {
def disjunction[E: Ordering](enumA: Enumerator[E], enumB: Enumerator[E])(implicit ec: ExecutionContext) = new Enumerator[E] {
def apply[A](iter: Iteratee[E, A]) = {
case class IterateeReturn(o: Option[(Promise[Promise[IterateeReturn]], E)])
val failP: Promise[Nothing] = Promise() // Fail promise
val failPF: Future[Nothing] = failP.future // Fail promise future
val initState1: Future[Seq[IterateeReturn]] = Future.traverse(Seq(enumA, enumB)) {
enum =>
val p: Promise[IterateeReturn] = Promise[IterateeReturn]()
// The flow to transform Enumerator in IterateeReturn form
enum.run(Iteratee.foldM(p)({
(oldP: Promise[IterateeReturn], elem: E) =>
val p = Promise[Promise[IterateeReturn]]()
// Return IterateeReturn pointing to the next foldM Future reference, and current element
oldP success IterateeReturn(Some(p, elem))
// Return new Future as a Result of foldM
p.future
}) map ({
promise => promise success IterateeReturn(None) // Finish last promise with empty IterateeReturn
})
) onFailure {
// In case of failure main flow needs to be informed
case t => failP failure t
}
p.future
}
val initState: Future[List[(Promise[Promise[IterateeReturn]], E)]] = initState1 map (_.map(_.o).flatten.toList)
val newEnum: Enumerator[Option[E]] = Enumerator.unfoldM(initState) { fstate =>
// Whatever happens first, fstate returned of failure happened during iteration
Future.firstCompletedOf(Seq(fstate, failPF)) map { state =>
// state is List[(Promise[Promise[IterateeReturn]], E)
// sort elements by E
if (state.isEmpty) {
None
} else if (state.length == 1) {
val (oldP, elem) = state.head
val p = Promise[IterateeReturn]()
oldP success p
// Return newState, with this iterator moved
val newState: Future[List[(Promise[Promise[IterateeReturn]], E)]] = p.future.map(ir => ir.o.map(List(_)).getOrElse(Nil))
Some(newState, Some(elem))
} else {
val sorted = state.sortBy(_._2)
val (firstP, fe) = sorted.head
val (secondP, se) = sorted.tail.head
if (fe != se) {
// Move first and combine with the second
val p = Promise[IterateeReturn]()
firstP success p
val newState: Future[List[(Promise[Promise[IterateeReturn]], E)]] = p.future.map(ir => ir.o.map(List(_, (secondP, se))).getOrElse(List((secondP, se))))
// Return new state
Some(newState, Some(fe))
} else {
// Move future 1
val p1 = Promise[IterateeReturn]()
firstP success p1
val fState: Future[Option[(Promise[Promise[IterateeReturn]], E)]] = p1.future.map(ir => ir.o)
// Move future 2
val p2 = Promise[IterateeReturn]()
secondP success p2
val sState: Future[Option[(Promise[Promise[IterateeReturn]], E)]] = p2.future.map(ir => ir.o)
// Combine in new state
val newState = Future.sequence(List(fState, sState)).map(_.flatten)
// Return
Some(newState , None)
}
}
}
}
newEnum &>
Enumeratee.filter(_.isDefined) &>
Enumeratee.map(_.get) apply iter
}
}
}
I checked, it works.