valdy

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 22, 2023 License: MIT Imports: 3 Imported by: 2

README

valdy

golangci-lint Go Reference

Description

valdy is a go package, that provides simple and flexible validations.

⚡️ The project is in rapid stage of development, issues and critics are welcome.

Features
  • reflection free
  • simple minded
  • generics usage
  • multierrors(using erry)

Table of contents

Requirements

go 1.18+

Getting started

Installation
go get github.com/k1gabyt0/valdy
Usage
Simple validation
type person struct {
 name     string
 age      int
 children []person
}

func Simple() {
 // ErrIsAdult is corresponding error for isAdult rule.
 // When isAdult check fails, the error(wrapped) is returned.
 // Thus, it is possible to check what rules have failed during validation process.
 var ErrIsAdult = errors.New("person is not adult")
 var isAdult valdy.ValidationFunc[person] = func(p person) error {
  if p.age < 18 {
   return valdy.ErrorFrom(ErrIsAdult).Wrap(
    fmt.Errorf("%s must be adult. age is %d", p.name, p.age),
   )
  }
  return nil
 }

 var validator valdy.Validator[person]

 john := person{
  name: "John",
  age:  18,
 }

 err := validator.Validate(john,
  isAdult,
 )

 fmt.Println(err)
 if errors.Is(err, ErrIsAdult) {
  fmt.Println("ErrIsAdult")
 }
}

Output:

validation has failed:
        person is not adult:
        John must be adult. age is 17
ErrIsAdult
A little bit complex
type person struct {
  name string
  age  int
 }

 // ErrIsAdult is corresponding error for isAdult rule.
 // When isAdult check fails, the error(wrapped) is returned.
 // Thus, it is possible to check what rules have failed during validation process.
 var ErrIsAdult = errors.New("person is not adult")
 var isAdult valdy.ValidationFunc[person] = func(p person) error {
  if p.age < 18 {
   return valdy.ErrorFrom(ErrIsAdult).Wrap(
    fmt.Errorf("%s must be adult. age is %d", p.name, p.age),
   )
  }
  return nil
 }

 var validator valdy.Validator[person]

 john := person{
  name: "John",
  age:  18,
 }

 err := validator.Validate(john,
  isAdult,
 )

 fmt.Println(err)
 if errors.Is(err, ErrIsAdult) {
  fmt.Println("ErrIsAdult")
 }

Output:

validation has failed:
  age verification error:
  John must be adult, but his age is 17

This is general validation error
This is age verification error
Complex validation
func Complex() {
 var wantedCriminals = []string{
  "Ivan",
  "Jackob",
  // "John",
 }

 type person struct {
  name     string
  age      int
  children []person
 }

 // Validation rules:
 var (
  // ErrIsAdult is corresponding error for isAdult rule.
  // When isAdult check fails, the error(wrapped) is returned.
  // Thus, it is possible to check what rules have failed during validation process.
  ErrIsAdult                              = errors.New("person is not adult")
  isAdult    valdy.ValidationFunc[person] = func(p person) error {
   if p.age < 18 {
    return valdy.ErrorFrom(ErrIsAdult).Wrap(
     fmt.Errorf("%s must be adult. age is %d", p.name, p.age),
    )
   }
   return nil
  }

  ErrHasChildren                              = errors.New("person doesn't have children")
  hasChildren    valdy.ValidationFunc[person] = func(p person) error {
   if len(p.children) == 0 {
    return valdy.ErrorFrom(ErrHasChildren).Wrap(
     fmt.Errorf("%s should has children, but he doesn't", p.name),
    )
   }
   return nil
  }

  ErrInWantedList = errors.New("person is not a wanted criminal")
  inWantedList    = func(criminalList []string) valdy.ValidationFunc[person] {
   return func(p person) error {
    var isCriminal bool
    for _, criminal := range criminalList {
     if p.name == criminal {
      isCriminal = true
      break
     }
    }
    if !isCriminal {
     return valdy.ErrorFrom(ErrInWantedList).Wrap(
      fmt.Errorf("%s should be wanted criminal, but he is not in the list: %v", p.name, criminalList),
     )
    }
    return nil
   }
  }
 )

 var validator valdy.Validator[person]

 john := person{
  name: "John",
  age:  18,
 }

 err := validator.Validate(john,
  isAdult,
  hasChildren,
  inWantedList(wantedCriminals),
 )
 fmt.Println(err)

 // Also you can check which ones validations have failed.
 // In this case the thing you need to do is to proivde
 // corressponding error for each validation.
 // Otherwise, only the ErrValidation error can be checked,
 // but in this case the error has no idea what validation has failed.
 if errors.Is(err, ErrIsAdult) {
  fmt.Println("ErrIsAdult")
 }
 if errors.Is(err, ErrHasChildren) {
  fmt.Println("ErrHasChildren")
 }
 if errors.Is(err, ErrInWantedList) {
  fmt.Println("ErrInWantedList")
 }
}

Output:

validation has failed:
        person doesn't have children:
        John should has children, but he doesn't
        person is not a wanted criminal:
        John should be wanted criminal, but he is not in the list: [Ivan Jackob]
ErrHasChildren
ErrInWantedList

Alternatives

Documentation

Overview

Example
package main

import (
	"errors"
	"fmt"

	"github.com/k1gabyt0/valdy"
)

