Skip to content

Support custom explains #7

@jeme

Description

@jeme

It should be possible to give rules a custom explanation.

Starting with considering the root, there is multiple ways to provide this syntactically, e.g.

// Option 1:
When("name", Is.Defined())
  .Then(It, Must.Be.String() & Have.MaxLength(256), "when name is provided, name must be a string and be max 256 characters long");

// Option 2:
When("name", Is.Defined())
  .Then(It, Must.Be.String() & Have.MaxLength(256))
  .Explain("when name is provided, name must be a string and be max 256 characters long");

If possible, the ability to give partial explanations may also be interesting, here option 2 are probably likely to be easier to implement as it allows for a more generic pattern in general and wrapper rules etc.

This could then be allowed to use on any construct in the framework from a single constraint to grouped constraints, field rules and all the way up to the when.

// Option 1:
When("name", Is.Defined())
  .Then(It, Must.Be.String() & Have.MaxLength(256, "max 256 characters"));

// Option 2:
When("name", Is.Defined())
  .Then(It, Must.Be.String() & Have.MaxLength(256).Explain("max 256 characters"));

Although this raises the question on how these should interact with each other in cases where custom explains has been attacked both at a outer and inner level.

// Option 2:
When("name", Is.Defined())
  .Then(It, Must.Be.String() & Have.MaxLength(256).Explain("max 256 characters"))
  .Explain("must be a string and be max 256 characters long");
// ???

Another challenge is that we can actually rationalize about which rules we should display to the user during validations when it fails.

E.g. given the object: { name: "John", surname: "Doe", age: 500 }

When(Any)
  .Then(Field("name", Must.Match("^[A-Za-z]*$")
      & Field("surname", Must.Match("^[A-Za-z]*$")
      & Field("age", Must.Be.Between(0, 150));

We can actually settle for displaying the failed "age" constraint rather than all of them, but this becomes tricky given a custom explanation. We can give a general rule that just says it will go as deep as it can until it hits a custom explanation and then it uses that, then the following would work reasonably:

When(Any)
  .Then(Field("name", Must.Match("^[A-Za-z]*$")).Explain("name must consist of alphabetic characters only")
      & Field("surname", Must.Match("^[A-Za-z]*$")).Explain("surname must consist of alphabetic characters only")
      & Field("age", Must.Be.Between(0, 150)).Explain("age must be a positive number and max 150"));

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions