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:
|
||||
timeout: 5m
|
||||
|
||||
linters-settings:
|
||||
importas:
|
||||
alias:
|
||||
- pkg: '^github.com\/foomo\/contentfulvalidation\/(.*\/)?([^\/]+)\/?$'
|
||||
alias: '${2}x' # enforce `x` suffix
|
||||
no-unaliased: true
|
||||
# linters-settings:
|
||||
# importas:
|
||||
# alias:
|
||||
# - pkg: '^github.com\/foomo\/contentfulvalidation\/(.*\/)?([^\/]+)\/?$'
|
||||
# alias: '${2}x' # enforce `x` suffix
|
||||
# no-unaliased: true
|
||||
|
||||
linters:
|
||||
enable:
|
||||
@ -20,7 +20,7 @@ linters:
|
||||
# Disabled by default linters:
|
||||
- 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]
|
||||
- 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]
|
||||
- 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]
|
||||
@ -32,7 +32,7 @@ linters:
|
||||
- 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]
|
||||
- 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]
|
||||
- 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]
|
||||
|
||||
143
constants/vo.go
143
constants/vo.go
@ -1,5 +1,148 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"github.com/RoaringBitmap/roaring"
|
||||
)
|
||||
|
||||
type Severity string
|
||||
type Health 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
|
||||
|
||||
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/contentserver v1.10.2
|
||||
github.com/foomo/gotsrpc/v2 v2.7.2
|
||||
@ -14,7 +14,6 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/RoaringBitmap/roaring v1.3.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.8.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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
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.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
||||
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
|
||||
@ -4,8 +4,8 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
catvo "github.com/bestbytes/catalogue/vo"
|
||||
"github.com/foomo/contentful"
|
||||
"github.com/foomo/contentfulvalidation/constants"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@ -43,8 +43,8 @@ func GetAspectRatio(asset *contentful.AssetNoLocale) (float64, error) {
|
||||
return aspectRatio, nil
|
||||
}
|
||||
|
||||
func LoadQuery(rawQuery any) (*catvo.Query, error) {
|
||||
query := &catvo.Query{}
|
||||
func LoadQuery(rawQuery *interface{}) (*constants.Query, error) {
|
||||
query := &constants.Query{}
|
||||
errMarshal := loadInterfaceAsJSON(rawQuery, query)
|
||||
if errMarshal != nil {
|
||||
return nil, errMarshal
|
||||
|
||||
@ -1,24 +1,23 @@
|
||||
package validations
|
||||
|
||||
import (
|
||||
catvo "github.com/bestbytes/catalogue/vo"
|
||||
"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{}
|
||||
|
||||
isValueExpired := func(value string, def catvo.AttributeDefinition) {
|
||||
isValueExpired := func(value string, def constants.AttributeDefinition) {
|
||||
if len(value) < 1 {
|
||||
errors = append(errors, constants.MissingQueryFieldValues)
|
||||
} else {
|
||||
if _, ok := def.EnumStrings[catvo.AttributeValueID(value)]; !ok {
|
||||
if _, ok := def.EnumStrings[constants.AttributeValueID(value)]; !ok {
|
||||
errors = append(errors, constants.QueryValueExpired)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
areValuesExpired := func(values []string, def catvo.AttributeDefinition) {
|
||||
areValuesExpired := func(values []string, def constants.AttributeDefinition) {
|
||||
if len(values) < 1 {
|
||||
errors = append(errors, constants.MissingQueryFieldValues)
|
||||
}
|
||||
|
||||
@ -4,19 +4,19 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/bestbytes/catalogue/vo"
|
||||
"github.com/foomo/contentfulvalidation/constants"
|
||||
"github.com/foomo/keel/log"
|
||||
"github.com/go-co-op/gocron"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type AttributeProviderFunc func() vo.Attributes
|
||||
type AttributeUpdateFunc func(ctx context.Context) vo.Attributes
|
||||
type AttributeProviderFunc func() constants.Attributes
|
||||
type AttributeUpdateFunc func(ctx context.Context) constants.Attributes
|
||||
|
||||
type AttributeProvider struct {
|
||||
l *zap.Logger
|
||||
ctx context.Context
|
||||
attributes vo.Attributes
|
||||
attributes constants.Attributes
|
||||
updateFunc AttributeUpdateFunc
|
||||
}
|
||||
|
||||
@ -43,6 +43,6 @@ func (ap *AttributeProvider) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AttributeProvider) GetAttributes() vo.Attributes {
|
||||
func (ap *AttributeProvider) GetAttributes() constants.Attributes {
|
||||
return ap.attributes
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ type ModelValidator interface {
|
||||
ValidateAll() (map[ModelID]*ValidationResult, error)
|
||||
}
|
||||
|
||||
type ValidatorProvider interface {
|
||||
type ValidatorProvider interface { //nolint:revive
|
||||
GetValidators() map[ModelType]ModelValidator
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user