I wrote this
def computeMap(map:Map[String, DataFrame], f: (String) => String, g: (DataFrame) => DataFrame ) : Map[String, DataFrame] = {
map.map{ case (key, value) => (f(key), g(value) }
}
My problem here is that f and g function are provided by 2 implicit classes wrapped in objects ( one implicit class for string transform and the second one is for dataframe transorm)
I rather want to write:
def computeMap(map:Map[String, DataFrame], f: tobecompleted, g: tobecompleted ) : Map[String, DataFrame] = {
map.map{ case (key, value) => (key.f, value.g) }
}
f for example can be defined
object Test {
implicit class Transform(s:String) {
def colm():String = {
s + "ded"
}
}
Is there any solution for this please ?
Related
I'm attempting to dynamically include a sortBy to my query which sorts based on its string name from a query parameter. In Slick 3 this has proven to be quite tricky. Currently my setup is:
trait Model {
type ATable <: AbstractTable[_]
def tableQuery: TableQuery[ATable]
def sortMap: Map[String, Rep[_]]
private def sortKey[T](e: ATable, sort: (String, SortOrder)): ColumnOrdered[_] = sort match {
case (field, SortOrder.Asc) => ColumnOrdered(sortMap.getOrElse(field, throw new ClientException(s"Can't sort by $field")), Ordering(Ordering.Asc))
case (field, SortOrder.Desc) => ColumnOrdered(sortMap.getOrElse(field, throw new ClientException(s"Can't sort by $field")), Ordering(Ordering.Desc))
}
def all(sort: (String, SortOrder)) = tableQuery.sortBy(sortKey(_, sort)).result
}
object User extends Model {
type ATable = Tables.User
val tableQuery = Tables.User
val sortMap = Map( "id" -> tableQuery.id )
}
But running db.run(User.all(("id", SortOrder.Asc)) throws the following error:
slick.SlickException: No type for symbol name found in Vector[t2<#t3<UnassignedType>>]
Does anyone know of a better solution or where I'm going wrong?
The way I solved this was to change my sortMap to contain the table type with column type implicit (from Map[String, Rep[_]] to Map[String, ATable => Rep[_]]):
trait Model {
type ATable <: AbstractTable[_]
def tableQuery: TableQuery[ATable]
def sortMap: Map[String, ATable => Rep[_]]
private def sortKey(baseQ: Query[ATable, ATable#TableElementType, Seq], sort: (String, SortOrder)) = {
val rep = sortMap.getOrElse(sort._1, throw new ClientException(s"Can't sort by ${sort._1}"))
val orderedRep = sort._2 match {
case SortOrder.Asc => (t: ATable) => ColumnOrdered(rep(t), slick.ast.Ordering(slick.ast.Ordering.Asc))
case SortOrder.Desc => (t: ATable) => ColumnOrdered(rep(t), slick.ast.Ordering(slick.ast.Ordering.Desc))
}
q.sortBy(orderedRep)
}
def all(sort: (String, SortOrder)) = sortKey(tableQuery, sort).result
}
object User extends Model {
type ATable = Tables.User
val tableQuery = Tables.User
val sortMap = Map( "id" -> { (t: ATable) => t.id } )
}
The only suboptimal aspect of this solution is that if a new column is added to the database it has to be manually added to the sortKey. I'm looking into including these maps in the table code generation scripts.
You just need to include in generation something like
val columns = Map( "id" -> { (t: User) => t.id } )
and use it like so:
class UserDAO{
//...
baseQuery = filterContext.sort.foldLeft[Query[User, UserRow, Seq]](User) ((_, s) => UserColumnFilter.getSort(s,User.baseTableRow.columns));
//...
}
case class Sort(columnName:String,value: String) {}
case class FilterContext(filters:List[Filter],page:Int,pageSize:Int,sort:List[Sort])
object UserColumnSort extends ColumnSort[User,UserRow](User)
class ColumnSort[T<:Table[C],C](query:TableQuery[T])
{
def getSort(s:Sort,columns:Map[String, T => Rep[_]]):Query[T, C, Seq] = {
val aux = columns.getOrElse(s.columnName, throw new Exception(s"Can't sort by ${s.columnName}"));
val orderedRep = s.value match {
case "asc" => (t: T) => ColumnOrdered(aux(t), slick.ast.Ordering(slick.ast.Ordering.Asc))
case _ => (t: T) => ColumnOrdered(aux(t), slick.ast.Ordering(slick.ast.Ordering.Desc))
}
return query.sortBy(orderedRep);
}
}
Let's consider a classification problem :
object Classify extends App {
type Tag = String
type Classifier[A] = A => Set[Tag]
case class Model(a: Int, b: String, c: String, d: String)
def aClassifier : Classifier[Int] = _ => Set("A", "a")
def bClassifier : Classifier[String] = _ => Set("B")
def cClassifier : Classifier[String] = _ => Set("C")
def modelClassifier : Classifier[Model] = {
m => aClassifier(m.a) ++ bClassifier(m.b) ++ cClassifier(m.c)
}
println(modelClassifier(Model(1,"b", "c", "d")))
}
Is there a smarter way to implement modelClassifier using scalaz ?
As an idea, consider this code:
for (i <- 0 until model.productArity) yield {
val fieldValue = model.productElement(i)
fieldValue match {
case x: Int => //use integer classifier
case s: String => //use string classifier
case _ =>
}
}
scalaz library hasn't any macro case class introspection by design, but shapeless has
Consider such definitions:
import shapeless._
import shapeless.tag._
import shapeless.labelled._
trait Omit
val omit = tag[Omit]
case class Model(a: Int, b: String, c: String, d: String ## Omit)
Let define following polymorphic function
object classifiers extends Poly1 {
implicit def stringClassifier[K <: Symbol](implicit witness: Witness.Aux[K]) =
at[FieldType[K, String]](value => Set(witness.value.name.toUpperCase))
implicit def intClassifier[K <: Symbol](implicit witness: Witness.Aux[K]) =
at[FieldType[K, Int]](value => {
val name = witness.value.name
Set(name.toUpperCase, name.toLowerCase)
})
implicit def omitClassifier[K, T] =
at[FieldType[K, T ## Omit]](_ => Set.empty[String])
}
Now your modelClassifier could be done as:
def modelClassifier: Classifier[Model] =
m => LabelledGeneric[Model].to(m).map(classifiers).toList.reduce(_ union _)
you can check it via
println(modelClassifier(Model(1, "b", "c", omit("d"))))
Note that Type ## Tag is subtype of Type so model.d still could be used as String everywhere
How do you intend to distinguish between bClassifier and cClassifier? By name? By order of declaration? That does not sound very "smart" or reliable. Consider encoding your intent explicitly instead. Something like this, perhaps:
case class Classifiable[T](data: T, classifier: Classifier[T])
object Classifiable {
def Null[T](data: T) = Classifiable(data, _ => Nil)
}
case class Model(a: Classifiable[Int], b: Classifiable[String], c: Classifiable[String], d: Classifiable[String])
object Model {
def apply(a: Int, b: String, c: String, d: String) =
Model(
Classifiable(a, aClassifier),
Classifiable(b, bClassifier),
Classifiable(c, cClassifier),
Classifiable.Null(d)
)
}
def modelClassifier(m: Model) = m
.productIterator
.collect { case x: Classifiable[_] =>
x.classifier()(x)
}
.reduce(_ ++ _)
println(modelClassifier(Model(1,"b", "c", "d")))
More specifically, I have:
case class Key (key: String)
abstract class abstr {
type MethodMap = PartialFunction[Key, String => Unit]
def myMap: MethodMap // abstract
def useIt (key: Key, value: String) = {
val meth = myMap(key)
meth(value)
}
def report = {
for (key <- myMap.keySet) // how to do this
println("I support "+key)
}
}
I use it like this:
class concrete extends abstr {
var one: Boolean
def method1(v: String): Unit = ???
def method2(v: String): Unit = ???
def map1: MethodMap = {
case Key("AAA") => method1
}
def map2: MethodMap = {
case Key("AAA") => method2
}
override def myMap: MethodMap = if (one) map1 else map2
}
Of course, this is somewhat simplified, but the report function is necessary.
Some history: I first had it implemented using Map but then I changed it to PartialFunction in order to support the following override def myMap: MethodMap = if (one) map1 else map2.
Any suggestion to refactor my code to support everything is also appreciated.
No. PartialFunction can be defined (and often is) on infinite sets. E.g. what do you expect report to return in these situations:
class concrete2 extends abstr {
def myMap = { case Key(_) => ??? }
}
or
class concrete2 extends abstr {
def myMap = { case Key(key) if key.length > 3 => ??? }
}
? If you have a finite list of values you are interested in, you can do
abstract class abstr {
type MethodMap = PartialFunction[Key, String => Unit]
def myMap: MethodMap // abstract
val keys: Seq[Key] = ...
def report = {
for (key <- keys if myMap.isDefined(key))
println("I support "+key)
}
}
Some history: I first had it implemented using Map but then I changed it to PartialFunction in order to support the last line in second part.
Why? This would work just as well with Map.
In your solution, is there any way to define the domain of the partial function to be the finite set keys
def f: MethodMap = { case key if keys.contains(key) => ... }
Of course, the domain isn't part of the type.
Here I create a List of objects where each element is of type (String , () => Unit)
case class FunctionDesc(label: String, fun: () => Unit)
def f() = {
println("in f")
}
val functionList = List[FunctionDesc](FunctionDesc("a1", f), FunctionDesc("a2", f))
functionList.foreach(f => f.fun())
This works fine but if I want to modify the function List to contain a parameter then have to decide what the parameter value
should be when the function is being implemented :
case class FunctionDesc2(label: String, fun: (String) => Unit)
def f2(str: String) = {
println("in f2")
}
def f3(str: String) = {
println("in f3")
}
val functionList2 = List[FunctionDesc2](FunctionDesc2("a3", f2), FunctionDesc2("a4", f3))
functionList2.foreach(f => f.fun("param value"))
Can decide what the function parameter type should before it's invoked ?
So instead of
val functionList2 = List[FunctionDesc2](FunctionDesc2("a3", f2), FunctionDesc2("a4", f3))
use something like :
val functionList2 = List[FunctionDesc2](FunctionDesc2("a3", f2("f5")), FunctionDesc2("a4", f2("f6"))
You can achieve this by making f2 and f3 return a function. Here's a simplified version:
case class FunctionDesc2(label: String, fun: (String) => Unit)
// `f` closes over `str` and returns a function from `String` to `Unit`
def f(str: String) = (s: String) => println(s"$str: $s")
val functionList = List(FunctionDesc2("a", f("foo")), FunctionDesc2("b", f("bar")))
functionList.foreach(_.fun("value"))
// foo: value
// bar: value
You can use currying:
scala> case class FunctionDesc2(label: String, fun: () => Unit)
defined class FunctionDesc2
scala> def f2(str: String)(): Unit = {
| println("in f2")
| }
f2: (str: String)()Unit
scala> def f3(str: String)(): Unit = {
| println("in f3")
| }
f3: (str: String)()Unit
scala> val functionList2 = List[FunctionDesc2](FunctionDesc2("a3", f2("f5")), FunctionDesc2("a4", f3("f6")))
functionList2: List[FunctionDesc2] = List(FunctionDesc2(a3,<function0>), FunctionDesc2(a4,<function0>))
scala> functionList2.foreach(desc => desc.fun())
in f2
in f3
I want to convert a partial function into a "safe" partial function, i.e. PartialFunction[T,R] into a PartialFunction[T,Try[R]], is there any better way than the following implementation?
def safe[T,R](pf:PartialFunction[T,R]):PartialFunction[T,Try[R]]=new PartialFunction[T, Try[R]]{
def isDefinedAt(t:T) = pf.isDefinedAt(t)
def apply(t:T) = Try(pf.apply(t))
}
You can define safe using a for expression:
def safe[T,R](pf:PartialFunction[T,R]) = PartialFunction {
(t:T) => for(a <- Try(pf(t))) yield a
}
Or using an implicit class:
object SafeImplicit {
implicit class Safe[T,R](pf: PartialFunction[T,R]){
def safe(t: =>T) = for(a<-Try(pf(t))) yield a
}
}
import SafeImplicit.Safe
def f: PartialFunction[Int, String] = {case 1 => "one"}
def g: PartialFunction[Int, String] = {case 1 => "a".toInt;"one"}
f.safe(1) // Success(one)
f.safe(2) // Failure(scala.MatchError: 2 ...)
f.safe("a".toInt) // Failure(java.lang.NumberFormatException ...)
g.safe(1) // Failure(java.lang.NumberFormatException ...)