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,65 +186,33 @@ 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 ;
189
+ Pair <Value , Boolean > segmentBound =
190
+ segment .getKind ().equals (FieldIndex .Segment .Kind .ASCENDING )
191
+ ? getAscendingBound (segment )
192
+ : getDescendingBound (segment );
190
193
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
- }
223
-
224
- // If there is a startAt bound, compare the values against the existing boundary to see
225
- // if we can narrow the scope.
194
+ // If there is a startAt bound, compare the values against the existing boundary to see if we
195
+ // can narrow the scope.
226
196
if (startAt != null ) {
227
197
for (int i = 0 ; i < orderBys .size (); ++i ) {
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 );
@@ -259,71 +228,130 @@ public Bound getLowerBound(FieldIndex fieldIndex) {
259
228
260
229
// For each segment, retrieve an upper bound if there is a suitable filter or endAt.
261
230
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 ;
231
+ Pair <Value , Boolean > segmentBound =
232
+ segment .getKind ().equals (FieldIndex .Segment .Kind .ASCENDING )
233
+ ? getDescendingBound (segment )
234
+ : getAscendingBound (segment );
269
235
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
- }
298
-
299
- // If there is an endAt bound, compare the values against the existing boundary to see
300
- // if we can narrow the scope.
236
+ // If there is an endAt bound, compare the values against the existing boundary to see if we
237
+ // can narrow the scope.
301
238
if (endAt != null ) {
302
239
for (int i = 0 ; i < orderBys .size (); ++i ) {
303
240
OrderBy orderBy = this .orderBys .get (i );
304
241
if (orderBy .getField ().equals (segment .getFieldPath ())) {
305
242
Value cursorValue = endAt .getPosition ().get (i );
306
- if (min (segmentValue , cursorValue ) == cursorValue ) {
307
- segmentValue = cursorValue ;
308
- segmentInclusive = endAt .isInclusive ();
243
+ if (min (segmentBound .first , cursorValue ) == cursorValue ) {
244
+ segmentBound = new Pair <>(cursorValue , endAt .isInclusive ());
309
245
}
310
246
break ;
311
247
}
312
248
}
313
249
}
314
250
315
- if (segmentValue == null ) {
316
- // No upper bound exists
251
+ if (segmentBound . first == null ) {
252
+ // No upper segmentBound exists
317
253
return null ;
318
254
}
319
255
320
- values .add (segmentValue );
321
- inclusive &= segmentInclusive ;
256
+ values .add (segmentBound . first );
257
+ inclusive &= segmentBound . second ;
322
258
}
323
259
324
260
return new Bound (values , inclusive );
325
261
}
326
262
263
+ /**
264
+ * Returns the value for an ascending bound of `segment`.
265
+ *
266
+ * @param segment The segment to get the value for.
267
+ * @return a Pair with a nullable Value and a boolean indicating whether the bound is inclusive
268
+ */
269
+ private Pair <Value , Boolean > getAscendingBound (FieldIndex .Segment segment ) {
270
+ Value segmentValue = null ;
271
+ boolean segmentInclusive = true ;
272
+
273
+ // Process all filters to find a value for the current field segment
274
+ for (FieldFilter fieldFilter : getFieldFiltersForPath (segment .getFieldPath ())) {
275
+ Value filterValue = null ;
276
+ boolean filterInclusive = true ;
277
+
278
+ switch (fieldFilter .getOperator ()) {
279
+ case LESS_THAN :
280
+ case LESS_THAN_OR_EQUAL :
281
+ filterValue = Values .getLowerBound (fieldFilter .getValue ().getValueTypeCase ());
282
+ break ;
283
+ case EQUAL :
284
+ case IN :
285
+ case GREATER_THAN_OR_EQUAL :
286
+ filterValue = fieldFilter .getValue ();
287
+ break ;
288
+ case GREATER_THAN :
289
+ filterValue = fieldFilter .getValue ();
290
+ filterInclusive = false ;
291
+ break ;
292
+ case NOT_EQUAL :
293
+ case NOT_IN :
294
+ filterValue = Values .MIN_VALUE ;
295
+ break ;
296
+ default :
297
+ // Remaining filters cannot be used as lower bounds.
298
+ }
299
+
300
+ if (max (segmentValue , filterValue ) == filterValue ) {
301
+ segmentValue = filterValue ;
302
+ segmentInclusive = filterInclusive ;
303
+ }
304
+ }
305
+
306
+ return new Pair <>(segmentValue , segmentInclusive );
307
+ }
308
+
309
+ /**
310
+ * Returns the value for a descending bound of `segment`.
311
+ *
312
+ * @param segment The segment to get the value for.
313
+ * @return a Pair with a nullable Value and a boolean indicating whether the bound is inclusive
314
+ */
315
+ private Pair <Value , Boolean > getDescendingBound (FieldIndex .Segment segment ) {
316
+ Value segmentValue = null ;
317
+ boolean segmentInclusive = true ;
318
+
319
+ // Process all filters to find a value for the current field segment
320
+ for (FieldFilter fieldFilter : getFieldFiltersForPath (segment .getFieldPath ())) {
321
+ Value filterValue = null ;
322
+ boolean filterInclusive = true ;
323
+
324
+ switch (fieldFilter .getOperator ()) {
325
+ case GREATER_THAN_OR_EQUAL :
326
+ case GREATER_THAN :
327
+ filterValue = Values .getUpperBound (fieldFilter .getValue ().getValueTypeCase ());
328
+ filterInclusive = false ;
329
+ break ;
330
+ case EQUAL :
331
+ case IN :
332
+ case LESS_THAN_OR_EQUAL :
333
+ filterValue = fieldFilter .getValue ();
334
+ break ;
335
+ case LESS_THAN :
336
+ filterValue = fieldFilter .getValue ();
337
+ filterInclusive = false ;
338
+ break ;
339
+ case NOT_EQUAL :
340
+ case NOT_IN :
341
+ filterValue = Values .MAX_VALUE ;
342
+ break ;
343
+ default :
344
+ // Remaining filters cannot be used as upper bounds.
345
+ }
346
+
347
+ if (min (segmentValue , filterValue ) == filterValue ) {
348
+ segmentValue = filterValue ;
349
+ segmentInclusive = filterInclusive ;
350
+ }
351
+ }
352
+ return new Pair <>(segmentValue , segmentInclusive );
353
+ }
354
+
327
355
public List <OrderBy > getOrderBy () {
328
356
return this .orderBys ;
329
357
}
0 commit comments