@@ -164,13 +164,13 @@ public void addIndexEntries(Document document) {
164
164
}
165
165
166
166
private void addSingleEntry (
167
- DocumentKey documentKey , int indexId , @ Nullable Value arrayIndex , Object directionalIndex ) {
167
+ DocumentKey documentKey , int indexId , @ Nullable Value arrayIndex , Object directionalIndex ) {
168
168
// TODO(indexing): Handle different values for different users
169
169
db .execute (
170
- "INSERT INTO index_entries (index_id, array_value, directional_value, document_name) " +
171
- "VALUES(?, ?, ?, ?)" ,
170
+ "INSERT INTO index_entries (index_id, array_value, directional_value, document_name) "
171
+ + "VALUES(?, ?, ?, ?)" ,
172
172
indexId ,
173
- arrayIndex != null ? encodeDocumentValues (Collections .singletonList (arrayIndex )) : null ,
173
+ arrayIndex != null ? encodeDocumentValues (Collections .singletonList (arrayIndex )) : null ,
174
174
directionalIndex ,
175
175
documentKey .toString ());
176
176
}
@@ -186,7 +186,7 @@ private List<Value> extractValue(
186
186
for (FieldIndex .Segment segment : fieldIndex ) {
187
187
if (segment .getKind ().equals (kind )) {
188
188
Value field = document .getField (segment .getFieldPath ());
189
- if (field == null ) {
189
+ if (field == null ) {
190
190
return null ;
191
191
}
192
192
if (segment .getKind ().equals (FieldIndex .Segment .Kind .ARRAYS )) {
@@ -209,25 +209,23 @@ public Set<DocumentKey> getDocumentsMatchingTarget(Target target) {
209
209
if (fieldIndex == null ) return null ;
210
210
211
211
@ Nullable List <Value > arrayValues = target .getArrayValues (fieldIndex );
212
- Bound lowerBound = target .getLowerBound (fieldIndex );
212
+ @ Nullable Bound lowerBound = target .getLowerBound (fieldIndex );
213
213
@ Nullable Bound upperBound = target .getUpperBound (fieldIndex );
214
214
215
215
if (Logger .isDebugEnabled ()) {
216
216
Logger .debug (
217
217
TAG ,
218
- "Using index '%s' to execute '%s' (Lower bound: %s, Upper bound: %s)" ,
218
+ "Using index '%s' to execute '%s' (Arrays: %s, Lower bound: %s, Upper bound: %s)" ,
219
219
fieldIndex ,
220
220
target ,
221
+ arrayValues ,
221
222
lowerBound ,
222
223
upperBound );
223
224
}
224
225
225
- Object [] lowerBoundValues = encodeTargetValues (fieldIndex , target , lowerBound .getPosition ());
226
- String lowerBoundOp = lowerBound .isInclusive () ? ">=" : ">" ;
227
- Object [] upperBoundValues =
228
- upperBound != null
229
- ? encodeTargetValues (fieldIndex , target , upperBound .getPosition ())
230
- : null ;
226
+ Object [] lowerBoundValues = encodeBound (fieldIndex , target , lowerBound );
227
+ String lowerBoundOp = lowerBound != null ? (lowerBound .isInclusive () ? ">=" : ">" ) : null ;
228
+ Object [] upperBoundValues = encodeBound (fieldIndex , target , upperBound );
231
229
String upperBoundOp = upperBound != null ? (upperBound .isInclusive () ? "<=" : "<" ) : null ;
232
230
233
231
SQLitePersistence .Query query =
@@ -253,40 +251,33 @@ private SQLitePersistence.Query generateQuery(
253
251
Target target ,
254
252
int indexId ,
255
253
@ Nullable List <Value > arrayValues ,
256
- Object [] lowerBounds ,
257
- String lowerBoundOp ,
254
+ @ Nullable Object [] lowerBounds ,
255
+ @ Nullable String lowerBoundOp ,
258
256
@ Nullable Object [] upperBounds ,
259
257
@ Nullable String upperBoundOp ) {
260
- String orderBy ;
261
- String limit ;
262
-
263
- if (target .getLimit () != -1 ) {
264
- String direction = target .getFirstOrderBy ().getDirection ().canonicalString ();
265
- orderBy = "ORDER BY directional_value " + direction + ", document_name " + direction ;
266
- limit = "LIMIT " + target .getLimit ();
267
- } else {
268
- orderBy = "" ;
269
- limit = "" ;
270
- }
271
-
272
258
StringBuilder statement = new StringBuilder ();
273
259
statement .append (
274
260
"SELECT document_name, directional_value FROM index_entries WHERE index_id = ? " );
275
-
276
- if (arrayValues != null ) {
277
- statement .append ("AND array_value = ? " );
278
- }
279
- statement .append ("AND directional_value " ).append (lowerBoundOp ).append (" ? " );
261
+ if (arrayValues != null ) {
262
+ statement .append ("AND array_value = ? " );
263
+ }
264
+ if (lowerBounds != null ) {
265
+ statement .append ("AND directional_value " ).append (lowerBoundOp ).append (" ? " );
266
+ }
280
267
if (upperBounds != null ) {
281
268
statement .append ("AND directional_value " ).append (upperBoundOp ).append (" ? " );
282
269
}
283
270
284
271
int statementCount =
285
- (arrayValues == null ? 1 : arrayValues .size ()) * lowerBounds .length
272
+ (arrayValues == null ? 1 : arrayValues .size ())
273
+ * (lowerBounds == null ? 1 : lowerBounds .length )
286
274
* (upperBounds == null ? 1 : upperBounds .length );
287
- String sql =
288
- String .format (
289
- "%s %s %s" , repeatSequence (statement , statementCount , " UNION " ), orderBy , limit );
275
+ String sql = repeatSequence (statement , statementCount , " UNION " );
276
+ if (target .getLimit () != -1 ) {
277
+ String direction = target .getFirstOrderBy ().getDirection ().canonicalString ();
278
+ sql += "ORDER BY directional_value " + direction + ", document_name " + direction ;
279
+ sql += "LIMIT " + target .getLimit ();
280
+ }
290
281
291
282
List <Object > bindArgs = new ArrayList <>();
292
283
if (arrayValues == null ) {
@@ -308,23 +299,28 @@ private SQLitePersistence.Query generateQuery(
308
299
private List <Object > computeBounds (
309
300
int indexId ,
310
301
@ Nullable Object arrayValue ,
311
- Object [] lowerBounds ,
302
+ @ Nullable Object [] lowerBounds ,
312
303
@ Nullable Object [] upperBounds ) {
304
+ if (lowerBounds == null ) {
305
+ lowerBounds = new Object [] {null };
306
+ }
307
+ if (upperBounds == null ) {
308
+ upperBounds = new Object [] {null };
309
+ }
310
+
313
311
List <Object > bindArgs = new ArrayList <>();
314
312
for (Object lower : lowerBounds ) {
315
- if (upperBounds != null ) {
316
- for (Object upper : upperBounds ) {
317
- bindArgs .add (indexId );
318
- if (arrayValue != null )
313
+ for (Object upper : upperBounds ) {
314
+ bindArgs .add (indexId );
315
+ if (arrayValue != null ) {
319
316
bindArgs .add (arrayValue );
317
+ }
318
+ if (lower != null ) {
320
319
bindArgs .add (lower );
320
+ }
321
+ if (upper != null ) {
321
322
bindArgs .add (upper );
322
323
}
323
- } else {
324
- bindArgs .add (indexId );
325
- if (arrayValue != null )
326
- bindArgs .add (arrayValue );
327
- bindArgs .add (lower );
328
324
}
329
325
}
330
326
return bindArgs ;
@@ -390,14 +386,23 @@ private Object encodeDocumentValues(List<Value> values) {
390
386
* Encodes the given field values according to the specification in {@code target}. For IN and
391
387
* ArrayContainsAny queries, a list of possible values is returned.
392
388
*/
393
- private Object [] encodeTargetValues (FieldIndex fieldIndex , Target target , List <Value > values ) {
389
+ private @ Nullable Object [] encodeBound (
390
+ FieldIndex fieldIndex , Target target , @ Nullable Bound bound ) {
391
+ if (bound == null ) {
392
+ return null ;
393
+ }
394
394
List <IndexByteEncoder > encoders = new ArrayList <>();
395
395
encoders .add (new IndexByteEncoder ());
396
- for (int i = 0 ; i < fieldIndex .segmentCount (); ++i ) {
397
- FieldIndex .Segment segment = fieldIndex .getSegment (i );
398
- Value value = values .get (i );
396
+
397
+ int i = 0 ;
398
+ for (FieldIndex .Segment segment : fieldIndex ) { // get ordered segments, get array segments
399
+ if (!segment .getKind ().equals (FieldIndex .Segment .Kind .ORDERED )) {
400
+ continue ;
401
+ }
402
+ Value value = bound .getPosition ().get (i );
399
403
for (IndexByteEncoder encoder : encoders ) {
400
- if (isMultiValueFilter (target , segment .getFieldPath ())) {
404
+ if (isMultiValueFilter (target , segment .getFieldPath ())
405
+ && value .getValueTypeCase () == Value .ValueTypeCase .ARRAY_VALUE ) {
401
406
encoders = expandIndexValues (encoders , value );
402
407
} else {
403
408
FirestoreIndexValueWriter .INSTANCE .writeIndexValue (value , encoder );
0 commit comments