Streaming process with different case classes - scala

I'm trying to implement a streaming process on Kafka. The data structure that I'm using looks like this one:
trait Base {def baseField: String}
final case class Elem0(baseField: String, oil: String, oil2: String) extends Base
final case class Elem1(baseField: String, engine: String, engine2: String) extends Base
final case class Elem2(baseField: String, tire: String, tire2: String) extends Base
This is just a simplification, the real "ElemX" classes (and the Base) have many more fields. The main App receives different objects of each of the classes using different Kafka topics. Each object needs to be processed independently.
I need to implement a function that does some complicated logic depending on the values of the fields of "ElemX". The possible values of "oil", "engine" and "tire" are the same for all classes (let's say that they can be "X", "Y", "Z"). I mean, there are just 3 possible values for all the case classes' fields. So my first approach is something like this:
def doSomethingWithElem0(record: Elem0) = {
if (record.oil == "X") {
... // logic1
} else if (record.oil == "Y") {
... // logic2
} else {
... // logic3
}
if (record.oil2 == "X") {
... // logic1
} else if (record.oil2 == "Y") {
... // logic2
} else {
... // logic3
}
...
}
def doSomethingWithElem1(record: Elem1) = {
if (record.engine == "X") {
... // logic1
} else if (record.engine == "Y") {
... // logic2
} else {
... // logic3
}
if (record.engine2 == "X") {
... // logic1
} else if (record.engine2 == "Y") {
... // logic2
} else {
... // logic3
}
...
}
def doSomethingWithElem2(record: Elem2) = {
if (record.tire == "X") {
... // logic1
} else if (record.tire == "Y") {
... // logic2
} else {
... // logic3
}
if (record.tire2 == "X") {
... // logic1
} else if (record.tire2 == "Y") {
... // logic2
} else {
... // logic3
}
...
}
As you can see there is a lot of duplicated logic but it all depends on the values of the case class fields. I cannot have something like this:
if (record.tire == "X" || record.tire2 == "X") {
// logic1
}
Because the logic involves doing something with each of the field values. This logic involves checking that specific value on a Redis database and things like checking the last time a certain value was received (for instance, I need to check if the value of record.tire was stored previously and do some calculations based on this). The key point is that I want to "apply" the same logic for all the case class fields without having to go over each record.field
Is there any way I could simplify this logic? I've been checking libraries like shapeless but I don't know if I can apply this kind of functions here.
Any help would be greatly appreciated.

Well, case classes are Products, so if you are talking about iterating over a case class fields, and applying the same logic to them, you could do something like:
record.productIterator.tail.foreach {
case "X" => logic1()
case "Y" => logic2()
case _ => logic3()
}

Related

Scala XML Elem Not Showing Up

I have a class where I want a conditional Elem in xml to be added, but I am unable to do this. Please help.
The ShortName block is supposed to be conditional.
While debugging I see that get shortname gets executed. In fact if I try wrapping that in a dummy tag (<dummy>{getShortName().get}</dummy> ) everything works. But I need the condition outside.
Here's my class:
import scala.xml.Elem
class MyClass(rob: ROB, scalaDTO: ScalaDTO, robStatus: Status) {
val myRob =
<FeatureNames>
{val allPoiNames = rob.Identity.Names.get.ROB_Name
allPoiNames.map(robName => {
if (!robName.Type.contains("Shortened")) {
<FeatureName CaseAutoCorrectionEnabled="true">
{robName.Text.map(text => {
val transType = text.Trans_Type
transType match {
case None => {
{
<Name>
{text.value}
</Name>
{
//Executes but does not get added
getShortName().getOrElse(null)
}
<Language>
{robName.Language_Code}
</Language>
}
}
case _ => {
<OtherName>
{text.value}
</OtherName>
}
}
})}
</FeatureName>
}
})}
</FeatureNames>
private def getShortName(): Option[Elem] = {
val condition = true
if (condition) {
Some(
<ShortName>ShortName</ShortName>
)
} else {
None
}
}
override def toString: String = {
val prettyPrinter = new scala.xml.PrettyPrinter(150, 2)
prettyPrinter.format(scala.xml.Utility.trim(myRob))
}
}
My output looks like:
<FeatureNames>
<FeatureName CaseAutoCorrectionEnabled="true">
<Language>ENF</Language>
<OtherName>The Name</OtherName>
</FeatureName>
</FeatureNames>
Note the Missing Name Tag,moving it below the getShortName() line prints it fine
For this kind of logic, you can express it as a NodeSeq instead of mixing it in with xml literals.
Something like:
case None =>
NodeSeq.fromSeq(Seq(<Name>{text.value}</Name>, getShortName().orNull, <Language>{robName.Language_Code}</Language>))

Scalatest: have a test which is valid if one of both matchers matches

I am having a hard time having an or relation between to matchers on an case class which match on different methods/fields of given class.
I know I could do it with exists an || which would end up with a Bool but will erase all Feedback from the testing Framework which I do not want.
Here is an example of what I would like to do:
class ExampleSpec extends FunSpec with Matchers {
case class Element(count: Int, value: String)
val data : List[Element] = List(
Element(0, "ok"),
Element(5, "")
Element(0,""),
Element(1, "a")
)
describe("My data test") {
data foreach {d =>
it("valid data either has a count > 0 or the value is not empty") {
d.count should be > 0 or d.value should not be empty // I have no idea how to get the or working
}
}
}
}
The best thing I could come up with was:
def okishSolution(e: Element) = {
val res = (e.count > 0 || d.value.nonEmpty)
if (! res) { info(s"Failed: $d , did not meet requirements") }
res should be(true)
}
It's not perfect but you could use should matchPattern
d should matchPattern {
case x:Element if x.count > 0 =>
case x:Element if x.value != "" =>
}

How to find an element in a tree using scala

How would I write the following Java code in Scala? The intention is to traverse a tree structure and return the first element that matches a predicate.
public class MyObject {
private String id;
private List<MyObject> children;
public MyObject findById(String otherId) {
if (this.id.equals(otherId)) {
return this;
} else {
for (MyObject child : children) {
MyObject found = child.findById(otherId);
if (found != null) {
return found;
}
}
return null;
}
}
}
The scala would look something like this but I don't know what to put in the else clause.
class MyObject(id: String, children: List[MyObject]) {
def findById(otherId: String): Option[MyObject] = {
if (this.id == otherId) {
Some(this)
} else {
//What goes here?
}
}
}
You should implement a tail recursive search, so you won't get a stack overflow:
class MyObject(val id: String, val children: List[MyObject]) {
def findById(otherId: String): Option[MyObject] = {
#tailrec
def recurseOverChildren(list: List[MyObject]): Option[MyObject] = {
list match {
case Nil => None
case head :: tail =>
if(head.id == otherId) Some(head)
else recurseOverChildren(tail ++ head.children)
}
}
recurseOverChildren(List(this))
}
}
The recursion is simple, we just check if the head of the list is the item we're searching for. If not we add it's children to the end of the list. If the list is empty the item is not in the tree. We initialize the search with a list containing one element: the element the function was invoked upon.
This will be a breadth first search, if you would like a depth first search then append the children in front of the list, not at the end.

In scala, check non nullity and apply method directly?

With the following definitions:
class Test {
var activated: Boolean = false
}
def maybeTest(): Test = {
if(...) {
val res = new Test
if(...) res.activated = true
} else null
}
I am having a lot of if structures like this one:
val myobject = maybeTest()
if(myobject != null && myobject.activated) {
// Do something that does not care about the object
}
I would like to condensate it a little bit. Is there a nice way to define/write something like this to avoid a nullPointerException:
if(maybeTest() &&> (_.activated)) {
...
}
What is a best way of achieving this in scala?
You can wrap such code in Option like this:
class Test(num: Int) {
def someNum = num
}
val test: Test = null
Option(test).map(t => t.someNum)
In this example if your variable is null then you will get None, otherwise just work with Some(value)
Update
If you don't want to use Option, then you can define such function
class Test(num: Int) {
def give = num
}
def ifDefAndTrue[T, K](obj: T)(ifTrue: T => Boolean)(then: => K) {
if (obj != null && ifTrue(obj))
then
}
In your case this look like this:
val test = new Test // assuming that activated is false
ifDefAndTrue(test)(_.activate) {
println("results in unit")
}
But it contains side effect and not functional
How about
for {m <- Option(maybeTest())
if m.activated
}
{
... // do something with non-null, activated, m
}
Found the best way with implicit classes, which properly handles the null case (although it might not be the most efficient way).
implicit class CheckNull[T](obj: T) {
def call(f: T => Unit): Unit = if(obj != null) f(obj) else ()
def is(f: T => Boolean): Boolean = if(obj != null) f(obj) else false
}
So I can write a type safe method and even calls:
if(maybeTest() is (_.activated)) {
...
}
myObjectMaybeNull call (_.pause())
Note that parenthesis around (_.activated) are necessary.

Scala - how to make val visible

I have this method
def example(something):something {
val c=List()
if(){
if(){
val a=List()
}
else{
val a=List()
}
}
//here a or b are not declared
c:::a
}
How to declare it and make it visible? I can not use var.
You can't make it visible outside declaration scope, so, maybe, try this:
def example(somthing):somthing{
val c = {
if (something) {
(0 to 10).toList
} else {
(0 to 5).toList
}
}
}
Almost Everything in Scala returns a value (the exception is for statements such as package declarations and imports)
if/else statements, pattern matches, etc. etc.
This means that your if/else block returns a value, and is especially keen to do so, very much like the ?: ternary operator in Java.
val foo = ... some integer ...
val bar = if(foo >= 0) "positive" else "negative"
Or using blocks:
val foo = ... some integer ...
val bar = if(foo >= 0) {
"positive"
} else {
"negative"
}
Nest 'em to your heart's content if you wish!
val foo2 = ... some other integer ...
val bar = if(foo >= 0) {
if(foo2 >= 0) {
"double positive"
} else {
"part-way there"
}
} else {
"foo was negative"
}
and even mix 'n' match styles:
println(
if(foo >= 0) {
if(foo2 >= 0) "double positive" else "part-way there"
} else {
"foo was negative"
}
)
In your particular case, you do not need the val a:
def example(something):something {
val c= yourListC ::: if(firstTest){
if(secondTest){
yourListA
}
else{
yourOtherListA
}
} else {
anAdequateEmptyList
}
}