2014-10-16 6 views
13

Sto utilizzando la convalida scalaz e ho del codice per convalidare i prodotti.Convalida scalaz: conversione della sequenza di validazioni in una singola convalida

def validateProduct(product: Option[Product]): ValidationNel[String, Product] = ??? 

Dato un elenco di prodotti, voglio ottenere un singolo convalida contenente la lista completa come valore di successo o un elenco di errori di convalida. Sembra che una sorta di piega dovrebbe farlo, ma non sono sicuro di quale dovrebbe essere la funzione di combinazione.

def validateProducts(products: Seq[Option[Product]]): ValidationNel[String, Seq[Product]] = { 
    val listOfValidations: Seq[ValidationNel[String, Product]] = products.map(validateProduct _) 
    val validatedList:ValidationNel[Seq[String], Seq[Product]] = ??? // what to do here? 
    ??? 
    } 

Ogni aiuto è apprezzato

risposta

16

Se invece di un ValidationNel[List[String], List[Product]] si desidera un ValidationNel[String, List[Product]] (cioè, tutti i fallimenti della stessa lista), si può semplicemente utilizzare traverse:

val result: ValidationNel[String, List[Product]] = 
    products.toList.traverseU(validateProduct) 

Nota che ho convertito il Seq in un List in quanto non ci sono istanze di classe di tipo per raw Seq, e sto usando traverseU anziché traverse come inferenza dei tipi di Scala funziona non del tutto per costruttori di tipo non banali come ValidationNel

+0

Bella! Grazie! – triggerNZ

7

È possibile utilizzare piega con applicativa

import scalaz.syntax.validation._ 
    import scalaz.syntax.applicative._ 

    case class Product(name: String) 

    val allGood = Seq(
    Product("a").successNel[String], 
    Product("b").successNel[String] 
) 

    val aggregated: ValidationNel[String, Seq[Product]] = 
    allGood.foldLeft(Seq.empty[Product].successNel[String]) { 
    case (acc , v) => (acc |@| v)(_ :+ _) 
    } 

    println(aggregated)