Search in sources :

Example 76 with DocumentKey

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

the class View method updateLimboDocuments.

private List<LimboDocumentChange> updateLimboDocuments() {
    // We can only determine limbo documents when we're in-sync with the server.
    if (!current) {
        return Collections.emptyList();
    }
    // TODO: Do this incrementally so that it's not quadratic when updating many
    // documents.
    ImmutableSortedSet<DocumentKey> oldLimboDocs = limboDocuments;
    limboDocuments = DocumentKey.emptyKeySet();
    for (Document doc : documentSet) {
        if (shouldBeLimboDoc(doc.getKey())) {
            limboDocuments = limboDocuments.insert(doc.getKey());
        }
    }
    // Diff the new limbo docs with the old limbo docs.
    List<LimboDocumentChange> changes = new ArrayList<>(oldLimboDocs.size() + limboDocuments.size());
    for (DocumentKey key : oldLimboDocs) {
        if (!limboDocuments.contains(key)) {
            changes.add(new LimboDocumentChange(LimboDocumentChange.Type.REMOVED, key));
        }
    }
    for (DocumentKey key : limboDocuments) {
        if (!oldLimboDocs.contains(key)) {
            changes.add(new LimboDocumentChange(LimboDocumentChange.Type.ADDED, key));
        }
    }
    return changes;
}
Also used : DocumentKey(com.google.firebase.firestore.model.DocumentKey) ArrayList(java.util.ArrayList) Document(com.google.firebase.firestore.model.Document)

Example 77 with DocumentKey

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

the class View method computeDocChanges.

/**
 * Iterates over a set of doc changes, applies the query limit, and computes what the new results
 * should be, what the changes were, and whether we may need to go back to the local cache for
 * more results. Does not make any changes to the view.
 *
 * @param docChanges The doc changes to apply to this view.
 * @param previousChanges If this is being called with a refill, then start with this set of docs
 *     and changes instead of the current view.
 * @return a new set of docs, changes, and refill flag.
 */
