Files
kubesphere/pkg/simple/client/es/query/builder.go
2021-03-30 13:44:24 +08:00

493 lines
8.1 KiB
Go

package query
import (
"reflect"
jsoniter "github.com/json-iterator/go"
)
// TODO: elastic/go-elasticsearch is working on Query DSL support.
// See https://github.com/elastic/go-elasticsearch/issues/42.
// We need refactor our query body builder when that is ready.
type Builder struct {
From int64 `json:"from,omitempty"`
Size int64 `json:"size,omitempty"`
Sorts []map[string]string `json:"sort,omitempty"`
*Query `json:",inline"`
*Aggregations `json:"aggs,omitempty"`
}
func NewBuilder() *Builder {
return &Builder{}
}
func (b *Builder) Bytes() ([]byte, error) {
return jsoniter.Marshal(b)
}
func (b *Builder) WithQuery(q *Query) *Builder {
if q == nil || q.Bool == nil || !q.IsValid() {
return b
}
b.Query = q
return b
}
func (b *Builder) WithAggregations(aggs *Aggregations) *Builder {
b.Aggregations = aggs
return b
}
func (b *Builder) WithFrom(n int64) *Builder {
b.From = n
return b
}
func (b *Builder) WithSize(n int64) *Builder {
b.Size = n
return b
}
func (b *Builder) WithSort(key, order string) *Builder {
if order == "" {
order = "desc"
}
b.Sorts = []map[string]string{{key: order}}
return b
}
// Query
type Query struct {
*Bool `json:"query,omitempty"`
}
func NewQuery() *Query {
return &Query{}
}
func (q *Query) WithBool(b *Bool) *Query {
if b == nil || !b.IsValid() {
return q
}
q.Bool = b
return q
}
// Aggregations
type Aggregations struct {
*CardinalityAggregation `json:"cardinality_aggregation,omitempty"`
*DateHistogramAggregation `json:"date_histogram_aggregation,omitempty"`
}
type CardinalityAggregation struct {
*Cardinality `json:"cardinality,omitempty"`
}
type Cardinality struct {
Field string `json:"field,omitempty"`
}
type DateHistogramAggregation struct {
*DateHistogram `json:"date_histogram,omitempty"`
}
type DateHistogram struct {
Field string `json:"field,omitempty"`
Interval string `json:"interval,omitempty"`
}
func NewAggregations() *Aggregations {
return &Aggregations{}
}
func (a *Aggregations) WithCardinalityAggregation(field string) *Aggregations {
a.CardinalityAggregation = &CardinalityAggregation{
&Cardinality{
Field: field,
},
}
return a
}
func (a *Aggregations) WithDateHistogramAggregation(field string, interval string) *Aggregations {
a.DateHistogramAggregation = &DateHistogramAggregation{
&DateHistogram{
Field: field,
Interval: interval,
},
}
return a
}
type Item interface {
IsValid() bool
}
// Example:
// {bool: {filter: <[]Match>}}
// {bool: {should: <[]Match>, minimum_should_match: 1}}
type Bool struct {
*Parameter `json:"bool,omitempty"`
}
type Parameter struct {
Filter []interface{} `json:"filter,omitempty"`
Should []interface{} `json:"should,omitempty"`
MustNot []interface{} `json:"must_not,omitempty"`
MinimumShouldMatch int32 `json:"minimum_should_match,omitempty"`
}
func NewBool() *Bool {
return &Bool{
&Parameter{},
}
}
func (b *Bool) IsValid() bool {
if (b.Filter == nil || len(b.Filter) == 0) &&
(b.Should == nil || len(b.Should) == 0) &&
(b.MustNot == nil || len(b.MustNot) == 0) {
return false
}
return true
}
func (b *Bool) AppendFilter(item Item) *Bool {
if reflect.ValueOf(item).IsNil() || !item.IsValid() {
return b
}
b.Filter = append(b.Filter, item)
return b
}
func (b *Bool) AppendMultiFilter(items []Item) *Bool {
if items == nil || len(items) == 0 {
return b
}
for _, item := range items {
if item.IsValid() {
b.Filter = append(b.Filter, item)
}
}
return b
}
func (b *Bool) AppendShould(item Item) *Bool {
if reflect.ValueOf(item).IsNil() || !item.IsValid() {
return b
}
b.Should = append(b.Should, item)
return b
}
func (b *Bool) AppendMultiShould(items []Item) *Bool {
if items == nil || len(items) == 0 {
return b
}
for _, item := range items {
if item.IsValid() {
b.Should = append(b.Should, item)
}
}
return b
}
func (b *Bool) AppendMustNot(item Item) *Bool {
if reflect.ValueOf(item).IsNil() || !item.IsValid() {
return b
}
b.MustNot = append(b.MustNot, item)
return b
}
func (b *Bool) AppendMultiMustNot(items []Item) *Bool {
if items == nil || len(items) == 0 {
return b
}
for _, item := range items {
if item.IsValid() {
b.MustNot = append(b.MustNot, item)
}
}
return b
}
func (b *Bool) WithMinimumShouldMatch(min int32) *Bool {
b.MinimumShouldMatch = min
return b
}
type MatchPhrase struct {
MatchPhrase map[string]string `json:"match_phrase,omitempty"`
}
func (m *MatchPhrase) IsValid() bool {
if m.MatchPhrase == nil || len(m.MatchPhrase) == 0 {
return false
}
return true
}
func NewMatchPhrase(key, val string) *MatchPhrase {
return &MatchPhrase{
MatchPhrase: map[string]string{
key: val,
},
}
}
func NewMultiMatchPhrase(key string, val []string) []Item {
var array []Item
if val == nil || len(val) == 0 {
return nil
}
for _, v := range val {
array = append(array, &MatchPhrase{
MatchPhrase: map[string]string{
key: v,
},
})
}
return array
}
type MatchPhrasePrefix struct {
MatchPhrasePrefix map[string]string `json:"match_phrase_prefix,omitempty"`
}
func (m *MatchPhrasePrefix) IsValid() bool {
if m.MatchPhrasePrefix == nil || len(m.MatchPhrasePrefix) == 0 {
return false
}
return true
}
func NewMatchPhrasePrefix(key, val string) *MatchPhrasePrefix {
return &MatchPhrasePrefix{
MatchPhrasePrefix: map[string]string{
key: val,
},
}
}
func NewMultiMatchPhrasePrefix(key string, val []string) []Item {
var array []Item
if val == nil || len(val) == 0 {
return nil
}
for _, v := range val {
array = append(array, &MatchPhrasePrefix{
MatchPhrasePrefix: map[string]string{
key: v,
},
})
}
return array
}
type Regexp struct {
Regexp map[string]string `json:"regexp,omitempty"`
}
func (m *Regexp) IsValid() bool {
if m.Regexp == nil || len(m.Regexp) == 0 {
return false
}
return true
}
func NewRegex(key, val string) *Regexp {
return &Regexp{
Regexp: map[string]string{
key: val,
},
}
}
type Range struct {
Range map[string]map[string]interface{} `json:"range,omitempty"`
}
func NewRange(key string) *Range {
return &Range{
Range: map[string]map[string]interface{}{
key: make(map[string]interface{}),
},
}
}
func (r *Range) WithGT(val interface{}) *Range {
r.withRange("gt", val)
return r
}
func (r *Range) WithGTE(val interface{}) *Range {
r.withRange("gte", val)
return r
}
func (r *Range) WithLT(val interface{}) *Range {
r.withRange("lt", val)
return r
}
func (r *Range) WithLTE(val interface{}) *Range {
r.withRange("lte", val)
return r
}
func (r *Range) IsValid() bool {
if r.Range == nil {
return false
}
if len(r.Range) == 0 {
return false
}
for _, v := range r.Range {
if len(v) != 0 {
return true
}
}
return false
}
func (r *Range) withRange(operator string, val interface{}) {
if r.Range == nil {
return
}
for _, v := range r.Range {
v[operator] = val
}
}
type Wildcard struct {
Wildcard map[string]string `json:"wildcard,omitempty"`
}
func (m *Wildcard) IsValid() bool {
if m.Wildcard == nil || len(m.Wildcard) == 0 {
return false
}
return true
}
func NewWildcard(key, val string) *Wildcard {
return &Wildcard{
Wildcard: map[string]string{
key: val,
},
}
}
func NewMultiWildcard(key string, val []string) []Item {
var array []Item
if val == nil || len(val) == 0 {
return nil
}
for _, v := range val {
array = append(array, &Wildcard{
Wildcard: map[string]string{
key: v,
},
})
}
return array
}
type Terms struct {
Terms map[string]interface{} `json:"terms,omitempty"`
}
func (m *Terms) IsValid() bool {
if m.Terms == nil || len(m.Terms) == 0 {
return false
}
return true
}
func NewTerms(key string, val interface{}) *Terms {
if reflect.ValueOf(val).IsNil() {
return nil
}
return &Terms{
Terms: map[string]interface{}{
key: val,
},
}
}
type Exists struct {
Exists map[string]string `json:"exists,omitempty"`
}
func (m *Exists) IsValid() bool {
if m.Exists == nil || len(m.Exists) == 0 {
return false
}
return true
}
func NewExists(key, val string) *Exists {
return &Exists{
Exists: map[string]string{
key: val,
},
}
}