public MutationBatch write(final ApplicationScope collectionScope, UniqueValue value) {

    Preconditions.checkNotNull(value, "value is required");

    final Id entityId = value.getEntityId();
    final UUID entityVersion = value.getEntityVersion();
    final Field<?> field = value.getField();

    ValidationUtils.verifyIdentity(entityId);
    ValidationUtils.verifyVersion(entityVersion);

    final EntityVersion ev = new EntityVersion(entityId, entityVersion);
    final UniqueFieldEntry uniqueFieldEntry = new UniqueFieldEntry(entityVersion, field);

    return doWrite(
        collectionScope,
        value,
        new RowOp() {

          @Override
          public void doLookup(final ColumnListMutation<EntityVersion> colMutation) {
            colMutation.putColumn(ev, COL_VALUE);
          }

          @Override
          public void doLog(final ColumnListMutation<UniqueFieldEntry> colMutation) {
            colMutation.putColumn(uniqueFieldEntry, COL_VALUE);
          }
        });
  }
  @Override
  public MutationBatch write(
      final ApplicationScope collectionScope, final UniqueValue value, final int timeToLive) {

    Preconditions.checkNotNull(value, "value is required");
    Preconditions.checkArgument(timeToLive > 0, "timeToLive must be greater than 0 is required");

    final Id entityId = value.getEntityId();
    final UUID entityVersion = value.getEntityVersion();
    final Field<?> field = value.getField();

    ValidationUtils.verifyIdentity(entityId);
    ValidationUtils.verifyVersion(entityVersion);

    final EntityVersion ev = new EntityVersion(entityId, entityVersion);
    final UniqueFieldEntry uniqueFieldEntry = new UniqueFieldEntry(entityVersion, field);

    return doWrite(
        collectionScope,
        value,
        new RowOp() {

          @Override
          public void doLookup(final ColumnListMutation<EntityVersion> colMutation) {
            colMutation.putColumn(ev, COL_VALUE, timeToLive);
          }

          // we purposefully leave out TTL.  Worst case we issue deletes against tombstoned columns
          // best case, we clean up an invalid secondary index entry when the log is used
          @Override
          public void doLog(final ColumnListMutation<UniqueFieldEntry> colMutation) {
            colMutation.putColumn(uniqueFieldEntry, COL_VALUE);
          }
        });
  }
  @Override
  public Iterator<MarkedEdge> getEdgesToTargetBySourceType(
      final ApplicationScope scope, final SearchByIdType edgeType) {

    ValidationUtils.validateApplicationScope(scope);
    GraphValidation.validateSearchByIdType(edgeType);

    final Id targetId = edgeType.getNode();
    final String sourceType = edgeType.getIdType();
    final String type = edgeType.getType();
    final long maxTimestamp = edgeType.getMaxTimestamp();

    final DirectedEdgeMeta directedEdgeMeta =
        DirectedEdgeMeta.fromTargetNodeSourceType(targetId, type, sourceType);

    final Iterator<ShardEntryGroup> readShards =
        edgeShardStrategy.getReadShards(scope, maxTimestamp, directedEdgeMeta);

    return new ShardGroupColumnIterator(scope, directedEdgeMeta, shardGroupDeletion, readShards) {
      @Override
      protected Iterator<MarkedEdge> getIterator(final Collection<Shard> readShards) {
        return shardedEdgeSerialization.getEdgesToTargetBySourceType(
            edgeColumnFamilies, scope, edgeType, readShards);
      }

      @Override
      protected Iterator<MarkedEdge> getIteratorFullRange(final Collection<Shard> readShards) {

        final SearchByIdType edgeTypeFullRange =
            new SimpleSearchByIdType(
                edgeType.getNode(),
                edgeType.getType(),
                Long.MAX_VALUE,
                SearchByEdgeType.Order.DESCENDING,
                edgeType.getIdType(),
                Optional.absent(),
                false);

        return shardedEdgeSerialization.getEdgesToTargetBySourceType(
            edgeColumnFamilies, scope, edgeTypeFullRange, readShards);
      }
    };
  }
  @Override
  public Iterator<MarkedEdge> getEdgeVersions(
      final ApplicationScope scope, final SearchByEdge search) {
    ValidationUtils.validateApplicationScope(scope);
    GraphValidation.validateSearchByEdge(search);

    final Id targetId = search.targetNode();
    final Id sourceId = search.sourceNode();
    final String type = search.getType();
    final long maxTimestamp = search.getMaxTimestamp();

    final DirectedEdgeMeta versionMetaData = DirectedEdgeMeta.fromEdge(sourceId, targetId, type);

    final Iterator<ShardEntryGroup> readShards =
        edgeShardStrategy.getReadShards(scope, maxTimestamp, versionMetaData);

    // now create a result iterator with our iterator of read shards

    return new ShardGroupColumnIterator(scope, versionMetaData, shardGroupDeletion, readShards) {
      @Override
      protected Iterator<MarkedEdge> getIterator(final Collection<Shard> readShards) {
        return shardedEdgeSerialization.getEdgeVersions(
            edgeColumnFamilies, scope, search, readShards);
      }

      @Override
      protected Iterator<MarkedEdge> getIteratorFullRange(final Collection<Shard> readShards) {

        final SearchByEdge searchFullRange =
            new SimpleSearchByEdge(
                search.sourceNode(),
                search.getType(),
                search.targetNode(),
                Long.MAX_VALUE,
                SearchByEdgeType.Order.DESCENDING,
                Optional.absent());

        return shardedEdgeSerialization.getEdgeVersions(
            edgeColumnFamilies, scope, searchFullRange, readShards);
      }
    };
  }
  @Override
  public MutationBatch writeEdge(
      final ApplicationScope scope, final MarkedEdge markedEdge, final UUID timestamp) {

    ValidationUtils.validateApplicationScope(scope);
    GraphValidation.validateEdge(markedEdge);
    ValidationUtils.verifyTimeUuid(timestamp, "timestamp");

    final long now = timeService.getCurrentTime();
    final Id sourceNode = markedEdge.getSourceNode();
    final Id targetNode = markedEdge.getTargetNode();
    final String edgeType = markedEdge.getType();
    final long edgeTimestamp = markedEdge.getTimestamp();

    /** Source write */
    final DirectedEdgeMeta sourceEdgeMeta = DirectedEdgeMeta.fromSourceNode(sourceNode, edgeType);

    final Collection<Shard> sourceWriteShards =
        edgeShardStrategy.getWriteShards(scope, edgeTimestamp, sourceEdgeMeta).getWriteShards(now);

    final MutationBatch batch =
        shardedEdgeSerialization.writeEdgeFromSource(
            edgeColumnFamilies, scope, markedEdge, sourceWriteShards, sourceEdgeMeta, timestamp);

    /** Source with target type write */
    final DirectedEdgeMeta sourceTargetTypeEdgeMeta =
        DirectedEdgeMeta.fromSourceNodeTargetType(sourceNode, edgeType, targetNode.getType());

    final Collection<Shard> sourceTargetTypeWriteShards =
        edgeShardStrategy
            .getWriteShards(scope, edgeTimestamp, sourceTargetTypeEdgeMeta)
            .getWriteShards(now);

    batch.mergeShallow(
        shardedEdgeSerialization.writeEdgeFromSourceWithTargetType(
            edgeColumnFamilies,
            scope,
            markedEdge,
            sourceTargetTypeWriteShards,
            sourceTargetTypeEdgeMeta,
            timestamp));

    /** Target write */
    final DirectedEdgeMeta targetEdgeMeta = DirectedEdgeMeta.fromTargetNode(targetNode, edgeType);

    final Collection<Shard> targetWriteShards =
        edgeShardStrategy.getWriteShards(scope, edgeTimestamp, targetEdgeMeta).getWriteShards(now);

    batch.mergeShallow(
        shardedEdgeSerialization.writeEdgeToTarget(
            edgeColumnFamilies, scope, markedEdge, targetWriteShards, targetEdgeMeta, timestamp));

    /** Target with source type write */
    final DirectedEdgeMeta targetSourceTypeEdgeMeta =
        DirectedEdgeMeta.fromTargetNodeSourceType(targetNode, edgeType, sourceNode.getType());

    final Collection<Shard> targetSourceTypeWriteShards =
        edgeShardStrategy
            .getWriteShards(scope, edgeTimestamp, targetSourceTypeEdgeMeta)
            .getWriteShards(now);

    batch.mergeShallow(
        shardedEdgeSerialization.writeEdgeToTargetWithSourceType(
            edgeColumnFamilies,
            scope,
            markedEdge,
            targetSourceTypeWriteShards,
            targetSourceTypeEdgeMeta,
            timestamp));

    /** Version write */
    final DirectedEdgeMeta edgeVersionsMeta =
        DirectedEdgeMeta.fromEdge(sourceNode, targetNode, edgeType);

    final Collection<Shard> edgeVersionsShards =
        edgeShardStrategy
            .getWriteShards(scope, edgeTimestamp, edgeVersionsMeta)
            .getWriteShards(now);

    batch.mergeShallow(
        shardedEdgeSerialization.writeEdgeVersions(
            edgeColumnFamilies,
            scope,
            markedEdge,
            edgeVersionsShards,
            edgeVersionsMeta,
            timestamp));

    return batch;
  }