use of com.google.firebase.database.collection.ImmutableSortedMap in project firebase-android-sdk by firebase.
the class NodeUtilities method NodeFromJSON.
public static Node NodeFromJSON(Object value, Node priority) throws DatabaseException {
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();
} else if (value instanceof String) {
return new StringNode((String) value, priority);
} else if (value instanceof Long) {
return new LongNode((Long) value, priority);
} else if (value instanceof Integer) {
return new LongNode((long) (Integer) value, priority);
} else if (value instanceof Double) {
return new DoubleNode((Double) value, priority);
} else if (value instanceof Boolean) {
return new BooleanNode((Boolean) value, priority);
} else if (value instanceof Map || value instanceof List) {
Map<ChildKey, Node> childData;
// List<NamedNode>
if (value instanceof Map) {
Map mapValue = (Map) value;
if (mapValue.containsKey(ServerValues.NAME_SUBKEY_SERVERVALUE)) {
@SuppressWarnings("unchecked") Node node = new DeferredValueNode(mapValue, priority);
return node;
} else {
childData = new HashMap<ChildKey, Node>(mapValue.size());
@SuppressWarnings("unchecked") Iterator<String> keyIter = (Iterator<String>) mapValue.keySet().iterator();
while (keyIter.hasNext()) {
String key = keyIter.next();
if (!key.startsWith(".")) {
Node childNode = NodeFromJSON(mapValue.get(key));
if (!childNode.isEmpty()) {
ChildKey childKey = ChildKey.fromString(key);
childData.put(childKey, childNode);
}
}
}
}
} else {
// List
List listValue = (List) value;
childData = new HashMap<ChildKey, Node>(listValue.size());
for (int i = 0; i < listValue.size(); ++i) {
String key = "" + i;
Node childNode = NodeFromJSON(listValue.get(i));
if (!childNode.isEmpty()) {
ChildKey childKey = ChildKey.fromString(key);
childData.put(childKey, childNode);
}
}
}
if (childData.isEmpty()) {
return EmptyNode.Empty();
} else {
ImmutableSortedMap<ChildKey, Node> childSet = ImmutableSortedMap.Builder.fromMap(childData, ChildrenNode.NAME_ONLY_COMPARATOR);
return new ChildrenNode(childSet, priority);
}
} else {
throw new DatabaseException("Failed to parse node with class " + value.getClass().toString());
}
} catch (ClassCastException e) {
throw new DatabaseException("Failed to parse node", e);
}
}
use of com.google.firebase.database.collection.ImmutableSortedMap in project firebase-android-sdk by firebase.
the class LocalStore method applyRemoteEvent.
/**
* Updates the "ground-state" (remote) documents. We assume that the remote event reflects any
* write batches that have been acknowledged or rejected (i.e. we do not re-apply local mutations
* to updates from this event).
*
* <p>LocalDocuments are re-calculated if there are remaining mutations in the queue.
*/
public ImmutableSortedMap<DocumentKey, Document> applyRemoteEvent(RemoteEvent remoteEvent) {
SnapshotVersion remoteVersion = remoteEvent.getSnapshotVersion();
// TODO: Call queryEngine.handleDocumentChange() appropriately.
return persistence.runTransaction("Apply remote event", () -> {
Map<Integer, TargetChange> targetChanges = remoteEvent.getTargetChanges();
long sequenceNumber = persistence.getReferenceDelegate().getCurrentSequenceNumber();
for (Map.Entry<Integer, TargetChange> entry : targetChanges.entrySet()) {
Integer boxedTargetId = entry.getKey();
int targetId = boxedTargetId;
TargetChange change = entry.getValue();
TargetData oldTargetData = queryDataByTarget.get(targetId);
if (oldTargetData == null) {
// we persist the updated query data along with the updated assignment.
continue;
}
targetCache.removeMatchingKeys(change.getRemovedDocuments(), targetId);
targetCache.addMatchingKeys(change.getAddedDocuments(), targetId);
TargetData newTargetData = oldTargetData.withSequenceNumber(sequenceNumber);
if (remoteEvent.getTargetMismatches().contains(targetId)) {
newTargetData = newTargetData.withResumeToken(ByteString.EMPTY, SnapshotVersion.NONE).withLastLimboFreeSnapshotVersion(SnapshotVersion.NONE);
} else if (!change.getResumeToken().isEmpty()) {
newTargetData = newTargetData.withResumeToken(change.getResumeToken(), remoteEvent.getSnapshotVersion());
}
queryDataByTarget.put(targetId, newTargetData);
// since the last update).
if (shouldPersistTargetData(oldTargetData, newTargetData, change)) {
targetCache.updateTargetData(newTargetData);
}
}
Map<DocumentKey, MutableDocument> documentUpdates = remoteEvent.getDocumentUpdates();
Set<DocumentKey> limboDocuments = remoteEvent.getResolvedLimboDocuments();
for (DocumentKey key : documentUpdates.keySet()) {
if (limboDocuments.contains(key)) {
persistence.getReferenceDelegate().updateLimboDocument(key);
}
}
DocumentChangeResult result = populateDocumentChanges(documentUpdates);
Map<DocumentKey, MutableDocument> changedDocs = result.changedDocuments;
// HACK: The only reason we allow snapshot version NONE is so that we can synthesize
// remote events when we get permission denied errors while trying to resolve the
// state of a locally cached document that is in limbo.
SnapshotVersion lastRemoteVersion = targetCache.getLastRemoteSnapshotVersion();
if (!remoteVersion.equals(SnapshotVersion.NONE)) {
hardAssert(remoteVersion.compareTo(lastRemoteVersion) >= 0, "Watch stream reverted to previous snapshot?? (%s < %s)", remoteVersion, lastRemoteVersion);
targetCache.setLastRemoteSnapshotVersion(remoteVersion);
}
return localDocuments.getLocalViewOfDocuments(changedDocs, result.existenceChangedKeys);
});
}
use of com.google.firebase.database.collection.ImmutableSortedMap in project firebase-android-sdk by firebase.
the class LocalDocumentsView method getDocumentsMatchingCollectionGroupQuery.
private ImmutableSortedMap<DocumentKey, Document> getDocumentsMatchingCollectionGroupQuery(Query query, IndexOffset offset) {
hardAssert(query.getPath().isEmpty(), "Currently we only support collection group queries at the root.");
String collectionId = query.getCollectionGroup();
ImmutableSortedMap<DocumentKey, Document> results = emptyDocumentMap();
List<ResourcePath> parents = indexManager.getCollectionParents(collectionId);
// aggregate the results.
for (ResourcePath parent : parents) {
Query collectionQuery = query.asCollectionQueryAtPath(parent.append(collectionId));
ImmutableSortedMap<DocumentKey, Document> collectionResults = getDocumentsMatchingCollectionQuery(collectionQuery, offset);
for (Map.Entry<DocumentKey, Document> docEntry : collectionResults) {
results = results.insert(docEntry.getKey(), docEntry.getValue());
}
}
return results;
}
use of com.google.firebase.database.collection.ImmutableSortedMap in project firebase-android-sdk by firebase.
the class SyncEngine method handleRemoteEvent.
/**
* Called by FirestoreClient to notify us of a new remote event.
*/
@Override
public void handleRemoteEvent(RemoteEvent event) {
assertCallback("handleRemoteEvent");
// Update `receivedDocument` as appropriate for any limbo targets.
for (Map.Entry<Integer, TargetChange> entry : event.getTargetChanges().entrySet()) {
Integer targetId = entry.getKey();
TargetChange targetChange = entry.getValue();
LimboResolution limboResolution = activeLimboResolutionsByTarget.get(targetId);
if (limboResolution != null) {
// Since this is a limbo resolution lookup, it's for a single document and it could be
// added, modified, or removed, but not a combination.
hardAssert(targetChange.getAddedDocuments().size() + targetChange.getModifiedDocuments().size() + targetChange.getRemovedDocuments().size() <= 1, "Limbo resolution for single document contains multiple changes.");
if (targetChange.getAddedDocuments().size() > 0) {
limboResolution.receivedDocument = true;
} else if (targetChange.getModifiedDocuments().size() > 0) {
hardAssert(limboResolution.receivedDocument, "Received change for limbo target document without add.");
} else if (targetChange.getRemovedDocuments().size() > 0) {
hardAssert(limboResolution.receivedDocument, "Received remove for limbo target document without add.");
limboResolution.receivedDocument = false;
} else {
// This was probably just a CURRENT targetChange or similar.
}
}
}
ImmutableSortedMap<DocumentKey, Document> changes = localStore.applyRemoteEvent(event);
emitNewSnapsAndNotifyLocalStore(changes, event);
}
use of com.google.firebase.database.collection.ImmutableSortedMap in project firebase-android-sdk by firebase.
the class SyncEngine method emitNewSnapsAndNotifyLocalStore.
/**
* Computes a new snapshot from the changes and calls the registered callback with the new
* snapshot.
*/
private void emitNewSnapsAndNotifyLocalStore(ImmutableSortedMap<DocumentKey, Document> changes, @Nullable RemoteEvent remoteEvent) {
List<ViewSnapshot> newSnapshots = new ArrayList<>();
List<LocalViewChanges> documentChangesInAllViews = new ArrayList<>();
for (Map.Entry<Query, QueryView> entry : queryViewsByQuery.entrySet()) {
QueryView queryView = entry.getValue();
View view = queryView.getView();
View.DocumentChanges viewDocChanges = view.computeDocChanges(changes);
if (viewDocChanges.needsRefill()) {
// The query has a limit and some docs were removed/updated, so we need to re-run the query
// against the local store to make sure we didn't lose any good docs that had been past the
// limit.
QueryResult queryResult = localStore.executeQuery(queryView.getQuery(), /* usePreviousResults= */
false);
viewDocChanges = view.computeDocChanges(queryResult.getDocuments(), viewDocChanges);
}
TargetChange targetChange = remoteEvent == null ? null : remoteEvent.getTargetChanges().get(queryView.getTargetId());
ViewChange viewChange = queryView.getView().applyChanges(viewDocChanges, targetChange);
updateTrackedLimboDocuments(viewChange.getLimboChanges(), queryView.getTargetId());
if (viewChange.getSnapshot() != null) {
newSnapshots.add(viewChange.getSnapshot());
LocalViewChanges docChanges = LocalViewChanges.fromViewSnapshot(queryView.getTargetId(), viewChange.getSnapshot());
documentChangesInAllViews.add(docChanges);
}
}
syncEngineListener.onViewSnapshots(newSnapshots);
localStore.notifyLocalViewChanges(documentChangesInAllViews);
}
Aggregations