private Iterator<UniquenessConstraint> applyConstraintsDiff(
     KernelStatement state, Iterator<UniquenessConstraint> constraints) {
   if (state.hasTxStateWithChanges()) {
     return state.txState().constraintsChanges().apply(constraints);
   }
   return constraints;
 }
  @Override
  public PrimitiveLongIterator graphGetPropertyKeys(KernelStatement state) {
    if (state.hasTxStateWithChanges()) {
      return new PropertyKeyIdIterator(graphGetAllProperties(state));
    }

    return storeLayer.graphGetPropertyKeys(state);
  }
  @Override
  public Iterator<DefinedProperty> graphGetAllProperties(KernelStatement state) {
    if (state.hasTxStateWithChanges()) {
      return state.txState().augmentGraphProperties(storeLayer.graphGetAllProperties());
    }

    return storeLayer.graphGetAllProperties();
  }
  @Override
  public Iterator<IndexDescriptor> uniqueIndexesGetAll(KernelStatement state) {
    if (state.hasTxStateWithChanges()) {
      return state.txState().constraintIndexChanges().apply(storeLayer.uniqueIndexesGetAll());
    }

    return storeLayer.uniqueIndexesGetAll();
  }
 @Override
 public PrimitiveIntIterator nodeGetLabels(KernelStatement state, long nodeId)
     throws EntityNotFoundException {
   if (state.hasTxStateWithChanges()) {
     return nodeGetLabels(storeLayer, state.txState(), nodeId);
   }
   return storeLayer.nodeGetLabels(nodeId);
 }
  @Override
  public PrimitiveLongIterator relationshipGetPropertyKeys(
      KernelStatement state, long relationshipId) throws EntityNotFoundException {
    if (state.hasTxStateWithChanges()) {
      return new PropertyKeyIdIterator(relationshipGetAllProperties(state, relationshipId));
    }

    return storeLayer.relationshipGetPropertyKeys(relationshipId);
  }
  @Override
  public Iterator<IndexDescriptor> uniqueIndexesGetForLabel(KernelStatement state, int labelId) {
    if (state.hasTxStateWithChanges()) {
      return state
          .txState()
          .constraintIndexDiffSetsByLabel(labelId)
          .apply(storeLayer.uniqueIndexesGetForLabel(labelId));
    }

    return storeLayer.uniqueIndexesGetForLabel(labelId);
  }
  private PrimitiveLongIterator filterIndexStateChanges(
      KernelStatement state, IndexDescriptor index, Object value, PrimitiveLongIterator nodeIds) {
    if (state.hasTxStateWithChanges()) {
      ReadableDiffSets<Long> labelPropertyChanges = state.txState().indexUpdates(index, value);
      ReadableDiffSets<Long> nodes = state.txState().addedAndRemovedNodes();

      // Apply to actual index lookup
      return nodes.augmentWithRemovals(labelPropertyChanges.augment(nodeIds));
    }
    return nodeIds;
  }
 // <Legacy index>
 @Override
 public <EXCEPTION extends Exception> void relationshipVisit(
     KernelStatement statement, long relId, RelationshipVisitor<EXCEPTION> visitor)
     throws EntityNotFoundException, EXCEPTION {
   if (statement.hasTxStateWithChanges()) {
     if (statement.txState().relationshipVisit(relId, visitor)) {
       return;
     }
   }
   storeLayer.relationshipVisit(relId, visitor);
 }
  private Iterator<UniquenessConstraint> applyConstraintsDiff(
      KernelStatement state, Iterator<UniquenessConstraint> constraints) {
    if (state.hasTxStateWithChanges()) {
      DiffSets<UniquenessConstraint> diff = state.txState().constraintsChanges();
      if (diff != null) {
        return diff.apply(constraints);
      }
    }

    return constraints;
  }
  @Override
  public PrimitiveLongIterator nodesGetForLabel(KernelStatement state, int labelId) {
    if (state.hasTxStateWithChanges()) {
      PrimitiveLongIterator wLabelChanges =
          state
              .txState()
              .nodesWithLabelChanged(labelId)
              .augment(storeLayer.nodesGetForLabel(state, labelId));
      return state.txState().addedAndRemovedNodes().augmentWithRemovals(wLabelChanges);
    }

    return storeLayer.nodesGetForLabel(state, labelId);
  }
 private Iterator<UniquenessConstraint> applyConstraintsDiff(
     KernelStatement state,
     Iterator<UniquenessConstraint> constraints,
     int labelId,
     int propertyKeyId) {
   if (state.hasTxStateWithChanges()) {
     return state
         .txState()
         .constraintsChangesForLabelAndProperty(labelId, propertyKeyId)
         .apply(constraints);
   }
   return constraints;
 }
  @Override
  public boolean nodeExists(KernelStatement state, long nodeId) {
    if (state.hasTxStateWithChanges()) {
      if (state.txState().nodeIsDeletedInThisTx(nodeId)) {
        return false;
      }

      if (state.txState().nodeIsAddedInThisTx(nodeId)) {
        return true;
      }
    }

    return storeLayer.nodeExists(nodeId);
  }
  @Override
  public boolean relationshipExists(KernelStatement state, long relId) {
    if (state.hasTxStateWithChanges()) {
      if (state.txState().relationshipIsDeletedInThisTx(relId)) {
        return false;
      }

      if (state.txState().relationshipIsAddedInThisTx(relId)) {
        return true;
      }
    }

    return storeLayer.relationshipExists(relId);
  }
  @Override
  public IndexDescriptor indexesGetForLabelAndPropertyKey(
      KernelStatement state, int labelId, int propertyKey) {
    IndexDescriptor indexDescriptor =
        storeLayer.indexesGetForLabelAndPropertyKey(labelId, propertyKey);

    Iterator<IndexDescriptor> rules = iterator(indexDescriptor);
    if (state.hasTxStateWithChanges()) {
      rules =
          filterByPropertyKeyId(
              state.txState().indexDiffSetsByLabel(labelId).apply(rules), propertyKey);
    }
    return singleOrNull(rules);
  }
 @Override
 public PrimitiveLongIterator nodeGetRelationships(
     KernelStatement state, long nodeId, Direction direction) throws EntityNotFoundException {
   if (state.hasTxStateWithChanges()) {
     ReadableTxState txState = state.txState();
     PrimitiveLongIterator stored;
     if (txState.nodeIsAddedInThisTx(nodeId)) {
       stored = PrimitiveLongCollections.emptyIterator();
     } else {
       stored = storeLayer.nodeListRelationships(nodeId, direction);
     }
     return txState.augmentRelationships(nodeId, direction, stored);
   }
   return storeLayer.nodeListRelationships(nodeId, direction);
 }
 @Override
 public Property relationshipGetProperty(
     KernelStatement state, long relationshipId, int propertyKeyId)
     throws EntityNotFoundException {
   if (state.hasTxStateWithChanges()) {
     Iterator<DefinedProperty> properties = relationshipGetAllProperties(state, relationshipId);
     while (properties.hasNext()) {
       Property property = properties.next();
       if (property.propertyKeyId() == propertyKeyId) {
         return property;
       }
     }
     return Property.noRelationshipProperty(relationshipId, propertyKeyId);
   }
   return storeLayer.relationshipGetProperty(relationshipId, propertyKeyId);
 }
  @Override
  public InternalIndexState indexGetState(KernelStatement state, IndexDescriptor descriptor)
      throws IndexNotFoundKernelException {
    // If index is in our state, then return populating
    if (state.hasTxStateWithChanges()) {
      if (checkIndexState(
          descriptor, state.txState().indexDiffSetsByLabel(descriptor.getLabelId()))) {
        return InternalIndexState.POPULATING;
      }
      if (checkIndexState(
          descriptor, state.txState().constraintIndexDiffSetsByLabel(descriptor.getLabelId()))) {
        return InternalIndexState.POPULATING;
      }
    }

    return storeLayer.indexGetState(descriptor);
  }
  @Override
  public int nodeGetDegree(KernelStatement state, long nodeId, Direction direction)
      throws EntityNotFoundException {
    if (state.hasTxStateWithChanges()) {
      int degree = 0;
      if (state.txState().nodeIsDeletedInThisTx(nodeId)) {
        return 0;
      }

      if (!state.txState().nodeIsAddedInThisTx(nodeId)) {
        degree = storeLayer.nodeGetDegree(nodeId, direction);
      }
      return state.txState().augmentNodeDegree(nodeId, degree, direction);
    } else {
      return storeLayer.nodeGetDegree(nodeId, direction);
    }
  }
  @Override
  public Iterator<DefinedProperty> nodeGetAllProperties(KernelStatement state, long nodeId)
      throws EntityNotFoundException {
    if (state.hasTxStateWithChanges()) {
      if (state.txState().nodeIsAddedInThisTx(nodeId)) {
        return state.txState().addedAndChangedNodeProperties(nodeId);
      }
      if (state.txState().nodeIsDeletedInThisTx(nodeId)) {
        // TODO Throw IllegalStateException to conform with beans API. We may want to introduce
        // EntityDeletedException instead and use it instead of returning empty values in similar
        // places
        throw new IllegalStateException("Node " + nodeId + " has been deleted");
      }
      return state.txState().augmentNodeProperties(nodeId, storeLayer.nodeGetAllProperties(nodeId));
    }

    return storeLayer.nodeGetAllProperties(nodeId);
  }
  @Override
  public IndexDescriptor indexesGetForLabelAndPropertyKey(
      KernelStatement state, int labelId, int propertyKey) {
    Iterable<IndexDescriptor> committedRules;
    try {
      committedRules = option(storeLayer.indexesGetForLabelAndPropertyKey(labelId, propertyKey));
    } catch (SchemaRuleNotFoundException e) {
      committedRules = emptyList();
    }
    DiffSets<IndexDescriptor> ruleDiffSet = state.txState().indexDiffSetsByLabel(labelId);

    boolean hasTxStateWithChanges = state.hasTxStateWithChanges();
    Iterator<IndexDescriptor> rules =
        hasTxStateWithChanges
            ? filterByPropertyKeyId(ruleDiffSet.apply(committedRules.iterator()), propertyKey)
            : committedRules.iterator();
    return singleOrNull(rules);
  }
  @Override
  public PrimitiveIntIterator nodeGetLabels(KernelStatement state, long nodeId)
      throws EntityNotFoundException {
    if (state.hasTxStateWithChanges()) {
      if (state.txState().nodeIsDeletedInThisTx(nodeId)) {
        return PrimitiveIntCollections.emptyIterator();
      }

      if (state.txState().nodeIsAddedInThisTx(nodeId)) {
        return PrimitiveIntCollections.toPrimitiveIterator(
            state.txState().nodeStateLabelDiffSets(nodeId).getAdded().iterator());
      }

      return state
          .txState()
          .nodeStateLabelDiffSets(nodeId)
          .augment(storeLayer.nodeGetLabels(nodeId));
    }

    return storeLayer.nodeGetLabels(nodeId);
  }
  @Override
  public boolean nodeHasLabel(KernelStatement state, long nodeId, int labelId)
      throws EntityNotFoundException {
    if (state.hasTxStateWithChanges()) {
      if (state.txState().nodeIsDeletedInThisTx(nodeId)) {
        return false;
      }

      if (state.txState().nodeIsAddedInThisTx(nodeId)) {
        TxState.UpdateTriState labelState = state.txState().labelState(nodeId, labelId);
        return labelState.isTouched() && labelState.isAdded();
      }

      TxState.UpdateTriState labelState = state.txState().labelState(nodeId, labelId);
      if (labelState.isTouched()) {
        return labelState.isAdded();
      }
    }

    return storeLayer.nodeHasLabel(nodeId, labelId);
  }
 public static KernelStatement mockedState(final TransactionState txState) {
   KernelStatement state = mock(KernelStatement.class);
   Locks.Client lockHolder = mock(Locks.Client.class);
   try {
     IndexReader indexReader = mock(IndexReader.class);
     when(indexReader.lookup(Matchers.any())).thenReturn(PrimitiveLongCollections.emptyIterator());
     when(state.getIndexReader(anyLong())).thenReturn(indexReader);
   } catch (IndexNotFoundKernelException e) {
     throw new Error(e);
   }
   when(state.txState()).thenReturn(txState);
   when(state.hasTxStateWithChanges())
       .thenAnswer(
           new Answer<Boolean>() {
             @Override
             public Boolean answer(InvocationOnMock invocation) throws Throwable {
               return txState.hasChanges();
             }
           });
   when(state.locks()).thenReturn(lockHolder);
   return state;
 }
  @Override
  public boolean nodeHasLabel(KernelStatement state, long nodeId, int labelId)
      throws EntityNotFoundException {
    if (state.hasTxStateWithChanges()) {
      if (state.txState().nodeIsDeletedInThisTx(nodeId)) {
        return false;
      }

      switch (state.txState().labelState(nodeId, labelId)) {
        case ADDED:
          return true;
        case REMOVED:
          return false;
        default: // i.e. UNTOUCHED
          if (state.txState().nodeIsAddedInThisTx(nodeId)) {
            return false;
          }
          // else fall through and return from the store layer
      }
    }

    return storeLayer.nodeHasLabel(nodeId, labelId);
  }
 @Override
 public Cursor expand(
     KernelStatement statement,
     Cursor inputCursor,
     NeoRegister.Node.In nodeId,
     Register.Object.In<int[]> types,
     Register.Object.In<Direction> expandDirection,
     NeoRegister.Relationship.Out relId,
     NeoRegister.RelType.Out relType,
     Register.Object.Out<Direction> direction,
     NeoRegister.Node.Out startNodeId,
     NeoRegister.Node.Out neighborNodeId) {
   if (statement.hasTxStateWithChanges()) {
     return new AugmentWithLocalStateExpandCursor(
         storeLayer,
         statement.txState(),
         inputCursor,
         nodeId,
         types,
         expandDirection,
         relId,
         relType,
         direction,
         startNodeId,
         neighborNodeId);
   }
   return storeLayer.expand(
       inputCursor,
       nodeId,
       types,
       expandDirection,
       relId,
       relType,
       direction,
       startNodeId,
       neighborNodeId);
 }
  @Override
  public PrimitiveIntIterator nodeGetRelationshipTypes(KernelStatement state, long nodeId)
      throws EntityNotFoundException {
    if (state.hasTxStateWithChanges() && state.txState().nodeModifiedInThisTx(nodeId)) {
      ReadableTxState tx = state.txState();
      if (tx.nodeIsDeletedInThisTx(nodeId)) {
        return PrimitiveIntCollections.emptyIterator();
      }

      if (tx.nodeIsAddedInThisTx(nodeId)) {
        return tx.nodeRelationshipTypes(nodeId);
      }

      Set<Integer> types = new HashSet<>();

      // Add types in the current transaction
      PrimitiveIntIterator typesInTx = tx.nodeRelationshipTypes(nodeId);
      while (typesInTx.hasNext()) {
        types.add(typesInTx.next());
      }

      // Augment with types stored on disk, minus any types where all rels of that type are deleted
      // in current tx.
      PrimitiveIntIterator committedTypes = storeLayer.nodeGetRelationshipTypes(nodeId);
      while (committedTypes.hasNext()) {
        int current = committedTypes.next();
        if (!types.contains(current) && nodeGetDegree(state, nodeId, Direction.BOTH, current) > 0) {
          types.add(current);
        }
      }

      return PrimitiveIntCollections.toPrimitiveIterator(types.iterator());
    } else {
      return storeLayer.nodeGetRelationshipTypes(nodeId);
    }
  }