Skip to content

Commit

Permalink
feature: add TermsSet query support for es-query-builder + unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
GokselKUCUKSAHIN committed Feb 16, 2025
1 parent 08bfb8e commit 5bc166a
Show file tree
Hide file tree
Showing 2 changed files with 219 additions and 0 deletions.
102 changes: 102 additions & 0 deletions es/terms_set_query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package es

type termsSetType Object

// TermsSet creates a new es.termsSetType object with the specified field and terms.
//
// This function initializes an es.termsSetType object for a terms_set query, where the key
// represents the field name, and values are the terms that must be matched in the field.
//
// Example usage:
//
// termsSet : es.TermsSet("tags", "go", "elasticsearch")
// // termsSet now contains an es.termsSetType object that matches documents where the "tags" field contains "go" or "elasticsearch".
//
// Parameters:
// - key: A string representing the field name for the terms_set query.
// - values: A variadic list of terms to be matched in the specified field.
//
// Returns:
//
// An es.termsSetType object containing the specified terms_set query.
func TermsSet(key string, values ...any) termsSetType {
return termsSetType{
"terms_set": Object{
key: Object{
"terms": values,
},
},
}
}

// Boost sets the "boost" field in the terms_set query.
//
// This method configures the terms_set query to use a specified boost factor, which influences
// the relevance scoring of the matched documents.
//
// Example usage:
//
// termsSet : es.TermsSet("tags", "go", "elasticsearch").Boost(1.2)
// // termsSet now has a "boost" field set to 1.2 in the terms_set query object.
//
// Parameters:
// - boost: A float64 value representing the boost factor to be applied to the terms_set query.
//
// Returns:
//
// The updated es.termsSetType object with the "boost" field set.
func (t termsSetType) Boost(boost float64) termsSetType {
return t.putInTheField("boost", boost)
}

// MinimumShouldMatchField sets the "minimum_should_match_field" in the terms_set query.
//
// This method specifies a field that determines the minimum number of terms that must be matched.
// The field's value should be an integer representing the required number of matches.
//
// Example usage:
//
// termsSet : es.TermsSet("tags", "go", "elasticsearch").MinimumShouldMatchField("match_count")
// // termsSet now has a "minimum_should_match_field" set to "match_count".
//
// Parameters:
// - minimumShouldMatchField: A string representing the field name that specifies the required number of matches.
//
// Returns:
//
// The updated es.termsSetType object with the "minimum_should_match_field" set.
func (t termsSetType) MinimumShouldMatchField(minimumShouldMatchField string) termsSetType {
return t.putInTheField("minimum_should_match_field", minimumShouldMatchField)
}

// MinimumShouldMatchScript sets the "minimum_should_match_script" in the terms_set query.
//
// This method specifies a script that determines the minimum number of terms that must be matched,
// allowing for more dynamic query logic.
//
// Example usage:
//
// script := es.ScriptSource("return doc['tag_count'].value;", es.ScriptLanguage.Painless)
// termsSet : es.TermsSet("tags", "go", "elasticsearch").MinimumShouldMatchScript(script)
// // termsSet now has a "minimum_should_match_script" field set with the provided script.
//
// Parameters:
// - minimumShouldMatchScript: A scriptType object defining the script to determine the required number of matches.
//
// Returns:
//
// The updated es.termsSetType object with the "minimum_should_match_script" field set.
func (t termsSetType) MinimumShouldMatchScript(minimumShouldMatchScript scriptType) termsSetType {
return t.putInTheField("minimum_should_match_script", minimumShouldMatchScript)
}

func (t termsSetType) putInTheField(key string, value any) termsSetType {
if termsSet, ok := t["terms_set"].(Object); ok {
for field := range termsSet {
if fieldObject, foOk := termsSet[field].(Object); foOk {
fieldObject[key] = value
}
}
}
return t
}
117 changes: 117 additions & 0 deletions es/terms_set_query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package es_test

import (
ScriptLanguage "github.com/Trendyol/es-query-builder/es/enums/script-language"
"testing"

"github.com/Trendyol/es-query-builder/es"
"github.com/Trendyol/es-query-builder/test/assert"
)

