I want to do something like this (this is a made-up example to simplify my actual problem):
def findByGender(isMale: Option[Boolean]) = {
People.filter(row => row.name.isNotNull && isMale match {
case Some(true) => row.wife.isNotNull // find rows where wife column is not null
case Some(false) => row.wife.isNull // find rows where wife column is null
case None => true // select everything
})
}
This does not compile because of the last "true". Any better way to do this?
You have to make it a Column[Boolean]:
def findByGender(isMale: Option[Boolean]) = {
People.filter(row => row.name.isNotNull && isMale match {
case Some(true) => row.wife.isNotNull // find rows where wife column is not null
case Some(false) => row.wife.isNull // find rows where wife column is null
case None => LiteralColumn(true) // select everything
})
}
If you're using Slick 3.3.x you can use the following solution:
def findByGender(isMale: Option[Boolean]) =
People
.filter(_.name.isDefined)
.filterIf(isMale == Some(true))(_.wife.isDefined)
.filterIf(isMale == Some(false))(_.wife.isEmpty)
or
def findByGender(isMale: Option[Boolean]) =
People
.filter(_.name.isDefined)
.filterOpt(isMale) {
case (row, true) => row.wife.isDefined
case (row, false) => row.wife.isEmpty
}
There are 3 cases:
isMale is defined and equal Some(true)
Result SQL: select * from people when (name is not null) and (wife is not null);
isMale is defined and equal Some(false):
Result SQL: select * from people when (name is not null) and (wife is null);
isMale is empty
Result SQL: select * from people when name is not null;
Related
At first, get all the children comments in a subquery
val getChildCommentStatQuery =
Tbcomments
.filter(row =>
row.itargetid === commentTargetId && row.iparentid =!= 0 && row.istatus === statusNormal)
.groupBy(_.iparentid)
.map { case (parentId, group) =>
// return parent commentId,the number of all the children,and the sum of like of all the children
(parentId, group.size, group.map(_.ilikecount).sum)
}
Secondly, use Table Tbcomments to left join with subquery table got in the first step.
val query =
Tbcomments
.joinLeft(getChildCommentStatQuery)
.on(_.iid == _._1)
.filter { case (comments, _) =>
// got the first level comment whose parentid equals to 0
comments.itargetid === commentTargetId && comments.iparentid === 0 && comments.istatus === statusNormal
}
.map { case (comments, childComments) =>
val replyCount = childComments.map(_._2)
val likeCountSum = comments.ilikecount + childComments.map(_._3.getOrElse(0))
val hot = replyCount + likeCountSum
val support = comments.ilikecount - comments.inotlikecount
(comments.iid, replyCount, likeCountSum, hot, support, comments.dtcreated)
}
.sortBy(row =>
sortOrder match {
case LATEST_COMMENT_ORDER => row._6.desc
case EARLIEST_COMMENT_ORDER => row._6.asc
case SUPPORT_COMMENT_ORDER => row._5.desc
// case HEAT_COMMENT_ORDER => row._4.get
})
The problem is, the row._4 is a field aggregate based on right table, and in the left join case it's an option. It seems can't sortBy the option field directly.
Thanks!
I'm doing the following to map and update a list:
if (colors.map(_.id).contains(updated.id)) {
val newColorList = updated :: colors.filterNot(s => s.id == updated.id)
SomeMethod(newColorList)
}
else {
this
}
The above works ok, However, I want to add a condition such as this: If, and only if, the updated quantity is 0 then also update the enddate to todays date.
I've done the following
if (color.map(_.id).contains(updated.id) && updated.quantity == 0) {
val newColorList = updated.copy(enddate = Instant.now().toEpochMilli) :: colors.filterNot(s => s.id == updated.id)
}
else if (color.map(_.id).contains(updated.id)) {
val newColorList = updated :: colors.filterNot(s => s.id == updated.id)
SomeMethod(newColorList)
}
else {
this
}
Is there a better way to do this than multiple if / else statements
something like
val hasColor=color.map(_.id).contains(updated.id)
newColorList = (hasColor,updated.quantity) match {
case (true,0) => updated.copy(enddate = Instant.now().toEpochMilli) :: colors.filterNot(s => s.id == updated.id)
case (true,_) => updated :: colors.filterNot(s => s.id == updated.id)
otherwise => this
}
You can use collect over the colors collection.
I assume there is a simple a case class Color like this
case class Color(id:String, quantity: Int, endDate : LocalDate)
And updated is also of type Color
import java.time.LocalDate
case class Color(id:String, quantity: Int, endDate : LocalDate)
val updated = Color("one", 0, LocalDate.now)
val colors = List(
Color("one", 1, LocalDate.now().minusMonths(2)),
Color("two", 2, LocalDate.now.minusMonths(4)),
Color("three", 3, LocalDate.now.minusMonths(6))
)
colors.collect{
case e if e.id == updated.id && updated.quantity == 0 =>
updated.copy(endDate = LocalDate.now) //add element to new list, call method
case e if e.id == updated.id => updated
case e => e
}
//List(Color(one,0,2018-12-06), Color(two,2,2018-08-06), Color(two,2,2018-06-06))
Hope this helps you.
I wanted to get Sale objects from HBase concatenated with their HBase ids (a string representation of ImmutableBytesWritable) as Option[String].
First I've implemented processSales method so that it just returned all sales + hBase ids as shown below:
private def processSales (result: Result, hBaseId: String): Option[String] = {
val triedSale: Try[Sale] = myThriftCodec.invert(result.getValue("binary", "object"))
triedSale match {
case Success(sale) => Some(hBaseId + sale)
case _ => None
}
}
Now I want to return only those concatenated hBaseIds + Sales where Sales have metric_1 == null
So I tried the following:
private def processSales (result: Result, hBaseId: String): Any = {
val triedSale: Try[Sale] = myThriftCodec.invert(result.getValue("binary", "object"))
triedSale match {
case Success(sale) => Some(hBaseId + sale)
case _ => None
}
triedSale match {
case someSale => if (someSale.get.metric_1 = null) someSale.map(sale => hBaseId + sale)
}
}
But it seems that I'm missing something here and the method returns Any even if I wrap this like this Option(hBaseId + sale).
What should I fix in my logic in order to return Option[String] with sales having metric_1 == null ?
UPD: Downvoting without pointing out the problems with my question doesn't make sense. It just totally demotivates seeking new knowledge.
You are missing the second option of the match case in your else, so it's returning Unit when the metric is not null, so Unit in one case, and Option(String) in another, the compiler guess that you want Any as return type
What do you want to return when the metric_1 is not null? In this example you return the exact same input:
triedSale match {
case someSale => if (someSale.get.metric_1 = null) someSale.map(s => hBaseId + s) else someSale
}
Or in a more elegant way you can do:
triedSale match {
case Success(metric_1) if metric_1 = null => Some(hBaseId + metric_1)
case Success(metric_1) if metric_1 != null => triedSale
case _ => None
}
EDIT
As per the comments, you only want to return something when the metric_1 is null so here is the best solution as for my understanding:
Also why are you pattern matching the same variable twice?
triedSale match {
case someSale => if (someSale.get.metric_1 = null) someSale.map(s => hBaseId + s) else None
}
Or something like this:
triedSale match {
case Success(metric_1) if metric_1 = null => Some(hBaseId + metric_1)
case _ => None
}
Isn't just as simple as below?
myThriftCodec.invert(result.getValue("binary", "object"))
.toOption
.filter(_.metric_1 == null)
.map(hBaseId+_)
I have a task need to find a particular string in an array:
1. if found, return its value;
2. if not found, return -1.
I wrote an "idea" code, but I don't know how to finish it correctly.
case class person(name:String, value: Int)
personList[Array[person]]
val result = personList match {
case x if x.name == "john" => x.value
case _ => -1 }
the complier reports errors at "case x if x.name"
Would this work for you?
persons.find(_.name == "john").fold(-1)(_.value)
Note: I've left the creation and/or population of the persons array up to you.
val result = personList.find(_.name=="john") match {
case some(x) => x.value
case None => -1 }
I was trying to insert if not exists, and get the row if it does.
I come up with this:
def saveOrGet(u: User) = (for {
userGet <- get(u.name).map(r => (r.id, r.active)).result.headOption
id <- save(u) if userGet.isEmpty
} yield {
userGet match {
case Some((id, active)) => (User(Some(id), u.name, active), false)
case None => (User(Some(id), u.name, u.active), true)
}
}).transactionally
private def get(name: String) = users.filter(_.name === name).take(1)
private def save(u: User) = users returning users.map(_.id) += u
EDIT
After making some modifications, now I get:
java.util.NoSuchElementException: Action.withFilter failed
Regards
Try using case _, because it seems that it's possible to have something empty rather than None
userGet match {
case Some((id, active)) => (User(Some(id), u.name, active), false)
case _ => (User(Some(id), u.name, u.active), true)
}