From d031b8b32047633460e4fd0df9a83aa96fe60d6c Mon Sep 17 00:00:00 2001 From: username1103 Date: Wed, 22 Oct 2025 10:59:40 +0900 Subject: [PATCH] feat: add search pagination operation --- .../core/aggregation/ProjectStageDsl.kt | 10 ++++ .../core/aggregation/search/SearchStageDsl.kt | 22 +++++++++ .../core/aggregation/ProjectStageDslTest.kt | 25 ++++++++++ .../aggregation/search/SearchStageDslTest.kt | 46 +++++++++++++++++++ 4 files changed, 103 insertions(+) diff --git a/core/src/main/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/ProjectStageDsl.kt b/core/src/main/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/ProjectStageDsl.kt index 4ee3d3f1..302e9146 100644 --- a/core/src/main/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/ProjectStageDsl.kt +++ b/core/src/main/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/ProjectStageDsl.kt @@ -139,6 +139,16 @@ class ProjectStageDsl { addMetaDataKeyword("indexKey", alias) } + /** + * Specifies an alias that contains the search sequence token for paginating through Atlas Search results. + * + * @param alias The alias for the field. + * @see Paginate the results + */ + fun searchSequenceToken(alias: String = "paginationToken") { + addMetaDataKeyword("searchSequenceToken", alias) + } + private fun addMetaDataKeyword(keyword: String, alias: String) { operation = operation.andExpression("{\$meta: \"$keyword\"}").`as`(alias) } diff --git a/core/src/main/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/search/SearchStageDsl.kt b/core/src/main/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/search/SearchStageDsl.kt index 0b7ece7a..dd1e6710 100644 --- a/core/src/main/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/search/SearchStageDsl.kt +++ b/core/src/main/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/search/SearchStageDsl.kt @@ -59,6 +59,28 @@ class SearchStageDsl : SearchOperator by SearchOperatorDsl(), SearchCollector by field = value } + /** + * A token that specifies the point after which to return search results. + * + * @see Search After + */ + var searchAfter: String? = null + set(value) { + value?.let { document["searchAfter"] = it } + field = value + } + + /** + * A token that specifies the point before which to return search results. + * + * @see Search Before + */ + var searchBefore: String? = null + set(value) { + value?.let { document["searchBefore"] = it } + field = value + } + /** * Configures an option to include a lower bound count of the number of documents that match the query. * diff --git a/core/src/test/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/ProjectStageDslTest.kt b/core/src/test/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/ProjectStageDslTest.kt index e0cb3906..be106215 100644 --- a/core/src/test/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/ProjectStageDslTest.kt +++ b/core/src/test/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/ProjectStageDslTest.kt @@ -245,6 +245,31 @@ internal class ProjectStageDslTest : FreeSpec({ } } + "searchSequenceToken" - { + "should add search sequence token meta with given alias" { + // given + val stage = project { + searchSequenceToken("alias") + } + + // when + val result = stage.get() + + // then + result.shouldBeJson( + """ + { + "${'$'}project": { + "alias": { + "${'$'}meta": "searchSequenceToken" + } + } + } + """.trimIndent(), + ) + } + } + "searchHighlights" - { "should add search highlights meta with given alias" { // given diff --git a/core/src/test/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/search/SearchStageDslTest.kt b/core/src/test/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/search/SearchStageDslTest.kt index 9878ae60..fd37795b 100644 --- a/core/src/test/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/search/SearchStageDslTest.kt +++ b/core/src/test/kotlin/com/github/inflab/spring/data/mongodb/core/aggregation/search/SearchStageDslTest.kt @@ -257,4 +257,50 @@ internal class SearchStageDslTest : FreeSpec({ ) } } + + "searchAfter" - { + "should build a searchAfter option" { + // given + val stage = search { + searchAfter = "token" + } + + // when + val result = stage.build() + + // then + result.shouldBeJson( + """ + { + "${"$"}search": { + "searchAfter": "token" + } + } + """.trimIndent(), + ) + } + } + + "searchBefore" - { + "should build a searchBefore option" { + // given + val stage = search { + searchBefore = "token" + } + + // when + val result = stage.build() + + // then + result.shouldBeJson( + """ + { + "${"$"}search": { + "searchBefore": "token" + } + } + """.trimIndent(), + ) + } + } })