//// Terms Set ////

func Test_TermsSet_should_exist_on_es_package(t *testing.T) {
t.Parallel()
// Given When Then
assert.NotNil(t, es.TermsSet)
}

func Test_TermsSet_should_create_json_with_terms_set_field_inside_query(t *testing.T) {
t.Parallel()
// Given
query := es.NewQuery(
es.TermsSet("key", "value1", "value2", "value3"),
)

// When Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
assert.Equal(t, "{\"query\":{\"terms_set\":{\"key\":{\"terms\":[\"value1\",\"value2\",\"value3\"]}}}}", bodyJSON)
}

func Test_TermsSet_method_should_create_termsSetType(t *testing.T) {
t.Parallel()
// Given
b := es.TermsSet("key", "value1", "value2", "value3")

// Then
assert.NotNil(t, b)
assert.IsTypeString(t, "es.termsSetType", b)
}

func Test_TermsSet_should_have_Boost_method(t *testing.T) {
t.Parallel()
// Given
termsSet := es.TermsSet("key", "value1", "value2", "value3")

// When Then
assert.NotNil(t, termsSet.Boost)
}

func Test_TermsSet_Boost_should_create_json_with_boost_field_inside_terms_set(t *testing.T) {
t.Parallel()
// Given
query := es.NewQuery(
es.TermsSet("sector.name", "a1", "b2", "c3").
Boost(2.718),
)

// When Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
assert.Equal(t, "{\"query\":{\"terms_set\":{\"sector.name\":{\"boost\":2.718,\"terms\":[\"a1\",\"b2\",\"c3\"]}}}}", bodyJSON)
}

func Test_TermsSet_should_have_MinimumShouldMatchField_method(t *testing.T) {
t.Parallel()
// Given
termsSet := es.TermsSet("key", "value1", "value2", "value3")

// When Then
assert.NotNil(t, termsSet.MinimumShouldMatchField)
}

func Test_TermsSet_MinimumShouldMatchField_should_create_json_with_minimum_should_match_field_field_inside_terms_set(t *testing.T) {
t.Parallel()
// Given
query := es.NewQuery(
es.TermsSet("sector.name", "a1", "b2", "c3").
MinimumShouldMatchField("match_threshold"),
)

// When Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
assert.Equal(t, "{\"query\":{\"terms_set\":{\"sector.name\":{\"minimum_should_match_field\":\"match_threshold\",\"terms\":[\"a1\",\"b2\",\"c3\"]}}}}", bodyJSON)
}

func Test_TermsSet_should_have_MinimumShouldMatchScript_method(t *testing.T) {
t.Parallel()
// Given
termsSet := es.TermsSet("key", "value1", "value2", "value3")

// When Then
assert.NotNil(t, termsSet.MinimumShouldMatchScript)
}

func Test_TermsSet_MinimumShouldMatchScript_should_create_json_with_minimum_should_match_script_field_inside_terms_set(t *testing.T) {
t.Parallel()
// Given
query := es.NewQuery(
es.TermsSet("sector.name", "a1", "b2", "c3").
MinimumShouldMatchScript(
es.ScriptSource("Math.max(1, doc['match_threshold'].value - 1)", ScriptLanguage.Painless).
Option("timeout", "10s").
Option("retry", "5").
Option("size", "500").
Parameter("threshold", 2).
Parameter("items", []int{1, 2, 3, 4}),
),
)

// When Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
// nolint:golint,lll
assert.Equal(t, "{\"query\":{\"terms_set\":{\"sector.name\":{\"minimum_should_match_script\":{\"lang\":\"painless\",\"options\":{\"retry\":\"5\",\"size\":\"500\",\"timeout\":\"10s\"},\"params\":{\"items\":[1,2,3,4],\"threshold\":2},\"source\":\"Math.max(1, doc['match_threshold'].value - 1)\"},\"terms\":[\"a1\",\"b2\",\"c3\"]}}}}", bodyJSON)
}

0 comments on commit 5bc166a

Please sign in to comment.