mirror of
https://github.com/foomo/contentfulvalidation.git
synced 2025-10-16 12:25:37 +00:00
feat: add query matchers
This commit is contained in:
parent
80dd06457a
commit
b1b492bea0
@ -1,12 +1,12 @@
|
|||||||
run:
|
run:
|
||||||
timeout: 5m
|
timeout: 5m
|
||||||
|
|
||||||
linters-settings:
|
# linters-settings:
|
||||||
importas:
|
# importas:
|
||||||
alias:
|
# alias:
|
||||||
- pkg: '^github.com\/foomo\/contentfulvalidation\/(.*\/)?([^\/]+)\/?$'
|
# - pkg: '^github.com\/foomo\/contentfulvalidation\/(.*\/)?([^\/]+)\/?$'
|
||||||
alias: '${2}x' # enforce `x` suffix
|
# alias: '${2}x' # enforce `x` suffix
|
||||||
no-unaliased: true
|
# no-unaliased: true
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
@ -20,7 +20,7 @@ linters:
|
|||||||
# Disabled by default linters:
|
# Disabled by default linters:
|
||||||
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers [fast: true, auto-fix: false]
|
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers [fast: true, auto-fix: false]
|
||||||
- bidichk # Checks for dangerous unicode character sequences [fast: true, auto-fix: false]
|
- bidichk # Checks for dangerous unicode character sequences [fast: true, auto-fix: false]
|
||||||
- depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
|
# - depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
|
||||||
- dupl # Tool for code clone detection [fast: true, auto-fix: false]
|
- dupl # Tool for code clone detection [fast: true, auto-fix: false]
|
||||||
- forcetypeassert # finds forced type assertions [fast: true, auto-fix: false]
|
- forcetypeassert # finds forced type assertions [fast: true, auto-fix: false]
|
||||||
- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false]
|
- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false]
|
||||||
@ -32,7 +32,7 @@ linters:
|
|||||||
- goprintffuncname # Checks that printf-like functions are named with `f` at the end [fast: true, auto-fix: false]
|
- goprintffuncname # Checks that printf-like functions are named with `f` at the end [fast: true, auto-fix: false]
|
||||||
- gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false]
|
- gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false]
|
||||||
- grouper # An analyzer to analyze expression groups. [fast: true, auto-fix: false]
|
- grouper # An analyzer to analyze expression groups. [fast: true, auto-fix: false]
|
||||||
- importas # Enforces consistent import aliases [fast: false, auto-fix: false]
|
# - importas # Enforces consistent import aliases [fast: false, auto-fix: false]
|
||||||
- maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false]
|
- maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false]
|
||||||
- makezero # Finds slice declarations with non-zero initial length [fast: false, auto-fix: false]
|
- makezero # Finds slice declarations with non-zero initial length [fast: false, auto-fix: false]
|
||||||
- misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
|
- misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
|
||||||
|
|||||||
143
constants/vo.go
143
constants/vo.go
@ -1,5 +1,148 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/RoaringBitmap/roaring"
|
||||||
|
)
|
||||||
|
|
||||||
type Severity string
|
type Severity string
|
||||||
type Health string
|
type Health string
|
||||||
type QueryError string
|
type QueryError string
|
||||||
|
|
||||||
|
type (
|
||||||
|
AttributeID string
|
||||||
|
AttributeValueID string
|
||||||
|
AttributeType string
|
||||||
|
|
||||||
|
// Locale like en or en_us
|
||||||
|
Locale string
|
||||||
|
LocalizedString map[Locale]string
|
||||||
|
)
|
||||||
|
|
||||||
|
type Attributes map[AttributeID]AttributeDefinition
|
||||||
|
|
||||||
|
// AttributeDefinition describes an attribute.
|
||||||
|
type AttributeDefinition struct {
|
||||||
|
ID AttributeID `json:"id"`
|
||||||
|
Type AttributeType `json:"type"`
|
||||||
|
EnumStrings map[AttributeValueID]*string `json:"enumStrings,omitempty"`
|
||||||
|
Meta AttributeMeta `json:"meta,omitempty"`
|
||||||
|
MetaValues map[AttributeValueID]AttributeMeta `json:"metaValues,omitempty"`
|
||||||
|
StepSize int `json:"stepSize,omitempty"`
|
||||||
|
Mandatory bool `json:"mandatory,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AttributeMeta models meta information for an attribute.
|
||||||
|
type AttributeMeta struct {
|
||||||
|
Label LocalizedString `json:"label,omitempty"`
|
||||||
|
Description LocalizedString `json:"description,omitempty"`
|
||||||
|
Custom map[string]string `json:"custom,omitempty"`
|
||||||
|
SortingRank map[string]int `json:"sortingRank,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query structure
|
||||||
|
type Query struct {
|
||||||
|
Explanation string `json:"explanation,omitempty"`
|
||||||
|
Operation Operation `json:"operation"`
|
||||||
|
Elements []*QueryElement `json:"elements"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operation defines how to compare bitmaps
|
||||||
|
type Operation string
|
||||||
|
|
||||||
|
// QueryElement structure
|
||||||
|
type QueryElement struct {
|
||||||
|
Matcher *Matcher `json:"matcher,omitempty"`
|
||||||
|
Query *Query `json:"query,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matcher structure
|
||||||
|
// Identifies a bitmap
|
||||||
|
// the result of each match operation is a bitmap of entity ids
|
||||||
|
type Matcher struct {
|
||||||
|
Attribute AttributeID `json:"attribute,omitempty"`
|
||||||
|
Explanation string `json:"explanation,omitempty"`
|
||||||
|
|
||||||
|
// strings
|
||||||
|
StringIn *StringIn `json:"stringIn,omitempty"`
|
||||||
|
StringAllIn *StringAllIn `json:"stringAllIn,omitempty"`
|
||||||
|
StringNotIn *StringNotIn `json:"stringNotIn,omitempty"`
|
||||||
|
StringEquals *StringEquals `json:"stringEquals,omitempty"`
|
||||||
|
StringNotEquals *StringNotEquals `json:"stringNotEquals,omitempty"`
|
||||||
|
|
||||||
|
// integers
|
||||||
|
IntInRange *IntInRange `json:"intInRange,omitempty"`
|
||||||
|
IntFrom *IntFrom `json:"intFrom,omitempty"`
|
||||||
|
IntTo *IntTo `json:"intTo,omitempty"`
|
||||||
|
IntEquals *IntEquals `json:"intEquals,omitempty"`
|
||||||
|
IntNotEquals *IntNotEquals `json:"intNotEquals,omitempty"`
|
||||||
|
|
||||||
|
// booleans
|
||||||
|
BoolEquals *BoolEquals `json:"boolEquals,omitempty"`
|
||||||
|
|
||||||
|
// bitmap
|
||||||
|
Bitmap *Bitmap `json:"bitmap,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringIn matches if the input value equals any of the strings specified
|
||||||
|
type StringIn struct {
|
||||||
|
Values []string `json:"values"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringAllIn matches if all values appear in the input
|
||||||
|
type StringAllIn struct {
|
||||||
|
Values []string `json:"values"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringNotIn matches if the input value does not equal any of the strings specified
|
||||||
|
type StringNotIn struct {
|
||||||
|
Values []string `json:"values"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringEquals matches strings that DO equal the supplied value
|
||||||
|
type StringEquals struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringNotEquals matches strings that DO NOT equal the supplied value
|
||||||
|
type StringNotEquals struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntInRange matches integers in the given range
|
||||||
|
type IntInRange struct {
|
||||||
|
From int `json:"from"`
|
||||||
|
To int `json:"to"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntFrom matches integers starting from the given value (>=)
|
||||||
|
type IntFrom struct {
|
||||||
|
From int `json:"from"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntTo matches integers until the given value (<=)
|
||||||
|
type IntTo struct {
|
||||||
|
To int `json:"to"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntEquals matches integers exactly (==)
|
||||||
|
type IntEquals struct {
|
||||||
|
Value int `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntNotEquals matches integers that do not equal the given value (!=)
|
||||||
|
type IntNotEquals struct {
|
||||||
|
Value int `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolEquals matches booleans exactly (==)
|
||||||
|
type BoolEquals struct {
|
||||||
|
Value bool `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bitmap allows to use a *roaring.Bitmap directly for a matcher
|
||||||
|
type Bitmap struct {
|
||||||
|
// value is private to hide it from gotsrpc
|
||||||
|
value *roaring.Bitmap `json:"-"`
|
||||||
|
|
||||||
|
FacetValue string `json:"facetValue"`
|
||||||
|
}
|
||||||
|
|||||||
3
go.mod
3
go.mod
@ -3,7 +3,7 @@ module github.com/foomo/contentfulvalidation
|
|||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bestbytes/catalogue v0.39.0
|
github.com/RoaringBitmap/roaring v1.3.0
|
||||||
github.com/foomo/contentful v0.4.4
|
github.com/foomo/contentful v0.4.4
|
||||||
github.com/foomo/contentserver v1.10.2
|
github.com/foomo/contentserver v1.10.2
|
||||||
github.com/foomo/gotsrpc/v2 v2.7.2
|
github.com/foomo/gotsrpc/v2 v2.7.2
|
||||||
@ -14,7 +14,6 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/RoaringBitmap/roaring v1.3.0 // indirect
|
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.8.0 // indirect
|
github.com/bits-and-blooms/bitset v1.8.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -3,8 +3,6 @@ github.com/RoaringBitmap/roaring v1.3.0/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/
|
|||||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bestbytes/catalogue v0.39.0 h1:UYUhABB7ByGuxZNdr+9CqK4DZtmC9UIB37MpTJyDmAk=
|
|
||||||
github.com/bestbytes/catalogue v0.39.0/go.mod h1:eyZEeaZJSqc/r78jejYM+h8fkLnS1Kzd+IPzG0hxLH0=
|
|
||||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||||
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
||||||
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
|
|||||||
@ -4,8 +4,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
catvo "github.com/bestbytes/catalogue/vo"
|
|
||||||
"github.com/foomo/contentful"
|
"github.com/foomo/contentful"
|
||||||
|
"github.com/foomo/contentfulvalidation/constants"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,8 +43,8 @@ func GetAspectRatio(asset *contentful.AssetNoLocale) (float64, error) {
|
|||||||
return aspectRatio, nil
|
return aspectRatio, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadQuery(rawQuery any) (*catvo.Query, error) {
|
func LoadQuery(rawQuery *interface{}) (*constants.Query, error) {
|
||||||
query := &catvo.Query{}
|
query := &constants.Query{}
|
||||||
errMarshal := loadInterfaceAsJSON(rawQuery, query)
|
errMarshal := loadInterfaceAsJSON(rawQuery, query)
|
||||||
if errMarshal != nil {
|
if errMarshal != nil {
|
||||||
return nil, errMarshal
|
return nil, errMarshal
|
||||||
|
|||||||
@ -1,24 +1,23 @@
|
|||||||
package validations
|
package validations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
catvo "github.com/bestbytes/catalogue/vo"
|
|
||||||
"github.com/foomo/contentfulvalidation/constants"
|
"github.com/foomo/contentfulvalidation/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ValidateQuery(query *catvo.Query, attributes catvo.Attributes) []constants.QueryError {
|
func ValidateQuery(query *constants.Query, attributes constants.Attributes) []constants.QueryError {
|
||||||
errors := []constants.QueryError{}
|
errors := []constants.QueryError{}
|
||||||
|
|
||||||
isValueExpired := func(value string, def catvo.AttributeDefinition) {
|
isValueExpired := func(value string, def constants.AttributeDefinition) {
|
||||||
if len(value) < 1 {
|
if len(value) < 1 {
|
||||||
errors = append(errors, constants.MissingQueryFieldValues)
|
errors = append(errors, constants.MissingQueryFieldValues)
|
||||||
} else {
|
} else {
|
||||||
if _, ok := def.EnumStrings[catvo.AttributeValueID(value)]; !ok {
|
if _, ok := def.EnumStrings[constants.AttributeValueID(value)]; !ok {
|
||||||
errors = append(errors, constants.QueryValueExpired)
|
errors = append(errors, constants.QueryValueExpired)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
areValuesExpired := func(values []string, def catvo.AttributeDefinition) {
|
areValuesExpired := func(values []string, def constants.AttributeDefinition) {
|
||||||
if len(values) < 1 {
|
if len(values) < 1 {
|
||||||
errors = append(errors, constants.MissingQueryFieldValues)
|
errors = append(errors, constants.MissingQueryFieldValues)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,19 +4,19 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bestbytes/catalogue/vo"
|
"github.com/foomo/contentfulvalidation/constants"
|
||||||
"github.com/foomo/keel/log"
|
"github.com/foomo/keel/log"
|
||||||
"github.com/go-co-op/gocron"
|
"github.com/go-co-op/gocron"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AttributeProviderFunc func() vo.Attributes
|
type AttributeProviderFunc func() constants.Attributes
|
||||||
type AttributeUpdateFunc func(ctx context.Context) vo.Attributes
|
type AttributeUpdateFunc func(ctx context.Context) constants.Attributes
|
||||||
|
|
||||||
type AttributeProvider struct {
|
type AttributeProvider struct {
|
||||||
l *zap.Logger
|
l *zap.Logger
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
attributes vo.Attributes
|
attributes constants.Attributes
|
||||||
updateFunc AttributeUpdateFunc
|
updateFunc AttributeUpdateFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +43,6 @@ func (ap *AttributeProvider) Init() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ap *AttributeProvider) GetAttributes() vo.Attributes {
|
func (ap *AttributeProvider) GetAttributes() constants.Attributes {
|
||||||
return ap.attributes
|
return ap.attributes
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,6 @@ type ModelValidator interface {
|
|||||||
ValidateAll() (map[ModelID]*ValidationResult, error)
|
ValidateAll() (map[ModelID]*ValidationResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ValidatorProvider interface {
|
type ValidatorProvider interface { //nolint:revive
|
||||||
GetValidators() map[ModelType]ModelValidator
|
GetValidators() map[ModelType]ModelValidator
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user