Use higher order functions to concise scala code - scala

I'm new to Scala and trying to write some programs to get better at it. I wrote a flow (version 1) that is very Java-like and I'm trying to write it using higher order functions (version 2).
version 1:
val entry: Option[Int] = getEntry()
if (entry.isDefined) {
val cachedEntry = entry.get
if (cachedEntry.state.isActive) {
return cachedEntry
} else {
Cache.invalidateCachedEntry(cachedEntry)
}
}
Cache.createNewEntry()
version 2:
val entry: Option[Int] = getEntry()
entry.filter(_.state.isActive).orElse((() => {
Cache.invalidateCachedEntry _
Option(Cache.createNewEntry())
})()).get
I'm not sure if this is the correct approach or there is a better way of doing this?

Let's consider following scenerio:
case class Entry(state: AnyState)
case class AnyState(isActive: Boolean = true)
object Cache {
def invalidateCachedEntry(entry: Entry): Unit = println("cleaned")
}
def getEntry: Option[Entry] = Some(Entry(AnyState()))
val optEntry: Option[Entry] = getEntry
val result: Option[Entry] = optEntry match {
case Some(entry) if entry.state.isActive =>
entry // do something
println("did something")
Some(entry)
case Some(entry) =>
Cache.invalidateCachedEntry(entry)
None
case _ =>
println("Entry not found")
None
}
This would be a one scenario. In general you should return something. But sometimes you don't have enough information. Such cases you can return Option and if you want to throw an error you can use Either

I prefer using match for clarity:
getEntry() match {
case Some(entry) if entry.state.isActive => entry
case opt => opt.foreach(Cache.invalidateCachedEntry); Cache.createNewEntry()
}

Related

Combining/chaining futures in scala play framework async action

I'm a scala newbie trying to write a Rest Api using play framework. I have the following 3 data access methods
getDataDict: (dsType:String, name:String) => Future[Option[DatasetDictionary]]
getDatasetData: (DatasetDictionary) => Future[List[DatasetData]]
getMetadata: (DatasetDictionary) => Future[List[Metadata]]
I need to use these 3 methods to get the result of my async action method.
def index(dstype:String, name:String, metadata:Option[Boolean]) = Action.async{
/*
1. val result = getDataDict(type, name)
2. If result is Some(d) call getDatasetData
3.1 if metadata = Some(true)
call getMetadata function
return Ok((dict, result, metadata))
3.2 if metadata is None or Some(false)
return Ok(result)
4. If result is None
return BadRequest("Dataset not found")
*/
}
I got the steps 1 and 2 working as follows
def index1(dsType:String, dsName: String, metadata:Option[Boolean]) = Action.async {
getDataDict(dsType, dsName) flatMap {
case Some(x) => getDatasetData(x) map (x => Ok(Json.toJson(x)))
case None => Future.successful(BadRequest("Dataset not found"))
}
}
I'm stuck at how to get the metadata part working.
First of all, it is not very clear (d, result, x) what you really want to return. Hopefully I guessed it correctly:
def index(dstype:String, name:String, metadata:Option[Boolean]) = Action.async {
getDataDict(dstype, name) flatMap {
case Some(datasetDictionary) =>
getDatasetData(datasetDictionary) flatMap { datasetDataList =>
if (metadata == Some(true)) {
getMetadata(datasetDictionary) map { metadataList =>
Ok(Json.toJson((datasetDictionary, datasetDataList, metadataList)))
}
} else {
Future.successful(Ok(Json.toJson(datasetDataList)))
}
}
case None => Future.successful(BadRequest("Dataset not found"))
}
}

Possible ways to check if a value exists in a sequence scala

case class dummy(val prop:Seq[Test])
case class Test(val s :String)
case class Result(val s :String)
def myFunc:Result = {
val s = "11,22,33"
val t = Test(s)
val list = dummy(Seq(t))
val code = Option("25")
val result = code.exists(p => {
list.prop.exists(d => d.s.split(",").contains(p))
})
if (result) {
Result("found")
} else {
Result("Not Found")
}
}
I am calling function myFunc, but instead of evaluating a boolean using if/else construct.
Any possible ways to avoid using If else construct
There is nothing wrong with using the if/else, but you could do this:
code
.flatMap(c => list.prop.find(_.s.split(",").contains(c)))
.map(_ => Result("Found")).getOrElse(Result("Not Found"))
The idea here is that instead of returning a Boolean at each stage we are passing an Option along. Then at the end if the Option is defined we can map that into a Result("Found"), and if it is not defined the .getOrElse will return a Result("Not Found").

