Search in sources :

Example 1 with ImmutableSortedMap

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);
    }
}
Also used : Iterator(java.util.Iterator) List(java.util.List) Map(java.util.Map) ImmutableSortedMap(com.google.firebase.database.collection.ImmutableSortedMap) HashMap(java.util.HashMap) DatabaseException(com.google.firebase.database.DatabaseException)

Example 2 with ImmutableSortedMap

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);
    });
}
Also used : MutableDocument(com.google.firebase.firestore.model.MutableDocument) TargetChange(com.google.firebase.firestore.remote.TargetChange) SnapshotVersion(com.google.firebase.firestore.model.SnapshotVersion) DocumentKey(com.google.firebase.firestore.model.DocumentKey) HashMap(java.util.HashMap) Map(java.util.Map) ImmutableSortedMap(com.google.firebase.database.collection.ImmutableSortedMap)

Example 3 with ImmutableSortedMap

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;
}
Also used : ResourcePath(com.google.firebase.firestore.model.ResourcePath) Query(com.google.firebase.firestore.core.Query) DocumentKey(com.google.firebase.firestore.model.DocumentKey) Document(com.google.firebase.firestore.model.Document) MutableDocument(com.google.firebase.firestore.model.MutableDocument) HashMap(java.util.HashMap) Map(java.util.Map) TreeMap(java.util.TreeMap) ImmutableSortedMap(com.google.firebase.database.collection.ImmutableSortedMap) DocumentCollections.emptyDocumentMap(com.google.firebase.firestore.model.DocumentCollections.emptyDocumentMap)

Example 4 with ImmutableSortedMap

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);
}
Also used : TargetChange(com.google.firebase.firestore.remote.TargetChange) DocumentKey(com.google.firebase.firestore.model.DocumentKey) Document(com.google.firebase.firestore.model.Document) MutableDocument(com.google.firebase.firestore.model.MutableDocument) HashMap(java.util.HashMap) Map(java.util.Map) ImmutableSortedMap(com.google.firebase.database.collection.ImmutableSortedMap)

Example 5 with ImmutableSortedMap

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);
}
Also used : LocalViewChanges(com.google.firebase.firestore.local.LocalViewChanges) ArrayList(java.util.ArrayList) QueryResult(com.google.firebase.firestore.local.QueryResult) TargetChange(com.google.firebase.firestore.remote.TargetChange) HashMap(java.util.HashMap) Map(java.util.Map) ImmutableSortedMap(com.google.firebase.database.collection.ImmutableSortedMap)

Aggregations

ImmutableSortedMap (com.google.firebase.database.collection.ImmutableSortedMap)10 Map (java.util.Map)10 HashMap (java.util.HashMap)9 DocumentKey (com.google.firebase.firestore.model.DocumentKey)7 Document (com.google.firebase.firestore.model.Document)6 MutableDocument (com.google.firebase.firestore.model.MutableDocument)5 DocumentCollections.emptyDocumentMap (com.google.firebase.firestore.model.DocumentCollections.emptyDocumentMap)3 TargetChange (com.google.firebase.firestore.remote.TargetChange)3 TreeMap (java.util.TreeMap)3 DatabaseException (com.google.firebase.database.DatabaseException)2 Overlay (com.google.firebase.firestore.model.mutation.Overlay)2 List (java.util.List)2 Query (com.google.firebase.firestore.core.Query)1 IndexEntry (com.google.firebase.firestore.index.IndexEntry)1 LocalViewChanges (com.google.firebase.firestore.local.LocalViewChanges)1 QueryResult (com.google.firebase.firestore.local.QueryResult)1 DocumentSet (com.google.firebase.firestore.model.DocumentSet)1 FieldIndex (com.google.firebase.firestore.model.FieldIndex)1 ResourcePath (com.google.firebase.firestore.model.ResourcePath)1 SnapshotVersion (com.google.firebase.firestore.model.SnapshotVersion)1