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);
          }
        });
  }
  @Test
  public void testBasicOperation() throws ConnectionException, InterruptedException {

    ApplicationScope scope = new ApplicationScopeImpl(new SimpleId("organization"));

    IntegerField field = new IntegerField("count", 5);
    Id entityId = new SimpleId(UUIDGenerator.newTimeUUID(), "entity");
    UUID version = UUIDGenerator.newTimeUUID();
    UniqueValue stored = new UniqueValueImpl(field, entityId, version);
    strategy.write(scope, stored).execute();

    UniqueValueSet fields =
        strategy.load(scope, entityId.getType(), Collections.<Field>singleton(field));

    UniqueValue retrieved = fields.getValue(field.getName());
    Assert.assertNotNull(retrieved);
    assertEquals(stored, retrieved);

    Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields(scope, entityId);

    assertTrue(allFieldsWritten.hasNext());

    // test this interface. In most cases, we won't know the field name, so we want them all
    UniqueValue allFieldsValue = allFieldsWritten.next();
    Assert.assertNotNull(allFieldsValue);

    assertEquals(field, allFieldsValue.getField());
    assertEquals(version, allFieldsValue.getEntityVersion());

    assertFalse(allFieldsWritten.hasNext());
  }
  /**
   * Do the column update or delete for the given column and row key
   *
   * @param applicationScope We need to use this when getting the keyspace
   * @param uniqueValue The unique value to write
   * @param op The operation to write
   */
  private MutationBatch doWrite(
      ApplicationScope applicationScope, UniqueValue uniqueValue, RowOp op) {
    final MutationBatch batch = keyspace.prepareMutationBatch();

    final Id applicationId = applicationScope.getApplication();

    final FieldKey fieldKey =
        createUniqueValueKey(
            applicationId, uniqueValue.getEntityId().getType(), uniqueValue.getField());

    op.doLookup(batch.withRow(CF_UNIQUE_VALUES, ScopedRowKey.fromKey(applicationId, fieldKey)));

    final EntityKey entityKey = createEntityUniqueLogKey(applicationId, uniqueValue.getEntityId());

    op.doLog(
        batch.withRow(CF_ENTITY_UNIQUE_VALUE_LOG, ScopedRowKey.fromKey(applicationId, entityKey)));

    if (log.isDebugEnabled()) {
      log.debug(
          "Writing unique value version={} name={} value={} ",
          new Object[] {
            uniqueValue.getEntityVersion(),
            uniqueValue.getField().getName(),
            uniqueValue.getField().getValue()
          });
    }

    return batch;
  }
  @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);
          }
        });
  }
  @Test
  public void testWriteWithTTL() throws InterruptedException, ConnectionException {

    ApplicationScope scope = new ApplicationScopeImpl(new SimpleId("organization"));

    // write object that lives 2 seconds
    IntegerField field = new IntegerField("count", 5);
    Id entityId = new SimpleId(UUIDGenerator.newTimeUUID(), "entity");
    UUID version = UUIDGenerator.newTimeUUID();
    UniqueValue stored = new UniqueValueImpl(field, entityId, version);
    strategy.write(scope, stored, 5).execute();

    Thread.sleep(1000);

    // waited one sec, should be still here
    UniqueValueSet fields =
        strategy.load(scope, entityId.getType(), Collections.<Field>singleton(field));

    UniqueValue retrieved = fields.getValue(field.getName());

    Assert.assertNotNull(retrieved);
    assertEquals(stored, retrieved);

    Thread.sleep(5000);

    // wait another second, should be gone now
    fields = strategy.load(scope, entityId.getType(), Collections.<Field>singleton(field));

    UniqueValue nullExpected = fields.getValue(field.getName());
    Assert.assertNull(nullExpected);

    // we still want to retain the log entry, even if we don't retain the unique value.  Deleting
    // something
    // that doesn't exist is a tombstone, but so is the timeout.
    Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields(scope, entityId);

    assertTrue(allFieldsWritten.hasNext());

    // test this interface. In most cases, we won't know the field name, so we want them all
    UniqueValue writtenFieldEntry = allFieldsWritten.next();
    Assert.assertNotNull(writtenFieldEntry);

    assertEquals(field, writtenFieldEntry.getField());
    assertEquals(version, writtenFieldEntry.getEntityVersion());

    assertFalse(allFieldsWritten.hasNext());
  }
  @Test
  public void twoFieldsPerVersion() throws ConnectionException, InterruptedException {

    ApplicationScope scope = new ApplicationScopeImpl(new SimpleId("organization"));

    Id entityId = new SimpleId(UUIDGenerator.newTimeUUID(), "entity");
    final UUID version1 = UUIDGenerator.newTimeUUID();

    // write V1 of everything
    IntegerField version1Field1 = new IntegerField("count", 1);
    StringField version1Field2 = new StringField("field", "v1value");

    UniqueValue version1Field1Value = new UniqueValueImpl(version1Field1, entityId, version1);
    UniqueValue version1Field2Value = new UniqueValueImpl(version1Field2, entityId, version1);

    final MutationBatch batch = strategy.write(scope, version1Field1Value);
    batch.mergeShallow(strategy.write(scope, version1Field2Value));

    // write V2 of everything
    final UUID version2 = UUIDGenerator.newTimeUUID();

    IntegerField version2Field1 = new IntegerField("count", 2);
    StringField version2Field2 = new StringField("field", "v2value");

    UniqueValue version2Field1Value = new UniqueValueImpl(version2Field1, entityId, version2);
    UniqueValue version2Field2Value = new UniqueValueImpl(version2Field2, entityId, version2);

    batch.mergeShallow(strategy.write(scope, version2Field1Value));
    batch.mergeShallow(strategy.write(scope, version2Field2Value));

    batch.execute();

    UniqueValueSet fields =
        strategy.load(
            scope, entityId.getType(), Arrays.<Field>asList(version1Field1, version1Field2));

    UniqueValue retrieved = fields.getValue(version1Field1.getName());

    assertEquals(version1Field1Value, retrieved);

    retrieved = fields.getValue(version1Field2.getName());
    assertEquals(version1Field2Value, retrieved);

    Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields(scope, entityId);

    assertTrue(allFieldsWritten.hasNext());

    // test this interface. In most cases, we won't know the field name, so we want them all
    UniqueValue allFieldsValue = allFieldsWritten.next();

    // version 2 fields should come first, ordered by field name
    assertEquals(version2Field1, allFieldsValue.getField());
    assertEquals(version2, allFieldsValue.getEntityVersion());

    allFieldsValue = allFieldsWritten.next();

    assertEquals(version2Field2, allFieldsValue.getField());
    assertEquals(version2, allFieldsValue.getEntityVersion());

    // version 1 should come next ordered by field name
    allFieldsValue = allFieldsWritten.next();

    assertEquals(version1Field1, allFieldsValue.getField());
    assertEquals(version1, allFieldsValue.getEntityVersion());

    allFieldsValue = allFieldsWritten.next();

    assertEquals(version1Field2, allFieldsValue.getField());
    assertEquals(version1, allFieldsValue.getEntityVersion());

    assertFalse(allFieldsWritten.hasNext());
  }
  @Test
  public void testCapitalizationFixes() throws ConnectionException {

    ApplicationScope scope = new ApplicationScopeImpl(new SimpleId("organization"));

    StringField field = new StringField("count", "MiXeD CaSe");
    Id entityId = new SimpleId(UUIDGenerator.newTimeUUID(), "entity");
    UUID version = UUIDGenerator.newTimeUUID();
    UniqueValue stored = new UniqueValueImpl(field, entityId, version);
    strategy.write(scope, stored).execute();

    UniqueValueSet fields =
        strategy.load(scope, entityId.getType(), Collections.<Field>singleton(field));

    UniqueValue value = fields.getValue(field.getName());

    assertEquals(field.getName(), value.getField().getName());

    assertEquals(entityId, value.getEntityId());

    // now test will all upper and all lower, we should get it all the same
    fields =
        strategy.load(
            scope,
            entityId.getType(),
            Collections.<Field>singleton(new StringField(field.getName(), "MIXED CASE")));

    value = fields.getValue(field.getName());

    assertEquals(field.getName(), value.getField().getName());

    assertEquals(entityId, value.getEntityId());

    fields =
        strategy.load(
            scope,
            entityId.getType(),
            Collections.<Field>singleton(new StringField(field.getName(), "mixed case")));

    value = fields.getValue(field.getName());

    assertEquals(field.getName(), value.getField().getName());

    assertEquals(entityId, value.getEntityId());

    Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields(scope, entityId);

    assertTrue(allFieldsWritten.hasNext());

    // test this interface. In most cases, we won't know the field name, so we want them all
    UniqueValue writtenFieldEntry = allFieldsWritten.next();
    Assert.assertNotNull(writtenFieldEntry);

    assertEquals(field.getName(), writtenFieldEntry.getField().getName());
    assertEquals(field.getValue().toLowerCase(), writtenFieldEntry.getField().getValue());
    assertEquals(version, writtenFieldEntry.getEntityVersion());

    assertFalse(allFieldsWritten.hasNext());
  }