Reading a file path from property and then reading the file idiomatic Scala

I want to read in the path of a file from configureation and then read the file in an idomatic Scala way. This is the code I have so far:
val key: Option[String] = {
val publicKeyPath: Option[String] = conf.getString("bestnet.publicKeyFile")
publicKeyPath match {
case Some(path) => {
Future {
val source = fromFile(s"./$path")
val key: String = source.getLines.toIterable.drop(1).dropRight(1).mkString
source.close()
key
} onComplete {
case Success(key) => Success(key)
case Failure(t) => None
}
}
case None => None
}
}
However this is not working since Im getting the error Expression of type Unit does not conform to Option[String]
What am I getting wrong and is my approach idiomatic Scala or should it be done in some other way?
If you want to return the contents as String there is no need to use a Future. E.g. the following would do:
val key: Option[String] = {
val publicKeyPath: Option[String] = conf.getString("bestnet.publicKeyFile")
publicKeyPath match {
case Some(path) =>
val source = fromFile(s"./$path")
val key: String = source.getLines.toIterable.drop(1).dropRight(1).mkString
source.close()
Some(key)
case None =>
None
}
}
The pattern of transforming the value of a Some(_) can be done more idiomatic using the higher-level function map, i.e.:
val key: Option[String] = {
val publicKeyPath = conf.getString("bestnet.publicKeyFile")
publicKeyPath.map(path => {
val source = fromFile(s"./$path")
val key = source.getLines.toIterable.drop(1).dropRight(1).mkString
source.close()
key
})
}
A more idiomatic way to do resource management (i.e. closing the Source) is by using the "Loan Pattern". For example:
def using[A](r: Resource)(f: Resource => A): A = try {
    f(r)
} finally {
r.dispose()
}
val key: Option[String] = {
val publicKeyPath = conf.getString("bestnet.publicKeyFile")
publicKeyPath.map(path =>
using(fromFile(s"./$path"))(source =>
source.getLines.toIterable.drop(1).dropRight(1).mkString
)
)
}
Scala is a flexible language and it is not uncommon to define such an abstraction in user-land (whereas in Java, the using abstraction is a language feature).
If you need non-blocking parallel code you should return a Future[String] instead of an Option[String]. This complicates the automatic resource management, since code is executed at a different time. Anyway, this should give you some pointers for improving your code.

Verify schema using Slick 3

