package search import ( "fmt" "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase/tools/inflector" "github.com/pocketbase/pocketbase/tools/list" ) // ResolverResult defines a single FieldResolver.Resolve() successfully parsed result. type ResolverResult struct { // Identifier is the plain SQL identifier/column that will be used // in the final db expression as left or right operand. Identifier string // Params is a map with db placeholder->value pairs that will be added // to the query when building both resolved operands/sides in a single expression. Params dbx.Params // MultiMatchSubQuery is an optional sub query expression that will be added // in addition to the combined ResolverResult expression during build. MultiMatchSubQuery dbx.Expression // AfterBuild is an optional function that will be called after building // and combining the result of both resolved operands/sides in a single expression. AfterBuild func(expr dbx.Expression) dbx.Expression } // FieldResolver defines an interface for managing search fields. type FieldResolver interface { // UpdateQuery allows to updated the provided db query based on the // resolved search fields (eg. adding joins aliases, etc.). // // Called internally by `search.Provider` before executing the search request. UpdateQuery(query *dbx.SelectQuery) error // Resolve parses the provided field and returns a properly // formatted db identifier (eg. NULL, quoted column, placeholder parameter, etc.). Resolve(field string) (*ResolverResult, error) } // NewSimpleFieldResolver creates a new `SimpleFieldResolver` with the // provided `allowedFields`. // // Each `allowedFields` could be a plain string (eg. "name") // or a regexp pattern (eg. `^\w+[\w\.]*$`). func NewSimpleFieldResolver(allowedFields ...string) *SimpleFieldResolver { return &SimpleFieldResolver{ allowedFields: allowedFields, } } // SimpleFieldResolver defines a generic search resolver that allows // only its listed fields to be resolved and take part in a search query. // // If `allowedFields` are empty no fields filtering is applied. type SimpleFieldResolver struct { allowedFields []string } // UpdateQuery implements `search.UpdateQuery` interface. func (r *SimpleFieldResolver) UpdateQuery(query *dbx.SelectQuery) error { // nothing to update... return nil } // Resolve implements `search.Resolve` interface. // // Returns error if `field` is not in `r.allowedFields`. func (r *SimpleFieldResolver) Resolve(field string) (*ResolverResult, error) { if !list.ExistInSliceWithRegex(field, r.allowedFields) { return nil, fmt.Errorf("Failed to resolve field %q.", field) } return &ResolverResult{ Identifier: "[[" + inflector.Columnify(field) + "]]", }, nil }