Skip to content

Commit 179960a

Browse files
authored
Merge pull request #286 from GitLiveApp/add-start-and-end-query-cursors
Add start and end query cursors
2 parents a135597 + 0bde8c6 commit 179960a

File tree

6 files changed

+192
-4
lines changed
  • firebase-common/src/jsMain/kotlin/dev/gitlive/firebase
  • firebase-firestore/src

6 files changed

+192
-4
lines changed

firebase-common/src/jsMain/kotlin/dev/gitlive/firebase/externals.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,13 @@ external object firebase {
381381
fun orderBy(field: String, direction: Any): Query
382382
fun orderBy(field: FieldPath, direction: Any): Query
383383
fun startAfter(document: DocumentSnapshot): Query
384+
fun startAfter(vararg fieldValues: Any): Query
385+
fun startAt(document: DocumentSnapshot): Query
386+
fun startAt(vararg fieldValues: Any): Query
387+
fun endBefore(document: DocumentSnapshot): Query
388+
fun endBefore(vararg fieldValues: Any): Query
389+
fun endAt(document: DocumentSnapshot): Query
390+
fun endAt(vararg fieldValues: Any): Query
384391
}
385392

386393
open class CollectionReference : Query {

firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,14 @@ actual open class Query(open val android: com.google.firebase.firestore.Query) {
369369
internal actual fun _orderBy(field: FieldPath, direction: Direction) = Query(android.orderBy(field.android, direction))
370370

371371
internal actual fun _startAfter(document: DocumentSnapshot) = Query(android.startAfter(document.android))
372+
internal actual fun _startAfter(vararg fieldValues: Any) = Query(android.startAfter(*fieldValues))
373+
internal actual fun _startAt(document: DocumentSnapshot) = Query(android.startAt(document.android))
374+
internal actual fun _startAt(vararg fieldValues: Any) = Query(android.startAt(*fieldValues))
375+
376+
internal actual fun _endBefore(document: DocumentSnapshot) = Query(android.endBefore(document.android))
377+
internal actual fun _endBefore(vararg fieldValues: Any) = Query(android.endBefore(*fieldValues))
378+
internal actual fun _endAt(document: DocumentSnapshot) = Query(android.endAt(document.android))
379+
internal actual fun _endAt(vararg fieldValues: Any) = Query(android.endAt(*fieldValues))
372380
}
373381

374382
actual typealias Direction = com.google.firebase.firestore.Query.Direction

firebase-firestore/src/commonMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ expect open class Query {
7070
internal fun _orderBy(field: FieldPath, direction: Direction): Query
7171

7272
internal fun _startAfter(document: DocumentSnapshot): Query
73+
internal fun _startAfter(vararg fieldValues: Any): Query
74+
internal fun _startAt(document: DocumentSnapshot): Query
75+
internal fun _startAt(vararg fieldValues: Any): Query
76+
77+
internal fun _endBefore(document: DocumentSnapshot): Query
78+
internal fun _endBefore(vararg fieldValues: Any): Query
79+
internal fun _endAt(document: DocumentSnapshot): Query
80+
internal fun _endAt(vararg fieldValues: Any): Query
7381
}
7482

7583
fun Query.where(field: String, equalTo: Any?) = _where(field, equalTo)
@@ -85,6 +93,14 @@ fun Query.orderBy(field: String, direction: Direction = Direction.ASCENDING) = _
8593
fun Query.orderBy(field: FieldPath, direction: Direction = Direction.ASCENDING) = _orderBy(field, direction)
8694

8795
fun Query.startAfter(document: DocumentSnapshot) = _startAfter(document)
96+
fun Query.startAfter(vararg fieldValues: Any) = _startAfter(*fieldValues)
97+
fun Query.startAt(document: DocumentSnapshot) = _startAt(document)
98+
fun Query.startAt(vararg fieldValues: Any) = _startAt(*fieldValues)
99+
100+
fun Query.endBefore(document: DocumentSnapshot) = _endBefore(document)
101+
fun Query.endBefore(vararg fieldValues: Any) = _endBefore(*fieldValues)
102+
fun Query.endAt(document: DocumentSnapshot) = _endAt(document)
103+
fun Query.endAt(vararg fieldValues: Any) = _endAt(*fieldValues)
88104

89105
expect class WriteBatch {
90106
inline fun <reified T> set(documentRef: DocumentReference, data: T, encodeDefaults: Boolean = true, merge: Boolean = false): WriteBatch

firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,11 +239,148 @@ class FirebaseFirestoreTest {
239239

240240
val lastDocumentSnapshot = firstPage.lastOrNull()
241241
assertNotNull(lastDocumentSnapshot)
242-
val secondPage = query.startAfter(lastDocumentSnapshot).limit(2).get().documents // Second 2 results (only one left)
242+
243+
val secondPage = query.startAfter(lastDocumentSnapshot).get().documents
243244
assertEquals(1, secondPage.size)
244245
assertEquals("ccc", secondPage[0].get("prop1"))
245246
}
246247

248+
@Test
249+
fun testStartAfterFieldValues() = runTest {
250+
setupFirestoreData()
251+
val query = Firebase.firestore
252+
.collection("testFirestoreQuerying")
253+
.orderBy("prop1", Direction.ASCENDING)
254+
255+
val firstPage = query.get().documents
256+
assertEquals(3, firstPage.size)
257+
assertEquals("aaa", firstPage[0].get("prop1"))
258+
assertEquals("bbb", firstPage[1].get("prop1"))
259+
assertEquals("ccc", firstPage[2].get("prop1"))
260+
261+
val secondPage = query.startAfter("bbb").get().documents
262+
assertEquals(1, secondPage.size)
263+
assertEquals("ccc", secondPage[0].get("prop1"))
264+
}
265+
266+
@Test
267+
fun testStartAtDocumentSnapshot() = runTest {
268+
setupFirestoreData()
269+
val query = Firebase.firestore
270+
.collection("testFirestoreQuerying")
271+
.orderBy("prop1", Direction.ASCENDING)
272+
273+
val firstPage = query.limit(2).get().documents // First 2 results
274+
assertEquals(2, firstPage.size)
275+
assertEquals("aaa", firstPage[0].get("prop1"))
276+
assertEquals("bbb", firstPage[1].get("prop1"))
277+
278+
val lastDocumentSnapshot = firstPage.lastOrNull()
279+
assertNotNull(lastDocumentSnapshot)
280+
281+
val secondPage = query.startAt(lastDocumentSnapshot).get().documents
282+
assertEquals(2, secondPage.size)
283+
assertEquals("bbb", secondPage[0].get("prop1"))
284+
assertEquals("ccc", secondPage[1].get("prop1"))
285+
}
286+
287+
@Test
288+
fun testStartAtFieldValues() = runTest {
289+
setupFirestoreData()
290+
val query = Firebase.firestore
291+
.collection("testFirestoreQuerying")
292+
.orderBy("prop1", Direction.ASCENDING)
293+
294+
val firstPage = query.get().documents // First 2 results
295+
assertEquals(3, firstPage.size)
296+
assertEquals("aaa", firstPage[0].get("prop1"))
297+
assertEquals("bbb", firstPage[1].get("prop1"))
298+
assertEquals("ccc", firstPage[2].get("prop1"))
299+
300+
val secondPage = query.startAt("bbb").get().documents
301+
assertEquals(2, secondPage.size)
302+
assertEquals("bbb", secondPage[0].get("prop1"))
303+
assertEquals("ccc", secondPage[1].get("prop1"))
304+
}
305+
306+
@Test
307+
fun testEndBeforeDocumentSnapshot() = runTest {
308+
setupFirestoreData()
309+
val query = Firebase.firestore
310+
.collection("testFirestoreQuerying")
311+
.orderBy("prop1", Direction.ASCENDING)
312+
313+
val firstPage = query.limit(2).get().documents // First 2 results
314+
assertEquals(2, firstPage.size)
315+
assertEquals("aaa", firstPage[0].get("prop1"))
316+
assertEquals("bbb", firstPage[1].get("prop1"))
317+
318+
val lastDocumentSnapshot = firstPage.lastOrNull()
319+
assertNotNull(lastDocumentSnapshot)
320+
321+
val secondPage = query.endBefore(lastDocumentSnapshot).get().documents
322+
assertEquals(1, secondPage.size)
323+
assertEquals("aaa", secondPage[0].get("prop1"))
324+
}
325+
326+
@Test
327+
fun testEndBeforeFieldValues() = runTest {
328+
setupFirestoreData()
329+
val query = Firebase.firestore
330+
.collection("testFirestoreQuerying")
331+
.orderBy("prop1", Direction.ASCENDING)
332+
333+
val firstPage = query.get().documents
334+
assertEquals(3, firstPage.size)
335+
assertEquals("aaa", firstPage[0].get("prop1"))
336+
assertEquals("bbb", firstPage[1].get("prop1"))
337+
assertEquals("ccc", firstPage[2].get("prop1"))
338+
339+
val secondPage = query.endBefore("bbb").get().documents
340+
assertEquals(1, secondPage.size)
341+
assertEquals("aaa", secondPage[0].get("prop1"))
342+
}
343+
344+
@Test
345+
fun testEndAtDocumentSnapshot() = runTest {
346+
setupFirestoreData()
347+
val query = Firebase.firestore
348+
.collection("testFirestoreQuerying")
349+
.orderBy("prop1", Direction.ASCENDING)
350+
351+
val firstPage = query.limit(2).get().documents // First 2 results
352+
assertEquals(2, firstPage.size)
353+
assertEquals("aaa", firstPage[0].get("prop1"))
354+
assertEquals("bbb", firstPage[1].get("prop1"))
355+
356+
val lastDocumentSnapshot = firstPage.lastOrNull()
357+
assertNotNull(lastDocumentSnapshot)
358+
359+
val secondPage = query.endAt(lastDocumentSnapshot).get().documents
360+
assertEquals(2, secondPage.size)
361+
assertEquals("aaa", secondPage[0].get("prop1"))
362+
assertEquals("bbb", secondPage[1].get("prop1"))
363+
}
364+
365+
@Test
366+
fun testEndAtFieldValues() = runTest {
367+
setupFirestoreData()
368+
val query = Firebase.firestore
369+
.collection("testFirestoreQuerying")
370+
.orderBy("prop1", Direction.ASCENDING)
371+
372+
val firstPage = query.get().documents // First 2 results
373+
assertEquals(3, firstPage.size)
374+
assertEquals("aaa", firstPage[0].get("prop1"))
375+
assertEquals("bbb", firstPage[1].get("prop1"))
376+
assertEquals("ccc", firstPage[2].get("prop1"))
377+
378+
val secondPage = query.endAt("bbb").get().documents
379+
assertEquals(2, secondPage.size)
380+
assertEquals("aaa", secondPage[0].get("prop1"))
381+
assertEquals("bbb", secondPage[1].get("prop1"))
382+
}
383+
247384
@Test
248385
fun testIncrementFieldValue() = runTest {
249386
val doc = Firebase.firestore

firebase-firestore/src/iosMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,14 @@ actual open class Query(open val ios: FIRQuery) {
284284
internal actual fun _orderBy(field: FieldPath, direction: Direction) = Query(ios.queryOrderedByFieldPath(field.ios, direction == Direction.DESCENDING))
285285

286286
internal actual fun _startAfter(document: DocumentSnapshot) = Query(ios.queryStartingAfterDocument(document.ios))
287+
internal actual fun _startAfter(vararg fieldValues: Any) = Query(ios.queryStartingAfterValues(fieldValues.asList()))
288+
internal actual fun _startAt(document: DocumentSnapshot) = Query(ios.queryStartingAtDocument(document.ios))
289+
internal actual fun _startAt(vararg fieldValues: Any) = Query(ios.queryStartingAtValues(fieldValues.asList()))
290+
291+
internal actual fun _endBefore(document: DocumentSnapshot) = Query(ios.queryEndingBeforeDocument(document.ios))
292+
internal actual fun _endBefore(vararg fieldValues: Any) = Query(ios.queryEndingBeforeValues(fieldValues.asList()))
293+
internal actual fun _endAt(document: DocumentSnapshot) = Query(ios.queryEndingAtDocument(document.ios))
294+
internal actual fun _endAt(vararg fieldValues: Any) = Query(ios.queryEndingAtValues(fieldValues.asList()))
287295

288296
}
289297
@Suppress("UNCHECKED_CAST")

firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,21 @@ actual open class Query(open val js: firebase.firestore.Query) {
332332
Query(js.orderBy(field.js, direction.jsString))
333333
}
334334

335-
internal actual fun _startAfter(document: DocumentSnapshot) = rethrow {
336-
Query(js.startAfter(document.js))
337-
}
335+
internal actual fun _startAfter(document: DocumentSnapshot) = rethrow { Query(js.startAfter(document.js)) }
336+
337+
internal actual fun _startAfter(vararg fieldValues: Any) = rethrow { Query(js.startAfter(*fieldValues)) }
338+
339+
internal actual fun _startAt(document: DocumentSnapshot) = rethrow { Query(js.startAt(document.js)) }
340+
341+
internal actual fun _startAt(vararg fieldValues: Any) = rethrow { Query(js.startAt(*fieldValues)) }
342+
343+
internal actual fun _endBefore(document: DocumentSnapshot) = rethrow { Query(js.endBefore(document.js)) }
344+
345+
internal actual fun _endBefore(vararg fieldValues: Any) = rethrow { Query(js.endBefore(*fieldValues)) }
346+
347+
internal actual fun _endAt(document: DocumentSnapshot) = rethrow { Query(js.endAt(document.js)) }
348+
349+
internal actual fun _endAt(vararg fieldValues: Any) = rethrow { Query(js.endAt(*fieldValues)) }
338350

339351
actual val snapshots get() = callbackFlow<QuerySnapshot> {
340352
val unsubscribe = rethrow {

0 commit comments

Comments
 (0)