I am looking to use the Slick 3 framework for a Scala application to manage database interactions. I have been able to automatically generate the necessary table objects using Slick, but I also would like an integration test that verifies that the schemas in the database match the schemas in the objects. This is because sometimes tables get altered without my team being alerted, and so we would prefer to catch the change in an integration test instead of a production application.
One way to do this is to simply run a select query on every single table in a test runner. However, I feel like there should be a more direct way. Furthermore, it is not clear to me how to systematically run through all the tables defined in the file, except to manually append the table object to some sequence the test runner moves through. I notice that there is a schema field, but it only has the ability to generate create and drop statements.
Any help would be greatly appreciated. Thank you!
EDIT:
Here is my solution, but I was hoping for a better one:
class TablesIT extends FunSuite with BeforeAndAfter with ScalaFutures {
var db: Database = _
before{ db = Database.forURL( /* personal details */ )}
object ResultMap extends GetResult[Map[String,Any]] { //Object borrowed from http://stackoverflow.com/questions/20262036/slick-query-multiple-tables-databases-with-getting-column-names
def apply(pr: PositionedResult) = {
val rs = pr.rs // <- jdbc result set
val md = rs.getMetaData
val res = (1 to pr.numColumns).map{ i=> md.getColumnName(i) -> rs.getObject(i) }.toMap
pr.nextRow // <- use Slick's advance method to avoid endless loop
res
}
}
def testTableHasCols[A <: Table[_]](table: slick.lifted.TableQuery[A]): Unit = {
whenReady(db.run(table.take(1).result.headOption.asTry)) { case Success(t) => t match {
case Some(r) => logTrace(r.toString)
case None => logTrace("Empty table")
}
case Failure(ex) => fail("Query exception: " + ex.toString)
}
}
def plainSqlSelect[A](query: String)(implicit gr: GetResult[A]): Future[Seq[A]] = {
val stmt = sql"""#$query""".as[A]
db.run(stmt)
}
def compareNumOfCols[A <: Table[_]](table: slick.lifted.TableQuery[A]) = {
val tableName = table.baseTableRow.tableName
val selectStar = whenReady(db.run(sql"""select * from #$tableName limit 1""".as(ResultMap).headOption)) {
case Some(m) => m.size
case None => 0
}
val model = whenReady(db.run(sql"""#${table.take(1).result.statements.head}""".as(ResultMap).headOption)) {
case Some(m) => m.size
case None => 0
}
assert(selectStar === model, "The number of columns do not match")
}
test("Test table1") {
testTableHasCols(Table1)
compareNumOfCols(Table1)
}
// And on for each table
}
I ended up devising a better solution that uses the following idea. It is more or less the same, and unfortunately I still have to manually create a test for each table, but the method is cleaner, I think. Note, however, that this only works for PostgreSQL because of the information schema, but other database systems have other methods.
class TablesIT extends FunSuite with BeforeAndAfter with ScalaFutures {
var db: Database = _
before{ db = Database.forURL( /* personal details */ )}
def testTableHasCols[A <: Table[_]](table: slick.lifted.TableQuery[A]): Unit = {
whenReady(db.run(table.take(1).result.headOption.asTry)) { case Success(t) => t match {
case Some(r) => logTrace(r.toString)
case None => logTrace("Empty table")
}
case Failure(ex) => fail("Query exception: " + ex.toString)
}
}
def compareNumOfCols[A <: Table[_]](table: slick.lifted.TableQuery[A]) = {
val tableName = table.baseTableRow.tableName
val selectStar = whenReady(db.run(sql"""select column_name from information_schema.columns where table_name='#$tableName'""".as[String])) {
case m: Seq[String] => m.size
case _ => 0
}
val model = table.baseTableRow.create_*.map(_.name).toSeq.size
assert(selectStar === model, "The number of columns do not match")
}
test("Test table1") {
testTableHasCols(Table1)
compareNumOfCols(Table1)
}
// And on for each table
}

Release IO resources in scala without maintaining mutable state

I need to use some Java library, which might throw some exceptions in one method and return error codes in another set of methods. So far it leads to the ugly code like
val txn = mgr.prepareTransaction()
val accessRecord = txn.readByQuery(...)
var state : Either[MyError, Result] = null //
try {
// do something here
val result = txn.runCodeWithin(new Callable[Result]() {...})
if (result == -1) {
state = Left(CanNotReadRecord)
} else {
state = Right(txn.getCachedRecord())
}
} catch {
case e: Exception => state = Left(GeneralError(e))
} finally {
state match {
case Right(_) => txn.commit();
case _ => txn.rollback();
}
}
I mostly interested in getting rid of state as var and ability to check the state in finally block. Please advice.
Scala 2.10 introduced the Try class, which is a more functional replacement to the use case of Either[Throwable, Result]. It's got all of the usual monad ops (the things that make for-comprehensions work), and some other helpful methods. (check out the docs for Try here)
Here's a possible re-implementation of your code, using Try, and replacing CanNotReadRecord with a CanNotReadRecordException. It should be functionally equivalent to your example, with the exception of that replacement.
def txResults(txn: Transaction): Try[Record] = for {
result <- Try{ txn.runCodeWithin(...) }
checked <- result match {
case -1 => Failure( new CanNotReadRecordException )
case _ => Success( txn.getCachedRecord )
}
} yield checked
txResults(txn) match {
case Success(record) => txn.commit()
case Failure(e) => txn.rollback() //and maybe handle `e`
}
The Scala ARM (Automatic Resource Management) library handles all this sort of thing elegantly and in a completely air-tight manner.
Check it out.