use of com.google.firebase.database.collection.ImmutableSortedMap 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.database.collection.ImmutableSortedMap in project firebase-android-sdk by firebase.
the class SQLiteIndexManager method updateIndexEntries.
@Override
public void updateIndexEntries(ImmutableSortedMap<DocumentKey, Document> documents) {
hardAssert(started, "IndexManager not started");
for (Map.Entry<DocumentKey, Document> entry : documents) {
Collection<FieldIndex> fieldIndexes = getFieldIndexes(entry.getKey().getCollectionGroup());
for (FieldIndex fieldIndex : fieldIndexes) {
SortedSet<IndexEntry> existingEntries = getExistingIndexEntries(entry.getKey(), fieldIndex);
SortedSet<IndexEntry> newEntries = computeIndexEntries(entry.getValue(), fieldIndex);
if (!existingEntries.equals(newEntries)) {
updateEntries(entry.getValue(), existingEntries, newEntries);
}
}
}
}
use of com.google.firebase.database.collection.ImmutableSortedMap in project firebase-android-sdk by firebase.
the class LocalDocumentsView method computeViews.
/*Computes the local view for doc */
private ImmutableSortedMap<DocumentKey, Document> computeViews(Map<DocumentKey, MutableDocument> docs, Map<DocumentKey, Overlay> overlays, Set<DocumentKey> existenceStateChanged) {
ImmutableSortedMap<DocumentKey, Document> results = emptyDocumentMap();
Map<DocumentKey, MutableDocument> recalculateDocuments = new HashMap<>();
for (MutableDocument doc : docs.values()) {
Overlay overlay = overlays.get(doc.getKey());
// but would now match.
if (existenceStateChanged.contains(doc.getKey()) && (overlay == null || overlay.getMutation() instanceof PatchMutation)) {
recalculateDocuments.put(doc.getKey(), doc);
} else if (overlay != null) {
overlay.getMutation().applyToLocalView(doc, null, Timestamp.now());
}
}
recalculateAndSaveOverlays(recalculateDocuments);
for (Map.Entry<DocumentKey, MutableDocument> entry : docs.entrySet()) {
results = results.insert(entry.getKey(), entry.getValue());
}
return results;
}
use of com.google.firebase.database.collection.ImmutableSortedMap in project firebase-android-sdk by firebase.
the class LocalDocumentsView method getDocumentsMatchingCollectionQuery.
private ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingCollectionQuery(Query query, IndexOffset offset) {
Map<DocumentKey, MutableDocument> remoteDocuments = remoteDocumentCache.getAll(query.getPath(), offset);
Map<DocumentKey, Overlay> overlays = documentOverlayCache.getOverlays(query.getPath(), offset.getLargestBatchId());
// for all overlays in the initial document set.
for (Map.Entry<DocumentKey, Overlay> entry : overlays.entrySet()) {
if (!remoteDocuments.containsKey(entry.getKey())) {
remoteDocuments.put(entry.getKey(), MutableDocument.newInvalidDocument(entry.getKey()));
}
}
// Apply the overlays and match against the query.
ImmutableSortedMap<DocumentKey, Document> results = emptyDocumentMap();
for (Map.Entry<DocumentKey, MutableDocument> docEntry : remoteDocuments.entrySet()) {
Overlay overlay = overlays.get(docEntry.getKey());
if (overlay != null) {
overlay.getMutation().applyToLocalView(docEntry.getValue(), null, Timestamp.now());
}
// Finally, insert the documents that still match the query
if (query.matches(docEntry.getValue())) {
results = results.insert(docEntry.getKey(), docEntry.getValue());
}
}
return results;
}
use of com.google.firebase.database.collection.ImmutableSortedMap in project GreenHouse by utsanjan.
the class NodeUtilities method NodeFromJSON.
public static Node NodeFromJSON(Object value, Node priority) throws DatabaseException {
Map<ChildKey, Node> childData;
try {
if (value instanceof Map) {
Map mapValue = (Map) value;
if (mapValue.containsKey(".priority")) {
priority = PriorityUtilities.parsePriority(mapValue.get(".priority"));
}
if (mapValue.containsKey(".value")) {
value = mapValue.get(".value");
}
}
if (value == null) {
return EmptyNode.Empty();
}
if (value instanceof String) {
return new StringNode((String) value, priority);
}
if (value instanceof Long) {
return new LongNode((Long) value, priority);
}
if (value instanceof Integer) {
return new LongNode(Long.valueOf(((Integer) value).intValue()), priority);
}
if (value instanceof Double) {
return new DoubleNode((Double) value, priority);
}
if (value instanceof Boolean) {
return new BooleanNode((Boolean) value, priority);
}
if (!(value instanceof Map) && !(value instanceof List)) {
throw new DatabaseException("Failed to parse node with class " + value.getClass().toString());
}
if (value instanceof Map) {
Map mapValue2 = (Map) value;
if (mapValue2.containsKey(ServerValues.NAME_SUBKEY_SERVERVALUE)) {
Node node = new DeferredValueNode(mapValue2, priority);
return node;
}
childData = new HashMap<>(mapValue2.size());
for (String key : mapValue2.keySet()) {
if (!key.startsWith(".")) {
Node childNode = NodeFromJSON(mapValue2.get(key));
if (!childNode.isEmpty()) {
ChildKey childKey = ChildKey.fromString(key);
childData.put(childKey, childNode);
}
}
}
} else {
List listValue = (List) value;
childData = new HashMap<>(listValue.size());
for (int i = 0; i < listValue.size(); i++) {
String key2 = "" + i;
Node childNode2 = NodeFromJSON(listValue.get(i));
if (!childNode2.isEmpty()) {
ChildKey childKey2 = ChildKey.fromString(key2);
childData.put(childKey2, childNode2);
}
}
}
if (childData.isEmpty()) {
return EmptyNode.Empty();
}
ImmutableSortedMap<ChildKey, Node> childSet = ImmutableSortedMap.Builder.fromMap(childData, ChildrenNode.NAME_ONLY_COMPARATOR);
return new ChildrenNode(childSet, priority);
} catch (ClassCastException e) {
throw new DatabaseException("Failed to parse node", e);
}
}
Aggregations