func main() {
	var wantedCriminals = []string{
		"Ivan",
		"Jackob",
		// "John",
	}

	type person struct {
		name     string
		age      int
		children []person
	}

	// Validation rules:
	var (
		// ErrIsAdult is corresponding error for isAdult rule.
		// When isAdult check fails, the error(wrapped) is returned.
		// Thus, it is possible to check what rules have failed during validation process.
		ErrIsAdult                              = errors.New("person is not adult")
		isAdult    valdy.ValidationFunc[person] = func(p person) error {
			if p.age < 18 {
				return valdy.ErrorFrom(ErrIsAdult).Wrap(
					fmt.Errorf("%s must be adult. age is %d", p.name, p.age),
				)
			}
			return nil
		}

		ErrHasChildren                              = errors.New("person doesn't have children")
		hasChildren    valdy.ValidationFunc[person] = func(p person) error {
			if len(p.children) == 0 {
				return valdy.ErrorFrom(ErrHasChildren).Wrap(
					fmt.Errorf("%s should has children, but he doesn't", p.name),
				)
			}
			return nil
		}

		ErrInWantedList = errors.New("person is not a wanted criminal")
		inWantedList    = func(criminalList []string) valdy.ValidationFunc[person] {
			return func(p person) error {
				var isCriminal bool
				for _, criminal := range criminalList {
					if p.name == criminal {
						isCriminal = true
						break
					}
				}
				if !isCriminal {
					return valdy.ErrorFrom(ErrInWantedList).Wrap(
						fmt.Errorf("%s should be wanted criminal, but he is not in the list: %v", p.name, criminalList),
					)
				}
				return nil
			}
		}
	)

	var validator valdy.Validator[person]

	john := person{
		name: "John",
		age:  18,
	}

	err := validator.Validate(john,
		isAdult,
		hasChildren,
		inWantedList(wantedCriminals),
	)
	fmt.Println(err)

	// Also you can check which ones validations have failed.
	// In this case the thing you need to do is to proivde
	// corressponding error for each validation.
	// Otherwise, only the ErrValidation error can be checked,
	// but in this case the error has no idea what validation has failed.
	if errors.Is(err, ErrIsAdult) {
		fmt.Println("ErrIsAdult")
	}
	if errors.Is(err, ErrHasChildren) {
		fmt.Println("ErrHasChildren")
	}
	if errors.Is(err, ErrInWantedList) {
		fmt.Println("ErrInWantedList")
	}

}
Output:

validation has failed:
	person doesn't have children:
	John should has children, but he doesn't
	person is not a wanted criminal:
	John should be wanted criminal, but he is not in the list: [Ivan Jackob]
ErrHasChildren
ErrInWantedList

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrValidation shows that validation is failed.
	ErrValidation = errors.New("validation error")
	// ErrInternal shows that non-validation error happened.
	ErrInternal = errors.New("internal error")
)

Functions

This section is empty.

Types

type Validation added in v0.3.0

type Validation[T any] interface {
	Check(T) error
}

Validation is something that can check and return appropriate error.

type ValidationError

type ValidationError struct {
	*erry.MError
}

ValidationError is an error that able to store multiple errors.

Whether ValidationError is checked by errors.Is(err, ErrValidation), it will be true.

func ErrorFrom added in v0.3.0

func ErrorFrom(original error) *ValidationError

func NewError added in v0.3.0

func NewError(msg string, errs ...error) *ValidationError

func (*ValidationError) Is

func (v *ValidationError) Is(target error) bool

Is reports whether any error in v's tree matches target.

It is always returns true if checked against ErrValidation.

func (*ValidationError) Wrap added in v0.3.0

func (v *ValidationError) Wrap(errs ...error) *ValidationError

type ValidationFunc added in v0.3.0

type ValidationFunc[T any] func(target T) error

ValidationFunc is a modest implementation of Validation.

It gives you full control over returned error. However, the error will be ErrValidation.

func (ValidationFunc[T]) Check added in v0.3.0

func (f ValidationFunc[T]) Check(target T) error

Check target against a function.

If Check is failed, then error is returned. Also, the error will be ErrValidation.

Example
var errIsJohn = errors.New("Jhonification is failed")
var isJohn valdy.ValidationFunc[personFixture] = func(target personFixture) error {
	if target.name != "John" {
		return valdy.ErrorFrom(errIsJohn).Wrap(
			fmt.Errorf("You are not John! You are %s!", target.name),
		)
	}
	return nil
}

michael := personFixture{name: "Michael"}

err := isJohn.Check(michael)
if err != nil {
	fmt.Println(err.Error())
}
fmt.Println(errors.Is(err, valdy.ErrValidation))
fmt.Println(errors.Is(err, errIsJohn))
Output:

Jhonification is failed:
	You are not John! You are Michael!
true
true

type Validator

type Validator[T any] struct {
	// Mode that Validator uses for validation.
	//
	// The new ones can be added by embedding Validator struct and
	// overriding Validate func.
	Mode ValidatorMode
}

Validator validates anything you pass to it.

It has different modes: RUN_ALL, STOP_ON_FIRST_FAIL. Zero-value of Validator uses RUN_ALL mode by default.

func (*Validator[T]) Validate

func (v *Validator[T]) Validate(target T, validations ...Validation[T]) error

Validate checks target against passed validations.

If Validator has incorrect Mode, then ErrInternal will be return .

type ValidatorMode

type ValidatorMode uint

ValidatorMode that tells validator what validation logic to use.

const (
	// RUN_ALL means that all validations will be runned.
	// Even if some of them may be failed.
	RUN_ALL ValidatorMode = iota
	// STOP_ON_FIRST_FAIL means that as soon as the first validation fails, the others will not be checked.
	STOP_ON_FIRST_FAIL
)

Validator modes:

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL