Quick custom validators
You can easily create custom validators on fly - it’s really helpful during working on new or custom validators
import pl.muninn.simple.validation._
 case class Field(name:String, otherField:String)
 val schema:ValidationSchema[Field] = createSchema { context =>
   context.field(_.name)
     .custom(code = "contains_test", reason = "Should contains test")(_.contains("test"))
 }
// schema: ValidationSchema[Field] = <function1>
 schema.validate(Field("",""))
// res0: ValidationResult = Invalid(
//   e = Singleton(
//     a = pl.muninn.simple.validation.model.InvalidField$$anon$1@7198ca6b
//   )
// )
 schema.validate(Field("test",""))
// res1: ValidationResult = Valid(a = ())
Complex validation schema
You can also easily create custom validation logic. For example, some values should be defined only if other value is set to specific value etc.
import pl.muninn.simple.validation._
 case class Product(name:String, price:Long)
 case class Order(totalPrice:Long, products:List[Product])
 val orderSchema: ValidationSchema[Order] = createSchema { context =>
    context.field(_.totalPrice).min(1) +
      context.field(_.products).notEmpty +
      context.custom { order =>
         // If total price is equal or above 100 we want all products to be at least 50
        if (order.totalPrice >= 100) {
          context.field(_.products.map(_.price)).all(min(50L))
        } else {
         // Don't validate anything - we are good
          context.noneValidator
        }
      }
  }
// orderSchema: ValidationSchema[Order] = <function1>
 orderSchema.validate(Order(10, List.empty))
// res2: ValidationResult = Invalid(
//   e = Singleton(a = EmptyField(field = "products"))
// )
 orderSchema.validate(
   Order(
     60,
     List(
       Product("My product", 20),
       Product("My product", 20),
       Product("My product", 20),
     )
   )
 )
// res3: ValidationResult = Valid(a = ())
 orderSchema.validate(
   Order(
     100,
     List(
       Product("My product", 20),
       Product("My product", 20),
       Product("My product", 20),
       Product("My product", 20),
       Product("My product", 20),
     )
   )
 )
// res4: ValidationResult = Invalid(
//   e = Append(
//     leftNE = Append(
//       leftNE = Append(
//         leftNE = Append(
//           leftNE = Singleton(
//             a = MinimalValue(
//               field = "products.price.0",
//               expected = 50L,
//               value = 20L
//             )
//           ),
//           rightNE = Singleton(
//             a = MinimalValue(
//               field = "products.price.1",
//               expected = 50L,
//               value = 20L
//             )
//           )
//         ),
//         rightNE = Singleton(
//           a = MinimalValue(
//             field = "products.price.2",
//             expected = 50L,
//             value = 20L
//           )
//         )
//       ),
//       rightNE = Singleton(
//         a = MinimalValue(
//           field = "products.price.3",
//           expected = 50L,
//           value = 20L
//         )
//       )
//     ),
//     rightNE = Singleton(
//       a = MinimalValue(field = "products.price.4", expected = 50L, value = 20L)
//     )
//   )
// )
 orderSchema.validate(
   Order(
     165,
     List(
       Product("My product", 55),
       Product("My product", 55),
       Product("My product", 55),
     )
   )
 )
// res5: ValidationResult = Valid(a = ())
Custom validators
You can define full own validators and errors
import pl.muninn.simple.validation._
 import pl.muninn.simple.validation.model.InvalidField
 import pl.muninn.simple.validation.validator.ValueValidator
 case class MyError(field:String) extends InvalidField {
   override def reason: String = "Because I think this filed is invalid"
   override def code: String = "error_code"
 }
 val myOwnValidator:ValueValidator[String] = ValueValidator.instance { case (key, value) =>
   if (value.contains("not error")) valid else invalid(MyError(key))
 }
// myOwnValidator: ValueValidator[String] = pl.muninn.simple.validation.validator.ValueValidator$$anon$1@2532b58e
 val customValidatorSchema:ValidationSchema[Field] = createSchema { context =>
   context.field(_.name).is(myOwnValidator)
 }
// customValidatorSchema: ValidationSchema[Field] = <function1>
 customValidatorSchema.validate(Field("error",""))
// res6: ValidationResult = Invalid(e = Singleton(a = MyError(field = "name")))
 customValidatorSchema.validate(Field("not error",""))
// res7: ValidationResult = Valid(a = ())
Reuse existing validators
You can reuse existing validators for other types if you can map it value to validator map
import pl.muninn.simple.validation._
  import pl.muninn.simple.validation.validator.typed.{NumberValidators, StringValidators}
  sealed trait Input
  object Input {
    case class StringInput(value: String) extends Input
    val nonEmptyStringInput = StringValidators.notEmptyString.contramap[StringInput](_.value)
    case class IntInput(value: Int) extends Input
    val nonEmptyIntInput = NumberValidators.min(0).contramap[IntInput](_.value)
  }
  case class InputRequest(stringValue: Input.StringInput, intValue: Input.IntInput)
  val inputSchema: ValidationSchema[InputRequest] = createSchema { context =>
    context.field(_.stringValue).is(Input.nonEmptyStringInput) +
      context.field(_.intValue).is(Input.nonEmptyIntInput)
  }
// inputSchema: ValidationSchema[InputRequest] = <function1>
  inputSchema.validate(InputRequest(Input.StringInput(""), Input.IntInput(0)))
// res8: ValidationResult = Invalid(
//   e = Singleton(a = EmptyField(field = "stringValue"))
// )