public DocumentChanges computeDocChanges(ImmutableSortedMap<DocumentKey, Document> docChanges, @Nullable DocumentChanges previousChanges) {
    DocumentViewChangeSet changeSet = previousChanges != null ? previousChanges.changeSet : new DocumentViewChangeSet();
    DocumentSet oldDocumentSet = previousChanges != null ? previousChanges.documentSet : documentSet;
    ImmutableSortedSet<DocumentKey> newMutatedKeys = previousChanges != null ? previousChanges.mutatedKeys : mutatedKeys;
    DocumentSet newDocumentSet = oldDocumentSet;
    boolean needsRefill = false;
    // Track the last doc in a (full) limit. This is necessary, because some update (a delete, or an
    // update moving a doc past the old limit) might mean there is some other document in the local
    // cache that either should come (1) between the old last limit doc and the new last document,
    // in the case of updates, or (2) after the new last document, in the case of deletes. So we
    // keep this doc at the old limit to compare the updates to.
    // 
    // Note that this should never get used in a refill (when previousChanges is set), because there
    // will only be adds -- no deletes or updates.
    Document lastDocInLimit = (query.hasLimitToFirst() && oldDocumentSet.size() == query.getLimitToFirst()) ? oldDocumentSet.getLastDocument() : null;
    Document firstDocInLimit = (query.hasLimitToLast() && oldDocumentSet.size() == query.getLimitToLast()) ? oldDocumentSet.getFirstDocument() : null;
    for (Map.Entry<DocumentKey, Document> entry : docChanges) {
        DocumentKey key = entry.getKey();
        Document oldDoc = oldDocumentSet.getDocument(key);
        Document newDoc = query.matches(entry.getValue()) ? entry.getValue() : null;
        boolean oldDocHadPendingMutations = oldDoc != null && this.mutatedKeys.contains(oldDoc.getKey());
        // We only consider committed mutations for documents that were mutated during the lifetime of
        // the view.
        boolean newDocHasPendingMutations = newDoc != null && (newDoc.hasLocalMutations() || (this.mutatedKeys.contains(newDoc.getKey()) && newDoc.hasCommittedMutations()));
        boolean changeApplied = false;
        // Calculate change
        if (oldDoc != null && newDoc != null) {
            boolean docsEqual = oldDoc.getData().equals(newDoc.getData());
            if (!docsEqual) {
                if (!shouldWaitForSyncedDocument(oldDoc, newDoc)) {
                    changeSet.addChange(DocumentViewChange.create(Type.MODIFIED, newDoc));
                    changeApplied = true;
                    if ((lastDocInLimit != null && query.comparator().compare(newDoc, lastDocInLimit) > 0) || (firstDocInLimit != null && query.comparator().compare(newDoc, firstDocInLimit) < 0)) {
                        // This doc moved from inside the limit to outside the limit. That means there may be
                        // some doc in the local cache that should be included instead.
                        needsRefill = true;
                    }
                }
            } else if (oldDocHadPendingMutations != newDocHasPendingMutations) {
                changeSet.addChange(DocumentViewChange.create(Type.METADATA, newDoc));
                changeApplied = true;
            }
        } else if (oldDoc == null && newDoc != null) {
            changeSet.addChange(DocumentViewChange.create(Type.ADDED, newDoc));
            changeApplied = true;
        } else if (oldDoc != null && newDoc == null) {
            changeSet.addChange(DocumentViewChange.create(Type.REMOVED, oldDoc));
            changeApplied = true;
            if (lastDocInLimit != null || firstDocInLimit != null) {
                // A doc was removed from a full limit query. We'll need to requery from the local cache
                // to see if we know about some other doc that should be in the results.
                needsRefill = true;
            }
        }
        if (changeApplied) {
            if (newDoc != null) {
                newDocumentSet = newDocumentSet.add(newDoc);
                if (newDoc.hasLocalMutations()) {
                    newMutatedKeys = newMutatedKeys.insert(newDoc.getKey());
                } else {
                    newMutatedKeys = newMutatedKeys.remove(newDoc.getKey());
                }
            } else {
                newDocumentSet = newDocumentSet.remove(key);
                newMutatedKeys = newMutatedKeys.remove(key);
            }
        }
    }
    // Drop documents out to meet limitToFirst/limitToLast requirement.
    if (query.hasLimitToFirst() || query.hasLimitToLast()) {
        long limit = query.hasLimitToFirst() ? query.getLimitToFirst() : query.getLimitToLast();
        for (long i = newDocumentSet.size() - limit; i > 0; --i) {
            Document oldDoc = query.hasLimitToFirst() ? newDocumentSet.getLastDocument() : newDocumentSet.getFirstDocument();
            newDocumentSet = newDocumentSet.remove(oldDoc.getKey());
            newMutatedKeys = newMutatedKeys.remove(oldDoc.getKey());
            changeSet.addChange(DocumentViewChange.create(Type.REMOVED, oldDoc));
        }
    }
    hardAssert(!needsRefill || previousChanges == null, "View was refilled using docs that themselves needed refilling.");
    return new DocumentChanges(newDocumentSet, changeSet, newMutatedKeys, needsRefill);
}
Also used : DocumentKey(com.google.firebase.firestore.model.DocumentKey) DocumentSet(com.google.firebase.firestore.model.DocumentSet) Document(com.google.firebase.firestore.model.Document) Map(java.util.Map) ImmutableSortedMap(com.google.firebase.database.collection.ImmutableSortedMap)

Example 78 with DocumentKey

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

the class Transaction method commit.

