2017-01-06 5 views
0

Я пытаюсь понять, как создать неявный конвертер для определенного типа. В моем случае, это было бы 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 
+0

добавить код ошибки причина пожалуйста – Cortwave

+0

Это где ошибка выбрасывают из: '[ошибка] GET/кампании @ dummy.Campaigns.all (ProfileID: Set [IdParam [ProfileIdTag]] = Set.empty) ' –

ответ

0

Вы должны сделать некоторые кодирования ошибку, потому что она отлично работает для меня: https://gist.github.com/kpbochenek/ce2a783d59a7bd28585e4cbf7a64cad4

следующий раз вставить полный код, который вызывает проблемы не только мелкие детали.

+0

Спасибо, что посмотрели на это. Я добавил дополнительные сведения о коде. @@ берется из бесформенной библиотеки, а не скаляз. Извините, я не упоминал об этом раньше. –