feat: add query matchers

This commit is contained in:
tomaz jejcic 2023-11-02 17:29:23 +01:00
parent 80dd06457a
commit b1b492bea0
8 changed files with 165 additions and 26 deletions

View File

@ -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]

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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

View File

@ -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)
}

View File

@ -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
}

View File

@ -7,6 +7,6 @@ type ModelValidator interface {
ValidateAll() (map[ModelID]*ValidationResult, error)
}
type ValidatorProvider interface {
type ValidatorProvider interface { //nolint:revive
GetValidators() map[ModelType]ModelValidator
}