public Task<Void> commit() {
    ensureCommitNotCalled();
    if (lastWriteError != null) {
        return Tasks.forException(lastWriteError);
    }
    HashSet<DocumentKey> unwritten = new HashSet<>(readVersions.keySet());
    // For each mutation, note that the doc was written.
    for (Mutation mutation : mutations) {
        unwritten.remove(mutation.getKey());
    }
    // For each document that was read but not written to, we want to perform a `verify` operation.
    for (DocumentKey key : unwritten) {
        mutations.add(new VerifyMutation(key, precondition(key)));
    }
    committed = true;
    return datastore.commit(mutations).continueWithTask(Executors.DIRECT_EXECUTOR, task -> {
        if (task.isSuccessful()) {
            return Tasks.forResult(null);
        } else {
            return Tasks.forException(task.getException());
        }
    });
}
Also used : DocumentKey(com.google.firebase.firestore.model.DocumentKey) VerifyMutation(com.google.firebase.firestore.model.mutation.VerifyMutation) Mutation(com.google.firebase.firestore.model.mutation.Mutation) VerifyMutation(com.google.firebase.firestore.model.mutation.VerifyMutation) DeleteMutation(com.google.firebase.firestore.model.mutation.DeleteMutation) HashSet(java.util.HashSet)

Example 79 with DocumentKey

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

the class LocalSerializer method decodeDocument.

/**
 * Decodes a Document proto to the equivalent model.
 */
private MutableDocument decodeDocument(com.google.firestore.v1.Document document, boolean hasCommittedMutations) {
    DocumentKey key = rpcSerializer.decodeKey(document.getName());
    SnapshotVersion version = rpcSerializer.decodeVersion(document.getUpdateTime());
    MutableDocument result = MutableDocument.newFoundDocument(key, version, ObjectValue.fromMap(document.getFieldsMap()));
    return hasCommittedMutations ? result.setHasCommittedMutations() : result;
}
Also used : SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) DocumentKey(com.google.firebase.firestore.model.DocumentKey) MutableDocument(com.google.firebase.firestore.model.MutableDocument)

Example 80 with DocumentKey

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

the class LocalViewChanges method fromViewSnapshot.

public static LocalViewChanges fromViewSnapshot(int targetId, ViewSnapshot snapshot) {
    ImmutableSortedSet<DocumentKey> addedKeys = new ImmutableSortedSet<DocumentKey>(new ArrayList<>(), DocumentKey.comparator());
    ImmutableSortedSet<DocumentKey> removedKeys = new ImmutableSortedSet<DocumentKey>(new ArrayList<>(), DocumentKey.comparator());
    for (DocumentViewChange docChange : snapshot.getChanges()) {
        switch(docChange.getType()) {
            case ADDED:
                addedKeys = addedKeys.insert(docChange.getDocument().getKey());
                break;
            case REMOVED:
                removedKeys = removedKeys.insert(docChange.getDocument().getKey());
                break;
            default:
                // Do nothing.
                break;
        }
    }
    return new LocalViewChanges(targetId, snapshot.isFromCache(), addedKeys, removedKeys);
}
Also used : DocumentViewChange(com.google.firebase.firestore.core.DocumentViewChange) ImmutableSortedSet(com.google.firebase.database.collection.ImmutableSortedSet) DocumentKey(com.google.firebase.firestore.model.DocumentKey)

Aggregations

DocumentKey (com.google.firebase.firestore.model.DocumentKey)134 MutableDocument (com.google.firebase.firestore.model.MutableDocument)52 Test (org.junit.Test)36 HashMap (java.util.HashMap)29 ArrayList (java.util.ArrayList)25 Document (com.google.firebase.firestore.model.Document)23 SnapshotVersion (com.google.firebase.firestore.model.SnapshotVersion)16 Mutation (com.google.firebase.firestore.model.mutation.Mutation)15 Map (java.util.Map)15 ResourcePath (com.google.firebase.firestore.model.ResourcePath)13 MutationBatch (com.google.firebase.firestore.model.mutation.MutationBatch)11 HashSet (java.util.HashSet)11 Overlay (com.google.firebase.firestore.model.mutation.Overlay)10 ImmutableSortedMap (com.google.firebase.database.collection.ImmutableSortedMap)9 TestUtil.patchMutation (com.google.firebase.firestore.testutil.TestUtil.patchMutation)7 TestUtil.setMutation (com.google.firebase.firestore.testutil.TestUtil.setMutation)7 ByteString (com.google.protobuf.ByteString)7 Query (com.google.firebase.firestore.core.Query)6 ObjectValue (com.google.firebase.firestore.model.ObjectValue)6 Timestamp (com.google.firebase.Timestamp)5