package esquery import ( "github.com/fatih/structs" ) // ExistsQuery represents a query of type "exists", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html type ExistsQuery struct { // Field is the name of the field to check for existence Field string `structs:"field"` } // Exists creates a new query of type "exists" on the provided field. func Exists(field string) *ExistsQuery { return &ExistsQuery{field} } // Map returns a map representation of the query, thus implementing the // Mappable interface. func (q *ExistsQuery) Map() map[string]interface{} { return map[string]interface{}{ "exists": structs.Map(q), } } //----------------------------------------------------------------------------// // IDsQuery represents a query of type "ids", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-query.html type IDsQuery struct { // IDs is the "ids" component of the query IDs struct { // Values is the list of ID values Values []string `structs:"values"` } `structs:"ids"` } // IDs creates a new query of type "ids" with the provided values. func IDs(vals ...string) *IDsQuery { q := &IDsQuery{} q.IDs.Values = vals return q } // Map returns a map representation of the query, thus implementing the // Mappable interface. func (q *IDsQuery) Map() map[string]interface{} { return structs.Map(q) } //----------------------------------------------------------------------------// // PrefixQuery represents query of type "prefix", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html type PrefixQuery struct { field string params prefixQueryParams } type prefixQueryParams struct { // Value is the prefix value to look for Value string `structs:"value"` // Rewrite is the method used to rewrite the query Rewrite string `structs:"rewrite,omitempty"` } // Prefix creates a new query of type "prefix", on the provided field and using // the provided prefix value. func Prefix(field, value string) *PrefixQuery { return &PrefixQuery{ field: field, params: prefixQueryParams{Value: value}, } } // Rewrite sets the rewrite method for the query func (q *PrefixQuery) Rewrite(s string) *PrefixQuery { q.params.Rewrite = s return q } // Map returns a map representation of the query, thus implementing the // Mappable interface. func (q *PrefixQuery) Map() map[string]interface{} { return map[string]interface{}{ "prefix": map[string]interface{}{ q.field: structs.Map(q.params), }, } } //----------------------------------------------------------------------------// // RangeQuery represents a query of type "range", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html type RangeQuery struct { field string params rangeQueryParams } type rangeQueryParams struct { Gt interface{} `structs:"gt,omitempty"` Gte interface{} `structs:"gte,omitempty"` Lt interface{} `structs:"lt,omitempty"` Lte interface{} `structs:"lte,omitempty"` Format string `structs:"format,omitempty"` Relation RangeRelation `structs:"relation,string,omitempty"` TimeZone string `structs:"time_zone,omitempty"` Boost float32 `structs:"boost,omitempty"` } // Range creates a new query of type "range" on the provided field func Range(field string) *RangeQuery { return &RangeQuery{field: field} } // Gt sets that the value of field must be greater than the provided value func (a *RangeQuery) Gt(val interface{}) *RangeQuery { a.params.Gt = val return a } // Gt sets that the value of field must be greater than or equal to the provided // value func (a *RangeQuery) Gte(val interface{}) *RangeQuery { a.params.Gte = val return a } // Lt sets that the value of field must be lower than the provided value func (a *RangeQuery) Lt(val interface{}) *RangeQuery { a.params.Lt = val return a } // Lte sets that the value of field must be lower than or equal to the provided // value func (a *RangeQuery) Lte(val interface{}) *RangeQuery { a.params.Lte = val return a } // Format sets the date format for date values func (a *RangeQuery) Format(f string) *RangeQuery { a.params.Format = f return a } // Relation sets how the query matches values for range fields func (a *RangeQuery) Relation(r RangeRelation) *RangeQuery { a.params.Relation = r return a } // TimeZone sets the time zone used for date values. func (a *RangeQuery) TimeZone(zone string) *RangeQuery { a.params.TimeZone = zone return a } // Boost sets the boost value of the query. func (a *RangeQuery) Boost(b float32) *RangeQuery { a.params.Boost = b return a } // Map returns a map representation of the query, thus implementing the // Mappable interface. func (a *RangeQuery) Map() map[string]interface{} { return map[string]interface{}{ "range": map[string]interface{}{ a.field: structs.Map(a.params), }, } } // RangeRelation is an enumeration type for a range query's "relation" field type RangeRelation uint8 const ( _ RangeRelation = iota // RangeIntersects is the "INTERSECTS" relation RangeIntersects // RangeContains is the "CONTAINS" relation RangeContains // RangeWithin is the "WITHIN" relation RangeWithin ) // String returns a string representation of the RangeRelation value, as // accepted by ElasticSearch func (a RangeRelation) String() string { switch a { case RangeIntersects: return "INTERSECTS" case RangeContains: return "CONTAINS" case RangeWithin: return "WITHIN" default: return "" } } //----------------------------------------------------------------------------// // RegexpQuery represents a query of type "regexp", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html type RegexpQuery struct { field string wildcard bool params regexpQueryParams } type regexpQueryParams struct { Value string `structs:"value"` Flags string `structs:"flags,omitempty"` MaxDeterminizedStates uint16 `structs:"max_determinized_states,omitempty"` Rewrite string `structs:"rewrite,omitempty"` } // Regexp creates a new query of type "regexp" on the provided field and using // the provided regular expression. func Regexp(field, value string) *RegexpQuery { return &RegexpQuery{ field: field, params: regexpQueryParams{ Value: value, }, } } // Value changes the regular expression value of the query. func (q *RegexpQuery) Value(v string) *RegexpQuery { q.params.Value = v return q } // Flags sets the regular expression's optional flags. func (q *RegexpQuery) Flags(f string) *RegexpQuery { if !q.wildcard { q.params.Flags = f } return q } // MaxDeterminizedStates sets the maximum number of automaton states required // for the query. func (q *RegexpQuery) MaxDeterminizedStates(m uint16) *RegexpQuery { if !q.wildcard { q.params.MaxDeterminizedStates = m } return q } // Rewrite sets the method used to rewrite the query. func (q *RegexpQuery) Rewrite(r string) *RegexpQuery { q.params.Rewrite = r return q } // Map returns a map representation of the query, thus implementing the // Mappable interface. func (q *RegexpQuery) Map() map[string]interface{} { var qType string if q.wildcard { qType = "wildcard" } else { qType = "regexp" } return map[string]interface{}{ qType: map[string]interface{}{ q.field: structs.Map(q.params), }, } } //----------------------------------------------------------------------------// // Wildcard creates a new query of type "wildcard" on the provided field and // using the provided regular expression value. Internally, wildcard queries // are simply specialized RegexpQuery values. // Wildcard queries are described in: // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html func Wildcard(field, value string) *RegexpQuery { return &RegexpQuery{ field: field, wildcard: true, params: regexpQueryParams{ Value: value, }, } } //----------------------------------------------------------------------------// // FuzzyQuery represents a query of type "fuzzy", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-fuzzy-query.html type FuzzyQuery struct { field string params fuzzyQueryParams } type fuzzyQueryParams struct { Value string `structs:"value"` Fuzziness string `structs:"fuzziness,omitempty"` MaxExpansions uint16 `structs:"max_expansions,omitempty"` PrefixLength uint16 `structs:"prefix_length,omitempty"` Transpositions *bool `structs:"transpositions,omitempty"` Rewrite string `structs:"rewrite,omitempty"` } // Fuzzy creates a new query of type "fuzzy" on the provided field and using // the provided value func Fuzzy(field, value string) *FuzzyQuery { return &FuzzyQuery{ field: field, params: fuzzyQueryParams{ Value: value, }, } } // Value sets the value of the query. func (q *FuzzyQuery) Value(val string) *FuzzyQuery { q.params.Value = val return q } // Fuzziness sets the maximum edit distance allowed for matching. func (q *FuzzyQuery) Fuzziness(fuzz string) *FuzzyQuery { q.params.Fuzziness = fuzz return q } // MaxExpansions sets the maximum number of variations created. func (q *FuzzyQuery) MaxExpansions(m uint16) *FuzzyQuery { q.params.MaxExpansions = m return q } // PrefixLength sets the number of beginning characters left unchanged when // creating expansions func (q *FuzzyQuery) PrefixLength(l uint16) *FuzzyQuery { q.params.PrefixLength = l return q } // Transpositions sets whether edits include transpositions of two adjacent // characters. func (q *FuzzyQuery) Transpositions(b bool) *FuzzyQuery { q.params.Transpositions = &b return q } // Rewrite sets the method used to rewrite the query. func (q *FuzzyQuery) Rewrite(s string) *FuzzyQuery { q.params.Rewrite = s return q } // Map returns a map representation of the query, thus implementing the // Mappable interface. func (q *FuzzyQuery) Map() map[string]interface{} { return map[string]interface{}{ "fuzzy": map[string]interface{}{ q.field: structs.Map(q.params), }, } } //----------------------------------------------------------------------------// // TermQuery represents a query of type "term", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html type TermQuery struct { field string params termQueryParams } type termQueryParams struct { Value interface{} `structs:"value"` Boost float32 `structs:"boost,omitempty"` } // Term creates a new query of type "term" on the provided field and using the // provide value func Term(field string, value interface{}) *TermQuery { return &TermQuery{ field: field, params: termQueryParams{ Value: value, }, } } // Value sets the term value for the query. func (q *TermQuery) Value(val interface{}) *TermQuery { q.params.Value = val return q } // Boost sets the boost value of the query. func (q *TermQuery) Boost(b float32) *TermQuery { q.params.Boost = b return q } // Map returns a map representation of the query, thus implementing the // Mappable interface. func (q *TermQuery) Map() map[string]interface{} { return map[string]interface{}{ "term": map[string]interface{}{ q.field: structs.Map(q.params), }, } } //----------------------------------------------------------------------------// // TermsQuery represents a query of type "terms", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html type TermsQuery struct { field string values []interface{} boost float32 } // Terms creates a new query of type "terms" on the provided field, and // optionally with the provided term values. func Terms(field string, values ...interface{}) *TermsQuery { return &TermsQuery{ field: field, values: values, } } // Values sets the term values for the query. func (q *TermsQuery) Values(values ...interface{}) *TermsQuery { q.values = values return q } // Boost sets the boost value of the query. func (q *TermsQuery) Boost(b float32) *TermsQuery { q.boost = b return q } // Map returns a map representation of the query, thus implementing the // Mappable interface. func (q TermsQuery) Map() map[string]interface{} { innerMap := map[string]interface{}{q.field: q.values} if q.boost > 0 { innerMap["boost"] = q.boost } return map[string]interface{}{"terms": innerMap} } //----------------------------------------------------------------------------// // TermsSetQuery represents a query of type "terms_set", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-set-query.html type TermsSetQuery struct { field string params termsSetQueryParams } type termsSetQueryParams struct { Terms []string `structs:"terms"` MinimumShouldMatchField string `structs:"minimum_should_match_field,omitempty"` MinimumShouldMatchScript string `structs:"minimum_should_match_script,omitempty"` } // TermsSet creates a new query of type "terms_set" on the provided field and // optionally using the provided terms. func TermsSet(field string, terms ...string) *TermsSetQuery { return &TermsSetQuery{ field: field, params: termsSetQueryParams{ Terms: terms, }, } } // Terms sets the terms for the query. func (q *TermsSetQuery) Terms(terms ...string) *TermsSetQuery { q.params.Terms = terms return q } // MinimumShouldMatchField sets the name of the field containing the number of // matching terms required to return a document. func (q *TermsSetQuery) MinimumShouldMatchField(field string) *TermsSetQuery { q.params.MinimumShouldMatchField = field return q } // MinimumShouldMatchScript sets the custom script containing the number of // matching terms required to return a document. func (q *TermsSetQuery) MinimumShouldMatchScript(script string) *TermsSetQuery { q.params.MinimumShouldMatchScript = script return q } // Map returns a map representation of the query, thus implementing the // Mappable interface. func (q TermsSetQuery) Map() map[string]interface{} { return map[string]interface{}{ "terms_set": map[string]interface{}{ q.field: structs.Map(q.params), }, } } // geoFilterParams represents a query of type "geo_distance", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-geo-distance-query.html type GeoFilter struct { params geoFilterParams filed string } func GeoFilterFunc(distance string, MiddleCentroid []float64, filed string) *GeoFilter { return &GeoFilter{ params: geoFilterParams{ Distance: distance, MiddleCentroid: MiddleCentroid, }, filed: filed, } } type geoFilterParams struct { Distance string `structs:"distance,omitempty"` MiddleCentroid []float64 `structs:"location,omitempty"` } func (g *GeoFilter) Distance(distance string) *GeoFilter { g.params.Distance = distance return g } func (g *GeoFilter) MiddleCentroid(middleCentroid []float64) *GeoFilter { g.params.MiddleCentroid = middleCentroid return g } func (g *GeoFilter) Map() map[string]interface{} { m := structs.Map(g.params) m[g.filed] = m["location"] delete(m, "location") response := map[string]interface{}{ "geo_distance": m} return response }