Variable from a function to get each changed value - scala

There are dataset in object. I can change the value, but like this I always get an old map.
var partnerURLs=getPartnerURLs()
def getPartnerURLs(): mutable.Map[String, List[String]] ={
val sql = "select * from table where status_flag=1 and del_flag=0"
val resultSet = DBUtils.doMapResult(sql)
var result = new scala.collection.mutable.HashMap[String, List[String]]()
resultSet.foreach(rows => {
val row = rows.asInstanceOf[util.HashMap[String, Any]]
result += (row.get("uname").toString -> row.get("urls").toString.split(",").toList)
})
result
}
If I update the database, the partnerURLS can't change, it always has old value.
this method is ok, can get latest value, I want this variable partnerURLs how get the latest value?
What I'm doing wrong?

var partnerURLs = getPartnerURLs()
This variable is your problem. If it is globally declared in the enclosing class or object, it will be initialized only once!
Also, please avoid using mutable state! Give some respect to Scala and Functional programming!

Related

while comparing the two objects in scala not getting correct result

Pojo classes
case class RulePojoMigration(val tolerance_id:Int,val asset_id:Int, measure: String, cond: String, function: String, threshold_value: String, rule_dts: String,
filter: util.List[Filter], is_enabled: String, mode: String, tolerance_status: String, action_key: String,
email_ids: util.List[String], rule_name:String, rule_owner:String, group_by: util.List[String], relax_variation_band:String, reconciliation_id:Int)
case class Filter(value: String, operator: String, dimension: String)
Below is the code used to fetch the object from DB
if (checkRuleIsEditOrNot) {
ps = con.prepareStatement(WSQueryConstant.RULE_MIGRATION_GET_COMPLETE_RULE_INFO_FROM_STAGE)
ps.setInt(1, rulePojo.tolerance_id)
rs = ps.executeQuery
var dbRulePojo: RulePojoMigration = null
val jsonRulePojo: RulePojoMigration = rulePojo
if (rs.next()) {
val rule_tolerance_asset_id = rs.getInt(2)
val measure = rs.getString(3)
val cond = rs.getString(4)
val function = rs.getString(5)
val threshold_value = rs.getString(6)
val rule_dts = rs.getString(7)
val filter = gson.fromJson(rs.getString(8), classOf[util.List[Filter]])
val is_enabled = rs.getString(9)
val mode = rs.getString(10)
val tolerance_status = rs.getString(11)
val email_ids = gson.fromJson(rs.getString(12), classOf[java.util.List[String]])
val rule_name = rs.getString(13)
val rule_owner = rs.getString(14)
val group_by = gson.fromJson(rs.getString(15), classOf[java.util.List[String]])
val relax_variation_band = rs.getString(16)
var reconciliation_id = rs.getString(17)
if(reconciliation_id== null)
reconciliation_id= "-1"
dbRulePojo = RulePojoMigration(jsonRulePojo.tolerance_id, rule_tolerance_asset_id, measure, cond, function, threshold_value, rule_dts, filter, is_enabled, mode, tolerance_status, jsonRulePojo.action_key, email_ids, rule_name, rule_owner, group_by, relax_variation_band, reconciliation_id.toInt)
user request with the below values.
RulePojoMigration(1274,1234,*,less than,count,100,2020-07-04 05:31:29,[Filter(Hello,equal,funnel_state)],1,static,null,EMAIL,[x],StaticRuleMigrationTesting,email,[ALL],0,-1)
Object available in MySQL database
RulePojoMigration(1274,1234,*,less than,count,100,2020-07-04 05:31:29,[{value=Hello, operator=equal, dimension=funnel_state}],1,static,null,EMAIL,[x],StaticRuleMigrationTesting,email,[ALL],0,-1)
So I want to check the equality of two objects so that the user can modify the the existing object if there is any changes in the payload or simply he/she should get a message saying duplicate entry exist. jsonRulePojo.equal(dbRulePojo) should be true, anyhow values are same of both object.
The default equals operation does not check the contents of the two classes, it just checks whether both values refer to the same object. So two instances of RulePojoMigration will always be different even if every field is the same. By default two classes are only equal if they are the same instance.
When a case class is defined, Scala will generate an equals that does check each of the fields passed to the constructor in turn. So two case classes will be equal if they have the same contents.
So you can fix this code in one of two ways:
Make RulePojoMigration a case class
Add an equals method to RulePojoMigration
I am able to resolve the bug by making the below changes.
From
val filter = gson.fromJson(rs.getString(8), classOf[util.List[Filter]])
To
val filter = gson.fromJson(rs.getString(8), classOf[Array[Filter]])
and
dbRulePojo = RulePojoMigration(jsonRulePojo.tolerance_id, rule_tolerance_asset_id, measure, cond, function, threshold_value, rule_dts, java.util.Arrays.asList(filter:_*)
, is_enabled, mode, tolerance_status, jsonRulePojo.action_key, email_ids, rule_name, rule_owner, group_by, relax_variation_band, reconciliation_id.toInt)
And instead of passing the filter directly into dbRulePojo i passed the java.util.Arrays.asList(filter:_*)

unable to convert a java.util.List into Scala list

I want that the if block returns Right(List[PracticeQuestionTags]) but I am not able to do so. The if/else returns Either
//I get java.util.List[Result]
val resultList:java.util.List[Result] = transaction.scan(scan);
if(resultList.isEmpty == false){
val listIterator = resultList.listIterator()
val finalList:List[PracticeQuestionTag] = List()
//this returns Unit. How do I make it return List[PracticeQuestionTags]
val answer = while(listIterator.hasNext){
val result = listIterator.next()
val convertedResult:PracticeQuestionTag = rowToModel(result) //rowToModel takes Result and converts it into PracticeQuestionTag
finalList ++ List(convertedResult) //Add to List. I assumed that the while will return List[PracticeQuestionTag] because it is the last statement of the block but the while returns Unit
}
Right(answer) //answer is Unit, The block is returning Right[Nothing,Unit] :(
} else {Left(Error)}
Change the java.util.List list to a Scala List as soon as possible. Then you can handle it in Scala fashion.
import scala.jdk.CollectionConverters._
val resultList = transaction.scan(scan).asScala.toList
Either.cond( resultList.nonEmpty
, resultList.map(rowToModel(_))
, new Error)
Your finalList: List[PracticeQuestionTag] = List() is immutable scala list. So you can not change it, meaning there is no way to add, remove or do change to this list.
One way to achieve this is by using scala functional approach. Another is using a mutable list, then adding to that and that list can be final value of if expression.
Also, a while expression always evaluates to Unit, it will never have any value. You can use while to create your answer and then return it seperately.
val resultList: java.util.List[Result] = transaction.scan(scan)
if (resultList.isEmpty) {
Left(Error)
}
else {
val listIterator = resultList.listIterator()
val listBuffer: scala.collection.mutable.ListBuffer[PracticeQuestionTag] =
scala.collection.mutable.ListBuffer()
while (listIterator.hasNext) {
val result = listIterator.next()
val convertedResult: PracticeQuestionTag = rowToModel(result)
listBuffer.append(convertedResult)
}
Right(listBuffer.toList)
}

Scala proper way to initialize ones changed in runtime fields: placeholder/null, None or zero element?

I got class with fields which value at initialization is unknown. But after, in runtime that values is will gained and setted to fields just ones.
I want to decide what first initialization is best to use for that fields. As i read, there are such methods:
using placeholder _ or null [Bad way]:
var name: String = _
var nextUser: User = null
using None, and than in my code Some(v)[Good, but verbose]:
var name: Option[String] = None
var nextUser: Option[User] = None
using "zero" element:
var name: String = ""
var nextUser: User = new User()
using stub:
var name: String = "undefined"
var nextUser: User = UndefinedUser
I see 3 problems:
it is verbose to get values from Some() writing any times .get or using match/case
it is bad to use var for field which really will be setted by value just one time, but in runtime
it is bad to write updateUser-like methods
Now i am using None in that fields, because for some types, which is not in my library, is no any constructor or empty\"zero" value:
class ClassWithLazyFields {
var name: String = ""
var age: Int = 0
//here, after first asignment as `None` i will set it values only one time
var myThread: Option[Thread] = None
var nextUser: Option[User] = None
var myTransformUnit: Option[TransformUnit] = None
def updateUser(u: User): Unit = {
nextUser = u
}
}
//after first asignment as `None` i set nextUser value like that
classInstance.updateUser(userCat)
// bad ".get" in callings
val name = classInstance.myThread.get.name
val hoursToStart = classInstance.myTransformUnit.get.waitTime.hours
// or more verbose match/case
val hoursToStart = classInstance.myTransformUnit match {
case Some(v) => v.waitTime.hours
case None => 0
}
What you can advice to me?
I need something like lazy var or any good advice.
The advice is to avoid using mutable data structures like this in the first place.
Make the class immutable and change methods like updateUser to return a new updated instance rather than modifying the current instance.
But if you must do this, Option is specifically designed for cases where values may or may not be present. Methods like map and getOrElse make it easy (and safe) to use Option values with very little overhead.
For example, this is how you safely calculate name and hoursToStart:
val name = classInstance.myThread.fold("NoName")(_.name)
val hoursToStart = classInstance.myTransformUnit.fold(0)(_.waitTime.hours)
If you want to use multiple Option values, use for like this:
for {
thread <- classInstance.myThread
user <- classInstance.nextUser
unit <- classInstance.myTransformUnit
} {
// Code that uses thread, user, and unit
}
The code will only be called if all three values are not None.

HBase Table Retrieval Data

If I am trying to retrieve data from an HBase table using this code:
val get = new Get(Bytes.toBytes(extracted.user.rowKey.toString))
val res = table.get(get)
I am not sure if the val res = table.get(get) line will return a result or not since a row with this row key: extracted.socialUser.socialUserConnectionId.toString passed to the Get constructor may not exist in the HBase table.
I am trying something like this:
val get = new Get(Bytes.toBytes(extracted.socialUser.socialUserConnectionId.toString))
val res = table.get(get)
if (!res) {
/* Create the row in the HBase table */
}
But it is giving me the error in that if statement saying: Expression of this type result doesn't convert to type Boolean. Is there a way I can solve this problem?
At first glance, it appears val res = table.get(get) would return a type Optional.
Given that, you should be calling res.isEmpty instead of !res
Edit:
Better still, you could use getOrElse instead of get :
val res = table.getOrElse{
// Create the row in the HBase table
}

Scala Lists and Option

I must be doing something wrong. I come form a Java background so this stuff should be easy.
I'm wanting to create a mapping between a key and multiple values held in a list:
var keys = Map[String, ListBuffer[String]]()
However, I can't seem to add a value to the list!!! What am I doing wrong??
def put(key: String, value: String) = {
var valueOption = keys.get(key)
var values = valueOption.getOrElse(ListBuffer)
values += value
// value not added
}
I do not want to use a MultiMap because I need to do some other operations which are not easy to do with a MultiMap.
Please help.
Thanks
The other answers are right about how you're not putting the new ListBuffer back in the Map, but their example code is verbose. A mutable Map has getOrElse and getOrElseUpdate methods for this. Also, use val not var for locals and the keys member, unless you have reason not to. I sometimes prefer append to +=.
def put(key: String, value: String) = {
keys.getOrElseUpdate(key, ListBuffer()) += value
}
The problem is here:
var valueOption = keys.get(key)
var values = valueOption.getOrElse(ListBuffer)
For any nonexistent key, keys.get will return a None Option. You then call getOrElse, and since the "else" part is used (because it's a None), a new ListBuffer is initialized. However, this is all that happens.
In particular, the new ListBuffer is NOT automatically put into the map. Such an operation wouldn't make sense - getOrElse is part of the Option API, it cannot "know" about any collection the Option is generated from.
To correct your problem, you have to put the new ListBuffer into the map yourself. An example if you're using a mutable Map:
def put(key: String, value: String) = {
var valueOption = keys.get(key)
var values = valueOption.getOrElse {val b = ListBuffer.empty[String]; keys.put(key,b); b;}
values += value
}
the problem is, that by calling getOrElse(ListBuffer) you do not insert the new ListBuffer into the Map. So you need to add an additional step:
def put(key: String, value: String) = {
var valueOption =
var values = keys.get(key) match {
case None => // key not yet defined
buffer = ListBuffer()
// insert into map!
keys += key -> buffer
buffer
case Some(buffer) => buffer // key is already defined just return it
}
values += value
}
Note that for keys += key -> buffer to work, i assume, that you use an mutable Map (import from scala.collection.mutable.Map) instad of the default immutable Map
getOrElse will return the default ListBuffer, which is an empty ListBuffer, if key doesn't exist. You will need to associate this with you key.