Refactor API, add aggregations and custom queries
This commit introduces a refactor of the codebase and the API, to make
it more user friendly. Queries can now directly be executed via the
`Run()` method. Internally, the library no longer uses JSON generation
as a major mechanism, instead all types need to implement a `Mappable`
interface which simply turns each type in a `map[string]interface{}`,
which is what the ElasticSearch client expects. This makes the code
easier to write, and makes writing tests less error prone, as JSON need
not be written directly.
Support for metrics aggregations is also added. However, aggregations of
type bucket, pipeline and matrix are not supported yet.
To make the library more useful in its current state, support is added
for running custom queries and aggregations, via the `CustomQuery()` and
`CustomAgg()` functions, which both accepts an arbitrary
`map[string]interface{}`.
2020-02-19 11:35:21 +00:00
|
|
|
package esquery
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
|
|
|
|
"github.com/elastic/go-elasticsearch/v7"
|
|
|
|
"github.com/elastic/go-elasticsearch/v7/esapi"
|
|
|
|
)
|
|
|
|
|
2020-02-27 14:19:07 +00:00
|
|
|
// QueryRequest represents a complete request of type "query" to ElasticSearch's
|
|
|
|
// search API. It simply wraps a value of a type that implements the Mappable
|
|
|
|
// interface.
|
Refactor API, add aggregations and custom queries
This commit introduces a refactor of the codebase and the API, to make
it more user friendly. Queries can now directly be executed via the
`Run()` method. Internally, the library no longer uses JSON generation
as a major mechanism, instead all types need to implement a `Mappable`
interface which simply turns each type in a `map[string]interface{}`,
which is what the ElasticSearch client expects. This makes the code
easier to write, and makes writing tests less error prone, as JSON need
not be written directly.
Support for metrics aggregations is also added. However, aggregations of
type bucket, pipeline and matrix are not supported yet.
To make the library more useful in its current state, support is added
for running custom queries and aggregations, via the `CustomQuery()` and
`CustomAgg()` functions, which both accepts an arbitrary
`map[string]interface{}`.
2020-02-19 11:35:21 +00:00
|
|
|
type QueryRequest struct {
|
|
|
|
Query Mappable
|
|
|
|
}
|
|
|
|
|
2020-02-27 14:19:07 +00:00
|
|
|
// Query generates a search request of type "query", represented by a
|
|
|
|
// *QueryRequest object. It receives any query type that implements the
|
|
|
|
// Mappable interface, whether provided internally by the library or custom
|
|
|
|
// types provided by consuming code.
|
Refactor API, add aggregations and custom queries
This commit introduces a refactor of the codebase and the API, to make
it more user friendly. Queries can now directly be executed via the
`Run()` method. Internally, the library no longer uses JSON generation
as a major mechanism, instead all types need to implement a `Mappable`
interface which simply turns each type in a `map[string]interface{}`,
which is what the ElasticSearch client expects. This makes the code
easier to write, and makes writing tests less error prone, as JSON need
not be written directly.
Support for metrics aggregations is also added. However, aggregations of
type bucket, pipeline and matrix are not supported yet.
To make the library more useful in its current state, support is added
for running custom queries and aggregations, via the `CustomQuery()` and
`CustomAgg()` functions, which both accepts an arbitrary
`map[string]interface{}`.
2020-02-19 11:35:21 +00:00
|
|
|
func Query(q Mappable) *QueryRequest {
|
|
|
|
return &QueryRequest{q}
|
|
|
|
}
|
|
|
|
|
2020-02-27 14:19:07 +00:00
|
|
|
// Map implements the Mappable interface. It converts the "query" request into a
|
|
|
|
// (potentially nested) map[string]interface{}.
|
Refactor API, add aggregations and custom queries
This commit introduces a refactor of the codebase and the API, to make
it more user friendly. Queries can now directly be executed via the
`Run()` method. Internally, the library no longer uses JSON generation
as a major mechanism, instead all types need to implement a `Mappable`
interface which simply turns each type in a `map[string]interface{}`,
which is what the ElasticSearch client expects. This makes the code
easier to write, and makes writing tests less error prone, as JSON need
not be written directly.
Support for metrics aggregations is also added. However, aggregations of
type bucket, pipeline and matrix are not supported yet.
To make the library more useful in its current state, support is added
for running custom queries and aggregations, via the `CustomQuery()` and
`CustomAgg()` functions, which both accepts an arbitrary
`map[string]interface{}`.
2020-02-19 11:35:21 +00:00
|
|
|
func (req *QueryRequest) Map() map[string]interface{} {
|
|
|
|
return map[string]interface{}{
|
|
|
|
"query": req.Query.Map(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-27 14:19:07 +00:00
|
|
|
// MarshalJSON implements the json.Marshaler interface, it simply encodes the
|
|
|
|
// map representation of the query (provided by the Map method) as JSON.
|
2020-02-20 14:45:08 +00:00
|
|
|
func (req *QueryRequest) MarshalJSON() ([]byte, error) {
|
|
|
|
return json.Marshal(req.Map())
|
|
|
|
}
|
|
|
|
|
2020-02-27 14:19:07 +00:00
|
|
|
// Run executes the request using the provided ElasticSearch client. Zero or
|
|
|
|
// more search options can be provided as well. It returns the standard Response
|
|
|
|
// type of the official Go client.
|
Refactor API, add aggregations and custom queries
This commit introduces a refactor of the codebase and the API, to make
it more user friendly. Queries can now directly be executed via the
`Run()` method. Internally, the library no longer uses JSON generation
as a major mechanism, instead all types need to implement a `Mappable`
interface which simply turns each type in a `map[string]interface{}`,
which is what the ElasticSearch client expects. This makes the code
easier to write, and makes writing tests less error prone, as JSON need
not be written directly.
Support for metrics aggregations is also added. However, aggregations of
type bucket, pipeline and matrix are not supported yet.
To make the library more useful in its current state, support is added
for running custom queries and aggregations, via the `CustomQuery()` and
`CustomAgg()` functions, which both accepts an arbitrary
`map[string]interface{}`.
2020-02-19 11:35:21 +00:00
|
|
|
func (req *QueryRequest) Run(
|
|
|
|
api *elasticsearch.Client,
|
|
|
|
o ...func(*esapi.SearchRequest),
|
|
|
|
) (res *esapi.Response, err error) {
|
|
|
|
var b bytes.Buffer
|
2020-02-20 14:45:08 +00:00
|
|
|
err = json.NewEncoder(&b).Encode(req.Map())
|
Refactor API, add aggregations and custom queries
This commit introduces a refactor of the codebase and the API, to make
it more user friendly. Queries can now directly be executed via the
`Run()` method. Internally, the library no longer uses JSON generation
as a major mechanism, instead all types need to implement a `Mappable`
interface which simply turns each type in a `map[string]interface{}`,
which is what the ElasticSearch client expects. This makes the code
easier to write, and makes writing tests less error prone, as JSON need
not be written directly.
Support for metrics aggregations is also added. However, aggregations of
type bucket, pipeline and matrix are not supported yet.
To make the library more useful in its current state, support is added
for running custom queries and aggregations, via the `CustomQuery()` and
`CustomAgg()` functions, which both accepts an arbitrary
`map[string]interface{}`.
2020-02-19 11:35:21 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
opts := append([]func(*esapi.SearchRequest){api.Search.WithBody(&b)}, o...)
|
|
|
|
|
|
|
|
return api.Search(opts...)
|
|
|
|
}
|
2020-02-27 14:19:07 +00:00
|
|
|
|
|
|
|
// RunSearch is the same as the Run method, except that it accepts a value of
|
|
|
|
// type esapi.Search (usually this is the Search field of an elasticsearch.Client
|
|
|
|
// object). Since the ElasticSearch client does not provide an interface type
|
|
|
|
// for its API (which would allow implementation of mock clients), this provides
|
|
|
|
// a workaround. The Search function in the ES client is actually a field of a
|
|
|
|
// function type.
|
|
|
|
func (req *QueryRequest) RunSearch(
|
|
|
|
search esapi.Search,
|
|
|
|
o ...func(*esapi.SearchRequest),
|
|
|
|
) (res *esapi.Response, err error) {
|
|
|
|
var b bytes.Buffer
|
|
|
|
err = json.NewEncoder(&b).Encode(req.Map())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
opts := append([]func(*esapi.SearchRequest){search.WithBody(&b)}, o...)
|
|
|
|
|
|
|
|
return search(opts...)
|
|
|
|
}
|