Functional Programming with kotlin - avoiding var - kotlin

I am working with kotlin and functional programming to develop an api.I really could not figure out whether did i break any FP rules here by using here.
I have a following function which gives me customerNumber and bunch of other fields.
data class CustomerInfo(val customerNumber:String?=null,val accountNumber:String?=null,val email:String?=null)
and I have function with lot of conditions but conditions are same for all fields
fun getCustomerInfo(someDto:SomeDto,someOtherDto:SomeOtherDto,oneMoreDto:OneMoreDto):CustomerInfo
{
var customerNumber = someDto.id
var accountNo = someDto.accountNumber
var email = someDto.email
if(someCondition())
{
customerNumber= someOtherDto.id
accountNo = someOtherDto.accountNo
email = someOtherDto.email
}else if(someOtherConditiion)
{
customerNumber= oneMoreDto.id
accountNo = oneMoreDto.accountNo
email = oneMoreDto.email
}
//and many more conditions like this
return CustomerInfo(customerNumber,accountNo,email)
}
Is using var inside a functions is wrong?How can write this function without using var's here ?
I know i can return the dto every-time directly once the condition met,but i feel like using same dto in 10 conditions?Any help would be appreciated

There is nothing technically wrong in using var, because you are in a local scope of a function.
But you could avoid lots of boilerplate code like:
fun getCustomerInfo(someDto:SomeDto,someOtherDto:SomeOtherDto,oneMoreDto:OneMoreDto):CustomerInfo
{
return when {
someCondition() -> CustomerInfo(someOtherDto.id, someOtherDto.accountNumber, someOtherDto.email)
someOtherConditiion() -> CustomerInfo(oneMoreDto.id, oneMoreDto.accountNumber, oneMoreDto.email)
else -> CustomerInfo(someDto.id, someDto.accountNumber, someDto.email)
}
}
If all your (different) DTO's gets generated you could consider creating mapper extension functions for all of them:
// top-level functions
fun SomeDto.toConsumerInfo(): CustomerInfo = ConsumerInfor(id, accountNumber, email)
fun SomeOtherDto.toConsumerInfo(): CustomerInfo = ConsumerInfor(id, accountNumber, email)
fun OneMoreDto.toConsumerInfo(): CustomerInfo = ConsumerInfor(id, accountNumber, email)
// and more for other DTO's you want to map
Then you could use them like:
fun getCustomerInfo(someDto:SomeDto,someOtherDto:SomeOtherDto,oneMoreDto:OneMoreDto):CustomerInfo {
return when {
someCondition() -> someOtherDto.toConsumerInfo()
someOtherConditiion() -> oneMoreDto.toConsumerInfo()
else -> someDto.toConsumerInfo()
}

Related

How can I translate this Kotlin code into a better one using high order functions instead of a simple for

I have this function that receives a barcode and looks for a product in a list that has the same barcode. The split( ",") is because there are some products that have more than one barcode written like this: ("barcode1,barcode2")
Could someone help me get a better code using high order functions rather than this for loop?
fun Product.byBarcode(barcode: String?) : Product? {
val productsList = Realm.getDefaultInstance().where(Product::class.java).findAll().toMutableList()
var foundProduct : Product? = null
for (it in productsList){
if ( it.barcode.split(",").contains(barcode)){
foundProduct = it
break
}
}
return foundProduct
}
You can use find
foundProduct = productList.find{ it.barcode.split(',').contains(barcode) }
also I don't think split is really required, in that case
foundProduct = productList.find{ it.barcode.contains(barcode) }

Mono.zip with null

My code:
Mono.zip(
credentialService.getCredentials(connect.getACredentialsId()),
credentialService.getCredentials(connect.getBCredentialsId())
)
.flatMap(...
From the frontend we get connect object with 2 fields:
connect{
aCredentialsId : UUID //required
bCredentialsId : UUID //optional
}
So sometimes the second line credentialService.getCredentials(connect.getBCredentialsId())) can return Mono.empty
How to write code to be prepared for this empty Mono when my second field bCredentialsId is null?
What should I do? In case of empty values return Mono.just(new Object) and then check if obj.getValue != null??? I need to fetch data from DB for 2 different values
The strategy I prefer here is to declare an optional() utility method like so:
public class Utils {
public static <T> Mono<Optional<T>> optional(Mono<T> in) {
return in.map(Optional::of).switchIfEmpty(Mono.just(Optional.empty()));
}
}
...which then allows you to transform your second Mono to one that will always return an optional, and thus do something like:
Mono.zip(
credentialService.getCredentials(connect.getACredentialsId()),
credentialService.getCredentials(connect.getBCredentialsId()).transform(Utils::optional)
).map(e -> new Connect(e.getT1(), e.getT2()))
(...assuming you have a Connect object that takes an Optional as the second parameter of course.)
An easier way is using mono's defaultIfEmpty method.
Mono<String> m1 = credentialService.getCredentials(connect.getACredentialsId());
Mono<String> m2 = credentialService.getCredentials(connect.getBCredentialsId()).defaultIfEmpty("");
Mono.zip(m1, m2).map(t -> connectService.connect(t.getT1(), t.getT2()));
Explanation: if m2 is null then get empty string as a default value instead of null.
Instead of using .zip here, I would work with a nullable property of Connect and use .flatMap in combination with .switchIfEmpty for it.
Kotlin-Version:
val aCredentials = credentialService.getCredentials(connect.getACredentialsId())
credentialService.getCredentials(connect.getBCredentialsId())
.flatMap { bCredentials -> aCredentials
.map { Connect(it, bCredentials)}
.switchIfEmpty(Connect(null, bCredentials))
}
.switchIfEmpty { aCredentials.map { Connect(it, null) } }

Kotlin nested for loops to asSequence

I'm trying to convert my nested for loop to asSequence in Kotlin. Here, my goal is to get and update the value of all my object array from another object array with the same key.
nested for loop:
val myFields = getMyFields()
val otherFields = getOtherFields()
for (myField in myFields) { // loop tru the my fields
for (otherField in otherFields) { // find the same fields
if (myField.key == otherField.key) { // if the same, update the value
val updatedMyField = myField.copy(value = otherValue.value)
myFields[myFields.indexOf(myField)] = updatedMyField // update my field value
break
}
}
}
What I've tried:
val updatedMyFields = getMyFields().asSequence()
.map { myField ->
getOtherFields().asSequence()
.map { otherField ->
if (myField.key == otherField.key) {
return#map otherField.value
} else {
return#map ""
}
}
.filter { it?.isNotEmpty() == true }
.first()?.map { myField.copy(value = it.toString()) }
}
.toList()
but this does not compile as it will return List<List<MyField>>.
I'm just looking for something much cleaner for this.
As comments suggest, this would probably be much more efficient with a Map.
(More precisely, a map solution would take time proportional to the sum of the list lengths, while the nested for loop takes time proportional to their product — which gets bigger much faster.)
Here's one way of doing that:
val otherFields = getOtherFields().associate{ it.key to it.value }
val myFields = getMyFields().map {
val otherValue = otherFields[it.key]
if (otherValue != null) it.copy(value = otherValue) else it
}
The first line creates a Map from the ‘other fields’ keys to their values.  The rest then uses it to create a new list from ‘my fields’, substituting the values from the ‘other fields’ where present.
I've had to make assumptions about the types &c, since the code in the question is incomplete, but this should do the same.  Obviously, you can change how it merges the values by amending the it.copy().
There are likely to be even simpler and more efficient ways, depending on the surrounding code.  If you expanded it into a Minimal, Complete, and Verifiable Example — in particular, one that illustrates how you already use a Map, as per your comment — we might be able to suggest something better.
Why do you want to use asSequence() ? You can go for something like that:
val myFields = getMyFields()
val otherFields = getOtherFields()
myFields.forEach{firstField ->
otherFields.forEach{secondField ->
if (firstField.key == secondField.key) {
myFields[myFields.indexOf(firstField)] = secondField.value
}
}
}
This will do the same job than your nested for loop and it's easier to read, to understand and so to maintain than your nested asSequence().

Is it possible to parameterize queries or parameters for an Acolyte ScalaCompositeHandler?

Background:
I have attempted to accomplish the question defined here, and I have not been able to succeed. Acolyte requires you to define the queries and parameters you want to handle within a match expression, and the values used in match expressions must be known at compile time. (Note, however, that this StackOverflow answer appears to provide a way around this limitation).
If this is indeed not possible, the inability to dynamically define the parameters and queries for Acolyte would be, for my use case, a severe limitation of the framework. I suspect this would be a limitation for others as well.
One SO user who has advocated for the use of Acolyte across a handful of questions stated in this comment that it is possible to dynamically define queries and their responses. So, I have opened this question as an invitation for someone to show that to be the case.
Question:
Using Acolyte, I want to be able to encapsulate the logic for matching queries and generating their responses. This is a desired feature because I want to keep my code DRY. In other words, I am looking for something like the following pseudo-code:
def generateHandler(query: String, accountId: Int, parameters: Seq[String]): ScalaCompositeHandler = AcolyteDSL.handleQuery {
parameters.foreach(p =>
// Tell the handler to handle this specific parameter
case acolyte.jdbc.QueryExecution(query, ExecutedParameter(accountId) :: ExecutedParameter(p) :: Nil) =>
someResultFunction(p)
)
}
Is this possible in Acolyte? If so, please provide an example.
It is indeed possible to parameterize queries and/or parameters by utilizing pattern matching.
See the code below for an example:
import java.sql.DriverManager
import acolyte.jdbc._
import acolyte.jdbc.Implicits._
import org.scalatest.FunSpec
class AcolyteTest extends FunSpec {
describe("Using pattern matching to extract a query parameter") {
it("should extract the parameter and make it usable for dynamic result returning") {
val query = "SELECT someresult FROM someDB WHERE id = ?"
val rows = RowLists.rowList1(classOf[String] -> "someresult")
val handlerName = "testOneHandler"
val handler = AcolyteDSL.handleQuery {
case acolyte.jdbc.QueryExecution(`query`, ExecutedParameter(id) :: _) =>
rows.append(id.toString)
}
Driver.register(handlerName, handler)
val connection = DriverManager.getConnection(s"jdbc:acolyte:anything-you-want?handler=$handlerName")
val preparedStatement = connection.prepareStatement(query)
preparedStatement.setString(1, "hello world")
val resultSet = preparedStatement.executeQuery()
resultSet.next()
assertResult(resultSet.getString(1))("hello world")
}
it("should support a slightly more complex example") {
val firstResult = "The first result"
val secondResult = "The second result"
val query = "SELECT someresult FROM someDB WHERE id = ?"
val rows = RowLists.rowList1(classOf[String] -> "someresult")
val results: Map[String, RowList1.Impl[String]] = Map(
"one" -> rows.append(firstResult),
"two" -> rows.append(secondResult)
)
def getResult(parameter: String): QueryResult = {
results.get(parameter) match {
case Some(row) => row.asResult()
case _ => acolyte.jdbc.QueryResult.Nil
}
}
val handlerName = "testTwoHandler"
val handler = AcolyteDSL.handleQuery {
case acolyte.jdbc.QueryExecution(`query`, ExecutedParameter(id) :: _) =>
getResult(id.toString)
}
Driver.register(handlerName, handler)
val connection = DriverManager.getConnection(s"jdbc:acolyte:anything-you-want?handler=$handlerName")
val preparedStatement = connection.prepareStatement(query)
preparedStatement.setString(1, "one")
val resultSetOne = preparedStatement.executeQuery()
resultSetOne.next()
assertResult(resultSetOne.getString(1))(firstResult)
preparedStatement.setString(1, "two")
val resultSetTwo = preparedStatement.executeQuery()
resultSetTwo.next()
assertResult(resultSetTwo.getString(1))(secondResult)
}
}
}

Scala SQL DSL (Internal/External)

I have been looking into scala primarily on how to build DSL similar to C# LINQ/SQL. Having worked with C# LINQ Query provider, it was easy to introduce our own custom query provider which translated LINQ query to our own proprietary data store scripts. I am looking something similar in scala for eg.
val query = select Min(Close), Max(Close)
from StockPrices
where open > 0
First of all is this even possible to achieve in scala using internal DSL.
Any thoughts/ideas in this regard is highly appreciated.
I am still new in scala space, but started looking into Scala MetaProgramming & Slick. My complaint with Slick is i want to align my DSL close to SQL query - similar to above syntax.
There is no way to have an internal DSL (with the currently release) that looks exactly like the example you provided.
Using a macro I still had from this answer, the closest I could get (relatively fast) was:
select(Min(StockPrices.Open), Max(StockPrices.Open))
.from(StockPrices)
A real solution would take quite some time to create. If you are willing to do that you could come quite far using macro's (not a simple topic).
If you really want the exact same syntax I recommend something like XText that allows you to create a DSL with an eclipse based editor for 'free'.
The code required for the above example (I did not include the mentioned macro):
trait SqlElement {
def toString(): String
}
trait SqlMethod extends SqlElement {
protected val methodName: String
protected val arguments: Seq[String]
override def toString() = {
val argumentsString = arguments mkString ","
s"$methodName($argumentsString)"
}
}
case class Select(elements: Seq[SqlElement]) extends SqlElement {
override def toString() = s"SELECT ${elements mkString ", "}"
}
case class From(table: Metadata) extends SqlElement {
private val tableName = table.name
override def toString() = s"FROM $tableName"
}
case class Min(element: Metadata) extends SqlMethod {
val methodName = "Min"
val arguments = Seq(element.name)
}
case class Max(element: Metadata) extends SqlMethod {
val methodName = "Max"
val arguments = Seq(element.name)
}
class QueryBuilder(elements: Seq[SqlElement]) {
def this(element: SqlElement) = this(Seq(element))
def from(o: Metadata) = new QueryBuilder(elements :+ From(o))
def where(element: SqlElement) = new QueryBuilder(elements :+ element)
override def toString() = elements mkString ("\n")
}
def select(args: SqlElement*) = new QueryBuilder(Select(args))
trait Column
object Column extends Column
object tables {
object StockPrices$ {
val Open: Column = Column
val Close: Column = Column
}
val StockPrices = StockPrices$
}
And then to use it:
import tables._
import StockPrices._
select(Min(StockPrices.Open), Max(StockPrices.Open))
.from(StockPrices)
.toString
That is an admirable project, but one that has been embarked upon and which is available in general release.
I'm talking about Slick, of course.
If Scala / Java interoperability is not too much of an issue for you, and if you're willing to use an internal DSL with a couple of syntax quirks compared to the syntax you have suggested, then jOOQ is growing to be a popular alternative to Slick. An example from the jOOQ manual:
for (r <- e
select (
T_BOOK.ID * T_BOOK.AUTHOR_ID,
T_BOOK.ID + T_BOOK.AUTHOR_ID * 3 + 4,
T_BOOK.TITLE || " abc" || " xy"
)
from T_BOOK
leftOuterJoin (
select (x.ID, x.YEAR_OF_BIRTH)
from x
limit 1
asTable x.getName()
)
on T_BOOK.AUTHOR_ID === x.ID
where (T_BOOK.ID <> 2)
or (T_BOOK.TITLE in ("O Alquimista", "Brida"))
fetch
) {
println(r)
}