From 55000abc77d2b4ceaece4c7e2b7b421281c3c01c Mon Sep 17 00:00:00 2001 From: Ido Perlmuter Date: Tue, 18 Feb 2020 18:43:19 +0200 Subject: [PATCH] Add Search() function, README and fix some lint errors This commit changes the internal `search()` function into an exposed `Search()` function that can be used to execute queries against an instance of an ElasticSearch client. The per-query-type methods of `Run()` are removed for now to prevent having to create them for every type. `Search()` is agnostic. A README.md file is added with some information, and a few lingering lint errors are fixed. --- .golangci.yml | 2 ++ README.md | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ es.go | 9 ++++-- go.mod | 6 +++- go.sum | 4 +++ match.go | 8 +---- match_all.go | 6 ---- 7 files changed, 109 insertions(+), 16 deletions(-) create mode 100644 README.md diff --git a/.golangci.yml b/.golangci.yml index faf3f2f..ee46e7c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,3 +1,5 @@ +run: + tests: false linters: disable-all: true enable: diff --git a/README.md b/README.md new file mode 100644 index 0000000..4d9f611 --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +# esquery + +`esquery` is an idiomatic, easy-to-use query builder for the [official Go client](https://github.com/elastic/go-elasticsearch) for [ElasticSearch](https://www.elastic.co/products/elasticsearch). It alleviates the need to use extremely nested maps of empty interfaces and serializing queries to JSON manually. It also helps eliminating common mistakes such as misspelling query types, as everything is statically typed. + +## Usage + +`esquery` can be used directly to build queries, with no need for external dependencies. It can execute the queries against an existing instance of `*esapi.API`, but the queries can also be manually converted to JSON if necessary. + +```go +package main + +import ( + "context" + "log" + + "bitbucket.org/scalock/esquery" + "github.com/elastic/go-elasticsearch/v7" +) + +func main() { + es, err := elasticsearch.NewDefaultClient() + if err != nil { + log.Fatalf("Failed creating client: %s", err) + } + + res, err := esquery.Search( + es, + esquery. + Bool(). + Must(esquery.Term("title", "Go and Stuff")). + Filter(esquery.Term("tag", "tech")), + es.Search.WithContext(context.TODO()), + es.Search.WithIndex("test"), + ) + if err != nil { + log.Fatalf("Failed searching for stuff: %s", err) + } + + defer res.Body.Close() + + // ... +} +``` + +## Notes + +* Library currently supports v7 of the ElasticSearch Go client. +* The library cannot currently generate "short queries". For example, whereas + ElasticSearch can accept this: + +```json +{ "query": { "term": { "user": "Kimchy" } } } +``` + + The library will always generate this: + +```json +{ "query": { "term": { "user": { "value": "Kimchy" } } } } +``` + + This is also true for queries such as "bool", where fields like "must" can + either receive one query object, or an array of query objects. `esquery` will + generate an array even if there's only one query object. + +## Supported queries + +The following queries are currently supported: + +| Query | `esquery` Function | +| ------------------------|---------------------- | +| `"match"` | `Match()` | +| `"match_bool_prefix"` | `MatchBoolPrefix()` | +| `"match_phrase"` | `MatchPhrase()` | +| `"match_phrase_prefix"` | `MatchPhrasePrefix()` | +| `"match_all"` | `MatchAll()` | +| `"match_none"` | `MatchNone()` | +| `"exists"` | `Exists()` | +| `"fuzzy"` | `Fuzzy()` | +| `"ids"` | `IDs()` | +| `"prefix"` | `Prefix()` | +| `"range"` | `Range()` | +| `"regexp"` | `Regexp()` | +| `"term"` | `Term()` | +| `"terms"` | `Terms()` | +| `"terms_set"` | `TermsSet()` | +| `"wildcard"` | `Wildcard()` | +| `"bool"` | `Bool()` | +| `"boosting"` | `Boosting()` | +| `"constant_score"` | `ConstantScore()` | +| `"dis_max"` | `DisMax()` | diff --git a/es.go b/es.go index 8d6698c..10e24eb 100644 --- a/es.go +++ b/es.go @@ -5,7 +5,8 @@ import ( "encoding/json" "fmt" - "github.com/elastic/go-elasticsearch/esapi" + "github.com/elastic/go-elasticsearch/v7" + "github.com/elastic/go-elasticsearch/v7/esapi" ) type ESQuery struct { @@ -22,7 +23,11 @@ func encode(q json.Marshaler, b *bytes.Buffer) (err error) { return nil } -func search(q json.Marshaler, api *esapi.API, o ...func(*esapi.SearchRequest)) (res *esapi.Response, err error) { +func Search( + api *elasticsearch.Client, + q json.Marshaler, + o ...func(*esapi.SearchRequest), +) (res *esapi.Response, err error) { var b bytes.Buffer err = encode(ESQuery{q}, &b) if err != nil { diff --git a/go.mod b/go.mod index 3b1d837..223085a 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,8 @@ module bitbucket.org/scalock/esquery go 1.13 -require github.com/elastic/go-elasticsearch v0.0.0 +require ( + github.com/elastic/go-elasticsearch v0.0.0 + github.com/elastic/go-elasticsearch/v7 v7.6.0 + github.com/elastic/go-elasticsearch/v8 v8.0.0-20200210103600-aff00e5adfde +) diff --git a/go.sum b/go.sum index 06225ee..30afa0b 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,6 @@ github.com/elastic/go-elasticsearch v0.0.0 h1:Pd5fqOuBxKxv83b0+xOAJDAkziWYwFinWnBO0y+TZaA= github.com/elastic/go-elasticsearch v0.0.0/go.mod h1:TkBSJBuTyFdBnrNqoPc54FN0vKf5c04IdM4zuStJ7xg= +github.com/elastic/go-elasticsearch/v7 v7.6.0 h1:sYpGLpEFHgLUKLsZUBfuaVI9QgHjS3JdH9fX4/z8QI8= +github.com/elastic/go-elasticsearch/v7 v7.6.0/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4= +github.com/elastic/go-elasticsearch/v8 v8.0.0-20200210103600-aff00e5adfde h1:Y9SZx8RQqFycLxi5W5eFmxMqnmijULVc3LMjBTtZQdM= +github.com/elastic/go-elasticsearch/v8 v8.0.0-20200210103600-aff00e5adfde/go.mod h1:xe9a/L2aeOgFKKgrO3ibQTnMdpAeL0GC+5/HpGScSa4= diff --git a/match.go b/match.go index 29e36e2..896d42c 100644 --- a/match.go +++ b/match.go @@ -5,8 +5,6 @@ import ( "encoding/json" "errors" "io" - - "github.com/elastic/go-elasticsearch/esapi" ) /******************************************************************************* @@ -51,10 +49,6 @@ func (a MatchQuery) MarshalJSON() ([]byte, error) { }) } -func (a *MatchQuery) Run(api *esapi.API, o ...func(*esapi.SearchRequest)) (res *esapi.Response, err error) { - return search(*a, api, o...) -} - type matchParams struct { Qry interface{} `json:"query"` Anl string `json:"analyzer,omitempty"` @@ -89,7 +83,7 @@ func MatchPhrasePrefix(fieldName string, simpleQuery ...interface{}) *MatchQuery func newMatch(mType matchType, fieldName string, simpleQuery ...interface{}) *MatchQuery { var qry interface{} - if simpleQuery != nil && len(simpleQuery) > 0 { + if len(simpleQuery) > 0 { qry = simpleQuery[len(simpleQuery)-1] } diff --git a/match_all.go b/match_all.go index 5079115..c26363c 100644 --- a/match_all.go +++ b/match_all.go @@ -2,8 +2,6 @@ package esquery import ( "encoding/json" - - "github.com/elastic/go-elasticsearch/esapi" ) // https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html @@ -28,10 +26,6 @@ func (a MatchAllQuery) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]matchAllParams{mType: a.params}) } -func (a *MatchAllQuery) Run(api *esapi.API, o ...func(*esapi.SearchRequest)) (res *esapi.Response, err error) { - return search(*a, api, o...) -} - func MatchAll() *MatchAllQuery { return &MatchAllQuery{all: true} }