Skip to content

Instantly share code, notes, and snippets.

@matfournier
Last active December 3, 2019 22:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matfournier/c8d46e60f9ab2882ac05eeec47b45869 to your computer and use it in GitHub Desktop.
Save matfournier/c8d46e60f9ab2882ac05eeec47b45869 to your computer and use it in GitHub Desktop.
RefinedCustomValidation
// the type I take in which isn't that useful
case class AuthorizeRequest(
code: Option[String],
token: Option[String],
secret: Option[String],
verifier: Option[String],
redirectUri: String,
clientId: String,
clientSecret: String
)
// what I actually want to construct
final case class ValidAuthorizeRequest(
clientId: String Refined NonEmpty,
redirectUri: String Refined Uri,
clientSecret: String Refined NonEmpty,
code: String Refined NonEmpty
)
// ideally I would be able to go something like this (assuming request is an instance of AuthorizeRequest
// refineV[ValidAuthorizeResult](request.clientId, request.redirectUri, request.secret, request.code))
// attempting to define a Validate instance NOT WORKING
implicit val vv:Validate[(String, String, String, Option[String]), ValidAuthorizeRequest] =
new Validate[(String, String, String, Option[String]), ValidAuthorizeRequest] {
override type R = ??? // not sure if I need to put something here
override def showExpr(t: (String, String, String, Option[String])): String = "boo?" // not sure what I need here
override def validate(t: (String, String, String, Option[String])): Res = {
val (rC, rU, cS, cc) = t
val result = for {
clientId <- RefType.applyRef[NonEmptyString](rC)
redirectUri <- RefType.applyRef[NonEmptyString](rU)
clientSecret <- RefType.applyRef[NonEmptyString](cS)
code <- cc.fold("Code is required but given as Optional".asLeft[NonEmptyString])(RefType.applyRef[NonEmptyString](_))
} yield ValidAuthorizeRequest(clientId, redirectUri, clientSecret, code)
// this gives me Either[String, ValidAuthorizeResult]
result match {
// THIS IS WRONG. Result[A] is not isomorphic to either
case e@Left(_) => Failed(e)
case r@Right(_) => Passed(r)
}
}
// I can always do this by hand but it would be nice to key into the validation syntax directly
// esp in the case of deeply nested objects each with their own instance of Validate
object ValidAuthorizeRequest {
def from(req: AuthorizeRequest): Either[String, ValidAuthorizeRequest] = for {
clientId <- refineV[NonEmpty](req.clientId)
redirectUri <- refineV[Uri](req.redirectUri)
clientSecret <- refineV[NonEmpty](req.clientSecret)
code <- req.code.fold("Code is required but given as Optional".asLeft[NonEmptyString])(refineV[NonEmpty](_))
} yield ValidAuthorizeRequest(clientId, redirectUri, clientSecret, code)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment