struct

Interro::Validations::Result(T)

Inherits Struct / Value / Object

The entrypoint into validating your objects is to instantiate a Result(T), which you then call validation methods on. When you're finished calling validations, you call valid with a block. That block will execute if your values pass all validations, returning the value in the block (which must be the T type of the Result), or an Interro::Validations::Failure object, which contains the validation errors for the given inputs.

struct UserQuery < Interro::QueryBuilder(User)
  def create(*, name : String, email : String, team : Team, role : User::Role)
    Result(User).new
      .validate_presence(name: name, email: email)
      .validate_uniqueness("email") { where(email: email).any? }
      .validate_format(/\w@\w/, email: email, failure_message: "must be a valid email address")
      .valid do
        insert(
          name: name,
          email: email,
          team_id: team.id,
          role: role.value,
        )
      end
  end
end

Constructors

Instance methods

|(other : Result)

Combine the errors of two different Result instances. The T types do not have to match.

Source
initialize
Source
valid

Execute the block given if all validations have passed, otherwise return a Failure containing all of the validation errors.

Source
validate(attribute : String, message : String, &)

Validate a block returns truthy, failing validation with the given message if it returns falsy.

struct Post < Interro::QueryBuilder(T)
  table "posts"

  def create(*, title : String, body : String, by author : User, published : Bool, tags : Array(String)? = nil) : Post | Failure
    Result(Post).new
      .validate("tags", "must be populated for published posts") do
        !published || tags.try(&.any?)
      end
      .valid do
        published_at = Time.utc if published
        insert(
          title: title,
          body: body,
          author_id: author.id,
          published_at: published_at,
          tags: tags,
        )
      end
  end
end
Source
validate(message : String, &)

Validate a block returns truthy, failing validation with the given message if it returns falsy.

struct Post < Interro::QueryBuilder(T)
  table "posts"

  def create(*, title : String, body : String, by author : User, published : Bool, tags : Array(String)? = nil) : Post | Failure
    Result(Post).new
      .validate("published posts must have tags") do
        !published || tags.try(&.any?)
      end
      .valid do
        published_at = Time.utc if published
        insert(
          title: title,
          body: body,
          author_id: author.id,
          published_at: published_at,
          tags: tags,
        )
      end
  end
end
Source
validate_format(name, value : String, format : Regex, *, failure_message : String = "is in the wrong format") : self

Validate that value matches the expected format in the Regex, using the attribute name specified in name and a default failure_message.

Result(User).new
  .validate_format("email", email, /\w@\w/, failure_message: "must be a valid email address")
Source
validate_format(value : String, format : Regex, *, failure_message : String) : self

Validate that value matches the expected format in the Regex. This method does not infer a name, so a custom failure_message must be provided.

Result(User).new
  .validate_format(email, /\w@\w/, failure_message: "Email must be a valid email address (user@domain.tld)")
Source
validate_format(format : Regex, **attributes) : self

Validate that all of the attributes match the expected format in the Regex.

Result(User).new
  .validate_format(/\w@\w/, email: email)
Source
validate_presence

Validate whether all of the values are present by calling .presence on them.

Result(Post).new
  .validate_presence(title: title, body: body)
Source
validate_size(name : String, value, size : Range, unit : String, *, failure_message = default_validate_size_failure_message(size, unit)) : self

Validate that value is of the expected size range. Value can be any object that responds to #size.

Result(User).new
  .validate_size("username", username, 2..64, "characters")
Source
validate_uniqueness(attribute, &) : self

Validate that the given attribute is unique by executing a block that returns truthy if any other objects exist with that attribute.

Result(User).new
  .validate_uniqueness("email") { where(email: email).any? }
Source
validate_uniqueness(*, message : String, &) : self

Validate that the given attribute is unique by executing a block that returns truthy if any other objects exist with that attribute.

Result(User).new
  .validate_uniqueness(message: "That email has already been taken") { where(email: email).any? }
Source