17
17
import static com .google .firebase .firestore .model .Values .max ;
18
18
import static com .google .firebase .firestore .model .Values .min ;
19
19
20
+ import android .util .Pair ;
20
21
import androidx .annotation .Nullable ;
21
22
import com .google .firebase .firestore .model .DocumentKey ;
22
23
import com .google .firebase .firestore .model .FieldIndex ;
@@ -185,41 +186,10 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
185
186
186
187
// For each segment, retrieve a lower bound if there is a suitable filter or startAt.
187
188
for (FieldIndex .Segment segment : fieldIndex .getDirectionalSegments ()) {
188
- Value segmentValue = null ;
189
- boolean segmentInclusive = true ;
190
-
191
- // Process all filters to find a value for the current field segment
192
- for (FieldFilter fieldFilter : getFieldFiltersForPath (segment .getFieldPath ())) {
193
- Value filterValue = null ;
194
- boolean filterInclusive = true ;
195
-
196
- switch (fieldFilter .getOperator ()) {
197
- case LESS_THAN :
198
- case LESS_THAN_OR_EQUAL :
199
- filterValue = Values .getLowerBound (fieldFilter .getValue ().getValueTypeCase ());
200
- break ;
201
- case EQUAL :
202
- case IN :
203
- case GREATER_THAN_OR_EQUAL :
204
- filterValue = fieldFilter .getValue ();
205
- break ;
206
- case GREATER_THAN :
207
- filterValue = fieldFilter .getValue ();
208
- filterInclusive = false ;
209
- break ;
210
- case NOT_EQUAL :
211
- case NOT_IN :
212
- filterValue = Values .MIN_VALUE ;
213
- break ;
214
- default :
215
- // Remaining filters cannot be used as lower bounds.
216
- }
217
-
218
- if (max (segmentValue , filterValue ) == filterValue ) {
219
- segmentValue = filterValue ;
220
- segmentInclusive = filterInclusive ;
221
- }
222
- }
189
+ Pair <Value , Boolean > segmentBound =
190
+ segment .getKind ().equals (FieldIndex .Segment .Kind .ASCENDING )
191
+ ? getAscendingBound (segment )
192
+ : getDescendingBound (segment );
223
193
224
194
// If there is a startAt bound, compare the values against the existing boundary to see
225
195
// if we can narrow the scope.
@@ -228,27 +198,118 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
228
198
OrderBy orderBy = this .orderBys .get (i );
229
199
if (orderBy .getField ().equals (segment .getFieldPath ())) {
230
200
Value cursorValue = startAt .getPosition ().get (i );
231
- if (max (segmentValue , cursorValue ) == cursorValue ) {
232
- segmentValue = cursorValue ;
233
- segmentInclusive = startAt .isInclusive ();
201
+ if (max (segmentBound .first , cursorValue ) == cursorValue ) {
202
+ segmentBound = new Pair <>(cursorValue , startAt .isInclusive ());
234
203
}
235
204
break ;
236
205
}
237
206
}
238
207
}
239
208
240
- if (segmentValue == null ) {
209
+ if (segmentBound . first == null ) {
241
210
// No lower bound exists
242
211
return null ;
243
212
}
244
213
245
- values .add (segmentValue );
246
- inclusive &= segmentInclusive ;
214
+ values .add (segmentBound . first );
215
+ inclusive &= segmentBound . second ;
247
216
}
248
217
249
218
return new Bound (values , inclusive );
250
219
}
251
220
221
+ /**
222
+ * Returns the value for the lower bound of `segment`.
223
+ *
224
+ * @param segment The segment to get the value for.
225
+ * @return a Pair with a nullable Value and a boolean indicating whether the bound is inclusive
226
+ */
227
+ private Pair <Value , Boolean > getAscendingBound (FieldIndex .Segment segment ) {
228
+ Value segmentValue = null ;
229
+ boolean segmentInclusive = true ;
230
+
231
+ // Process all filters to find a value for the current field segment
232
+ for (FieldFilter fieldFilter : getFieldFiltersForPath (segment .getFieldPath ())) {
233
+ Value filterValue = null ;
234
+ boolean filterInclusive = true ;
235
+
236
+ switch (fieldFilter .getOperator ()) {
237
+ case LESS_THAN :
238
+ case LESS_THAN_OR_EQUAL :
239
+ filterValue = Values .getLowerBound (fieldFilter .getValue ().getValueTypeCase ());
240
+ break ;
241
+ case EQUAL :
242
+ case IN :
243
+ case GREATER_THAN_OR_EQUAL :
244
+ filterValue = fieldFilter .getValue ();
245
+ break ;
246
+ case GREATER_THAN :
247
+ filterValue = fieldFilter .getValue ();
248
+ filterInclusive = false ;
249
+ break ;
250
+ case NOT_EQUAL :
251
+ case NOT_IN :
252
+ filterValue = Values .MIN_VALUE ;
253
+ break ;
254
+ default :
255
+ // Remaining filters cannot be used as lower bounds.
256
+ }
257
+
258
+ if (max (segmentValue , filterValue ) == filterValue ) {
259
+ segmentValue = filterValue ;
260
+ segmentInclusive = filterInclusive ;
261
+ }
262
+ }
263
+
264
+ return new Pair <>(segmentValue , segmentInclusive );
265
+ }
266
+
267
+ /**
268
+ * Returns the value for the upper bound of `segment`.
269
+ *
270
+ * @param segment The segment to get the value for.
271
+ * @return a Pair with a nullable Value and a boolean indicating whether the bound is inclusive
272
+ */
273
+ private Pair <Value , Boolean > getDescendingBound (FieldIndex .Segment segment ) {
274
+ Value segmentValue = null ;
275
+ boolean segmentInclusive = true ;
276
+
277
+ // Process all filters to find a value for the current field segment
278
+ for (FieldFilter fieldFilter : getFieldFiltersForPath (segment .getFieldPath ())) {
279
+ Value filterValue = null ;
280
+ boolean filterInclusive = true ;
281
+
282
+ switch (fieldFilter .getOperator ()) {
283
+ case GREATER_THAN_OR_EQUAL :
284
+ case GREATER_THAN :
285
+ filterValue = Values .getUpperBound (fieldFilter .getValue ().getValueTypeCase ());
286
+ filterInclusive = false ;
287
+ break ;
288
+ case EQUAL :
289
+ case IN :
290
+ case LESS_THAN_OR_EQUAL :
291
+ filterValue = fieldFilter .getValue ();
292
+ break ;
293
+ case LESS_THAN :
294
+ filterValue = fieldFilter .getValue ();
295
+ filterInclusive = false ;
296
+ break ;
297
+ case NOT_EQUAL :
298
+ case NOT_IN :
299
+ filterValue = Values .MAX_VALUE ;
300
+ break ;
301
+ default :
302
+ // Remaining filters cannot be used as upper bounds.
303
+ }
304
+
305
+ if (min (segmentValue , filterValue ) == filterValue ) {
306
+ segmentValue = filterValue ;
307
+ segmentInclusive = filterInclusive ;
308
+ }
309
+ }
310
+ return new Pair <>(segmentValue , segmentInclusive );
311
+ }
312
+
252
313
/**
253
314
* Returns an upper bound of field values that can be used as an ending point when scanning the
254
315
* index defined by {@code fieldIndex}. Returns {@code null} if no upper bound exists.
@@ -259,66 +320,33 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
259
320
260
321
// For each segment, retrieve an upper bound if there is a suitable filter or endAt.
261
322
for (FieldIndex .Segment segment : fieldIndex .getDirectionalSegments ()) {
262
- @ Nullable Value segmentValue = null ;
263
- boolean segmentInclusive = true ;
264
-
265
- // Process all filters to find a value for the current field segment
266
- for (FieldFilter fieldFilter : getFieldFiltersForPath (segment .getFieldPath ())) {
267
- Value filterValue = null ;
268
- boolean filterInclusive = true ;
269
-
270
- switch (fieldFilter .getOperator ()) {
271
- case GREATER_THAN_OR_EQUAL :
272
- case GREATER_THAN :
273
- filterValue = Values .getUpperBound (fieldFilter .getValue ().getValueTypeCase ());
274
- filterInclusive = false ;
275
- break ;
276
- case EQUAL :
277
- case IN :
278
- case LESS_THAN_OR_EQUAL :
279
- filterValue = fieldFilter .getValue ();
280
- break ;
281
- case LESS_THAN :
282
- filterValue = fieldFilter .getValue ();
283
- filterInclusive = false ;
284
- break ;
285
- case NOT_EQUAL :
286
- case NOT_IN :
287
- filterValue = Values .MAX_VALUE ;
288
- break ;
289
- default :
290
- // Remaining filters cannot be used as upper bounds.
291
- }
292
-
293
- if (min (segmentValue , filterValue ) == filterValue ) {
294
- segmentValue = filterValue ;
295
- segmentInclusive = filterInclusive ;
296
- }
297
- }
323
+ Pair <Value , Boolean > segmentBound =
324
+ segment .getKind ().equals (FieldIndex .Segment .Kind .ASCENDING )
325
+ ? getDescendingBound (segment )
326
+ : getAscendingBound (segment );
298
327
299
- // If there is an endAt bound , compare the values against the existing boundary to see
328
+ // If there is an endAt segmentBound , compare the values against the existing boundary to see
300
329
// if we can narrow the scope.
301
330
if (endAt != null ) {
302
331
for (int i = 0 ; i < orderBys .size (); ++i ) {
303
332
OrderBy orderBy = this .orderBys .get (i );
304
333
if (orderBy .getField ().equals (segment .getFieldPath ())) {
305
334
Value cursorValue = endAt .getPosition ().get (i );
306
- if (min (segmentValue , cursorValue ) == cursorValue ) {
307
- segmentValue = cursorValue ;
308
- segmentInclusive = endAt .isInclusive ();
335
+ if (min (segmentBound .first , cursorValue ) == cursorValue ) {
336
+ segmentBound = new Pair <>(cursorValue , endAt .isInclusive ());
309
337
}
310
338
break ;
311
339
}
312
340
}
313
341
}
314
342
315
- if (segmentValue == null ) {
316
- // No upper bound exists
343
+ if (segmentBound . first == null ) {
344
+ // No upper segmentBound exists
317
345
return null ;
318
346
}
319
347
320
- values .add (segmentValue );
321
- inclusive &= segmentInclusive ;
348
+ values .add (segmentBound . first );
349
+ inclusive &= segmentBound . second ;
322
350
}
323
351
324
352
return new Bound (values , inclusive );
0 commit comments