stevenbooru/vendor/src/github.com/peterbourgon/elasticsearch/types.go

406 lines
8.7 KiB
Go

package elasticsearch
import (
"encoding/json"
)
// This file contains structures that represent all of the various JSON-
// marshalable queries and sub-queries that are part of the ElasticSearch
// grammar. These structures are one-way: they're only meant to be Marshaled.
type SubQuery interface{}
var nilSubQuery SubQuery
//
//
//
// Wrapper gives a dynamic name to a SubQuery. For example, Name="foo"
// Wrapped=`{"bar": 123}` marshals to `{"foo": {"bar": 123}}`.
//
// You *can* use this directly in your business-logic code, but if you do, it's
// probably a sign you should file an issue (or make a pull request) to give
// your specific use-case proper, first class support, via a FooQuery[Params]
// type-set.
type Wrapper struct {
Name string
Wrapped SubQuery
}
func (w *Wrapper) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]SubQuery{
w.Name: w.Wrapped,
})
}
//
//
//
func QueryWrapper(q SubQuery) SubQuery {
return &Wrapper{
Name: "query",
Wrapped: q,
}
}
//
//
//
// GenericQueryParams marshal to a valid query object for a large number of
// query types. You generally use them applied to a particular field, ie. scope;
// see FieldedGenericQuery.
type GenericQueryParams struct {
Query string `json:"query,omitempty"`
Analyzer string `json:"analyzer,omitempty"`
Type string `json:"type,omitempty"`
MaxExpansions string `json:"max_expansions,omitempty"`
Boost float32 `json:"boost,omitempty"`
Operator string `json:"operator,omitempty"`
MinimumShouldMatch string `json:"minimum_should_match,omitempty"`
CutoffFrequency float32 `json:"cutoff_frequency,omitempty"`
}
// FieldedGenericQuery returns a SubQuery representing the passed QueryParams
// applied to the given scope, ie. field. The returned SubQuery can be used as
// the Query in a MatchQuery, for example.
func FieldedGenericQuery(field string, p GenericQueryParams) SubQuery {
return &Wrapper{
Name: field,
Wrapped: p,
}
}
//
//
//
// http://www.elasticsearch.org/guide/reference/query-dsl/match-query.html
type MatchQueryParams struct {
Query SubQuery `json:"match"`
}
func MatchQuery(p MatchQueryParams) SubQuery {
return p
}
//
//
//
// http://www.elasticsearch.org/guide/reference/query-dsl/term-query.html
// Typically `Query` would be &Wrapper{Name: "fieldname", Wrapped: "value"}.
type TermQueryParams struct {
Query SubQuery `json:"term"`
}
func TermQuery(p TermQueryParams) SubQuery {
return p
}
//
//
//
// http://www.elasticsearch.org/guide/reference/query-dsl/terms-query.html
// "a simpler syntax query for using a `bool` query with several `term` queries
// in the `should` clauses."
type TermsQueryParams struct {
Query SubQuery `json:"terms"` // often `{ "field": ["value1", "value2"] }`
}
func TermsQuery(p TermsQueryParams) SubQuery {
return p
}
//
//
//
// http://www.elasticsearch.org/guide/reference/query-dsl/dis-max-query.html
type DisMaxQueryParams struct {
Queries []SubQuery `json:"queries"`
Boost float32 `json:"boost,omitempty"`
TieBreaker float32 `json:"tie_breaker,omitempty"`
}
func DisMaxQuery(p DisMaxQueryParams) SubQuery {
return &Wrapper{
Name: "dis_max",
Wrapped: p,
}
}
//
//
//
// http://www.elasticsearch.org/guide/reference/query-dsl/bool-query.html
type BoolQueryParams struct {
Must SubQuery `json:"must,omitempty"` // can be slice!
Should SubQuery `json:"should,omitempty"`
MustNot SubQuery `json:"must_not,omitempty"`
MinimumNumberShouldMatch int `json:"minimum_number_should_match,omitempty"`
Boost float32 `json:"boost,omitempty"`
}
func BoolQuery(p BoolQueryParams) SubQuery {
return &Wrapper{
Name: "bool",
Wrapped: p,
}
}
//
//
//
// http://www.elasticsearch.org/guide/reference/query-dsl/custom-score-query.html
type CustomScoreQueryParams struct {
Script string `json:"script"`
Lang string `json:"lang"`
Params map[string]interface{} `json:"params"`
Query SubQuery `json:"query"`
}
func CustomScoreQuery(p CustomScoreQueryParams) SubQuery {
return &Wrapper{
Name: "custom_score",
Wrapped: p,
}
}
//
//
//
type ConstantScoreQueryParams struct {
Query SubQuery `json:"query,omitempty"`
Filter FilterSubQuery `json:"filter,omitempty"`
Boost float32 `json:"boost,omitempty"`
}
func ConstantScoreQuery(p ConstantScoreQueryParams) SubQuery {
return &Wrapper{
Name: "constant_score",
Wrapped: p,
}
}
//
//
//
func MatchAllQuery() SubQuery {
return &Wrapper{
Name: "match_all",
Wrapped: map[string]interface{}{}, // render to '{}'
}
}
//
//
//
// Haven't quite figured out how to best represent this.
// TODO break these up into embeddable query-parts?
type OffsetLimitFacetsFilterQueryParams struct {
Offset int `json:"from"`
Limit int `json:"size"`
Facets FacetSubQuery `json:"facets,omitempty"`
Filter FilterSubQuery `json:"filter,omitempty"`
Query SubQuery `json:"query"`
}
//
//
//
// =============================================================================
// HERE BE FILTERS
// =============================================================================
//
//
//
type FilterSubQuery SubQuery
func MakeFilter(filter SubQuery) FilterSubQuery {
return FilterSubQuery(filter)
}
func MakeFilters(filters []SubQuery) []FilterSubQuery {
a := []FilterSubQuery{}
for _, filter := range filters {
a = append(a, MakeFilter(filter))
}
return a
}
type BooleanFiltersParams struct {
AndFilters []FilterSubQuery
OrFilters []FilterSubQuery
}
func BooleanFilters(p BooleanFiltersParams) SubQuery {
switch nAnd, nOr := len(p.AndFilters), len(p.OrFilters); true {
case nAnd <= 0 && nOr <= 0:
return map[string]interface{}{} // render to '{}'
case nAnd > 0 && nOr <= 0:
return &Wrapper{
Name: "and",
Wrapped: p.AndFilters,
}
case nAnd <= 0 && nOr > 0:
return &Wrapper{
Name: "or",
Wrapped: p.OrFilters,
}
case nAnd > 0 && nOr > 0:
combinedFilters := append(p.AndFilters, &Wrapper{
Name: "or",
Wrapped: p.OrFilters,
})
return &Wrapper{
Name: "and",
Wrapped: combinedFilters,
}
}
panic("unreachable")
}
//
//
//
type QueryFilterParams struct {
Query SubQuery `json:"query"`
}
func QueryFilter(p QueryFilterParams) FilterSubQuery {
return p // no need for another layer of indirection; just like a typecast
}
//
//
//
type TermFilterParams struct {
Field string
Value string // for multiple values, use TermsFilter
}
func TermFilter(p TermFilterParams) FilterSubQuery {
return &Wrapper{
Name: "term",
Wrapped: &Wrapper{
Name: p.Field,
Wrapped: p.Value,
},
}
}
type TermsFilterParams struct {
Field string
Values []string
Execution string
}
func TermsFilter(p TermsFilterParams) FilterSubQuery {
terms := map[string]interface{}{
p.Field: p.Values,
}
if p.Execution != "" {
terms["execution"] = p.Execution
}
return map[string]interface{}{
"terms": terms,
}
}
//
//
//
// http://www.elasticsearch.org/guide/reference/query-dsl/type-filter.html
type FieldedFilterParams struct {
Value string `json:"value"`
}
// TODO I guess remove all Fielded* functions except FieldedGenericQuery?
// TODO and rename FieldedGenericQuery to like FieldedSubObject, maybe?
func FieldedFilter(fieldName string, p FieldedFilterParams) FilterSubQuery {
return &Wrapper{
Name: fieldName,
Wrapped: p,
}
}
//
//
//
type RangeSubQuery SubQuery
// http://www.elasticsearch.org/guide/reference/query-dsl/range-filter.html
type RangeFilterParams struct {
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`
IncludeLower bool `json:"include_lower"`
IncludeUpper bool `json:"include_upper"`
}
func FieldedRangeSubQuery(field string, p RangeFilterParams) RangeSubQuery {
return &Wrapper{
Name: field,
Wrapped: p,
}
}
func RangeFilter(q RangeSubQuery) FilterSubQuery {
return &Wrapper{
Name: "range",
Wrapped: q,
}
}
//
//
//
// =============================================================================
// HERE BE FACETS
// =============================================================================
//
//
//
type FacetSubQuery SubQuery
// http://www.elasticsearch.org/guide/reference/api/search/facets/terms-facet.html
type TermsFacetParams struct {
Field string `json:"field"`
Size int `json:"size"`
}
func TermsFacet(p TermsFacetParams) FacetSubQuery {
return &Wrapper{
Name: "terms",
Wrapped: p,
}
}
// TODO other types of facets
// NamedFacet wraps any FooFacet SubQuery so that it can be used
// wherever a facet is called for.
func NamedFacet(name string, q FacetSubQuery) FacetSubQuery {
return &Wrapper{
Name: name,
Wrapped: q,
}
}