Skip to content

poslegm/brief

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

brief

Currently Scala 2 only

Maven Central

The validations are useless if programmers ignore them. We need to reduce an amount of boilerplate to adopt a typesafe validations for mass usage.

breif is an automated constructor generator for the case classes with a refined fields. The purpose of this micro-library is to reduce an adoption cost of a refined types.

brief is just a wrapper around powerful Refined library by Frank S. Thomas.

It will help if:

  1. I want typesafe fields validation for case classes, but I don't want to write boilerplate to its validation manually;
  2. Something went wrong and I don't want to "fail fast" on the first invalid field. I want to get all validation errors together;
  3. I want to have a failed field name in an every error message.

Usage

sbt

libraryDependencies += "com.github.poslegm" %% "brief" % "0.0.1-RC1-M1" // for Scala 2.13 scalacOptions += "-Ymacro-annotations" // for Scala 2.12 libraryDependencies += compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)

Public API of brief consists of the only one macro annotation @Validation! It creates constructor for the case class with refined fields and accumulates all validation errors to List[String].

Example

import brief.annotations.Validation import eu.timepit.refined._ import eu.timepit.refined.api.Refined import eu.timepit.refined.numeric._ @Validation case class Test(a: Int, b: Int Refined Positive, c: Int Refined Negative) // MACRO GENERATED CODE START object Test { def create(a: Int, b: Int, c: Int): Either[List[String] Refined NonEmpty, Test] = brief.util.either.product( brief.util.either.liftErrors(refineV[Positive](b)), brief.util.either.liftErrors(refineV[Negative](c)) ).map { case (b, c) => new Test(a = a, b = b, c = c) } } // MACRO GENERATED CODE END Test.create(1, 2, -3) // Right(Test(1, 2, -3)) Test.create(1, -2, 3) // Left(List("For field Test.b: Predicate failed: (-2 > 0).", "For field Test.c: Predicate failed: (3 < 0)."))

Custom predicate example

import brief.annotations.Validation import eu.timepit.refined._ import eu.timepit.refined.api.{Refined, Validate} val russianPhoneNumberRegex = "\\+7[0-9]{10}".r final case class RussianPhoneNumber() implicit def phoneNumber: Validate.Plain[String, RussianPhoneNumber] = Validate.fromPredicate( x => russianPhoneNumberRegex.matches(x), x => s"($x has format +7XXXXXXXXXX)", RussianPhoneNumber() ) @Validation case class Call( source: String Refined RussianPhoneNumber, target: String Refined RussianPhoneNumber ) Call.create("+71234567890", "+71112223344") // Right(Call(...))

Custom errors

It's possible to return your own exception from a create method instead of raw List[String] with errors. Just define your error datatype with a contract:

  1. It should be a class or a case class
  2. It should receive List[String] or List[String] Refined NonEmpty to the constructor

And then pass it to the annotation type parameter as @Validation[CustomError].

Example

final case class CallValidationError(msgs: List[String]) extends Exception(s"call validation errors: ${msgs.mkString("; ")}") with NoStackTrace @Validation[CallValidationError] case class Call( source: String Refined RussianPhoneNumber, target: String Refined RussianPhoneNumber ) Call.create("+71234567890", "+71112") // Left(CallValidationError(...))

Constraints

Generic case classes

case class with a type parameters will not compile. Feel free to fix it!

@Validation case class Test[T](a: T) // <- doesn't compile

Type aliases

There are constraints for type aliases. Feel free to fix it!

// predicate aliases are OK type PaE = Positive And Even @Validation case class Test(x: Int Refined PaE) // <- works good :) // full type aliases aren't OK type Pos = Int Refined Positive @Validation case class Test(x: Pos) // <- will not work :(

Supported Scala versions

Currently supported versions are 2.12 and 2.13. Scala 3 support not ready yet.

About

Automated case classes validation using refinement types and macros

Topics

Resources

License

Stars

Watchers

Forks

Languages