I am using Slick 2.1.0 with Scala 2.10.
I have a value object (EMail) that I map to a VARCHAR column.
object EMail {
import java.util.regex.Pattern
val emailRegex = Pattern.compile("^[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE)
val empty = EMail("x#y.com")
}
case class EMail(value: String) extends AnyVal with MappedTo[String] {
def isValid: Boolean = EMail.emailRegex.matcher(value).find
def validate: EMail = {
assert(isValid)
EMail(value.trim.toLowerCase)
}
override def toString = validate.value
}
The Column definition is:
def email = column[Option[EMail]]("email_address")
This is my attempt at writing a finder:
def findByEmail(email: Option[EMail]): Option[User] =
database.withSession { implicit session: Session =>
queryAll.filter(e => e.email.isDefined && e.email === email).firstOption
}
This is the error message I get:
[error] Users.scala:52: ambiguous implicit values:
[error] both value BooleanCanBeQueryCondition in object CanBeQueryCondition of type => scala.slick.lifted.CanBeQueryCondition[Boolean]
[error] and value BooleanOptionColumnCanBeQueryCondition in object CanBeQueryCondition of type => scala.slick.lifted.CanBeQueryCondition[scala.slick.lifted.Column[Option[Boolean]]]
[error] match expected type scala.slick.lifted.CanBeQueryCondition[Nothing]
[error] queryAll.filter(_.email === email.map(_.value)).firstOption
[error] ^
You don't have to pass an Option[EMail] to your method, you could simply make:
def findByEmail(email: EMail): Option[User] = {
database.withSession { implicit session =>
queryAll.filter(_.email === email).firstOption
}
}
If you really need an Option[EMail]] as the input parameter, you should try the following:
def findByEmail(emailOpt: Option[EMail]): Option[User] = {
emailOpt.flatMap { email =>
database.withSession { implicit session =>
queryAll.filter(_.email === email).firstOption
}
}
}
Related
I have a case class like this
case class OffboardingError1(
userId: Option[String],
error: OffboardingErrorType1
)
object OffboardingError1 {
implicit val encode: Encoder[OffboardingError1] = deriveEncoder[OffboardingError1]
implicit val decode: Decoder[OffboardingError1] = deriveDecoder[OffboardingError1]
implicit val codecJson: CodecJson[OffboardingError1] = CodecJson.derive[OffboardingError1]
implicit val schema: Schema[OffboardingError1] = implicitly[Derived[Schema[OffboardingError1]]].value
}
OffboardingErrorType1 is defined as below:
trait OffboardingErrorType1 {
val name: String
val message: String
}
object OffboardingErrorType1 {
case class UnknownError1(name: String = "UnknownError", message: String) extends OffboardingErrorType1
case class S3ImageFindError1(name: String = "S3ImageFindError", message: String) extends OffboardingErrorType1
def getErrorTypeFromString(name: String, errorMessage: String): Option[OffboardingErrorType1] = name match {
case "UnknownError" => Some(UnknownError1(message = errorMessage))
case "S3ImageFindError" => Some(S3ImageFindError1(message = errorMessage))
case _ => None
}
implicit val encoder: Encoder[OffboardingErrorType1] = {
(offBoardingTypeError: OffboardingErrorType1) =>
Json.obj(
("name", offBoardingTypeError.name.asJson),
("message", offBoardingTypeError.message.asJson)
)
}
implicit val decoder: Decoder[OffboardingErrorType1] = {
c =>
for {
name <- c.downField("name").as[String]
errorMessage <- c.downField("message").as[String]
} yield getErrorTypeFromString(name, errorMessage) match {
case Some(cType) => cType
case _ => throw new IllegalArgumentException(s"bad name for offboarding error type: [${name}]")
}
}
implicit val codec: CodecJson[OffboardingErrorType1] = {
import argonaut._
import Argonaut._
CodecJson(
(errorType: OffboardingErrorType1) =>
("name" := errorType.name) ->:
("message" := errorType.message) ->:
jEmptyObject,
c => for {
name <- c.downField("name").as[String]
message <- c.downField("message").as[String]
result <- getErrorTypeFromString(name, message).fold(
DecodeResult.fail[OffboardingErrorType1](s"bad name for offboarding error type: [${name}]", CursorHistory.empty)
)(DecodeResult.ok)
} yield result
)
}
}
I am using tapir for end point , the code is like this
val coursePlanCreationJob: Endpoint[(String, CoursePlanCreationRequest), ServiceThrowable, JobInfo1, Nothing] =
V1Endpoint.v1Endpoint
.post
.description("create a coursePlan")
.in("courses" / "type" / "create-courseplan")
.in(jsonBody[CoursePlanCreationRequest])
.out(jsonBody[OffboardingError1])
the set compile gives me error could not find implicit value for parameter e: sttp.tapir.generic.Derived[sttp.tapir.Schema[io.ctek.services.palpatine.model.response.OffboardingError1]]
[error] implicit val schema: Schema[OffboardingError1] = implicitly[Derived[Schema[OffboardingError1]]].valueI am guessing it's because of "OffboardingErrorType1" trait. Anyone knows how to write Schema for this type of trait?
I'm puzzled by the compile error for the line that defines endState. Here is the code:
import java.util.UUID
object Evaluation {
def default: Evaluation[Unit, Unit] = new Evaluation[Unit, Unit](identity)
}
case class Evaluation[From, +To](evaluate: (From) => To)
object FSMLike {
val uuidEmpty: UUID = new UUID(0L, 0L)
val endState: Evaluation[Unit, FSMLike[Nothing]] = new Evaluation(() => FSMEmpty)
lazy val stop: FSMEntry[Unit, Unit, Nothing] = FSMEntry(uuidEmpty, Evaluation.default, endState)
def apply[From1, From2, To](
action: Evaluation[From1, Unit],
nextState: Evaluation[From2, FSMLike[To]]
): (UUID, FSMLike[To]) = {
val uuid = UUID.randomUUID
uuid -> FSMEntry(uuid, action, nextState)
}
}
sealed trait FSMLike[+A]
case object FSMEmpty extends FSMLike[Nothing]
case class FSMEntry[From1, From2, +To](
id: UUID,
action: Evaluation[From1, Unit],
nextState: Evaluation[From2, FSMLike[To]]
) extends FSMLike[To] {
def transition(arg1: From1, arg2: From2): FSMLike[To] = {
action.evaluate(arg1)
nextState.evaluate(arg2)
}
override def toString: String = s"^$id^"
}
Here is the error:
Error:(14, 72) type mismatch;
found : () => FSMEmpty.type (with underlying type () => FSMEmpty.type)
required: Unit => FSMLike[Nothing]
val endState: Evaluation[Unit, FSMLike[Nothing]] = new Evaluation(() => FSMEmpty)
You are trying to pass () => FSMEmpty, a function with no arguments, where a function with one argument of type Unit is expected. Sure, when you use () as an expression, it's the only value of type Unit, but the left-hand side of => isn't an expression.
You should write _ => FSMEmpty instead. { case () => FSMEmpty } would work as well, I think, but there isn't much point to using it.
Do i have a misunderstanding how implciits work in Scala - given the following trait in Scala,
trait hasConfig {
implicit def string2array(s: java.lang.String): Array[String] = {
LoadedProperties.getList(s)
}
implicit def string2boolean(s: java.lang.String) : java.lang.Boolean = {
s.toLowerCase() match {
case "true" => true
case "false" => false
}
}
var config: Properties = new Properties()
def getConfigs : Properties = config
def loadConfigs(prop:Properties) : Properties = {
config = prop
config
}
def getConfigAs[T](key:String):T = {
if (hasConfig(key)) {
val value : T = config.getProperty(key).asInstanceOf[T]
value
}
else throw new Exception("Key not found in config")
}
def hasConfig(key: String): Boolean = {
config.containsKey(k)
}
}
Though java.util.properties contains (String, String) key value pairs, I expect the following code to work due to the implicit converstion defined,
class hasConfigTest extends FunSuite {
val recModel = new Object with hasConfig
//val prop = LoadedProperties.fromFile("test") Read properties from some file
recModel.loadConfigs(prop)
test("test string paramater") {
assert(recModel.getConfigAs[String]("application.id").equals("framework"))
}
test("test boolean paramater") {
assert(recModel.getConfigAs[Boolean]("framework.booleanvalue") == true)
//Property file contains framework.booleanvalue=true
//expected to return java.lang.boolean, get java.lang.string
}
}
However, I get the following error,
java.lang.String cannot be cast to java.lang.Boolean
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
Why is the implcit conversion not taking care of this?
It doesn't work because casting (asInstanceOf) is something entirely different than implicit conversions. There are multiple ways in which you can solve this.
Implicit conversion
If you want to use the hardcore implicit conversions magic you should rewrite you getConfigAs method like this:
def getConfig(key:String): String = {
if (hasConfig(key)) {
val value: String = config.getProperty(key)
value
}
else throw new Exception("Key not found in config")
}
You will have to import the conversions into the current scope when you use getConfig.
val recModel = new Object with hasConfig
import recModel._
recModel.loadConfigs(prop)
val value: Boolean = recModel.getConfig("framework.booleanvalue")
Implicit parameters
A better way would be to keep your current API, but then you will have to introduce an implicit parameter because the implementation of getConfigAs needs access to the conversion.
def getConfigAs[T](key:String)(implicit conv: String => T): T = {
if (hasConfig(key)) {
val value: String = config.getProperty(key)
value
}
else throw new Exception("Key not found in config")
}
You will still need to import the necessary conversions at the use site though.
val recModel = new Object with hasConfig
import recModel._
recModel.loadConfigs(prop)
val value = recModel.getConfigAs[Boolean]("framework.booleanvalue")
Typeclasses
A way to avoid having to import your conversions (and possibly implicitly converting all kinds of Strings by accident) is to introduce a new type to encode your conversions. Then you can implement the conversions in its companion object, where implicit search can find them without importing them.
trait Converter[To]{
def convert(s: String): To
}
object Converter {
implicit val string2array: Converter[Array[String]] = new Converter[Array[String]] {
def convert(s: String): Array[String] =
LoadedProperties.getList(s)
}
implicit val string2boolean: Converter[Boolean] = new Converter[Boolean] {
def convert(s: String): Boolean =
s.toLowerCase() match {
case "true" => true
case "false" => false
}
}
}
Then you can change your getConfigAs method.
def getConfigAs[T](key:String)(implicit conv: Converter[T]): T = {
if (hasConfig(key)) {
val value: String = config.getProperty(key)
conv.convert(value)
}
else throw new Exception("Key not found in config")
}
And use it.
val recModel = new Object with hasConfig
recModel.loadConfigs(prop)
val value = recModel.getConfigAs[Boolean]("framework.booleanvalue")
You might also want to take a look over here.
Implicit conversions should be defined in scope, for example in enclosing object or imported into the current scope. In your case they should be defined in scope of the hasConfigTest class.
http://docs.scala-lang.org/tutorials/FAQ/finding-implicits
Here's a simple reproducible example:
object m {
implicit def string2boolean(s: String): Boolean = {
s.toLowerCase() match {
case "true" => true
case "false" => false
}
} //> string2boolean: (s: String)Boolean
println(false || "true") //> true
println(false || "false") //> false
}
I think what you are trying to say, is something like this:
import java.util.Properties
object LoadedProperties {
def getList(s: String): Array[String] = Array.empty
}
object hasConfig {
sealed trait ConfigReader[T] {
def read(conf: String): T
}
implicit object BooleanConfigReader extends ConfigReader[Boolean] {
override def read(conf: String): Boolean = conf.toLowerCase() match {
case "true" => true
case "false" => false
}
}
implicit object ArrayConfigReader extends ConfigReader[Array[String]] {
override def read(s: String): Array[String] = {
LoadedProperties.getList(s)
}
}
var config: Properties = new Properties()
def getConfigs: Properties = config
def loadConfigs(prop: Properties): Properties = {
config = prop
config
}
def getConfigAs[T](key: String)(implicit reader: ConfigReader[T]): T = {
val prop = config.getProperty(key)
if (prop == null)
throw new Exception("Key not found in config")
reader.read(prop)
}
}
val props = new Properties()
props.setProperty("a", "false")
props.setProperty("b", "some")
hasConfig.loadConfigs(props)
hasConfig.getConfigAs[Boolean]("a")
hasConfig.getConfigAs[Array[String]]("a")
Already asked at scala-user, didn't get an answer.
I expect the below to compile:
trait Elems {
trait Dummy
abstract class Elem[A] extends Serializable with Dummy
class BaseElem[A] extends Elem[A]
implicit val BooleanElement: Elem[Boolean] = new BaseElem[Boolean]
implicit val ByteElement: Elem[Byte] = new BaseElem[Byte]
implicit val ShortElement: Elem[Short] = new BaseElem[Short]
implicit val IntElement: Elem[Int] = new BaseElem[Int]
implicit val LongElement: Elem[Long] = new BaseElem[Long]
implicit val FloatElement: Elem[Float] = new BaseElem[Float]
implicit val DoubleElement: Elem[Double] = new BaseElem[Double]
implicit val UnitElement: Elem[Unit] = new BaseElem[Unit]
implicit val StringElement: Elem[String] = new BaseElem[String]
implicit val CharElement: Elem[Char] = new BaseElem[Char]
}
trait GoodMatch { self: Elems =>
private def boxed_class(e: Elem[_]): Class[_] = e match {
case BooleanElement => classOf[java.lang.Boolean]
case ByteElement => classOf[java.lang.Byte]
case ShortElement => classOf[java.lang.Short]
case IntElement => classOf[java.lang.Integer]
case LongElement => classOf[java.lang.Long]
case FloatElement => classOf[java.lang.Float]
case DoubleElement => classOf[java.lang.Double]
case CharElement => classOf[java.lang.Character]
case _ => ???
}
}
abstract class BadMatch[+A <: Elems](scalan: A) {
import scalan._
protected def toLuaValue(x: Any, eX: Elem[_]): String = eX match {
case UnitElement => ""
case _ => ???
}
// should check type before conversion?
protected def fromLuaValue[B](lv: Any, eA: Elem[B]): B = (eA match {
case UnitElement => ()
}).asInstanceOf[B]
}
And GoodMatch does, but BadMatch fails (in Scala 2.11.8):
[error] /tmp/rendererqu0xjasKpX/src/main/scala/test.scala:48: type mismatch;
[error] found : BadMatch.this.scalan.Elem[Unit]
[error] required: BadMatch.this.scalan.Elem[_$3] where type _$3
[error] case UnitElement => ""
[error] ^
[error] /tmp/rendererqu0xjasKpX/src/main/scala/test.scala:63: type mismatch;
[error] found : BadMatch.this.scalan.Elem[Unit]
[error] required: BadMatch.this.scalan.Elem[B]
[error] case UnitElement => ()
[error] ^
Removing with Dummy makes BadMatch compile as well.
Is this a Scala bug? If so, is it a known one?
Yes, it's a Scala compiler bug: https://issues.scala-lang.org/browse/SI-9779.
Long story short, I'm trying to figure out how to define a function from a generic input to a single-typed output.
The background: This is a continuation of Mapping over Shapeless record. After Travis's excellent answer, I now have the following:
import shapeless._
import poly._
import syntax.singleton._
import record._
type QueryParams = Map[String, Seq[String]]
trait RequestParam[T] {
def value: T
/** Convert value back to a query parameter representation */
def toQueryParams: Seq[(String, String)]
/** Mark this parameter for auto-propagation in new URLs */
def propagate: Boolean
protected def queryStringPresent(qs: String, allParams: QueryParams): Boolean = allParams.get(qs).nonEmpty
}
type RequestParamBuilder[T] = QueryParams => RequestParam[T]
def booleanRequestParam(paramName: String, willPropagate: Boolean): RequestParamBuilder[Boolean] = { params =>
new RequestParam[Boolean] {
def propagate: Boolean = willPropagate
def value: Boolean = queryStringPresent(paramName, params)
def toQueryParams: Seq[(String, String)] = Seq(paramName -> "true").filter(_ => value)
}
}
def stringRequestParam(paramName: String, willPropagate: Boolean): RequestParamBuilder[Option[String]] = { params =>
new RequestParam[Option[String]] {
def propagate: Boolean = willPropagate
def value: Option[String] = params.get(paramName).flatMap(_.headOption)
def toQueryParams: Seq[(String, String)] = value.map(paramName -> _).toSeq
}
}
In reality, the following would be a class constructor that takes this Map read from the query string as a parameter, but for simplicity's sake, I'm just defining a val:
val requestParams = Map("no_ads" -> Seq("true"), "edition" -> Seq("us"))
// In reality, there are many more possible parameters, but this is simplified
val options = ('adsDebug ->> booleanRequestParam("ads_debug", true)) ::
('hideAds ->> booleanRequestParam("no_ads", true)) ::
('edition ->> stringRequestParam("edition", false)) ::
HNil
object bind extends FieldPoly {
implicit def rpb[T, K](implicit witness: Witness.Aux[K]): Case.Aux[
FieldType[K, RequestParamBuilder[T]],
FieldType[K, RequestParam[T]]
] = atField(witness)(_(requestParams))
}
// Create queryable option values record by binding the request parameters
val boundOptions = options.map(bind)
This lets me do:
boundOptions.get('hideAds).value // -> true
The problem: Now I want to be able to reserialize options that have propagate = true. So basically, I need to filter my HList on the propagate field of every member, which should always return a Boolean, and then have each parameter reserialize itself to a Seq[(String, String)]. I've tried the following:
object propagateFilter extends (RequestParam ~> Const[Boolean]) {
override def apply[T](r: RequestParam[T]): Boolean = r.propagate
}
object unbind extends (RequestParam ~> Const[Seq[(String, String)]]) {
override def apply[T](r: RequestParam[T]): Seq[(String, String)] = r.toQueryParams
}
// Reserialize a query string for options that should be propagated
val propagatedParams = boundOptions.values.filter(propagateFilter).map(unbind).toList
// (followed by conventional collections methods)
, but it doesn't like my functions. I got the following error:
<console>:31: error: type mismatch;
found : Boolean
required: shapeless.Const[T]
(which expands to) AnyRef{type λ[T] = T}
override def apply[T](r: RequestParam[T]) = r.propagate
I believe I'm taking the wrong approach to a function that's supposed to have a polymorphic input but monomorphic output.
Other failed attempts:
object propagateFilter extends Poly1 {
implicit def default[T](implicit st: Case.Aux[RequestParam[T], Boolean]) = at[RequestParam[T]](_.propagate)
}
and
def propagate[T](x: RequestParam[T]): Boolean = x.propagate
and
object propagateFilter extends Poly1 {
implicit def default = at[RequestParam[_]](_.propagate)
}
and
object propagateFilter extends FieldPoly {
implicit def rpb[T, K](implicit witness: Witness.Aux[K]): Case.Aux[
FieldType[K, RequestParam[T]],
Boolean
] = atField(witness)(_.propagate)
}
None of which work, probably due to my own misunderstanding of what's going on.