All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.firebase.database.core.view.filter.IndexedFilter Maven / Gradle / Ivy

/*
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.firebase.database.core.view.filter;

import com.google.firebase.database.core.Path;
import com.google.firebase.database.core.view.Change;
import com.google.firebase.database.snapshot.ChildKey;
import com.google.firebase.database.snapshot.Index;
import com.google.firebase.database.snapshot.IndexedNode;
import com.google.firebase.database.snapshot.NamedNode;
import com.google.firebase.database.snapshot.Node;

/** Doesn't really filter nodes but applies an index to the node and keeps track of any changes */
public class IndexedFilter implements NodeFilter {

  private final Index index;

  public IndexedFilter(Index index) {
    this.index = index;
  }

  @Override
  public IndexedNode updateChild(
      IndexedNode indexedNode,
      ChildKey key,
      Node newChild,
      Path affectedPath,
      CompleteChildSource source,
      ChildChangeAccumulator optChangeAccumulator) {
    assert indexedNode.hasIndex(this.index) : "The index must match the filter";
    Node snap = indexedNode.getNode();
    Node oldChild = snap.getImmediateChild(key);
    // Check if anything actually changed.
    if (oldChild.getChild(affectedPath).equals(newChild.getChild(affectedPath))) {
      // There's an edge case where a child can enter or leave the view because
      // affectedPath was
      // set to null. In this case, affectedPath will appear null in both the old and new
      // snapshots.
      // So we need to avoid treating these cases as "nothing changed."
      if (oldChild.isEmpty() == newChild.isEmpty()) {
        // Nothing changed.

        // This assert should be valid, but it's expensive (can dominate perf testing) so
        // don't
        // actually do it.
        //assert oldChild.equals(newChild): "Old and new snapshots should be equal.";
        return indexedNode;
      }
    }
    if (optChangeAccumulator != null) {
      if (newChild.isEmpty()) {
        if (snap.hasChild(key)) {
          optChangeAccumulator.trackChildChange(Change.childRemovedChange(key, oldChild));
        } else {
          assert snap.isLeafNode()
              : "A child remove without an old child only makes sense on a leaf node";
        }
      } else if (oldChild.isEmpty()) {
        optChangeAccumulator.trackChildChange(Change.childAddedChange(key, newChild));
      } else {
        optChangeAccumulator.trackChildChange(Change.childChangedChange(key, newChild, oldChild));
      }
    }
    if (snap.isLeafNode() && newChild.isEmpty()) {
      return indexedNode;
    } else {
      // Make sure the node is indexed
      return indexedNode.updateChild(key, newChild);
    }
  }

  @Override
  public IndexedNode updateFullNode(
      IndexedNode oldSnap, IndexedNode newSnap, ChildChangeAccumulator optChangeAccumulator) {
    assert newSnap.hasIndex(this.index)
        : "Can't use IndexedNode that doesn't have filter's " + "index";
    if (optChangeAccumulator != null) {
      for (NamedNode child : oldSnap.getNode()) {
        if (!newSnap.getNode().hasChild(child.getName())) {
          optChangeAccumulator.trackChildChange(
              Change.childRemovedChange(child.getName(), child.getNode()));
        }
      }
      if (!newSnap.getNode().isLeafNode()) {
        for (NamedNode child : newSnap.getNode()) {
          if (oldSnap.getNode().hasChild(child.getName())) {
            Node oldChild = oldSnap.getNode().getImmediateChild(child.getName());
            if (!oldChild.equals(child.getNode())) {
              optChangeAccumulator.trackChildChange(
                  Change.childChangedChange(child.getName(), child.getNode(), oldChild));
            }
          } else {
            optChangeAccumulator.trackChildChange(
                Change.childAddedChange(child.getName(), child.getNode()));
          }
        }
      }
    }
    return newSnap;
  }

  @Override
  public IndexedNode updatePriority(IndexedNode oldSnap, Node newPriority) {
    if (oldSnap.getNode().isEmpty()) {
      return oldSnap;
    } else {
      return oldSnap.updatePriority(newPriority);
    }
  }

  @Override
  public NodeFilter getIndexedFilter() {
    return this;
  }

  @Override
  public Index getIndex() {
    return this.index;
  }

  @Override
  public boolean filtersNodes() {
    return false;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy