Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions es/condition/if_else.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package condition

// Branch represents a conditional branch used in IfElse chains.
// Create branches using ElseIf or Else functions.
type Branch struct {
item any
condition bool
isElse bool
}

// ElseIf creates a conditional branch for use in IfElse.
// The item is selected only if no previous condition was true and this condition is true.
//
// Parameters:
// - condition: A boolean that determines if `item` should be selected.
// - item: The value to return if this branch is selected.
//
// Returns:
//
// A Branch to be passed to IfElse.
//
// Example usage:
//
// condition.IfElse(x > 10, es.Term("foo", "bar"),
// condition.ElseIf(y < 20, es.Exists("fizz")),
// )
func ElseIf(condition bool, item any) Branch {
return Branch{condition: condition, item: item}
}

// Else creates a default branch for use in IfElse.
// The item is selected when no previous condition was true.
//
// Parameters:
// - item: The value to return if no other condition matched.
//
// Returns:
//
// A Branch to be passed as the last argument to IfElse.
//
// Example usage:
//
// condition.IfElse(x > 10, es.Term("foo", "bar"),
// condition.ElseIf(y < 20, es.Exists("fizz")),
// condition.Else(es.Range("date").LesserThan("now-2h")),
// )
func Else(item any) Branch {
return Branch{item: item, isElse: true}
}

// IfElse evaluates conditions in order and returns the item associated with the
// first true condition. If no condition is true and no Else branch is provided,
// it returns nil.
//
// Parameters:
// - condition: A boolean that determines if `item` should be returned.
// - item: The map or slice to return if the condition is true.
// - branches: Optional ElseIf and Else branches to evaluate in order.
//
// Returns:
//
// The item from the first matching condition, the Else item, or nil.
//
// Example usage:
//
// // Simple if
// condition.IfElse(x > 10, es.Term("foo", "bar"))
//
// // if + elseIf
// condition.IfElse(x > 10, es.Term("foo", "bar"),
// condition.ElseIf(y < 20, es.Exists("fizz")),
// )
//
// // if + elseIf + else
// condition.IfElse(x > 10, es.Term("foo", "bar"),
// condition.ElseIf(y < 20, es.Exists("fizz")),
// condition.Else(es.Range("date").LesserThan("now-2h")),
// )
func IfElse[T ~map[string]any | ~[]any](condition bool, item T, branches ...Branch) any {
if condition {
return item
}
for _, branch := range branches {
if branch.isElse {
return branch.item
}
if branch.condition {
return branch.item
}
}
return nil
}
238 changes: 238 additions & 0 deletions es/condition/if_else_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
package condition_test

