Skip to content

Commit

Permalink
Feat opt (#13)
Browse files Browse the repository at this point in the history
* optimize code

* update README_zh.md

* update travis

* update travis

* fix travis

* update README
  • Loading branch information
liangyaopei authored Mar 18, 2021
1 parent 5dcf01f commit 43b4ba1
Show file tree
Hide file tree
Showing 20 changed files with 695 additions and 439 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ install:
script:
- test -z "`gofmt -l -d .`"
- go test -v -covermode=count -coverprofile=coverage.out
- $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci
- $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci
128 changes: 110 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,127 @@ When use `Add` to add rule,`fieldExpr` has three situations:
- `fieldExpr` is single field,fetch value in struct, then validate.
- `fieldExpr` is string separated by `.`, fetch value in struct according hierarchy of struct, then validate.

When fetching value by `fieldExpr`, if the field is pointer, it will fetch the underlying value of pointer
to validate; if the field is nil pointer, it failed validation rule.

example from `checker_test.go`
```go
// Item.Email is the format of email address
type Item struct {
Info typeInfo
Info typeInfo
Email string
}

// typeInfo.Type = "range", length of typeInfo.Type is 2,elements meets format of "2006-01-02"
// typeInfo.Type = "last", length of typeInfo.Typeis 1,elements meets of format positive integer,
// Granularity must be one of day/week/month
type typeStr string
// Item.Info.Type = "range",typeInfo.Type 's length is 2,elements with format of "2006-01-02"
// Item.Info.Type = "last",typeInfo.Type 'is length is 1,elements is positive integer,Granularity is one of day/week/month
type typeInfo struct {
Type string
Type typeStr
Range []string
Unit string
Granularity string
}

// here is the rule
rule := Field("Info",
Or(
And(
EqStr("Type", "range"),
Length("Range", 2, 2),
Array("Range", isDatetime("", "2006-01-02")),
),
And(
EqStr("Type", "last"),
InStr("Granularity", "day", "week", "month"),
Number("Unit"),

// rules are as follow
rule := And(
Email("Email"),
Field("Info",
Or(
And(
EqStr("Type", "range"),
Length("Range", 2, 2),
Array("Range", isDatetime("", "2006-01-02")),
),
And(
EqStr("Type", "last"),
InStr("Granularity", "day", "week", "month"),
Number("Unit"),
),
),
),
)
```
itemChecker := NewChecker()
// validate parameter
itemChecker.Add(rule, "wrong item")
```

## Rule
`Rule` is an interface, it has many implementations. Its implementations can be categorized into
two kinds: composite rule and singleton rule.

### Composite Rule

Composite Rule contains other rules.

| Name | Usage |
| ---------------------------------------------------------- | ----------------------------------------------------- |
| `Field(fieldExpr string, rule Rule) Rule` | Applies `rule` to validate `fieldExpr` |
| `And(rules ...Rule) Rule` | It needs all rules pass |
| `Or(rules ...Rule) Rule` | It needs any rule passed |
| `Not(innerRule Rule) Rule` | opposite the rule |
| `Array(fieldExpr string, innerRule Rule) Rule` | Applies rule to elements in array |
| `Map(fieldExpr string, keyRule Rule, valueRule Rule) Rule` | Applies keyRule and valueRule to key and value in map |



### Singleton Rule

Singleton Rule can be categorized into comparison rule, enum rule and format rule.

#### Comparison Rule


Comparison Rule can be categorized into single field comparison rule and multi-field comparison rule



single field comparison rule includes:

| Name |
| ------------------------------------------------- |
| `EqInt(filedExpr string, equivalent int) Rule` |
| `NeInt(filedExpr string, inequivalent int) Rule` |
| `RangeInt(filedExpr string, ge int, le int) Rule` |


It also has the implementation of `uint`, `string``float``time.Time` , `Comparable`.



multi-field comparison rule includes

| Name |
| ------------------------------------------------------------ |
| `CrossComparable(fieldExprLeft string, fieldExprRight string, op operand) Rule` |


`fieldExprLeft``fieldExprRight` is to located the field involving comparsion, `op` is the operand.

`CrossComparable` supports `int`\`uint`\`float`\`string`\`time.Time`\`Comparable`.

#### Enum Rule

Enum Rule includes

| Name |
| ------------------------------------------------- |
| `InStr(filedExpr string, enum ...string) Rule` |
| `InInt(filedExpr string, enum ...int) Rule` |
| `InUint(filedExpr string, enum ...uint) Rule` |
| `InFloat(filedExpr string, enum ...float64) Rule` |



#### Format Rule

Format Rule includes

| Name |
| ------------------------------- |
| `Email(fieldExpr string) Rule` |
| `Number(fieldExpr string) Rule` |
| `URL(fieldExpr string) Rule` |
| `Ip(fieldExpr string) Rule` |

etc.
123 changes: 107 additions & 16 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,124 @@ go get -u github.com/liangyaopei/checker
- `fieldExpr`为单个字段,这时会先取字段的值,再校验。
- `fieldExpr`为点(.)分割的字段,先按照`.`的层级关系取值,再校验。

按字段取值时,如果字段是指针,就取指针的值校验;如果是空指针,则视为没有通过校验。

来自`checker_test.go`的例子:
```go
// Item.Email需要符合电子邮箱的格式
type Item struct {
Info typeInfo
Info typeInfo
Email string
}

// typeInfo.Type = "range",typeInfo.Type的长度为2,元素都是格式符合"2006-01-02"
// typeInfo.Type = "last",typeInfo.Type的长度为1,元素是正整数,Granularity只能是day/week/month之一
type typeStr string
// Item.Info.Type = "range",typeInfo.Type的长度为2,元素都是格式符合"2006-01-02"
// Item.Info.Type = "last",typeInfo.Type的长度为1,元素是正整数,Granularity只能是day/week/month之一
type typeInfo struct {
Type string
Type typeStr
Range []string
Unit string
Granularity string
}


// 规则如下
rule := Field("Info",
Or(
And(
EqStr("Type", "range"),
Length("Range", 2, 2),
Array("Range", isDatetime("", "2006-01-02")),
),
And(
EqStr("Type", "last"),
InStr("Granularity", "day", "week", "month"),
Number("Unit"),
rule := And(
Email("Email"),
Field("Info",
Or(
And(
EqStr("Type", "range"),
Length("Range", 2, 2),
Array("Range", isDatetime("", "2006-01-02")),
),
And(
EqStr("Type", "last"),
InStr("Granularity", "day", "week", "month"),
Number("Unit"),
),
),
),
)
```
itemChecker := NewChecker()
// 校验参数
itemChecker.Add(rule, "wrong item")
```

## 规则
`Rule`是一个接口,它有很多的实现。`Rule`的实现可以分为复合规则和单个规则。



### 复合规则

复合规则包含其他的规则。

| 名字 | 作用 |
| ---------------------------------------------------------- | ---------------------------------------------- |
| `Field(fieldExpr string, rule Rule) Rule` | 对字段使用`rule`校验 |
| `And(rules ...Rule) Rule` | 需要所有的规则都通过 |
| `Or(rules ...Rule) Rule` | 需要由一个规则通过 |
| `Not(innerRule Rule) Rule` | 对规则取反 |
| `Array(fieldExpr string, innerRule Rule) Rule` | 对数组的每一个元素使用规则 |
| `Map(fieldExpr string, keyRule Rule, valueRule Rule) Rule` | 对map的key/value使用keyRule和valueRule进行校验 |



### 单个规则

单个规则可分为比较型,枚举型,格式型等。

#### 比较型规则

比较型规则分为单个字段比较规则,多个字段比较规则。



单个字段比较规则包括:

| 名字 |
| ------------------------------------------------- |
| `EqInt(filedExpr string, equivalent int) Rule` |
| `NeInt(filedExpr string, inequivalent int) Rule` |
| `RangeInt(filedExpr string, ge int, le int) Rule` |

以及`uint`, `string``float``time.Time` , `Comparable`的实现。

多个字段比较规则

| 名字 |
| ------------------------------------------------------------ |
| `CrossComparable(fieldExprLeft string, fieldExprRight string, op operand) Rule` |

`fieldExprLeft``fieldExprRight`用来定位参加比较的字段,`op`是运算操作符,包括相等/不等/大于等。

``CrossComparable`支持的字段类型包括`int`\`uint`\`float`\`string`\`time.Time`\`Comparable`。



#### 枚举型规则

枚举型包括

| 名字 |
| ------------------------------------------------- |
| `InStr(filedExpr string, enum ...string) Rule` |
| `InInt(filedExpr string, enum ...int) Rule` |
| `InUint(filedExpr string, enum ...uint) Rule` |
| `InFloat(filedExpr string, enum ...float64) Rule` |



#### 格式型规则

格式型规则包括

| 名字 |
| ------------------------------- |
| `Email(fieldExpr string) Rule` |
| `Number(fieldExpr string) Rule` |
| `URL(fieldExpr string) Rule` |
| `Ip(fieldExpr string) Rule` |

等等
54 changes: 54 additions & 0 deletions benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package checker

import "testing"

func BenchmarkIp(b *testing.B) {
type Test struct {
IP string
}
test := Test{IP: "127.0.0.1"}

ipChecker := NewChecker()
ipChecker.Add(Ip("IP"), "wrong ip")
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, _, _ = ipChecker.Check(test)
}
}

func BenchmarkNot(b *testing.B) {
type Test struct {
NotIP string
}
test := Test{NotIP: "127.0.0.1.1"}

notIPChecker := NewChecker()
notIPChecker.Add(Not(Ip("IP")), "wrong ip")
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, _, _ = notIPChecker.Check(test)
}
}

func BenchmarkMap(b *testing.B) {

kvMap := make(map[keyStruct]valueStruct)
keys := []keyStruct{{1}, {2}, {3}}
for _, key := range keys {
kvMap[key] = valueStruct{Value: 9}
}
m := mapStruct{
kvMap,
}

mapChecker := NewChecker()
mapRule := Map("Map",
RangeInt("Key", 1, 10),
InInt("Value", 8, 9, 10))
mapChecker.Add(mapRule, "invalid map")

b.ResetTimer()
for n := 0; n < b.N; n++ {
_, _, _ = mapChecker.Check(m)
}
}
Loading

0 comments on commit 43b4ba1

Please sign in to comment.