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;
}
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);
}
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());
}
});
}
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;
}
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);
}
Aggregations