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