You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mongox-go-driver/mongox/query/compose.go

160 lines
2.9 KiB

package query
import (
"fmt"
4 years ago
"github.com/modern-go/reflect2"
"go.mongodb.org/mongo-driver/bson/primitive"
5 years ago
"github.com/mainnika/mongox-go-driver/v2/mongox/base/protection"
)
type applyFilterFunc = func(query *Query, filter interface{}) (ok bool)
6 years ago
// Compose is a function to compose filters into a single query
func Compose(filters ...interface{}) (query *Query, err error) {
query = &Query{}
for _, filter := range filters {
ok, err := Push(query, filter)
if err != nil {
return nil, fmt.Errorf("invalid filter %v, %w", filter, err)
}
if !ok {
panic(fmt.Errorf("unknown filter %v", filter))
}
}
return
}
// Push applies single filter to a query
func Push(query *Query, filter interface{}) (ok bool, err error) {
ok = reflect2.IsNil(filter)
if ok {
return
}
validator, hasValidator := filter.(Validator)
if hasValidator {
err = validator.Validate()
}
if err != nil {
return
}
for _, applier := range []applyFilterFunc{
applyBson,
applyLimit,
applySort,
applySkip,
applyProtection,
applyPreloader,
applyUpdater,
applyCallbacks,
} {
ok = applier(query, filter) || ok
}
return
}
// applyBson is a fallback for a custom primitive.M
func applyBson(query *Query, filter interface{}) (ok bool) {
if filter, ok := filter.(primitive.M); ok {
query.And(filter)
return true
}
return false
}
// applyLimits extends query with a limiter
func applyLimit(query *Query, filter interface{}) (ok bool) {
if filter, ok := filter.(Limiter); ok {
query.limiter = filter
return true
}
return false
}
// applySort extends query with a sort rule
func applySort(query *Query, filter interface{}) (ok bool) {
if filter, ok := filter.(Sorter); ok {
query.sorter = filter
return true
}
return false
}
// applySkip extends query with a skip number
func applySkip(query *Query, filter interface{}) (ok bool) {
if filter, ok := filter.(Skipper); ok {
query.skipper = filter
return true
}
return false
}
func applyProtection(query *Query, filter interface{}) (ok bool) {
var keyDoc = primitive.M{}
switch filter := filter.(type) {
case protection.Key:
filter.PutToDocument(keyDoc)
case *protection.Key:
filter.PutToDocument(keyDoc)
default:
return false
}
query.And(keyDoc)
return true
}
func applyPreloader(query *Query, filter interface{}) (ok bool) {
if filter, ok := filter.(Preloader); ok {
query.preloader = filter
return true
}
return false
}
func applyUpdater(query *Query, filter interface{}) (ok bool) {
if filter, ok := filter.(Updater); ok {
query.updater = filter
return true
}
return false
}
func applyCallbacks(query *Query, filter interface{}) (ok bool) {
switch callback := filter.(type) {
case OnDecode:
query.ondecode = append(query.ondecode, Callback(callback))
case OnClose:
query.onclose = append(query.onclose, Callback(callback))
default:
return false
}
return true
}