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

168 lines
3.1 KiB

package query
import (
"fmt"
"github.com/modern-go/reflect2"
"go.mongodb.org/mongo-driver/bson/primitive"
"github.com/mainnika/mongox-go-driver/v2/mongox/base/protection"
)
type applyFilterFunc = func(query *Query, filter interface{}) (ok bool)
// 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
}
valider, hasValider := filter.(Valider)
if hasValider {
err = valider.Valid()
}
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 x *primitive.ObjectID
var v *int64
switch filter := filter.(type) {
case protection.Key:
x = &filter.X
v = &filter.V
case *protection.Key:
x = &filter.X
v = &filter.V
default:
return false
}
if x.IsZero() {
query.And(primitive.M{"_x": primitive.M{"$exists": false}})
query.And(primitive.M{"_v": primitive.M{"$exists": false}})
} else {
query.And(primitive.M{"_x": *x})
query.And(primitive.M{"_v": *v})
}
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
}