Search in sources :

Example 6 with FieldIndex

use of com.google.firebase.firestore.model.FieldIndex in project firebase-android-sdk by firebase.

the class SQLiteIndexManager method memoizeIndex.

/**
 * Stores the index in the memoized indexes table and updates {@link #nextIndexToUpdate}, {@link
 * #memoizedMaxIndexId} and {@link #memoizedMaxSequenceNumber}.
 */
private void memoizeIndex(FieldIndex fieldIndex) {
    Map<Integer, FieldIndex> existingIndexes = memoizedIndexes.get(fieldIndex.getCollectionGroup());
    if (existingIndexes == null) {
        existingIndexes = new HashMap<>();
        memoizedIndexes.put(fieldIndex.getCollectionGroup(), existingIndexes);
    }
    FieldIndex existingIndex = existingIndexes.get(fieldIndex.getIndexId());
    if (existingIndex != null) {
        nextIndexToUpdate.remove(existingIndex);
    }
    existingIndexes.put(fieldIndex.getIndexId(), fieldIndex);
    nextIndexToUpdate.add(fieldIndex);
    memoizedMaxIndexId = Math.max(memoizedMaxIndexId, fieldIndex.getIndexId());
    memoizedMaxSequenceNumber = Math.max(memoizedMaxSequenceNumber, fieldIndex.getIndexState().getSequenceNumber());
}
Also used : FieldIndex(com.google.firebase.firestore.model.FieldIndex)

Example 7 with FieldIndex

use of com.google.firebase.firestore.model.FieldIndex in project firebase-android-sdk by firebase.

the class SQLiteIndexManager method start.

@Override
public void start() {
    Map<Integer, FieldIndex.IndexState> indexStates = new HashMap<>();
    // Fetch all index states if persisted for the user. These states contain per user information
    // on how up to date the index is.
    db.query("SELECT index_id, sequence_number, read_time_seconds, read_time_nanos, document_key, " + "largest_batch_id FROM index_state WHERE uid = ?").binding(uid).forEach(row -> {
        int indexId = row.getInt(0);
        long sequenceNumber = row.getLong(1);
        SnapshotVersion readTime = new SnapshotVersion(new Timestamp(row.getLong(2), row.getInt(3)));
        DocumentKey documentKey = DocumentKey.fromPath(EncodedPath.decodeResourcePath(row.getString(4)));
        int largestBatchId = row.getInt(5);
        indexStates.put(indexId, FieldIndex.IndexState.create(sequenceNumber, readTime, documentKey, largestBatchId));
    });
    // Fetch all indices and combine with user's index state if available.
    db.query("SELECT index_id, collection_group, index_proto FROM index_configuration").forEach(row -> {
        try {
            int indexId = row.getInt(0);
            String collectionGroup = row.getString(1);
            List<FieldIndex.Segment> segments = serializer.decodeFieldIndexSegments(Index.parseFrom(row.getBlob(2)));
            // If we fetched an index state for the user above, combine it with this index.
            // We use the default state if we don't have an index state (e.g. the index was
            // created while a different user as logged in).
            FieldIndex.IndexState indexState = indexStates.containsKey(indexId) ? indexStates.get(indexId) : FieldIndex.INITIAL_STATE;
            FieldIndex fieldIndex = FieldIndex.create(indexId, collectionGroup, segments, indexState);
            // Store the index and update `memoizedMaxIndexId` and `memoizedMaxSequenceNumber`.
            memoizeIndex(fieldIndex);
        } catch (InvalidProtocolBufferException e) {
            throw fail("Failed to decode index: " + e);
        }
    });
    started = true;
}
Also used : FieldIndex(com.google.firebase.firestore.model.FieldIndex) HashMap(java.util.HashMap) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) Timestamp(com.google.firebase.Timestamp) SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) DocumentKey(com.google.firebase.firestore.model.DocumentKey)

Example 8 with FieldIndex

use of com.google.firebase.firestore.model.FieldIndex in project firebase-android-sdk by firebase.

the class SQLiteIndexManager method computeIndexEntries.

