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"))
// )