import (
"testing"

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

func Test_IfElse_should_return_item_when_condition_is_true(t *testing.T) {
t.Parallel()
// Given
x := 15

// When
query := es.NewQuery(
es.Bool().
Filter(
condition.IfElse(x > 10, es.Term("foo", "bar")),
es.Exists("brandId"),
),
)

// Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
// nolint:golint,lll
assert.Equal(t, "{\"query\":{\"bool\":{\"filter\":[{\"term\":{\"foo\":{\"value\":\"bar\"}}},{\"exists\":{\"field\":\"brandId\"}}]}}}", bodyJSON)
}

func Test_IfElse_should_return_nil_when_condition_is_false(t *testing.T) {
t.Parallel()
// Given
x := 5

// When
query := es.NewQuery(
es.Bool().
Filter(
condition.IfElse(x > 10, es.Term("foo", "bar")),
es.Exists("brandId"),
),
)

// Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
assert.Equal(t, "{\"query\":{\"bool\":{\"filter\":[{\"exists\":{\"field\":\"brandId\"}}]}}}", bodyJSON)
}

func Test_IfElse_ElseIf_should_return_elseIf_item_when_first_is_false_and_second_is_true(t *testing.T) {
t.Parallel()
// Given
x := 5
y := 10

// When
query := es.NewQuery(
es.Bool().
Filter(
condition.IfElse(x > 10, es.Term("foo", "bar"),
condition.ElseIf(y < 20, es.Exists("fizz")),
),
),
)

// Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
assert.Equal(t, "{\"query\":{\"bool\":{\"filter\":[{\"exists\":{\"field\":\"fizz\"}}]}}}", bodyJSON)
}

func Test_IfElse_ElseIf_should_return_first_item_when_both_conditions_are_true(t *testing.T) {
t.Parallel()
// Given
x := 15
y := 10

// When
query := es.NewQuery(
es.Bool().
Filter(
condition.IfElse(x > 10, es.Term("foo", "bar"),
condition.ElseIf(y < 20, es.Exists("fizz")),
),
),
)

// Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
assert.Equal(t, "{\"query\":{\"bool\":{\"filter\":[{\"term\":{\"foo\":{\"value\":\"bar\"}}}]}}}", bodyJSON)
}

func Test_IfElse_ElseIf_should_return_nil_when_all_conditions_are_false(t *testing.T) {
t.Parallel()
// Given
x := 5
y := 25

// When
query := es.NewQuery(
es.Bool().
Filter(
condition.IfElse(x > 10, es.Term("foo", "bar"),
condition.ElseIf(y < 20, es.Exists("fizz")),
),
es.Exists("brandId"),
),
)

// Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
assert.Equal(t, "{\"query\":{\"bool\":{\"filter\":[{\"exists\":{\"field\":\"brandId\"}}]}}}", bodyJSON)
}

func Test_IfElse_Else_should_return_default_when_all_conditions_are_false(t *testing.T) {
t.Parallel()
// Given
x := 5
y := 25

// When
query := es.NewQuery(
es.Bool().
Filter(
condition.IfElse(x > 10, es.Term("foo", "bar"),
condition.ElseIf(y < 20, es.Exists("fizz")),
condition.Else(es.Term("default", "value")),
),
),
)

// Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
assert.Equal(t, "{\"query\":{\"bool\":{\"filter\":[{\"term\":{\"default\":{\"value\":\"value\"}}}]}}}", bodyJSON)
}

func Test_IfElse_Else_should_return_first_item_when_condition_is_true(t *testing.T) {
t.Parallel()
// Given
x := 15

// When
query := es.NewQuery(
es.Bool().
Filter(
condition.IfElse(x > 10, es.Term("foo", "bar"),
condition.Else(es.Term("default", "value")),
),
),
)

// Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
assert.Equal(t, "{\"query\":{\"bool\":{\"filter\":[{\"term\":{\"foo\":{\"value\":\"bar\"}}}]}}}", bodyJSON)
}

func Test_IfElse_Else_should_return_elseIf_item_when_first_false_second_true(t *testing.T) {
t.Parallel()
// Given
x := 5
y := 10

// When
query := es.NewQuery(
es.Bool().
Filter(
condition.IfElse(x > 10, es.Term("foo", "bar"),
condition.ElseIf(y < 20, es.Exists("fizz")),
condition.Else(es.Term("default", "value")),
),
),
)

// Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
assert.Equal(t, "{\"query\":{\"bool\":{\"filter\":[{\"exists\":{\"field\":\"fizz\"}}]}}}", bodyJSON)
}

func Test_IfElse_multiple_ElseIf_should_return_correct_item(t *testing.T) {
t.Parallel()
// Given
x := 5
y := 25
z := 3

// When
query := es.NewQuery(
es.Bool().
Filter(
condition.IfElse(x > 10, es.Term("first", "value"),
condition.ElseIf(y < 20, es.Term("second", "value")),
condition.ElseIf(z < 5, es.Term("third", "value")),
),
),
)

// Then
assert.NotNil(t, query)
bodyJSON := assert.MarshalWithoutError(t, query)
assert.Equal(t, "{\"query\":{\"bool\":{\"filter\":[{\"term\":{\"third\":{\"value\":\"value\"}}}]}}}", bodyJSON)
}

func Test_IfElse_should_work_with_slices(t *testing.T) {
t.Parallel()
// Given
cond := true

// When
result := condition.IfElse(cond, es.Array{1, 2, 3})

// Then
assert.NotNil(t, result)
bodyJSON := assert.MarshalWithoutError(t, result)
assert.Equal(t, "[1,2,3]", bodyJSON)
}

func Test_IfElse_Else_should_work_with_slices(t *testing.T) {
t.Parallel()
// Given
cond := false

// When
result := condition.IfElse(cond, es.Array{1, 2, 3},
condition.Else(es.Array{4, 5, 6}),
)

// Then
assert.NotNil(t, result)
bodyJSON := assert.MarshalWithoutError(t, result)
assert.Equal(t, "[4,5,6]", bodyJSON)
}
Loading