/**
 * Creates the index entries for the given document.
 */
private SortedSet<IndexEntry> computeIndexEntries(Document document, FieldIndex fieldIndex) {
    SortedSet<IndexEntry> result = new TreeSet<>();
    @Nullable byte[] directionalValue = encodeDirectionalElements(fieldIndex, document);
    if (directionalValue == null) {
        return result;
    }
    @Nullable FieldIndex.Segment arraySegment = fieldIndex.getArraySegment();
    if (arraySegment != null) {
        Value value = document.getField(arraySegment.getFieldPath());
        if (isArray(value)) {
            for (Value arrayValue : value.getArrayValue().getValuesList()) {
                result.add(IndexEntry.create(fieldIndex.getIndexId(), document.getKey(), encodeSingleElement(arrayValue), directionalValue));
            }
        }
    } else {
        result.add(IndexEntry.create(fieldIndex.getIndexId(), document.getKey(), new byte[] {}, directionalValue));
    }
    return result;
}
Also used : FieldIndex(com.google.firebase.firestore.model.FieldIndex) TreeSet(java.util.TreeSet) Value(com.google.firestore.v1.Value) IndexEntry(com.google.firebase.firestore.index.IndexEntry) Nullable(androidx.annotation.Nullable)

Example 9 with FieldIndex

use of com.google.firebase.firestore.model.FieldIndex in project firebase-android-sdk by firebase.

the class Target method getLowerBound.

/**
 * Returns a lower bound of field values that can be used as a starting point to scan the index
 * defined by {@code fieldIndex}. Returns {@code null} if no lower bound exists.
 */
@Nullable
public Bound getLowerBound(FieldIndex fieldIndex) {
    List<Value> values = new ArrayList<>();
    boolean inclusive = true;
    // For each segment, retrieve a lower bound if there is a suitable filter or startAt.
    for (FieldIndex.Segment segment : fieldIndex.getDirectionalSegments()) {
        Value segmentValue = null;
        boolean segmentInclusive = true;
        // Process all filters to find a value for the current field segment
        for (FieldFilter fieldFilter : getFieldFiltersForPath(segment.getFieldPath())) {
            Value filterValue = null;
            boolean filterInclusive = true;
            switch(fieldFilter.getOperator()) {
                case LESS_THAN:
                case LESS_THAN_OR_EQUAL:
                    filterValue = Values.getLowerBound(fieldFilter.getValue().getValueTypeCase());
                    break;
                case EQUAL:
                case IN:
                case GREATER_THAN_OR_EQUAL:
                    filterValue = fieldFilter.getValue();
                    break;
                case GREATER_THAN:
                    filterValue = fieldFilter.getValue();
                    filterInclusive = false;
                    break;
                case NOT_EQUAL:
                case NOT_IN:
                    filterValue = Values.MIN_VALUE;
                    break;
                default:
            }
            if (max(segmentValue, filterValue) == filterValue) {
                segmentValue = filterValue;
                segmentInclusive = filterInclusive;
            }
        }
        // if we can narrow the scope.
        if (startAt != null) {
            for (int i = 0; i < orderBys.size(); ++i) {
                OrderBy orderBy = this.orderBys.get(i);
                if (orderBy.getField().equals(segment.getFieldPath())) {
                    Value cursorValue = startAt.getPosition().get(i);
                    if (max(segmentValue, cursorValue) == cursorValue) {
                        segmentValue = cursorValue;
                        segmentInclusive = startAt.isInclusive();
                    }
                    break;
                }
            }
        }
        if (segmentValue == null) {
            // No lower bound exists
            return null;
        }
        values.add(segmentValue);
        inclusive &= segmentInclusive;
    }
    return new Bound(values, inclusive);
}
Also used : FieldIndex(com.google.firebase.firestore.model.FieldIndex) Value(com.google.firestore.v1.Value) ArrayList(java.util.ArrayList) Nullable(androidx.annotation.Nullable)

Example 10 with FieldIndex

