Я пытаюсь понять, как создать неявный конвертер для определенного типа. В моем случае, это было бы Set[IdParam[T]]
к Set[IdTag[T]]
, гдеScala неявные преобразователи
import [email protected]@
case class IdParam[T](value: IdTag[T])
type IdTag[T] = Id @@ T
class Id(val value: Long)
object Id {
def tag[T](l: Long) = shapeless.tag[T][Id](new Id(l))
def value[T](l: Long) = Id.tag[T](l)
}
Я написал простой
implicit def toIds[T](idParams: Set[IdParam[T]]): Set[IdTag[T]] = idParams.map(_.value)
, который работает нормально. Но теперь мой главный вопрос заключается в том, есть ли способ создать неявный конвертер, который будет охватывать как Seq, так и Set. Поднимая иерархию, это означало бы Итерабельность. Пробовал следующие
implicit def toIds[I <: Iterable[IdParam[T]], T](idParams: I): Iterable[IdTag[T]] = idParams.map(_.value)
компилятор отказывается принимать этот конвертер, где это необходимо.
[error] found : Set[tags.IdParam[tags.ProfileIdTag]]
[error] required: Set[tags.ProfileId]
[error] (which expands to) Set[model.Id with shapeless.tag.Tagged[tags.ProfileIdTag]]
EDIT Это неявный преобразователь должен быть использован в конечной точке контроллера.
GET /campaigns @dummy.Campaigns.all(profileId: Set[IdParam[ProfileIdTag]] ?= Set.empty)
У меня есть QueryStringBindable, который преобразует из параметров запроса найденных в виде строки в Set[IdParam[A]]
object IdQueryStringBinder {
implicit def idParamQueryStringBinder[A](implicit stringBinder: QueryStringBindable[String]) =
new QueryStringBindable[IdParam[A]] {
def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, IdParam[A]]] =
for {
idEither <- stringBinder.bind(key, params)
} yield {
idEither match {
case Right(idString) =>
IdBinder.parseIdString(idString)
case Left(_) => Left("Unable to bind an Id")
}
}
override def unbind(key: String, id: IdParam[A]): String =
stringBinder.unbind(key, id.value.toString)
}
implicit def idsParamQueryStringBinder[A](implicit stringBinder: QueryStringBindable[String]) =
new QueryStringBindable[Set[IdParam[A]]] {
override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, Set[IdParam[A]]]] = {
stringBinder.bind(key, params).map(_.right.flatMap(parse))
}
private def parse(idsString: String): Either[String, Set[IdParam[A]]] = {
val (wrongIds, correctIds) = idsString.split(",")
.map(id => IdBinder.parseIdString[A](id))
.partition(_.isLeft)
if (wrongIds.nonEmpty) {
Left(s"Could not bind the following Ids: ${wrongIds.map(_.left.get).mkString(",")}")
} else {
Right(correctIds.map(_.right.get).toSet)
}
}
override def unbind(key: String, ids: Set[IdParam[A]]): String =
stringBinder.unbind(key, ids.map(_.value.toString).mkString(","))
}
}
Моего Контролер
class Campaigns extends play.api.mvc.Controller {
def allByProfileId(profile: ProfileId) = ...
def all(profileIds: Set[ProfileId]) = ...
}
Первая конечная точка работает, которая использует определенную idParamQueryStringBinder
со следующим неявным преобразователем
implicit def toId[T](idParam: IdParam[T]): IdTag[T] = idParam.value
добавить код ошибки причина пожалуйста – Cortwave
Это где ошибка выбрасывают из: '[ошибка] GET/кампании @ dummy.Campaigns.all (ProfileID: Set [IdParam [ProfileIdTag]] = Set.empty) ' –