Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add compound option only if there is any clause #96

Merged
merged 1 commit into from
Oct 13, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.bson.Document
@AggregationMarker
class CompoundSearchOperatorDsl {
private val document = Document()
private var hasClause = false

/**
* Specify a minimum number of should clauses that must match to include a document in the results.
Expand Down Expand Up @@ -40,7 +41,11 @@ class CompoundSearchOperatorDsl {
* Maps to the `AND` boolean operator.
*/
fun must(mustConfiguration: SearchOperatorDsl.() -> Unit) {
document["must"] = SearchOperatorDsl().apply(mustConfiguration).operators
val operators = SearchOperatorDsl().apply(mustConfiguration).operators
if (operators.isNotEmpty()) {
document["must"] = operators
hasClause = true
}
}

/**
Expand All @@ -49,7 +54,11 @@ class CompoundSearchOperatorDsl {
* Maps to the `AND NOT` boolean operator.
*/
fun mustNot(mustNotConfiguration: SearchOperatorDsl.() -> Unit) {
document["mustNot"] = SearchOperatorDsl().apply(mustNotConfiguration).operators
val operators = SearchOperatorDsl().apply(mustNotConfiguration).operators
if (operators.isNotEmpty()) {
document["mustNot"] = operators
hasClause = true
}
}

/**
Expand All @@ -59,19 +68,33 @@ class CompoundSearchOperatorDsl {
* Maps to the `OR` boolean operator.
*/
fun should(shouldConfiguration: SearchOperatorDsl.() -> Unit) {
document["should"] = SearchOperatorDsl().apply(shouldConfiguration).operators
val operators = SearchOperatorDsl().apply(shouldConfiguration).operators
if (operators.isNotEmpty()) {
document["should"] = operators
hasClause = true
}
}

/**
* Clauses that must all match for a document to be included in the results.
* `filter` clauses do not contribute to a returned document's score.
*/
fun filter(filterConfiguration: SearchOperatorDsl.() -> Unit) {
document["filter"] = SearchOperatorDsl().apply(filterConfiguration).operators
val operators = SearchOperatorDsl().apply(filterConfiguration).operators
if (operators.isNotEmpty()) {
document["filter"] = operators
hasClause = true
}
}

internal fun build(): Document {
minimumShouldMatch?.let { document.put("minimumShouldMatch", it) }
internal fun build(): Document? {
if (!hasClause) {
return null
}

if (document["should"] != null && minimumShouldMatch != null) {
document["minimumShouldMatch"] = minimumShouldMatch
}

return Document("compound", document)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class SearchOperatorDsl : SearchOperator {
}

override fun compound(configuration: CompoundSearchOperatorDsl.() -> Unit) {
operators.add(CompoundSearchOperatorDsl().apply(configuration).build())
CompoundSearchOperatorDsl().apply(configuration).build()?.let { operators.add(it) }
}

override fun phrase(configuration: PhraseSearchOperatorDsl.() -> Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,92 @@ package com.github.inflab.spring.data.mongodb.core.aggregation.search

import com.github.inflab.spring.data.mongodb.core.util.shouldBeJson
import io.kotest.core.spec.style.FreeSpec
import io.kotest.matchers.nulls.shouldBeNull
import io.kotest.matchers.nulls.shouldNotBeNull

internal class CompoundSearchOperatorDslTest : FreeSpec({
fun compound(block: CompoundSearchOperatorDsl.() -> Unit) =
CompoundSearchOperatorDsl().apply(block)

"empty" - {
"should return null if there is no clause" {
// given
val operator = compound {
score {
constant(2.0)
}
}

// when
val result = operator.build()

// then
result.shouldBeNull()
}
}

"minimumShouldMatch" - {
"should build a with given value" {
"should build a given option" {
// given
val operator = compound {
should {
text {
path("field")
}
}
minimumShouldMatch = 1
}

// when
val result = operator.build()

// then
result.shouldNotBeNull()
result.shouldBeJson(
"""
{
"compound": {
"should": [
{
"text": {
"path": "field"
}
}
],
"minimumShouldMatch": 1
}
}
""".trimIndent(),
)
}

"should not build if there is no should clause" {
// given
val operator = compound {
minimumShouldMatch = 2
must {
text {
path("field")
}
}
minimumShouldMatch = 1
}

// when
val result = operator.build()

// then
result.shouldNotBeNull()
result.shouldBeJson(
"""
{
"compound": {
"minimumShouldMatch": 2
"must": [
{
"text": {
"path": "field"
}
}
]
}
}
""".trimIndent(),
Expand All @@ -34,6 +99,11 @@ internal class CompoundSearchOperatorDslTest : FreeSpec({
"should add score block" {
// given
val operator = compound {
should {
text {
path("field")
}
}
score {
constant(2.0)
}
Expand All @@ -43,10 +113,18 @@ internal class CompoundSearchOperatorDslTest : FreeSpec({
val result = operator.build()

// then
result.shouldNotBeNull()
result.shouldBeJson(
"""
{
"compound": {
"should": [
{
"text": {
"path": "field"
}
}
],
"score": {
"constant": {
"value": 2.0
Expand Down Expand Up @@ -74,6 +152,7 @@ internal class CompoundSearchOperatorDslTest : FreeSpec({
val result = operator.build()

// then
result.shouldNotBeNull()
result.shouldBeJson(
"""
{
Expand Down Expand Up @@ -107,6 +186,7 @@ internal class CompoundSearchOperatorDslTest : FreeSpec({
val result = operator.build()

// then
result.shouldNotBeNull()
result.shouldBeJson(
"""
{
Expand Down Expand Up @@ -140,6 +220,7 @@ internal class CompoundSearchOperatorDslTest : FreeSpec({
val result = operator.build()

// then
result.shouldNotBeNull()
result.shouldBeJson(
"""
{
Expand Down Expand Up @@ -173,6 +254,7 @@ internal class CompoundSearchOperatorDslTest : FreeSpec({
val result = operator.build()

// then
result.shouldNotBeNull()
result.shouldBeJson(
"""
{
Expand Down