use of com.google.firebase.firestore.model.FieldIndex in project firebase-android-sdk by firebase.

the class Target method getUpperBound.

/**
 * Returns an upper bound of field values that can be used as an ending point when scanning the
 * index defined by {@code fieldIndex}. Returns {@code null} if no upper bound exists.
 */
@Nullable
public Bound getUpperBound(FieldIndex fieldIndex) {
    List<Value> values = new ArrayList<>();
    boolean inclusive = true;
    // For each segment, retrieve an upper bound if there is a suitable filter or endAt.
    for (FieldIndex.Segment segment : fieldIndex.getDirectionalSegments()) {
        @Nullable Value segmentValue = null;
        boolean segmentInclusive = true;
        // Process all filters to find a value for the current field segment
        for (FieldFilter fieldFilter : getFieldFiltersForPath(segment.getFieldPath())) {
            Value filterValue = null;
            boolean filterInclusive = true;
            switch(fieldFilter.getOperator()) {
                case GREATER_THAN_OR_EQUAL:
                case GREATER_THAN:
                    filterValue = Values.getUpperBound(fieldFilter.getValue().getValueTypeCase());
                    filterInclusive = false;
                    break;
                case EQUAL:
                case IN:
                case LESS_THAN_OR_EQUAL:
                    filterValue = fieldFilter.getValue();
                    break;
                case LESS_THAN:
                    filterValue = fieldFilter.getValue();
                    filterInclusive = false;
                    break;
                case NOT_EQUAL:
                case NOT_IN:
                    filterValue = Values.MAX_VALUE;
                    break;
                default:
            }
            if (min(segmentValue, filterValue) == filterValue) {
                segmentValue = filterValue;
                segmentInclusive = filterInclusive;
            }
        }
        // if we can narrow the scope.
        if (endAt != null) {
            for (int i = 0; i < orderBys.size(); ++i) {
                OrderBy orderBy = this.orderBys.get(i);
                if (orderBy.getField().equals(segment.getFieldPath())) {
                    Value cursorValue = endAt.getPosition().get(i);
                    if (min(segmentValue, cursorValue) == cursorValue) {
                        segmentValue = cursorValue;
                        segmentInclusive = endAt.isInclusive();
                    }
                    break;
                }
            }
        }
        if (segmentValue == null) {
            // No upper bound exists
            return null;
        }
        values.add(segmentValue);
        inclusive &= segmentInclusive;
    }
    return new Bound(values, inclusive);
}
Also used : FieldIndex(com.google.firebase.firestore.model.FieldIndex) Value(com.google.firestore.v1.Value) ArrayList(java.util.ArrayList) Nullable(androidx.annotation.Nullable) Nullable(androidx.annotation.Nullable)

Aggregations

FieldIndex (com.google.firebase.firestore.model.FieldIndex)49 Test (org.junit.Test)32 Nullable (androidx.annotation.Nullable)8 Value (com.google.firestore.v1.Value)8 Query (com.google.firebase.firestore.core.Query)6 ArrayList (java.util.ArrayList)6 DocumentKey (com.google.firebase.firestore.model.DocumentKey)3 DirectionalIndexByteEncoder (com.google.firebase.firestore.index.DirectionalIndexByteEncoder)2 IndexByteEncoder (com.google.firebase.firestore.index.IndexByteEncoder)2 IndexEntry (com.google.firebase.firestore.index.IndexEntry)2 IndexOffset (com.google.firebase.firestore.model.FieldIndex.IndexOffset)2 HashMap (java.util.HashMap)2 VisibleForTesting (androidx.annotation.VisibleForTesting)1 Timestamp (com.google.firebase.Timestamp)1 ImmutableSortedMap (com.google.firebase.database.collection.ImmutableSortedMap)1 Bound (com.google.firebase.firestore.core.Bound)1 Target (com.google.firebase.firestore.core.Target)1 Document (com.google.firebase.firestore.model.Document)1 FieldPath (com.google.firebase.firestore.model.FieldPath)1 SnapshotVersion (com.google.firebase.firestore.model.SnapshotVersion)1