@Override
  public void insertOrUpdateTuple(
      EntityKey key, TuplePointer tuplePointer, TupleContext tupleContext) {
    Tuple tuple = tuplePointer.getTuple();
    EmbeddedNeo4jTupleSnapshot snapshot = (EmbeddedNeo4jTupleSnapshot) tuple.getSnapshot();

    // insert
    if (snapshot.isNew()) {
      Node node = insertTuple(key, tuple);
      snapshot.setNode(node);
      applyTupleOperations(key, tuple, node, tuple.getOperations(), tupleContext);
      GraphLogger.log("Inserted node: %1$s", node);
    }
    // update
    else {
      Node node = snapshot.getNode();
      applyTupleOperations(key, tuple, node, tuple.getOperations(), tupleContext);
      GraphLogger.log("Updated node: %1$s", node);
    }
  }
  @Override
  public Tuple getTuple(EntityKey key, OperationContext context) {
    Node entityNode =
        entityQueries.get(key.getMetadata()).findEntity(dataBase, key.getColumnValues());
    if (entityNode == null) {
      return null;
    }

    return new Tuple(
        EmbeddedNeo4jTupleSnapshot.fromNode(
            entityNode,
            context.getTupleTypeContext().getAllAssociatedEntityKeyMetadata(),
            context.getTupleTypeContext().getAllRoles(),
            key.getMetadata()),
        SnapshotType.UPDATE);
  }
 @Override
 public void forEachTuple(
     ModelConsumer consumer,
     TupleTypeContext tupleTypeContext,
     EntityKeyMetadata entityKeyMetadata) {
   ResourceIterator<Node> queryNodes = entityQueries.get(entityKeyMetadata).findEntities(dataBase);
   try {
     while (queryNodes.hasNext()) {
       Node next = queryNodes.next();
       Tuple tuple =
           new Tuple(
               EmbeddedNeo4jTupleSnapshot.fromNode(
                   next,
                   tupleTypeContext.getAllAssociatedEntityKeyMetadata(),
                   tupleTypeContext.getAllRoles(),
                   entityKeyMetadata),
               SnapshotType.UPDATE);
       consumer.consume(tuple);
     }
   } finally {
     queryNodes.close();
   }
 }
 /*
  * This method assumes that the nodes might not be in the same order as the keys and some keys might not have a
  * matching result in the db.
  */
 private List<Tuple> tuplesResult(
     EntityKey[] keys, TupleContext tupleContext, ResourceIterator<Node> nodes) {
   // The list is initialized with null because some keys might not have a corresponding node
   Tuple[] tuples = new Tuple[keys.length];
   while (nodes.hasNext()) {
     Node node = nodes.next();
     for (int i = 0; i < keys.length; i++) {
       if (matches(node, keys[i].getColumnNames(), keys[i].getColumnValues())) {
         tuples[i] =
             new Tuple(
                 EmbeddedNeo4jTupleSnapshot.fromNode(
                     node,
                     tupleContext.getTupleTypeContext().getAllAssociatedEntityKeyMetadata(),
                     tupleContext.getTupleTypeContext().getAllRoles(),
                     keys[i].getMetadata()),
                 SnapshotType.UPDATE);
         // We assume there are no duplicated keys
         break;
       }
     }
   }
   return Arrays.asList(tuples);
 }
 @Override
 public Tuple createTuple(EntityKey key, OperationContext tupleContext) {
   return new Tuple(
       EmbeddedNeo4jTupleSnapshot.emptySnapshot(key.getMetadata()), SnapshotType.INSERT);
 }