631 lines
31 KiB
Java
631 lines
31 KiB
Java
package com.google.firebase.firestore.local;
|
|
|
|
import android.database.Cursor;
|
|
import android.text.TextUtils;
|
|
import com.airbnb.deeplinkdispatch.UrlTreeKt;
|
|
import com.google.firebase.Timestamp;
|
|
import com.google.firebase.database.collection.ImmutableSortedMap;
|
|
import com.google.firebase.firestore.auth.User;
|
|
import com.google.firebase.firestore.core.Bound;
|
|
import com.google.firebase.firestore.core.CompositeFilter;
|
|
import com.google.firebase.firestore.core.FieldFilter;
|
|
import com.google.firebase.firestore.core.Filter;
|
|
import com.google.firebase.firestore.core.OrderBy;
|
|
import com.google.firebase.firestore.core.Target;
|
|
import com.google.firebase.firestore.index.FirestoreIndexValueWriter;
|
|
import com.google.firebase.firestore.index.IndexByteEncoder;
|
|
import com.google.firebase.firestore.index.IndexEntry;
|
|
import com.google.firebase.firestore.local.IndexManager;
|
|
import com.google.firebase.firestore.local.MemoryIndexManager;
|
|
import com.google.firebase.firestore.local.SQLitePersistence;
|
|
import com.google.firebase.firestore.model.Document;
|
|
import com.google.firebase.firestore.model.DocumentKey;
|
|
import com.google.firebase.firestore.model.FieldIndex;
|
|
import com.google.firebase.firestore.model.FieldPath;
|
|
import com.google.firebase.firestore.model.ResourcePath;
|
|
import com.google.firebase.firestore.model.SnapshotVersion;
|
|
import com.google.firebase.firestore.model.TargetIndexMatcher;
|
|
import com.google.firebase.firestore.model.Values;
|
|
import com.google.firebase.firestore.util.Assert;
|
|
import com.google.firebase.firestore.util.Consumer;
|
|
import com.google.firebase.firestore.util.Logger;
|
|
import com.google.firebase.firestore.util.LogicUtils;
|
|
import com.google.firebase.firestore.util.Util;
|
|
import com.google.protobuf.InvalidProtocolBufferException;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.PriorityQueue;
|
|
import java.util.Queue;
|
|
import java.util.SortedSet;
|
|
import java.util.TreeSet;
|
|
import o.ECo;
|
|
import o.sbb;
|
|
import o.uOO;
|
|
|
|
/* JADX INFO: Access modifiers changed from: package-private */
|
|
/* loaded from: classes2.dex */
|
|
public final class SQLiteIndexManager implements IndexManager {
|
|
private static final byte[] EMPTY_BYTES_VALUE = new byte[0];
|
|
private static final String TAG = "SQLiteIndexManager";
|
|
private final SQLitePersistence db;
|
|
private final LocalSerializer serializer;
|
|
private final String uid;
|
|
private final Map<Target, List<Target>> targetToDnfSubTargets = new HashMap();
|
|
private final MemoryIndexManager.MemoryCollectionParentIndex collectionParentsCache = new MemoryIndexManager.MemoryCollectionParentIndex();
|
|
private final Map<String, Map<Integer, FieldIndex>> memoizedIndexes = new HashMap();
|
|
private final Queue<FieldIndex> nextIndexToUpdate = new PriorityQueue(10, new Comparator() { // from class: com.google.firebase.firestore.local.SQLiteIndexManager$$ExternalSyntheticLambda3
|
|
@Override // java.util.Comparator
|
|
public final int compare(Object obj, Object obj2) {
|
|
return SQLiteIndexManager.lambda$new$0((FieldIndex) obj, (FieldIndex) obj2);
|
|
}
|
|
});
|
|
private boolean started = false;
|
|
private int memoizedMaxIndexId = -1;
|
|
private long memoizedMaxSequenceNumber = -1;
|
|
|
|
/* JADX INFO: Access modifiers changed from: package-private */
|
|
public static /* synthetic */ int lambda$new$0(FieldIndex fieldIndex, FieldIndex fieldIndex2) {
|
|
int compare = Long.compare(fieldIndex.getIndexState().getSequenceNumber(), fieldIndex2.getIndexState().getSequenceNumber());
|
|
return compare == 0 ? fieldIndex.getCollectionGroup().compareTo(fieldIndex2.getCollectionGroup()) : compare;
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: package-private */
|
|
public SQLiteIndexManager(SQLitePersistence sQLitePersistence, LocalSerializer localSerializer, User user) {
|
|
this.db = sQLitePersistence;
|
|
this.serializer = localSerializer;
|
|
this.uid = user.isAuthenticated() ? user.getUid() : "";
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.local.IndexManager
|
|
public final void start() {
|
|
final HashMap hashMap = new HashMap();
|
|
this.db.query("SELECT index_id, sequence_number, read_time_seconds, read_time_nanos, document_key, largest_batch_id FROM index_state WHERE uid = ?").binding(this.uid).forEach(new Consumer(hashMap) { // from class: com.google.firebase.firestore.local.SQLiteIndexManager$$ExternalSyntheticLambda6
|
|
public final Map f$0;
|
|
|
|
@Override // com.google.firebase.firestore.util.Consumer
|
|
public final void accept(Object obj) {
|
|
SQLiteIndexManager.lambda$start$1(this.f$0, (Cursor) obj);
|
|
}
|
|
|
|
{
|
|
this.f$0 = hashMap;
|
|
}
|
|
});
|
|
this.db.query("SELECT index_id, collection_group, index_proto FROM index_configuration").forEach(new Consumer(this, hashMap) { // from class: com.google.firebase.firestore.local.SQLiteIndexManager$$ExternalSyntheticLambda7
|
|
public final SQLiteIndexManager f$0;
|
|
public final Map f$1;
|
|
|
|
@Override // com.google.firebase.firestore.util.Consumer
|
|
public final void accept(Object obj) {
|
|
this.f$0.m204x30c0807a(this.f$1, (Cursor) obj);
|
|
}
|
|
|
|
{
|
|
this.f$0 = this;
|
|
this.f$1 = hashMap;
|
|
}
|
|
});
|
|
this.started = true;
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: package-private */
|
|
public static /* synthetic */ void lambda$start$1(Map map, Cursor cursor) {
|
|
int i = cursor.getInt(0);
|
|
map.put(Integer.valueOf(i), FieldIndex.IndexState.create(cursor.getLong(1), new SnapshotVersion(new Timestamp(cursor.getLong(2), cursor.getInt(3))), DocumentKey.fromPath(EncodedPath.decodeResourcePath(cursor.getString(4))), cursor.getInt(5)));
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: package-private */
|
|
/* renamed from: lambda$start$2$com-google-firebase-firestore-local-SQLiteIndexManager, reason: not valid java name */
|
|
public final /* synthetic */ void m204x30c0807a(Map map, Cursor cursor) {
|
|
FieldIndex.IndexState indexState;
|
|
try {
|
|
int i = cursor.getInt(0);
|
|
String string = cursor.getString(1);
|
|
List<FieldIndex.Segment> decodeFieldIndexSegments = this.serializer.decodeFieldIndexSegments(ECo.c(cursor.getBlob(2)));
|
|
if (map.containsKey(Integer.valueOf(i))) {
|
|
indexState = (FieldIndex.IndexState) map.get(Integer.valueOf(i));
|
|
} else {
|
|
indexState = FieldIndex.INITIAL_STATE;
|
|
}
|
|
memoizeIndex(FieldIndex.create(i, string, decodeFieldIndexSegments, indexState));
|
|
} catch (InvalidProtocolBufferException e) {
|
|
throw Assert.fail("Failed to decode index: ".concat(String.valueOf(e)), new Object[0]);
|
|
}
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.local.IndexManager
|
|
public final void addToCollectionParentIndex(ResourcePath resourcePath) {
|
|
Assert.hardAssert(this.started, "IndexManager not started", new Object[0]);
|
|
Assert.hardAssert(resourcePath.length() % 2 == 1, "Expected a collection path.", new Object[0]);
|
|
if (this.collectionParentsCache.add(resourcePath)) {
|
|
this.db.execute("INSERT OR REPLACE INTO collection_parents (collection_id, parent) VALUES (?, ?)", resourcePath.getLastSegment(), EncodedPath.encode(resourcePath.popLast()));
|
|
}
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.local.IndexManager
|
|
public final List<ResourcePath> getCollectionParents(String str) {
|
|
Assert.hardAssert(this.started, "IndexManager not started", new Object[0]);
|
|
final ArrayList arrayList = new ArrayList();
|
|
this.db.query("SELECT parent FROM collection_parents WHERE collection_id = ?").binding(str).forEach(new Consumer(arrayList) { // from class: com.google.firebase.firestore.local.SQLiteIndexManager$$ExternalSyntheticLambda4
|
|
public final ArrayList f$0;
|
|
|
|
@Override // com.google.firebase.firestore.util.Consumer
|
|
public final void accept(Object obj) {
|
|
this.f$0.add(EncodedPath.decodeResourcePath(((Cursor) obj).getString(0)));
|
|
}
|
|
|
|
{
|
|
this.f$0 = arrayList;
|
|
}
|
|
});
|
|
return arrayList;
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.local.IndexManager
|
|
public final String getNextCollectionGroupToUpdate() {
|
|
Assert.hardAssert(this.started, "IndexManager not started", new Object[0]);
|
|
FieldIndex peek = this.nextIndexToUpdate.peek();
|
|
if (peek != null) {
|
|
return peek.getCollectionGroup();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.local.IndexManager
|
|
public final void updateIndexEntries(ImmutableSortedMap<DocumentKey, Document> immutableSortedMap) {
|
|
Assert.hardAssert(this.started, "IndexManager not started", new Object[0]);
|
|
Iterator<Map.Entry<DocumentKey, Document>> it = immutableSortedMap.iterator();
|
|
while (it.hasNext()) {
|
|
Map.Entry<DocumentKey, Document> next = it.next();
|
|
for (FieldIndex fieldIndex : getFieldIndexes(next.getKey().getCollectionGroup())) {
|
|
SortedSet<IndexEntry> existingIndexEntries = getExistingIndexEntries(next.getKey(), fieldIndex);
|
|
SortedSet<IndexEntry> computeIndexEntries = computeIndexEntries(next.getValue(), fieldIndex);
|
|
if (!existingIndexEntries.equals(computeIndexEntries)) {
|
|
updateEntries(next.getValue(), existingIndexEntries, computeIndexEntries);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void updateEntries(final Document document, SortedSet<IndexEntry> sortedSet, SortedSet<IndexEntry> sortedSet2) {
|
|
Logger.debug(TAG, "Updating index entries for document '%s'", document.getKey());
|
|
Util.diffCollections(sortedSet, sortedSet2, new Consumer(this, document) { // from class: com.google.firebase.firestore.local.SQLiteIndexManager$$ExternalSyntheticLambda1
|
|
public final SQLiteIndexManager f$0;
|
|
public final Document f$1;
|
|
|
|
@Override // com.google.firebase.firestore.util.Consumer
|
|
public final void accept(Object obj) {
|
|
this.f$0.m205x55deb5b3(this.f$1, (IndexEntry) obj);
|
|
}
|
|
|
|
{
|
|
this.f$0 = this;
|
|
this.f$1 = document;
|
|
}
|
|
}, new Consumer(this, document) { // from class: com.google.firebase.firestore.local.SQLiteIndexManager$$ExternalSyntheticLambda2
|
|
public final SQLiteIndexManager f$0;
|
|
public final Document f$1;
|
|
|
|
@Override // com.google.firebase.firestore.util.Consumer
|
|
public final void accept(Object obj) {
|
|
this.f$0.m206x57150892(this.f$1, (IndexEntry) obj);
|
|
}
|
|
|
|
{
|
|
this.f$0 = this;
|
|
this.f$1 = document;
|
|
}
|
|
});
|
|
}
|
|
|
|
public final Collection<FieldIndex> getFieldIndexes(String str) {
|
|
Assert.hardAssert(this.started, "IndexManager not started", new Object[0]);
|
|
Map<Integer, FieldIndex> map = this.memoizedIndexes.get(str);
|
|
return map == null ? Collections.emptyList() : map.values();
|
|
}
|
|
|
|
private FieldIndex.IndexOffset getMinOffset(Collection<FieldIndex> collection) {
|
|
Assert.hardAssert(!collection.isEmpty(), "Found empty index group when looking for least recent index offset.", new Object[0]);
|
|
Iterator<FieldIndex> it = collection.iterator();
|
|
FieldIndex.IndexOffset offset = it.next().getIndexState().getOffset();
|
|
int largestBatchId = offset.getLargestBatchId();
|
|
while (it.hasNext()) {
|
|
FieldIndex.IndexOffset offset2 = it.next().getIndexState().getOffset();
|
|
if (offset2.compareTo(offset) < 0) {
|
|
offset = offset2;
|
|
}
|
|
largestBatchId = Math.max(offset2.getLargestBatchId(), largestBatchId);
|
|
}
|
|
return FieldIndex.IndexOffset.create(offset.getReadTime(), offset.getDocumentKey(), largestBatchId);
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.local.IndexManager
|
|
public final FieldIndex.IndexOffset getMinOffset(String str) {
|
|
Collection<FieldIndex> fieldIndexes = getFieldIndexes(str);
|
|
Assert.hardAssert(!fieldIndexes.isEmpty(), "minOffset was called for collection without indexes", new Object[0]);
|
|
return getMinOffset(fieldIndexes);
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.local.IndexManager
|
|
public final IndexManager.IndexType getIndexType(Target target) {
|
|
IndexManager.IndexType indexType = IndexManager.IndexType.FULL;
|
|
List<Target> subTargets = getSubTargets(target);
|
|
Iterator<Target> it = subTargets.iterator();
|
|
while (true) {
|
|
if (!it.hasNext()) {
|
|
break;
|
|
}
|
|
Target next = it.next();
|
|
FieldIndex fieldIndex = getFieldIndex(next);
|
|
if (fieldIndex == null) {
|
|
indexType = IndexManager.IndexType.NONE;
|
|
break;
|
|
}
|
|
if (fieldIndex.getSegments().size() < next.getSegmentCount()) {
|
|
indexType = IndexManager.IndexType.PARTIAL;
|
|
}
|
|
}
|
|
return (target.hasLimit() && subTargets.size() > 1 && indexType == IndexManager.IndexType.FULL) ? IndexManager.IndexType.PARTIAL : indexType;
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.local.IndexManager
|
|
public final FieldIndex.IndexOffset getMinOffset(Target target) {
|
|
ArrayList arrayList = new ArrayList();
|
|
Iterator<Target> it = getSubTargets(target).iterator();
|
|
while (it.hasNext()) {
|
|
FieldIndex fieldIndex = getFieldIndex(it.next());
|
|
if (fieldIndex != null) {
|
|
arrayList.add(fieldIndex);
|
|
}
|
|
}
|
|
return getMinOffset(arrayList);
|
|
}
|
|
|
|
private List<Target> getSubTargets(Target target) {
|
|
if (this.targetToDnfSubTargets.containsKey(target)) {
|
|
return this.targetToDnfSubTargets.get(target);
|
|
}
|
|
ArrayList arrayList = new ArrayList();
|
|
if (target.getFilters().isEmpty()) {
|
|
arrayList.add(target);
|
|
} else {
|
|
Iterator<Filter> it = LogicUtils.getDnfTerms(new CompositeFilter(target.getFilters(), CompositeFilter.Operator.AND)).iterator();
|
|
while (it.hasNext()) {
|
|
arrayList.add(new Target(target.getPath(), target.getCollectionGroup(), it.next().getFilters(), target.getOrderBy(), target.getLimit(), target.getStartAt(), target.getEndAt()));
|
|
}
|
|
}
|
|
this.targetToDnfSubTargets.put(target, arrayList);
|
|
return arrayList;
|
|
}
|
|
|
|
private void memoizeIndex(FieldIndex fieldIndex) {
|
|
Map<Integer, FieldIndex> map = this.memoizedIndexes.get(fieldIndex.getCollectionGroup());
|
|
if (map == null) {
|
|
map = new HashMap<>();
|
|
this.memoizedIndexes.put(fieldIndex.getCollectionGroup(), map);
|
|
}
|
|
FieldIndex fieldIndex2 = map.get(Integer.valueOf(fieldIndex.getIndexId()));
|
|
if (fieldIndex2 != null) {
|
|
this.nextIndexToUpdate.remove(fieldIndex2);
|
|
}
|
|
map.put(Integer.valueOf(fieldIndex.getIndexId()), fieldIndex);
|
|
this.nextIndexToUpdate.add(fieldIndex);
|
|
this.memoizedMaxIndexId = Math.max(this.memoizedMaxIndexId, fieldIndex.getIndexId());
|
|
this.memoizedMaxSequenceNumber = Math.max(this.memoizedMaxSequenceNumber, fieldIndex.getIndexState().getSequenceNumber());
|
|
}
|
|
|
|
private SortedSet<IndexEntry> computeIndexEntries(Document document, FieldIndex fieldIndex) {
|
|
uOO e;
|
|
TreeSet treeSet = new TreeSet();
|
|
byte[] encodeDirectionalElements = encodeDirectionalElements(fieldIndex, document);
|
|
if (encodeDirectionalElements == null) {
|
|
return treeSet;
|
|
}
|
|
FieldIndex.Segment arraySegment = fieldIndex.getArraySegment();
|
|
if (arraySegment != null) {
|
|
sbb field = document.getField(arraySegment.getFieldPath());
|
|
if (Values.isArray(field)) {
|
|
if (field.valueTypeCase_ == 9) {
|
|
e = (uOO) field.valueType_;
|
|
} else {
|
|
e = uOO.e();
|
|
}
|
|
Iterator<sbb> it = e.values_.iterator();
|
|
while (it.hasNext()) {
|
|
treeSet.add(IndexEntry.create(fieldIndex.getIndexId(), document.getKey(), encodeSingleElement(it.next()), encodeDirectionalElements));
|
|
}
|
|
}
|
|
} else {
|
|
treeSet.add(IndexEntry.create(fieldIndex.getIndexId(), document.getKey(), new byte[0], encodeDirectionalElements));
|
|
}
|
|
return treeSet;
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: private */
|
|
/* renamed from: addIndexEntry, reason: merged with bridge method [inline-methods] */
|
|
public void m205x55deb5b3(Document document, IndexEntry indexEntry) {
|
|
SQLitePersistence sQLitePersistence = this.db;
|
|
int indexId = indexEntry.getIndexId();
|
|
sQLitePersistence.execute("INSERT INTO index_entries (index_id, uid, array_value, directional_value, document_key) VALUES(?, ?, ?, ?, ?)", Integer.valueOf(indexId), this.uid, indexEntry.getArrayValue(), indexEntry.getDirectionalValue(), document.getKey().toString());
|
|
}
|
|
|
|
/* JADX INFO: Access modifiers changed from: private */
|
|
/* renamed from: deleteIndexEntry, reason: merged with bridge method [inline-methods] */
|
|
public void m206x57150892(Document document, IndexEntry indexEntry) {
|
|
SQLitePersistence sQLitePersistence = this.db;
|
|
int indexId = indexEntry.getIndexId();
|
|
sQLitePersistence.execute("DELETE FROM index_entries WHERE index_id = ? AND uid = ? AND array_value = ? AND directional_value = ? AND document_key = ?", Integer.valueOf(indexId), this.uid, indexEntry.getArrayValue(), indexEntry.getDirectionalValue(), document.getKey().toString());
|
|
}
|
|
|
|
private SortedSet<IndexEntry> getExistingIndexEntries(final DocumentKey documentKey, final FieldIndex fieldIndex) {
|
|
final TreeSet treeSet = new TreeSet();
|
|
SQLitePersistence.Query query = this.db.query("SELECT array_value, directional_value FROM index_entries WHERE index_id = ? AND document_key = ? AND uid = ?");
|
|
int indexId = fieldIndex.getIndexId();
|
|
query.binding(Integer.valueOf(indexId), documentKey.toString(), this.uid).forEach(new Consumer(treeSet, fieldIndex, documentKey) { // from class: com.google.firebase.firestore.local.SQLiteIndexManager$$ExternalSyntheticLambda5
|
|
public final SortedSet f$0;
|
|
public final FieldIndex f$1;
|
|
public final DocumentKey f$2;
|
|
|
|
@Override // com.google.firebase.firestore.util.Consumer
|
|
public final void accept(Object obj) {
|
|
this.f$0.add(IndexEntry.create(this.f$1.getIndexId(), this.f$2, r4.getBlob(0), ((Cursor) obj).getBlob(1)));
|
|
}
|
|
|
|
{
|
|
this.f$0 = treeSet;
|
|
this.f$1 = fieldIndex;
|
|
this.f$2 = documentKey;
|
|
}
|
|
});
|
|
return treeSet;
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.local.IndexManager
|
|
public final List<DocumentKey> getDocumentsMatchingTarget(Target target) {
|
|
Assert.hardAssert(this.started, "IndexManager not started", new Object[0]);
|
|
ArrayList arrayList = new ArrayList();
|
|
ArrayList arrayList2 = new ArrayList();
|
|
Iterator<Target> it = getSubTargets(target).iterator();
|
|
while (true) {
|
|
if (it.hasNext()) {
|
|
Target next = it.next();
|
|
FieldIndex fieldIndex = getFieldIndex(next);
|
|
if (fieldIndex == null) {
|
|
return null;
|
|
}
|
|
List<sbb> arrayValues = next.getArrayValues(fieldIndex);
|
|
Collection<sbb> notInValues = next.getNotInValues(fieldIndex);
|
|
Bound lowerBound = next.getLowerBound(fieldIndex);
|
|
Bound upperBound = next.getUpperBound(fieldIndex);
|
|
if (Logger.isDebugEnabled()) {
|
|
Logger.debug(TAG, "Using index '%s' to execute '%s' (Arrays: %s, Lower bound: %s, Upper bound: %s)", fieldIndex, next, arrayValues, lowerBound, upperBound);
|
|
}
|
|
Object[] encodeBound = encodeBound(fieldIndex, next, lowerBound);
|
|
String str = lowerBound.isInclusive() ? ">=" : UrlTreeKt.configurablePathSegmentSuffix;
|
|
Object[] encodeBound2 = encodeBound(fieldIndex, next, upperBound);
|
|
String str2 = upperBound.isInclusive() ? "<=" : UrlTreeKt.configurablePathSegmentPrefix;
|
|
Object[] generateQueryAndBindings = generateQueryAndBindings(next, fieldIndex.getIndexId(), arrayValues, encodeBound, str, encodeBound2, str2, encodeValues(fieldIndex, next, notInValues));
|
|
arrayList.add(String.valueOf(generateQueryAndBindings[0]));
|
|
arrayList2.addAll(Arrays.asList(generateQueryAndBindings).subList(1, generateQueryAndBindings.length));
|
|
} else {
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append(TextUtils.join(" UNION ", arrayList));
|
|
sb.append("ORDER BY directional_value, document_key ");
|
|
sb.append(target.getKeyOrder().equals(OrderBy.Direction.ASCENDING) ? "asc " : "desc ");
|
|
String obj = sb.toString();
|
|
StringBuilder sb2 = new StringBuilder("SELECT DISTINCT document_key FROM (");
|
|
sb2.append(obj);
|
|
sb2.append(")");
|
|
String obj2 = sb2.toString();
|
|
if (target.hasLimit()) {
|
|
StringBuilder sb3 = new StringBuilder();
|
|
sb3.append(obj2);
|
|
sb3.append(" LIMIT ");
|
|
sb3.append(target.getLimit());
|
|
obj2 = sb3.toString();
|
|
}
|
|
Assert.hardAssert(arrayList2.size() < 1000, "Cannot perform query with more than 999 bind elements", new Object[0]);
|
|
SQLitePersistence.Query binding = this.db.query(obj2).binding(arrayList2.toArray());
|
|
final ArrayList arrayList3 = new ArrayList();
|
|
binding.forEach(new Consumer(arrayList3) { // from class: com.google.firebase.firestore.local.SQLiteIndexManager$$ExternalSyntheticLambda0
|
|
public final List f$0;
|
|
|
|
@Override // com.google.firebase.firestore.util.Consumer
|
|
public final void accept(Object obj3) {
|
|
this.f$0.add(DocumentKey.fromPath(ResourcePath.fromString(((Cursor) obj3).getString(0))));
|
|
}
|
|
|
|
{
|
|
this.f$0 = arrayList3;
|
|
}
|
|
});
|
|
Logger.debug(TAG, "Index scan returned %s documents", Integer.valueOf(arrayList3.size()));
|
|
return arrayList3;
|
|
}
|
|
}
|
|
}
|
|
|
|
private Object[] generateQueryAndBindings(Target target, int i, List<sbb> list, Object[] objArr, String str, Object[] objArr2, String str2, Object[] objArr3) {
|
|
StringBuilder sb;
|
|
int max = Math.max(objArr.length, objArr2.length) * (list != null ? list.size() : 1);
|
|
StringBuilder sb2 = new StringBuilder();
|
|
sb2.append("SELECT document_key, directional_value FROM index_entries WHERE index_id = ? AND uid = ? AND array_value = ? AND directional_value ");
|
|
sb2.append(str);
|
|
sb2.append(" ? AND directional_value ");
|
|
sb2.append(str2);
|
|
sb2.append(" ? ");
|
|
CharSequence repeatSequence = Util.repeatSequence(sb2, max, " UNION ");
|
|
if (objArr3 != null) {
|
|
StringBuilder sb3 = new StringBuilder("SELECT document_key, directional_value FROM (");
|
|
sb3.append(repeatSequence);
|
|
sb3.append(") WHERE directional_value NOT IN (");
|
|
sb3.append((CharSequence) Util.repeatSequence("?", objArr3.length, ", "));
|
|
sb3.append(")");
|
|
sb = sb3;
|
|
} else {
|
|
sb = repeatSequence;
|
|
}
|
|
Object[] fillBounds = fillBounds(max, i, list, objArr, objArr2, objArr3);
|
|
ArrayList arrayList = new ArrayList();
|
|
arrayList.add(sb.toString());
|
|
arrayList.addAll(Arrays.asList(fillBounds));
|
|
return arrayList.toArray();
|
|
}
|
|
|
|
private Object[] fillBounds(int i, int i2, List<sbb> list, Object[] objArr, Object[] objArr2, Object[] objArr3) {
|
|
int size = i / (list != null ? list.size() : 1);
|
|
int i3 = 0;
|
|
Object[] objArr4 = new Object[(i * 5) + (objArr3 != null ? objArr3.length : 0)];
|
|
int i4 = 0;
|
|
int i5 = 0;
|
|
while (i4 < i) {
|
|
objArr4[i5] = Integer.valueOf(i2);
|
|
objArr4[i5 + 1] = this.uid;
|
|
objArr4[i5 + 2] = list != null ? encodeSingleElement(list.get(i4 / size)) : EMPTY_BYTES_VALUE;
|
|
int i6 = i4 % size;
|
|
objArr4[i5 + 3] = objArr[i6];
|
|
objArr4[i5 + 4] = objArr2[i6];
|
|
i4++;
|
|
i5 += 5;
|
|
}
|
|
if (objArr3 != null) {
|
|
int length = objArr3.length;
|
|
while (i3 < length) {
|
|
objArr4[i5] = objArr3[i3];
|
|
i3++;
|
|
i5++;
|
|
}
|
|
}
|
|
return objArr4;
|
|
}
|
|
|
|
private FieldIndex getFieldIndex(Target target) {
|
|
String lastSegment;
|
|
Assert.hardAssert(this.started, "IndexManager not started", new Object[0]);
|
|
TargetIndexMatcher targetIndexMatcher = new TargetIndexMatcher(target);
|
|
if (target.getCollectionGroup() != null) {
|
|
lastSegment = target.getCollectionGroup();
|
|
} else {
|
|
lastSegment = target.getPath().getLastSegment();
|
|
}
|
|
Collection<FieldIndex> fieldIndexes = getFieldIndexes(lastSegment);
|
|
FieldIndex fieldIndex = null;
|
|
if (fieldIndexes.isEmpty()) {
|
|
return null;
|
|
}
|
|
for (FieldIndex fieldIndex2 : fieldIndexes) {
|
|
if (targetIndexMatcher.servedByIndex(fieldIndex2) && (fieldIndex == null || fieldIndex2.getSegments().size() > fieldIndex.getSegments().size())) {
|
|
fieldIndex = fieldIndex2;
|
|
}
|
|
}
|
|
return fieldIndex;
|
|
}
|
|
|
|
private byte[] encodeDirectionalElements(FieldIndex fieldIndex, Document document) {
|
|
IndexByteEncoder indexByteEncoder = new IndexByteEncoder();
|
|
for (FieldIndex.Segment segment : fieldIndex.getDirectionalSegments()) {
|
|
sbb field = document.getField(segment.getFieldPath());
|
|
if (field == null) {
|
|
return null;
|
|
}
|
|
FirestoreIndexValueWriter.INSTANCE.writeIndexValue(field, indexByteEncoder.forKind(segment.getKind()));
|
|
}
|
|
return indexByteEncoder.getEncodedBytes();
|
|
}
|
|
|
|
private byte[] encodeSingleElement(sbb sbbVar) {
|
|
IndexByteEncoder indexByteEncoder = new IndexByteEncoder();
|
|
FirestoreIndexValueWriter.INSTANCE.writeIndexValue(sbbVar, indexByteEncoder.forKind(FieldIndex.Segment.Kind.ASCENDING));
|
|
return indexByteEncoder.getEncodedBytes();
|
|
}
|
|
|
|
private Object[] encodeValues(FieldIndex fieldIndex, Target target, Collection<sbb> collection) {
|
|
if (collection == null) {
|
|
return null;
|
|
}
|
|
List<IndexByteEncoder> arrayList = new ArrayList<>();
|
|
arrayList.add(new IndexByteEncoder());
|
|
Iterator<sbb> it = collection.iterator();
|
|
for (FieldIndex.Segment segment : fieldIndex.getDirectionalSegments()) {
|
|
sbb next = it.next();
|
|
for (IndexByteEncoder indexByteEncoder : arrayList) {
|
|
if (isInFilter(target, segment.getFieldPath()) && Values.isArray(next)) {
|
|
arrayList = expandIndexValues(arrayList, segment, next);
|
|
} else {
|
|
FirestoreIndexValueWriter.INSTANCE.writeIndexValue(next, indexByteEncoder.forKind(segment.getKind()));
|
|
}
|
|
}
|
|
}
|
|
return getEncodedBytes(arrayList);
|
|
}
|
|
|
|
private Object[] encodeBound(FieldIndex fieldIndex, Target target, Bound bound) {
|
|
return encodeValues(fieldIndex, target, bound.getPosition());
|
|
}
|
|
|
|
private Object[] getEncodedBytes(List<IndexByteEncoder> list) {
|
|
Object[] objArr = new Object[list.size()];
|
|
for (int i = 0; i < list.size(); i++) {
|
|
objArr[i] = list.get(i).getEncodedBytes();
|
|
}
|
|
return objArr;
|
|
}
|
|
|
|
private List<IndexByteEncoder> expandIndexValues(List<IndexByteEncoder> list, FieldIndex.Segment segment, sbb sbbVar) {
|
|
uOO e;
|
|
ArrayList<IndexByteEncoder> arrayList = new ArrayList(list);
|
|
ArrayList arrayList2 = new ArrayList();
|
|
if (sbbVar.valueTypeCase_ == 9) {
|
|
e = (uOO) sbbVar.valueType_;
|
|
} else {
|
|
e = uOO.e();
|
|
}
|
|
for (sbb sbbVar2 : e.values_) {
|
|
for (IndexByteEncoder indexByteEncoder : arrayList) {
|
|
IndexByteEncoder indexByteEncoder2 = new IndexByteEncoder();
|
|
indexByteEncoder2.seed(indexByteEncoder.getEncodedBytes());
|
|
FirestoreIndexValueWriter.INSTANCE.writeIndexValue(sbbVar2, indexByteEncoder2.forKind(segment.getKind()));
|
|
arrayList2.add(indexByteEncoder2);
|
|
}
|
|
}
|
|
return arrayList2;
|
|
}
|
|
|
|
private boolean isInFilter(Target target, FieldPath fieldPath) {
|
|
for (Filter filter : target.getFilters()) {
|
|
if (filter instanceof FieldFilter) {
|
|
FieldFilter fieldFilter = (FieldFilter) filter;
|
|
if (fieldFilter.getField().equals(fieldPath)) {
|
|
FieldFilter.Operator operator = fieldFilter.getOperator();
|
|
if (operator.equals(FieldFilter.Operator.IN) || operator.equals(FieldFilter.Operator.NOT_IN)) {
|
|
return true;
|
|
}
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override // com.google.firebase.firestore.local.IndexManager
|
|
public final void updateCollectionGroup(String str, FieldIndex.IndexOffset indexOffset) {
|
|
Assert.hardAssert(this.started, "IndexManager not started", new Object[0]);
|
|
this.memoizedMaxSequenceNumber++;
|
|
for (FieldIndex fieldIndex : getFieldIndexes(str)) {
|
|
FieldIndex create = FieldIndex.create(fieldIndex.getIndexId(), fieldIndex.getCollectionGroup(), fieldIndex.getSegments(), FieldIndex.IndexState.create(this.memoizedMaxSequenceNumber, indexOffset));
|
|
SQLitePersistence sQLitePersistence = this.db;
|
|
int indexId = fieldIndex.getIndexId();
|
|
sQLitePersistence.execute("REPLACE INTO index_state (index_id, uid, sequence_number, read_time_seconds, read_time_nanos, document_key, largest_batch_id) VALUES(?, ?, ?, ?, ?, ?, ?)", Integer.valueOf(indexId), this.uid, Long.valueOf(this.memoizedMaxSequenceNumber), Long.valueOf(indexOffset.getReadTime().getTimestamp().getSeconds()), Integer.valueOf(indexOffset.getReadTime().getTimestamp().getNanoseconds()), EncodedPath.encode(indexOffset.getDocumentKey().getPath()), Integer.valueOf(indexOffset.getLargestBatchId()));
|
|
memoizeIndex(create);
|
|
}
|
|
}
|
|
}
|