Skip to content

A simple, not flexible, mediocre performance Object Fields Validator

License

Notifications You must be signed in to change notification settings

lost22git/validate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

e3cf950 · Apr 13, 2024

History

21 Commits
Apr 13, 2024
Apr 13, 2024
Apr 13, 2024
Apr 13, 2024
Jan 22, 2024
Jan 22, 2024
Jan 24, 2024
Jan 30, 2024
Jan 22, 2024

Repository files navigation

A simple, not flexible, mediocre performance Object Fields Validator

Features

  • based on pragma and macro
  • tags to group/filter validation rules
    • compile-time: tagsFilter expr
    • runtime: filterTags params
  • custom validation function
  • custom validation error message
  • nested validation

TODO

  • i18n validation error message

pragmas

{.valid: @[built-in rules].} for built-in validation rules

{.validFn(fn="function name").} for custom validation function

{.validate: "tag filter expr".} for marking a proc as validation proc

built-in validation rules

rules for types usage description
nonNil ref | ptr | pointer | cstring a {.valid: @[nonNil()].}: ptr int not nil
nonEmpty string | array | set | seq a {.valid: nonEmpty().}: string len > 0
nonBlank string a {.valid: @[nonBlank()].}: string not isEmptyOrWhiteSpace, use std/strutils
range int a {.valid: @[range(min=1, max=10)].}: int int range
frange float a {.valid: @[frange(min=1,max=10)].}: float float range
length string | array | set | seq a {.valid: @[length(min=1,max=10)].}: string length range

usage

Note

Due to use std/strutils, std/sequtils in generated code, you should import them where you use {.validate.}

  • code:
import validate
import std/[sequtils, strutils]

type Category = ref object
  name {.valid: @[length(min = 2)].}: string

type Status = enum
  onsale
  sold

proc isHttpUrl(v: string): bool =
    v.startswith("http://")

type Book = object
  # {.validFn.} use custom validate function
  url {.validFn(fn = "isHttpUrl", tags = ["show"], msg = "the url is not http url").}: string
  # nested validation
  category {.valid: @[nonNil()].}: Category
  tags {.valid: @[length(min = 2, max = 4, tags = ["show"])].}: seq[string]
  # msg template interpolation: $min and $max
  price {.valid: @[frange(min = 5, max = 50, tags = ["hide"], msg = "the price requires from $min to $max")].}: float
  # support object variants
  case status: Status
  of onsale, sold:
    count {.valid: @[range(min = 100, tags = ["hide"])].}: int

# validate book with filterTags
proc validate(book: Book, filterTags: varargs[string]): ValidateResult {.validate: "".}

# validate book with tagFilterExpr
proc validateWithTagFilterExpr(book: Book): ValidateResult {.validate: """ it in ["default","show","hide"] """.}


let category = Category(name: "T")
let book = Book(
    url: "ftp://127.0.0.1/books/1.pdf",
    category: category,
    tags: @["nim"],
    price: 52'd,
    status: onsale,
    count: 10,
)

# let validateResult = book.validate("default", "show", "hide")
let validateResult = book.validateWithTagFilterExpr()
for error in validateResult.errors:
    echo error
  • output:
the url is not http url
Book.category.name: require match range `2 .. 9223372036854775807`
Book.tags: require match range `2 .. 4`
the price requires from 5.0 to 50.0
Book.count: require match range `100 .. 9223372036854775807`

benchmark

bench.nim

root in validate/bench on  main [✘?] via 👑 v2.0.2
❯ ./bench filterTags
len: 1000000
tag filter method: filterTags
result: 1.203444μs/op

root in validate/bench on  main [✘?] via 👑 v2.0.2
❯ ./bench tagFilterExpr
len: 1000000
tag filter method: tagFilterExpr
result: 1.186805μs/op

About

A simple, not flexible, mediocre performance Object Fields Validator

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages