Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to write rule for validating collections? #13

Open
mii9000 opened this issue Mar 23, 2018 · 7 comments
Open

How to write rule for validating collections? #13

mii9000 opened this issue Mar 23, 2018 · 7 comments
Labels

Comments

@mii9000
Copy link

mii9000 commented Mar 23, 2018

case class Customer(id: Int, name: String)

case class CustomerCollection(customers: Vector[Customer])

implicit val customerValidator: AsyncValidator[CustomerCollection] =
    AsyncValidator[CustomerCollection]
.async.rule(_.customers, ....)
@krzemin
Copy link
Owner

krzemin commented Mar 23, 2018

That's the point - you don't need to write rules for collections manually.

import octopus.dsl._
import octopus.syntax._

case class Customer(id: Int, name: String)
case class CustomerCollection(customers: Vector[Customer])

implicit val cutsomerValidator: Validator[Customer] = Validator[Customer]
  .rule(_.name, (_: String).trim.nonEmpty, "name must not be empty")

val customers = CustomerCollection(Vector(Customer(1, "C1"), Customer(2, "   "), Customer(3, "")))
customers.validate
// invalid:
//  customers[1].name: name must not be empty
//  customers[2].name: name must not be empty

Octopus will derive rules for collection automatically!

However sometimes you may want to additionally restrict collection itself. In this case you can define your own rules and compose with derived ones:

implicit val customerCollectionValidator: Validator[CustomerCollection] = Validator[CustomerCollection]
  .derived
  .rule(_.customers, (_: Vector[Customer]).length % 2 == 0, "number of customers must be even")

customers.validate
// invalid:
//  customers[1].name: name must not be empty
//  customers[2].name: name must not be empty
//  customers: number of customers must be even

Intentionally this should work equally well for asynchronous validators.

@mii9000
Copy link
Author

mii9000 commented Mar 26, 2018

@krzemin This works as well but how do I combine the collection validator to the actual class validator as in my original example:

case class Customer(id: Int, name: String)

case class CustomerCollection(customers: Vector[Customer])

implicit val customerValidator: AsyncValidator[CustomerCollection] =
    AsyncValidator[CustomerCollection]
.async.rule(_.customers, ....)

the advantage I would get is all the validation result would be combined

@krzemin
Copy link
Owner

krzemin commented Mar 26, 2018

I'm not sure if I got your question right. If you mark your rule for Customer as implicit, validation results for the whole collection would be automatically combined by the library (as in the example). In case this is not what you want to achieve, can you write more precisely what kind of result composing would you expect? Perhaps providing a type signature or code with example values and expected semantics.

@mii9000
Copy link
Author

mii9000 commented Mar 26, 2018

I think I misunderstood. If it combines automatically due to implicit then that should be good enough. I will try it out. Thanks.

@andyczerwonka
Copy link

@ibrahim-islam can we close this?

@pixime
Copy link

pixime commented Sep 9, 2021

Hello,

I'm using version 0.4.1, which seems to be the latest.
I have tried the example above like this:

  test("Customer collectionsexample") {

    import octopus.dsl._
    import octopus.syntax._

    case class Customer(id: Int, name: String)
    case class CustomerCollection(customers: Vector[Customer])

    implicit val customerValidator: Validator[Customer] = Validator[Customer]
      .rule(_.name, (_: String).trim.nonEmpty, "name must not be empty")

    implicit val customerCollectionValidator: Validator[CustomerCollection] = Validator
      .derived
      .rule(_.customers, (_: Vector[Customer]).length % 2 == 0, "number of customers must be even")

    val customers = CustomerCollection(Vector(Customer(1, "C1"), Customer(2, "   "), Customer(3, "")))
    println(customers.validate)
  }

And the test can not compile with the following error:

value derived is not a member of octopus.Validator[CustomerCollection]
possible cause: maybe a semicolon is missing before `value derived`?
      .derived

Do I missed something ?

Notice also that when I remove the customerCollection validator, it works fine. But I need to introduce validation items at collection level

@pixime
Copy link

pixime commented Sep 9, 2021

It seems that works better like this:

    implicit val customerCollectionValidator: Validator[CustomerCollection] = Validator[CustomerCollection]
      .rule(_.customers, (_: Vector[Customer]).length % 2 == 0, "number of customers must be even")
      .composeDerived

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants