Skip to content

Commit

Permalink
Replaced usage of 'tag' with 'rule'
Browse files Browse the repository at this point in the history
  • Loading branch information
BoBch27 committed Dec 2, 2024
1 parent 0edd920 commit 8cae0a4
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 40 deletions.
42 changes: 21 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,18 @@ type Address struct {

Tags
------------
When defining a new struct type with Firevault tags, note that the tags' order matters (apart from the different `omitempty` tags, which can be used anywhere).
When defining a new struct type with a Firevault tag, note that the rules' order matters (apart from the different `omitempty` rules, which can be used anywhere).

The first tag is always the **field name** which will be used in Firestore. You can skip that by just using a comma, before adding further tags.
The first rule is always the **field name** which will be used in Firestore. You can skip that by just using a comma, before adding the others.

After that, each tag is a different validation rule, and they will be parsed in order.
After that, each rule is a different validation, and they will be parsed in order.

Other than the validation tags, Firevault supports the following built-in tags:
Other than the validation rules, Firevault supports the following built-in ones:
- `omitempty` - If the field is set to it’s default value (e.g. `0` for `int`, or `""` for `string`), the field will be omitted from validation and Firestore.
- `omitempty_create` - Works the same way as `omitempty`, but only for the `Create` method. Ignored during `Update` and `Validate` methods.
- `omitempty_update` - Works the same way as `omitempty`, but only for the `Update` method. Ignored during `Create` and `Validate` methods.
- `omitempty_validate` - Works the same way as `omitempty`, but only for the `Validate` method. Ignored during `Create` and `Update` methods.
- `dive` - If the field is an array/slice or a map, this tag allows to recursively loop through and validate inner fields. Useful when the inner fields are structs with custom validation tags. Ignored for fields that are not arrays/slices or maps.
- `dive` - If the field is an array/slice or a map, this rule allows to recursively loop through and validate inner fields. Useful when the inner fields are structs with custom validation tags. Ignored for fields that are not arrays/slices or maps.
- `-` - Ignores the field.

Validations
Expand Down Expand Up @@ -123,7 +123,7 @@ connection.RegisterValidation(
)
```

You can then chain the tag like a normal one.
You can then chain the rule like a normal one.

```go
type User struct {
Expand All @@ -133,7 +133,7 @@ type User struct {

Transformations
------------
Firevault also supports rules that transform the field's value. There are built-in transformations, with support for adding **custom** ones. To use them, it's as simple as adding a prefix to the tag.
Firevault also supports rules that transform the field's value. There are built-in transformations, with support for adding **custom** ones. To use them, it's as simple as adding a prefix to the rule.

*Again, the order in which they are executed depends on the tag order.*

Expand Down Expand Up @@ -170,7 +170,7 @@ connection.RegisterTransformation(
)
```

You can then chain the tag like a normal one, but don't forget to use the `transform=` prefix.
You can then chain the rule like a normal one, but don't forget to use the `transform=` prefix.

*Again, the tag order matters. Defining a transformation at the end, means the value will be updated **after** the validations, whereas a definition at the start, means the field will be updated and **then** validated.*

Expand Down Expand Up @@ -209,9 +209,9 @@ The `CollectionRef` instance has **7** built-in methods to support interaction w
- data: A `pointer` of a `struct` with populated fields which will be added to Firestore after validation.
- options *(optional)*: An instance of `Options` with the following properties having an
effect.
- SkipValidation: A `bool` which when `true`, means all validation tags will be ingored (the `name` and `omitempty` tags will be acknowledged). Default is `false`.
- SkipValidation: A `bool` which when `true`, means all validation tags will be ingored (the `name` and `omitempty` rules will be acknowledged). Default is `false`.
- ID: A `string` which will add a document to Firestore with the specified ID.
- AllowEmptyFields: An optional `string` `slice`, which is used to specify which fields can ignore the `omitempty` and `omitempty_create` tags. This can be useful when a field must be set to its zero value only on certain method calls. If left empty, all fields will honour the two tags.
- AllowEmptyFields: An optional `string` `slice`, which is used to specify which fields can ignore the `omitempty` and `omitempty_create` rules. This can be useful when a field must be set to its zero value only on certain method calls. If left empty, all fields will honour the two rules.
- *Returns*:
- id: A `string` with the new document's ID.
- error: An `error` in case something goes wrong during validation or interaction with Firestore.
Expand Down Expand Up @@ -271,13 +271,13 @@ fmt.Println(id) // "6QVHL46WCE680ZG2Xn3X"
- data: A `pointer` of a `struct` with populated fields which will be used to update the documents after validation.
- options *(optional)*: An instance of `Options` with the following properties having an
effect.
- SkipValidation: A `bool` which when `true`, means all validation tags will be ingored (the `name` and `omitempty` tags will be acknowledged). Default is `false`.
- SkipValidation: A `bool` which when `true`, means all validation tags will be ingored (the `name` and `omitempty` rules will be acknowledged). Default is `false`.
- MergeFields: An optional `string` `slice`, which is used to specify which fields to be overwritten. Other fields on the document will be untouched. If left empty, all the fields given in the data argument will be overwritten. If a field is specified, but is not present in the data passed, the field will be deleted from the document (using `firestore.Delete`).
- AllowEmptyFields: An optional `string` `slice`, which is used to specify which fields can ignore the `omitempty` and `omitempty_update` tags. This can be useful when a field must be set to its zero value only on certain updates. If left empty, all fields will honour the two tags.
- AllowEmptyFields: An optional `string` `slice`, which is used to specify which fields can ignore the `omitempty` and `omitempty_update` rules. This can be useful when a field must be set to its zero value only on certain updates. If left empty, all fields will honour the two rules.
- *Returns*:
- error: An `error` in case something goes wrong during validation or interaction with Firestore.
- ***Important***:
- If neither `omitempty`, nor `omitempty_update` tags have been used, non-specified field values in the passed in data will be set to Go's default values, thus updating all document fields. To prevent that behaviour, please use one of the two tags.
- If neither `omitempty`, nor `omitempty_update` rules have been used, non-specified field values in the passed in data will be set to Go's default values, thus updating all document fields. To prevent that behaviour, please use one of the two rules.
- If no documents match the provided `Query`, the operation will do nothing and will not return an error.
```go
user := User{
Expand Down Expand Up @@ -349,12 +349,12 @@ fmt.Println("Success") // address.Line1 field will be deleted from document, sin
- data: A `pointer` of a `struct` with populated fields which will be validated.
- options *(optional)*: An instance of `Options` with the following properties having an
effect.
- SkipValidation: A `bool` which when `true`, means all validation tags will be ingored (the `name` and `omitempty` tags will be acknowledged). Default is `false`.
- AllowEmptyFields: An optional `string` `slice`, which is used to specify which fields can ignore the `omitempty` and `omitempty_validate` tags. This can be useful when a field must be set to its zero value only on certain method calls. If left empty, all fields will honour the two tags.
- SkipValidation: A `bool` which when `true`, means all validation tags will be ingored (the `name` and `omitempty` rules will be acknowledged). Default is `false`.
- AllowEmptyFields: An optional `string` `slice`, which is used to specify which fields can ignore the `omitempty` and `omitempty_validate` rules. This can be useful when a field must be set to its zero value only on certain method calls. If left empty, all fields will honour the two rules.
- *Returns*:
- error: An `error` in case something goes wrong during validation.
- ***Important***:
- If neither `omitempty`, nor `omitempty_validate` tags have been used, non-specified field values in the passed in data will be set to Go's default values.
- If neither `omitempty`, nor `omitempty_validate` rules have been used, non-specified field values in the passed in data will be set to Go's default values.
```go
user := User{
Email: "[email protected]",
Expand Down Expand Up @@ -555,13 +555,13 @@ Methods
------------
The `Options` instance has **4** built-in methods to support overriding default `CollectionRef` method options.

- `SkipValidation` - Returns a new `Options` instance that allows to skip the data validation during creation, updating and validation methods. The "name" tag, "omitempty" tags and "ignore" tag will still be honoured.
- `SkipValidation` - Returns a new `Options` instance that allows to skip the data validation during creation, updating and validation methods. The "name" rule, "omitempty" rules and "ignore" rule will still be honoured.
- *Returns*:
- A new `Options` instance.
```go
newOptions := options.SkipValidation()
```
- `AllowEmptyFields` - Returns a new `Options` instance that allows to specify which field paths should ignore the "omitempty" tags. This can be useful when zero values are needed only during a specific method call. If left empty, those tags will be honoured for all fields.
- `AllowEmptyFields` - Returns a new `Options` instance that allows to specify which field paths should ignore the "omitempty" rules. This can be useful when zero values are needed only during a specific method call. If left empty, those rules will be honoured for all fields.
- *Expects*:
- path: A varying number of `string` values (using dot separation) used to select field paths.
- *Returns*:
Expand Down Expand Up @@ -605,7 +605,7 @@ Firevault supports the creation of custom, user-friendly, error messages, throug

```go
connection.RegisterErrorFormatter(func(fe FieldError) error {
if err.Tag() == "min" {
if err.Rule() == "min" {
return fmt.Errorf("%s must be at least %s characters long.", fe.DisplayField(), fe.Param())
}

Expand Down Expand Up @@ -635,7 +635,7 @@ if err != nil {
```go
id, err := collection.Create(ctx, &User{
Name: "Bobby Donev",
Email: "[email protected]", // will fail on the "email" tag
Email: "[email protected]", // will fail on the "email" rule
Password: "123456",
Age: 25,
Address: &Address{
Expand All @@ -655,7 +655,7 @@ You can also directly handle and parse returned `FieldError`, without registerin
```go
func parseError(fe FieldError) {
if fe.StructField() == "Password" { // or fe.Field() == "password"
if fe.Tag() == "min" {
if fe.Rule() == "min" {
fmt.Printf("Password must be at least %s characters long.", fe.Param())
} else {
fmt.Println(fe.Error())
Expand Down
2 changes: 1 addition & 1 deletion built_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
const restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}"

var (
restrictedTags = map[string]struct{}{
restrictedRules = map[string]struct{}{
"dive": {},
"omitempty": {},
"omitempty_create": {},
Expand Down
12 changes: 6 additions & 6 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ type Options struct {
skipValidation bool
// Specify which field paths (using dot-separated strings)
// should ignore the "omitempty" (including method-specific)
// tags.
// rules.
//
// This can be useful when zero values are needed only during
// a specific method call.
//
// If left empty, those tags will be honoured for all fields.
// If left empty, those rules will be honoured for all fields.
allowEmptyFields []string
// Specify which field paths (using dot-separated strings)
// to be overwritten. Other fields on the existing document
Expand Down Expand Up @@ -63,21 +63,21 @@ func NewOptions() Options {
return Options{}
}

// Skip all validations - the "name" tag, "omitempty" tags and
// "ignore" tag will still be honoured.
// Skip all validations - the "name" rule, "omitempty" rules and
// "ignore" rule will still be honoured.
func (o Options) SkipValidation() Options {
o.skipValidation = true
return o
}

// Specify which field paths (using dot-separated strings)
// should ignore the "omitempty" (including method-specific)
// tags.
// rules.
//
// This can be useful when zero values are needed only during
// a specific method call.
//
// If left empty, those tags will be honoured for all fields.
// If left empty, those rules will be honoured for all fields.
func (o Options) AllowEmptyFields(fields ...string) Options {
o.allowEmptyFields = append(o.allowEmptyFields, fields...)
return o
Expand Down
24 changes: 12 additions & 12 deletions validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func newValidator() *validator {
// register predefined validators
for name, val := range builtInValidators {
runOnNil := false
// required tags will be called on nil values
// required rules will be called on nil values
if strings.Contains(name, "required") {
runOnNil = true
}
Expand Down Expand Up @@ -89,10 +89,10 @@ func (v *validator) registerValidation(
}

if !builtIn {
_, found := restrictedTags[name]
_, found := restrictedRules[name]
if found || strings.ContainsAny(name, restrictedTagChars) {
return errors.New(
"firevault: validation rule contains restricted characters or is the same as a built-in tag",
"firevault: validation rule contains restricted characters or is the same as a built-in rule",
)
}
}
Expand Down Expand Up @@ -121,10 +121,10 @@ func (v *validator) registerTransformation(
}

if !builtIn {
_, found := restrictedTags[name]
_, found := restrictedRules[name]
if found || strings.ContainsAny(name, restrictedTagChars) {
return errors.New(
"firevault: transformation rule contains restricted characters or is the same as a built-in tag",
"firevault: transformation rule contains restricted characters or is the same as a built-in rule",
)
}
}
Expand Down Expand Up @@ -235,15 +235,15 @@ func (v *validator) validateFields(
return nil, err
}

// check if field should be skipped based on provided tags
// check if field should be skipped based on provided rules
if v.shouldSkipField(fs.value, fs.path, rules, opts) {
continue
}

// check whether to dive into slice/map field
fs.dive = slices.Contains(rules, "dive")

// remove name, dive and omitempty tags from rules, so no validation is attempted
// remove name, dive and omitempty from rules, so no validation is attempted
fs.rules = v.cleanRules(rules)

// get pointer value, only if it's not nil
Expand Down Expand Up @@ -336,16 +336,16 @@ func (v *validator) validateFieldType(fieldValue reflect.Value, fieldPath string
return nil
}

// skip field validation if value is zero and an omitempty tag is present
// (unless tags are skipped using options)
// skip field validation if value is zero and an omitempty rule is present
// (unless rules are skipped using options)
func (v *validator) shouldSkipField(
fieldValue reflect.Value,
fieldPath string,
rules []string,
opts validationOpts,
) bool {
omitEmptyMethodTag := string("omitempty_" + opts.method)
shouldOmitEmpty := slices.Contains(rules, "omitempty") || slices.Contains(rules, omitEmptyMethodTag)
omitEmptyMethod := string("omitempty_" + opts.method)
shouldOmitEmpty := slices.Contains(rules, "omitempty") || slices.Contains(rules, omitEmptyMethod)

if shouldOmitEmpty && !slices.Contains(opts.emptyFieldsAllowed, fieldPath) {
return !hasValue(fieldValue)
Expand All @@ -354,7 +354,7 @@ func (v *validator) shouldSkipField(
return false
}

// remove name, dive and omitempty tags from rules
// remove name, dive and omitempty from rules
func (v *validator) cleanRules(rules []string) []string {
cleanedRules := make([]string, 0, len(rules))

Expand Down

0 comments on commit 8cae0a4

Please sign in to comment.