davegurnell / checklist

Validation library for Scala.
Apache License 2.0
47 stars 11 forks source link

Build HLists or tuples for composing outputs #6

Closed Jacoby6000 closed 7 years ago

Jacoby6000 commented 7 years ago

I don't know how to put this in to words, so I'll throw it in an example..

case class AddressInput(house: Option[Int], street: Option[String], street2: Option[String])
case class ValidatedAddress(house: Int, street: String, street2: Option[String])

implicit val checkAddress: Rule[AddressInput, ValidatedAddress]
  Rule[AddressInput]
    .field(_.house)(req andThen gte(1))
    .field(_.street)(req andThen trimString andThen nonEmpty)
    .field(_.street2)(optional(trimString))
    .map { addr => 
      ValidatedAddress(addr.house.get, addr.street.get, addr.street2.get 
    }

Having to use .get in there is pretty unfortunate. If instead running .field would return some sort of RuleBuilder[A, B] where A is the input type, and B is the output type, you could do something like

case class AddressInput(house: Option[Int], street: Option[String], street2: Option[String])
case class ValidatedAddress(house: Int, street: String, street2: Option[String])

implicit val checkAddress: Rule[AddressInput, ValidatedAddress]
  Rule[AddressInput]
    .field(_.house)(req andThen gte(1)) // RuleBuilder[AddressInput, Int :: HNil]
    .field(_.street)(req andThen trimString andThen nonEmpty) // RuleBuilder[AddressInput, Int :: String :: HNil]
    .field(_.street2)(optional(trimString)) // RuleBuilder[AddressInput, Int :: String :: Option[String] :: HNil]
    .build { 
      case street2 :: street :: house :: HNil => ValidatedAddress(street2, street, house) 
    }

This could be expanded upon and you could have the builder function derived from shapeless Generic as well. When working with scalapb especially this feature would be useful. A builder which just returns a Rule[A, A] would also be possible, but I think that the Rule class itself should have a method for running a sanitization and returning the validated (and unsanitized) result.

I'll consider making a PR as a POC sometime soon if I can find time.

Jacoby6000 commented 7 years ago

Resolved with the merge of #7. Thanks @davegurnell! I'll look in to writing some docs sometime this weekend.