func (r *SearchRequest) SetSearchAfter(after []string) {
	r.SearchAfter = after
}
SetSearchAfter sets the request to skip over hits with a sort
value less than the provided sort after key
package bleve
import (
	"encoding/json"
	"fmt"
	"reflect"
	"sort"
	"time"
	"github.com/blevesearch/bleve/v2/analysis"
	"github.com/blevesearch/bleve/v2/analysis/datetime/optional"
	"github.com/blevesearch/bleve/v2/document"
	"github.com/blevesearch/bleve/v2/registry"
	"github.com/blevesearch/bleve/v2/search"
	"github.com/blevesearch/bleve/v2/search/collector"
	"github.com/blevesearch/bleve/v2/search/query"
	"github.com/blevesearch/bleve/v2/size"
)
var reflectStaticSizeSearchResult int
var reflectStaticSizeSearchStatus int
func init() {
	var sr SearchResult
	reflectStaticSizeSearchResult = int(reflect.TypeOf(sr).Size())
	var ss SearchStatus
	reflectStaticSizeSearchStatus = int(reflect.TypeOf(ss).Size())
}
var cache = registry.NewCache()
const defaultDateTimeParser = optional.Name
type numericRange struct {
	Name string   `json:"name,omitempty"`
	Min  *float64 `json:"min,omitempty"`
	Max  *float64 `json:"max,omitempty"`
}
type dateTimeRange struct {
	Name        string    `json:"name,omitempty"`
	Start       time.Time `json:"start,omitempty"`
	End         time.Time `json:"end,omitempty"`
	startString *string
	endString   *string
}
func (dr *dateTimeRange) ParseDates(dateTimeParser analysis.DateTimeParser) (start, end time.Time) {
	start = dr.Start
	if dr.Start.IsZero() && dr.startString != nil {
		s, err := dateTimeParser.ParseDateTime(*dr.startString)
		if err == nil {
			start = s
		}
	}
	end = dr.End
	if dr.End.IsZero() && dr.endString != nil {
		e, err := dateTimeParser.ParseDateTime(*dr.endString)
		if err == nil {
			end = e
		}
	}
	return start, end
}
func (dr *dateTimeRange) UnmarshalJSON(input []byte) error {
	var temp struct {
		Name  string  `json:"name,omitempty"`
		Start *string `json:"start,omitempty"`
		End   *string `json:"end,omitempty"`
	}
	err := json.Unmarshal(input, &temp)
	if err != nil {
		return err
	}
	dr.Name = temp.Name
	if temp.Start != nil {
		dr.startString = temp.Start
	}
	if temp.End != nil {
		dr.endString = temp.End
	}
	return nil
}
func (dr *dateTimeRange) MarshalJSON() ([]byte, error) {
	rv := map[string]interface{}{
		"name":  dr.Name,
		"start": dr.Start,
		"end":   dr.End,
	}
	if dr.Start.IsZero() && dr.startString != nil {
		rv["start"] = dr.startString
	}
	if dr.End.IsZero() && dr.endString != nil {
		rv["end"] = dr.endString
	}
	return json.Marshal(rv)
}
type FacetRequest struct {
	Size           int              `json:"size"`
	Field          string           `json:"field"`
	NumericRanges  []*numericRange  `json:"numeric_ranges,omitempty"`
	DateTimeRanges []*dateTimeRange `json:"date_ranges,omitempty"`
}
func (fr *FacetRequest) Validate() error {
	nrCount := len(fr.NumericRanges)
	drCount := len(fr.DateTimeRanges)
	if nrCount > 0 && drCount > 0 {
		return fmt.Errorf("facet can only conain numeric ranges or date ranges, not both")
	}
	if nrCount > 0 {
		nrNames := map[string]interface{}{}
		for _, nr := range fr.NumericRanges {
			if _, ok := nrNames[nr.Name]; ok {
				return fmt.Errorf("numeric ranges contains duplicate name '%s'", nr.Name)
			}
			nrNames[nr.Name] = struct{}{}
			if nr.Min == nil && nr.Max == nil {
				return fmt.Errorf("numeric range query must specify either min, max or both for range name '%s'", nr.Name)
			}
		}
	} else {
		dateTimeParser, err := cache.DateTimeParserNamed(defaultDateTimeParser)
		if err != nil {
			return err
		}
		drNames := map[string]interface{}{}
		for _, dr := range fr.DateTimeRanges {
			if _, ok := drNames[dr.Name]; ok {
				return fmt.Errorf("date ranges contains duplicate name '%s'", dr.Name)
			}
			drNames[dr.Name] = struct{}{}
			start, end := dr.ParseDates(dateTimeParser)
			if start.IsZero() && end.IsZero() {
				return fmt.Errorf("date range query must specify either start, end or both for range name '%s'", dr.Name)
			}
		}
	}
	return nil
}
func NewFacetRequest(field string, size int) *FacetRequest {
	return &FacetRequest{
		Field: field,
		Size:  size,
	}
}
func (fr *FacetRequest) AddDateTimeRange(name string, start, end time.Time) {
	if fr.DateTimeRanges == nil {
		fr.DateTimeRanges = make([]*dateTimeRange, 0, 1)
	}
	fr.DateTimeRanges = append(fr.DateTimeRanges, &dateTimeRange{Name: name, Start: start, End: end})
}
func (fr *FacetRequest) AddDateTimeRangeString(name string, start, end *string) {
	if fr.DateTimeRanges == nil {
		fr.DateTimeRanges = make([]*dateTimeRange, 0, 1)
	}
	fr.DateTimeRanges = append(fr.DateTimeRanges,
		&dateTimeRange{Name: name, startString: start, endString: end})
}
func (fr *FacetRequest) AddNumericRange(name string, min, max *float64) {
	if fr.NumericRanges == nil {
		fr.NumericRanges = make([]*numericRange, 0, 1)
	}
	fr.NumericRanges = append(fr.NumericRanges, &numericRange{Name: name, Min: min, Max: max})
}
type FacetsRequest map[string]*FacetRequest
func (fr FacetsRequest) Validate() error {
	for _, v := range fr {
		err := v.Validate()
		if err != nil {
			return err
		}
	}
	return nil
}
type HighlightRequest struct {
	Style  *string  `json:"style"`
	Fields []string `json:"fields"`
}
func NewHighlight() *HighlightRequest {
	return &HighlightRequest{}
}
func NewHighlightWithStyle(style string) *HighlightRequest {
	return &HighlightRequest{
		Style: &style,
	}
}
func (h *HighlightRequest) AddField(field string) {
	if h.Fields == nil {
		h.Fields = make([]string, 0, 1)
	}
	h.Fields = append(h.Fields, field)
}
type SearchRequest struct {
	Query            query.Query       `json:"query"`
	Size             int               `json:"size"`
	From             int               `json:"from"`
	Highlight        *HighlightRequest `json:"highlight"`
	Fields           []string          `json:"fields"`
	Facets           FacetsRequest     `json:"facets"`
	Explain          bool              `json:"explain"`
	Sort             search.SortOrder  `json:"sort"`
	IncludeLocations bool              `json:"includeLocations"`
	Score            string            `json:"score,omitempty"`
	SearchAfter      []string          `json:"search_after"`
	SearchBefore     []string          `json:"search_before"`
	sortFunc func(sort.Interface)
}
func (r *SearchRequest) Validate() error {
	if srq, ok := r.Query.(query.ValidatableQuery); ok {
		err := srq.Validate()
		if err != nil {
			return err
		}
	}
	if r.SearchAfter != nil && r.SearchBefore != nil {
		return fmt.Errorf("cannot use search after and search before together")
	}
	if r.SearchAfter != nil {
		if r.From != 0 {
			return fmt.Errorf("cannot use search after with from !=0")
		}
		if len(r.SearchAfter) != len(r.Sort) {
			return fmt.Errorf("search after must have same size as sort order")
		}
	}
	if r.SearchBefore != nil {
		if r.From != 0 {
			return fmt.Errorf("cannot use search before with from !=0")
		}
		if len(r.SearchBefore) != len(r.Sort) {
			return fmt.Errorf("search before must have same size as sort order")
		}
	}
	return r.Facets.Validate()
}
func (r *SearchRequest) AddFacet(facetName string, f *FacetRequest) {
	if r.Facets == nil {
		r.Facets = make(FacetsRequest, 1)
	}
	r.Facets[facetName] = f
}
func (r *SearchRequest) SortBy(order []string) {
	so := search.ParseSortOrderStrings(order)
	r.Sort = so
}
func (r *SearchRequest) SortByCustom(order search.SortOrder) {
	r.Sort = order
}