Skip to content

Commit b78f1c6

Browse files
feat(firestore): Added search stage support for languageCode, offset, limit, and retrievalDepth (#8066)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 81f5614 commit b78f1c6

5 files changed

Lines changed: 285 additions & 230 deletions

File tree

firebase-firestore/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Unreleased
22

3+
- [feature] Added search stage support for `languageCode`, `offset`, `limit`, and `retrievalDepth`.
34
- [feature] Added support for Pipeline expressions `arraySlice`, `arraySliceToEnd`, `arrayFilter`, `arrayTransform` and `arrayTransformWithIndex`.
45
[#7989](https://github.com/firebase/firebase-android-sdk/pull/7989)
56
- [feature] Added support for `parent` Pipeline expression.

firebase-firestore/api.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,8 +2009,12 @@ package com.google.firebase.firestore.pipeline {
20092009

20102010
@com.google.common.annotations.Beta public final class SearchStage extends com.google.firebase.firestore.pipeline.Stage<com.google.firebase.firestore.pipeline.SearchStage> {
20112011
method public com.google.firebase.firestore.pipeline.SearchStage withAddFields(com.google.firebase.firestore.pipeline.Selectable field, com.google.firebase.firestore.pipeline.Selectable... additionalFields);
2012+
method public com.google.firebase.firestore.pipeline.SearchStage withLanguageCode(String languageCode);
2013+
method public com.google.firebase.firestore.pipeline.SearchStage withLimit(long limit);
2014+
method public com.google.firebase.firestore.pipeline.SearchStage withOffset(long offset);
20122015
method public static com.google.firebase.firestore.pipeline.SearchStage withQuery(com.google.firebase.firestore.pipeline.BooleanExpression query);
20132016
method public static com.google.firebase.firestore.pipeline.SearchStage withQuery(String rquery);
2017+
method public com.google.firebase.firestore.pipeline.SearchStage withRetrievalDepth(long retrievalDepth);
20142018
method public com.google.firebase.firestore.pipeline.SearchStage withSort(com.google.firebase.firestore.pipeline.Ordering order, com.google.firebase.firestore.pipeline.Ordering... additionalOrderings);
20152019
field public static final com.google.firebase.firestore.pipeline.SearchStage.Companion Companion;
20162020
}

firebase-firestore/src/androidTest/java/com/google/firebase/firestore/PipelineSearchTest.kt

Lines changed: 92 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -168,22 +168,36 @@ class PipelineSearchTest {
168168
// --- DISABLE query expansion ---
169169

170170
// query
171-
// TODO(search) enable with backend support
172-
// @Test
173-
// fun searchWithLanguageCode() {
174-
// val ppl =
175-
// firestore
176-
// .pipeline()
177-
// .collection(COLLECTION_NAME)
178-
// .search(
179-
// SearchStage.withQuery("waffles")
180-
// .withLanguageCode("en")
181-
// .withQueryEnhancement(SearchStage.QueryEnhancement.DISABLED)
182-
// )
183-
//
184-
// val snapshot = IntegrationTestUtil.waitFor(ppl.execute())
185-
// assertResultIds(snapshot, "goldenWaffle")
186-
// }
171+
@Test
172+
fun searchWithLanguageCode() {
173+
val ppl =
174+
firestore
175+
.pipeline()
176+
.collection(COLLECTION_NAME)
177+
.search(
178+
SearchStage.withQuery("al pastor").withLanguageCode("en")
179+
// .withQueryEnhancement(SearchStage.QueryEnhancement.DISABLED)
180+
)
181+
182+
val snapshot = IntegrationTestUtil.waitFor(ppl.execute())
183+
assertResultIds(snapshot, "solTacos")
184+
}
185+
186+
@Test
187+
fun searchWithLanguageCodeUnknown() {
188+
val ppl =
189+
firestore
190+
.pipeline()
191+
.collection(COLLECTION_NAME)
192+
.search(
193+
SearchStage.withQuery("al pastor").withLanguageCode("unknown")
194+
// .withQueryEnhancement(SearchStage.QueryEnhancement.DISABLED)
195+
)
196+
197+
org.junit.Assert.assertThrows(Exception::class.java) {
198+
IntegrationTestUtil.waitFor(ppl.execute())
199+
}
200+
}
187201

188202
@Test
189203
fun searchFullDocument() {
@@ -527,59 +541,71 @@ class PipelineSearchTest {
527541
// }
528542

529543
// limit
530-
// TODO(search) enable with backend support
531-
// @Test
532-
// fun limit_limitsTheNumberOfDocumentsReturned() {
533-
// val ppl =
534-
// firestore
535-
// .pipeline()
536-
// .collection(COLLECTION_NAME)
537-
// .search(
538-
// SearchStage.withQuery(constant(true))
539-
// .withSort(field("location").geoDistance(GeoPoint(39.6985, -105.024)).ascending())
540-
// .withLimit(5)
541-
// .withQueryEnhancement(SearchStage.QueryEnhancement.DISABLED)
542-
// )
543-
//
544-
// val snapshot = IntegrationTestUtil.waitFor(ppl.execute())
545-
// assertResultIds(snapshot, "solTacos", "lotusBlossomThai", "goldenWaffle")
546-
// }
544+
@Test
545+
fun limit_limitsTheNumberOfDocumentsReturned() {
546+
val ppl =
547+
firestore
548+
.pipeline()
549+
.collection(COLLECTION_NAME)
550+
.search(
551+
SearchStage.withQuery(
552+
field("location").geoDistance(GeoPoint(39.6985, -105.024)).lessThanOrEqual(100000000)
553+
)
554+
.withSort(field("location").geoDistance(GeoPoint(39.6985, -105.024)).ascending())
555+
.withLimit(3)
556+
// .withQueryEnhancement(SearchStage.QueryEnhancement.DISABLED)
557+
)
547558

548-
// TODO(search) enable with backend support
549-
// @Test
550-
// fun limit_limitsTheNumberOfDocumentsScored() {
551-
// val ppl =
552-
// firestore
553-
// .pipeline()
554-
// .collection(COLLECTION_NAME)
555-
// .search(
556-
// SearchStage.withQuery(field("menu").matches("chicken OR tacos OR fish OR waffles"))
557-
// .withRetrievalDepth(6)
558-
// .withQueryEnhancement(SearchStage.QueryEnhancement.DISABLED)
559-
// )
560-
//
561-
// val snapshot = IntegrationTestUtil.waitFor(ppl.execute())
562-
// assertResultIds(snapshot, "eastsideChicken", "eastsideTacos", "solTacos", "mileHighCatch")
563-
// }
559+
val snapshot = IntegrationTestUtil.waitFor(ppl.execute())
560+
assertResultIds(snapshot, "solTacos", "lotusBlossomThai", "mileHighCatch")
561+
}
562+
563+
@Test
564+
fun limit_limitsTheNumberOfDocumentsScoredWithRetrievalDepth() {
565+
var ppl =
566+
firestore
567+
.pipeline()
568+
.collection(COLLECTION_NAME)
569+
.search(
570+
SearchStage.withQuery(documentMatches("taco"))
571+
.withRetrievalDepth(2)
572+
.withSort(score().descending())
573+
// .withQueryEnhancement(SearchStage.QueryEnhancement.DISABLED)
574+
)
575+
576+
var snapshot = IntegrationTestUtil.waitFor(ppl.execute())
577+
assertResultIds(snapshot, "solTacos", "eastsideTacos")
578+
579+
ppl =
580+
firestore
581+
.pipeline()
582+
.collection(COLLECTION_NAME)
583+
.search(
584+
SearchStage.withQuery(documentMatches("taco"))
585+
.withRetrievalDepth(1)
586+
.withSort(score().descending())
587+
// .withQueryEnhancement(SearchStage.QueryEnhancement.DISABLED)
588+
)
589+
590+
snapshot = IntegrationTestUtil.waitFor(ppl.execute())
591+
assertResultIds(snapshot, "eastsideTacos")
592+
}
564593

565594
// offset
566-
// TODO(search) enable with backend support
567-
// @Test
568-
// fun offset_skipsNDocuments() {
569-
// val ppl =
570-
// firestore
571-
// .pipeline()
572-
// .collection(COLLECTION_NAME)
573-
// .search(
574-
// SearchStage.withQuery(constant(true))
575-
// .withLimit(2)
576-
// .withOffset(2)
577-
// .withQueryEnhancement(SearchStage.QueryEnhancement.DISABLED)
578-
// )
579-
//
580-
// val snapshot = IntegrationTestUtil.waitFor(ppl.execute())
581-
// assertResultIds(snapshot, "eastsideChicken", "eastsideTacos")
582-
// }
595+
@Test
596+
fun offset_skipsNDocuments() {
597+
val ppl =
598+
firestore
599+
.pipeline()
600+
.collection(COLLECTION_NAME)
601+
.search(
602+
SearchStage.withQuery("chicken").withLimit(2).withOffset(2)
603+
// .withQueryEnhancement(SearchStage.QueryEnhancement.DISABLED)
604+
)
605+
606+
val snapshot = IntegrationTestUtil.waitFor(ppl.execute())
607+
assertResultIds(snapshot, "goldenWaffle")
608+
}
583609

584610
// =========================================================================
585611
// Snippet

firebase-firestore/src/main/java/com/google/firebase/firestore/pipeline/options.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ internal constructor(private val options: ImmutableMap<String, Value>) {
6464
}
6565
}
6666

67+
override fun equals(other: Any?): Boolean {
68+
if (this === other) return true
69+
if (other !is InternalOptions) return false
70+
return options == other.options
71+
}
72+
73+
override fun hashCode(): Int {
74+
return options.hashCode()
75+
}
76+
6777
private fun toValue(): Value {
6878
val mapValue = MapValue.newBuilder().putAllFields(options).build()
6979
return Value.newBuilder().setMapValue(mapValue).build()

0 commit comments

Comments
 (0)