From 51cd3d22fa9368fe3630b1011fdb2ea751c284c0 Mon Sep 17 00:00:00 2001
From: Jeff Nelson
Date: Sat, 14 Mar 2026 15:34:41 -0400
Subject: [PATCH 01/13] Initial implementation of Command builder to support
new CCL syntax
---
concourse-driver-java/build.gradle | 3 +-
.../concourse/lang/ConcourseCompiler.java | 10 +-
.../concourse/lang/command/AddCommand.java | 279 ++++++++
.../concourse/lang/command/AuditCommand.java | 541 ++++++++++++++
.../concourse/lang/command/BrowseCommand.java | 115 +++
.../concourse/lang/command/BuiltCommand.java | 51 ++
.../lang/command/CalculateCommand.java | 271 +++++++
.../concourse/lang/command/CclRenderer.java | 254 +++++++
.../lang/command/ChronicleCommand.java | 336 +++++++++
.../concourse/lang/command/ClearCommand.java | 200 ++++++
.../concourse/lang/command/Command.java | 668 ++++++++++++++++++
.../lang/command/ConsolidateCommand.java | 92 +++
.../lang/command/DescribeCommand.java | 115 +++
.../concourse/lang/command/DiffCommand.java | 484 +++++++++++++
.../concourse/lang/command/FindCommand.java | 192 +++++
.../lang/command/FindOrAddCommand.java | 128 ++++
.../lang/command/FindOrInsertCommand.java | 168 +++++
.../concourse/lang/command/GetCommand.java | 444 ++++++++++++
.../concourse/lang/command/HoldsCommand.java | 81 +++
.../concourse/lang/command/InsertCommand.java | 238 +++++++
.../lang/command/JsonifyCommand.java | 146 ++++
.../concourse/lang/command/LinkCommand.java | 201 ++++++
.../lang/command/NavigateCommand.java | 277 ++++++++
.../lang/command/ReconcileCommand.java | 204 ++++++
.../concourse/lang/command/RemoveCommand.java | 324 +++++++++
.../concourse/lang/command/RevertCommand.java | 247 +++++++
.../concourse/lang/command/SearchCommand.java | 127 ++++
.../concourse/lang/command/SelectCommand.java | 444 ++++++++++++
.../concourse/lang/command/SetCommand.java | 225 ++++++
.../concourse/lang/command/TraceCommand.java | 115 +++
.../concourse/lang/command/UnlinkCommand.java | 184 +++++
.../lang/command/VerifyAndSwapCommand.java | 259 +++++++
.../concourse/lang/command/VerifyCommand.java | 305 ++++++++
.../lang/command/VerifyOrSetCommand.java | 194 +++++
.../lang/command/CclRendererTest.java | 254 +++++++
.../lang/command/InspectionCommandTest.java | 409 +++++++++++
.../lang/command/LinkCommandTest.java | 308 ++++++++
.../lang/command/QueryCommandTest.java | 553 +++++++++++++++
.../lang/command/TemporalCommandTest.java | 637 +++++++++++++++++
.../lang/command/WriteCommandTest.java | 536 ++++++++++++++
40 files changed, 10617 insertions(+), 2 deletions(-)
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/AddCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/AuditCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/BrowseCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/BuiltCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CalculateCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CclRenderer.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/ChronicleCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/ClearCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/Command.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/ConsolidateCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/DescribeCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/DiffCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/FindCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/FindOrAddCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/FindOrInsertCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/GetCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/HoldsCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/InsertCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/JsonifyCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/LinkCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/NavigateCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/ReconcileCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/RemoveCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/RevertCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/SearchCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/SelectCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/SetCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/TraceCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/UnlinkCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/VerifyAndSwapCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/VerifyCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/VerifyOrSetCommand.java
create mode 100644 concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CclRendererTest.java
create mode 100644 concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/InspectionCommandTest.java
create mode 100644 concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/LinkCommandTest.java
create mode 100644 concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/QueryCommandTest.java
create mode 100644 concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/TemporalCommandTest.java
create mode 100644 concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/WriteCommandTest.java
diff --git a/concourse-driver-java/build.gradle b/concourse-driver-java/build.gradle
index ce4368380..6b5f43ffa 100644
--- a/concourse-driver-java/build.gradle
+++ b/concourse-driver-java/build.gradle
@@ -18,7 +18,8 @@ dependencies {
api "org.slf4j:log4j-over-slf4j:${slf4jVersion}"
api "org.slf4j:jcl-over-slf4j:${slf4jVersion}"
api 'com.google.code.gson:gson:2.5'
- api 'com.cinchapi:ccl:3.2.1'
+ // api 'com.cinchapi:ccl:4.0.0-SNAPSHOT'
+ api group: 'com.cinchapi', name: 'ccl', version: '4.0.0-SNAPSHOT', changing:true
testImplementation project(':concourse-unit-test-core')
testImplementation 'com.github.marschall:memoryfilesystem:0.9.0'
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/ConcourseCompiler.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/ConcourseCompiler.java
index 97c08d81a..6698ab76f 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/ConcourseCompiler.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/ConcourseCompiler.java
@@ -15,6 +15,8 @@
*/
package com.cinchapi.concourse.lang;
+import java.util.List;
+
import com.cinchapi.ccl.Compiler;
import com.cinchapi.ccl.syntax.AbstractSyntaxTree;
import com.cinchapi.ccl.syntax.ConditionTree;
@@ -99,9 +101,15 @@ public AbstractSyntaxTree parse(String ccl, Multimap data) {
return delegate.parse(ccl, data);
}
+ @Override
+ public List compile(String ccl,
+ Multimap data) {
+ return delegate.compile(ccl, data);
+ }
+
/**
* {@link #parse(String) Parse} the {@code criteria}.
- *
+ *
* @param criteria
* @return an {@link AbstractSyntaxTree} representing the {@code criteria}
*/
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/AddCommand.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/AddCommand.java
new file mode 100644
index 000000000..310dda985
--- /dev/null
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/AddCommand.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2013-2026 Cinchapi 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.cinchapi.concourse.lang.command;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A {@link Command} builder for {@code add} commands.
+ *
+ * {@code add} associates a value with a key in one or more records.
+ *
+ *
+ *
+ * add <key> as <value>
+ * add <key> as <value> in <record>
+ * add <key> as <value> in [<records>]
+ *
+ *
+ * @author Jeff Nelson
+ */
+public final class AddCommand {
+
+ /**
+ * The state after specifying the key for the {@code add} command.
+ */
+ public static final class KeyState {
+
+ /**
+ * The key to add.
+ */
+ private final String key;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param key the key to add
+ */
+ KeyState(String key) {
+ this.key = key;
+ }
+
+ /**
+ * Specify the value to add for this key.
+ *
+ * @param value the value to add
+ * @return the next builder state
+ */
+ public ValueState as(Object value) {
+ return new ValueState(key, value);
+ }
+
+ }
+
+ /**
+ * The state after specifying the key and value for the {@code add} command.
+ * This is a terminal state that produces CCL without a record target, but
+ * can optionally be narrowed to specific records via
+ * {@link #in(long, long...)}.
+ */
+ public static final class ValueState implements Command {
+
+ /**
+ * The key to add.
+ */
+ private final String key;
+
+ /**
+ * The value to add.
+ */
+ private final Object value;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param key the key
+ * @param value the value
+ */
+ ValueState(String key, Object value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ /**
+ * Add into the specified {@code record}.
+ *
+ * @param record the target record
+ * @return the next builder state
+ */
+ public RecordState in(long record) {
+ return new RecordState(key, value,
+ CclRenderer.collectRecords(record));
+ }
+
+ /**
+ * Add into the specified {@code records}.
+ *
+ * @param first the first record
+ * @param more additional records
+ * @return the next builder state
+ */
+ public RecordState in(long first, long... more) {
+ return new RecordState(key, value,
+ CclRenderer.collectRecords(first, more));
+ }
+
+ /**
+ * Alias for {@link #in(long)} to support alternate CCL dialects.
+ *
+ * @param record the target record
+ * @return the next builder state
+ */
+ public RecordState to(long record) {
+ return in(record);
+ }
+
+ /**
+ * Alias for {@link #in(long, long...)} to support alternate CCL
+ * dialects.
+ *
+ * @param first the first record
+ * @param more additional records
+ * @return the next builder state
+ */
+ public RecordState to(long first, long... more) {
+ return in(first, more);
+ }
+
+ /**
+ * Alias for {@link #in(long)} to support alternate CCL dialects.
+ *
+ * @param record the target record
+ * @return the next builder state
+ */
+ public RecordState within(long record) {
+ return in(record);
+ }
+
+ /**
+ * Alias for {@link #in(long, long...)} to support alternate CCL
+ * dialects.
+ *
+ * @param first the first record
+ * @param more additional records
+ * @return the next builder state
+ */
+ public RecordState within(long first, long... more) {
+ return in(first, more);
+ }
+
+ /**
+ * Return the key for this command.
+ *
+ * @return the key
+ */
+ public String key() {
+ return key;
+ }
+
+ /**
+ * Return the value for this command.
+ *
+ * @return the value
+ */
+ public Object value() {
+ return value;
+ }
+
+ @Override
+ public String ccl() {
+ StringBuilder sb = new StringBuilder("add ");
+ sb.append(key);
+ sb.append(" as ");
+ sb.append(CclRenderer.value(value));
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return ccl();
+ }
+
+ }
+
+ /**
+ * The terminal state for an {@code add} command that targets specific
+ * records.
+ */
+ public static final class RecordState implements Command {
+
+ /**
+ * The key to add.
+ */
+ private final String key;
+
+ /**
+ * The value to add.
+ */
+ private final Object value;
+
+ /**
+ * The target records.
+ */
+ private final List records;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param key the key
+ * @param value the value
+ * @param records the target records
+ */
+ RecordState(String key, Object value, List records) {
+ this.key = key;
+ this.value = value;
+ this.records = records;
+ }
+
+ /**
+ * Return the key for this command.
+ *
+ * @return the key
+ */
+ public String key() {
+ return key;
+ }
+
+ /**
+ * Return the value for this command.
+ *
+ * @return the value
+ */
+ public Object value() {
+ return value;
+ }
+
+ /**
+ * Return the target records for this command.
+ *
+ * @return the records
+ */
+ public List records() {
+ return Collections.unmodifiableList(records);
+ }
+
+ @Override
+ public String ccl() {
+ StringBuilder sb = new StringBuilder("add ");
+ sb.append(key);
+ sb.append(" as ");
+ sb.append(CclRenderer.value(value));
+ sb.append(" in ");
+ sb.append(CclRenderer.records(records));
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return ccl();
+ }
+
+ }
+
+ private AddCommand() {/* no-init */}
+
+}
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/AuditCommand.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/AuditCommand.java
new file mode 100644
index 000000000..2ae961224
--- /dev/null
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/AuditCommand.java
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2013-2026 Cinchapi 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.cinchapi.concourse.lang.command;
+
+import com.cinchapi.concourse.Timestamp;
+
+/**
+ * A {@link Command} builder for {@code audit} commands.
+ *
+ * {@code audit} retrieves the log of changes to a record or a key within a
+ * record, optionally bounded by one or two timestamps.
+ *
+ *
+ *
+ * audit <record>
+ * audit <record> at <start>
+ * audit <record> at <start> at <end>
+ * audit <key> in <record>
+ * audit <key> in <record> at <start>
+ * audit <key> in <record> at <start> at <end>
+ *
+ *
+ * @author Jeff Nelson
+ */
+public final class AuditCommand {
+
+ /**
+ * The terminal state for a record-scoped {@code audit} command. Supports an
+ * optional {@code at} clause for a start timestamp.
+ */
+ public static final class RecordState implements Command {
+
+ /**
+ * The target record.
+ */
+ private final long record;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param record the target record
+ */
+ RecordState(long record) {
+ this.record = record;
+ }
+
+ /**
+ * Specify the start {@link Timestamp} for the audit.
+ *
+ * @param start the start {@link Timestamp}
+ * @return the next builder state
+ */
+ public RecordTimestampState at(Timestamp start) {
+ return new RecordTimestampState(record, start);
+ }
+
+ /**
+ * Return the target record for this command.
+ *
+ * @return the record
+ */
+ public long record() {
+ return record;
+ }
+
+ @Override
+ public String ccl() {
+ StringBuilder sb = new StringBuilder("audit ");
+ sb.append(Long.toString(record));
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return ccl();
+ }
+
+ }
+
+ /**
+ * The state after specifying the key for the {@code audit} command.
+ */
+ public static final class KeyState {
+
+ /**
+ * The key to audit.
+ */
+ private final String key;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param key the key to audit
+ */
+ KeyState(String key) {
+ this.key = key;
+ }
+
+ /**
+ * Specify the record in which to audit the key.
+ *
+ * @param record the target record
+ * @return the next builder state
+ */
+ public KeyRecordState in(long record) {
+ return new KeyRecordState(key, record);
+ }
+
+ /**
+ * Alias for {@link #in(long)} to support alternate CCL dialects.
+ *
+ * @param record the target record
+ * @return the next builder state
+ */
+ public KeyRecordState within(long record) {
+ return in(record);
+ }
+
+ }
+
+ /**
+ * The terminal state for a key-scoped {@code audit} command after
+ * specifying the key and record. Supports an optional {@code at} clause for
+ * a start timestamp.
+ */
+ public static final class KeyRecordState implements Command {
+
+ /**
+ * The key to audit.
+ */
+ private final String key;
+
+ /**
+ * The target record.
+ */
+ private final long record;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param key the key
+ * @param record the target record
+ */
+ KeyRecordState(String key, long record) {
+ this.key = key;
+ this.record = record;
+ }
+
+ /**
+ * Specify the start {@link Timestamp} for the audit.
+ *
+ * @param start the start {@link Timestamp}
+ * @return the next builder state
+ */
+ public KeyRecordTimestampState at(Timestamp start) {
+ return new KeyRecordTimestampState(key, record, start);
+ }
+
+ /**
+ * Return the key for this command.
+ *
+ * @return the key
+ */
+ public String key() {
+ return key;
+ }
+
+ /**
+ * Return the target record for this command.
+ *
+ * @return the record
+ */
+ public long record() {
+ return record;
+ }
+
+ @Override
+ public String ccl() {
+ StringBuilder sb = new StringBuilder("audit ");
+ sb.append(key);
+ sb.append(" in ");
+ sb.append(Long.toString(record));
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return ccl();
+ }
+
+ }
+
+ /**
+ * The terminal state for a record-scoped {@code audit} command that
+ * includes a start {@link Timestamp}. Supports an optional second
+ * {@code at} clause for an end timestamp.
+ */
+ public static final class RecordTimestampState implements Command {
+
+ /**
+ * The target record.
+ */
+ private final long record;
+
+ /**
+ * The start {@link Timestamp}.
+ */
+ private final Timestamp start;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param record the target record
+ * @param start the start {@link Timestamp}
+ */
+ RecordTimestampState(long record, Timestamp start) {
+ this.record = record;
+ this.start = start;
+ }
+
+ /**
+ * Specify the end {@link Timestamp} for this command.
+ *
+ * @param end the end {@link Timestamp}
+ * @return the next builder state
+ */
+ public RecordRangeState at(Timestamp end) {
+ return new RecordRangeState(record, start, end);
+ }
+
+ /**
+ * Return the target record for this command.
+ *
+ * @return the record
+ */
+ public long record() {
+ return record;
+ }
+
+ /**
+ * Return the start {@link Timestamp} for this command.
+ *
+ * @return the start {@link Timestamp}
+ */
+ public Timestamp start() {
+ return start;
+ }
+
+ @Override
+ public String ccl() {
+ StringBuilder sb = new StringBuilder("audit ");
+ sb.append(Long.toString(record));
+ CclRenderer.appendTimestamp(sb, start);
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return ccl();
+ }
+
+ }
+
+ /**
+ * The terminal state for a record-scoped {@code audit} command that
+ * includes both a start and end {@link Timestamp}.
+ */
+ public static final class RecordRangeState implements Command {
+
+ /**
+ * The target record.
+ */
+ private final long record;
+
+ /**
+ * The start {@link Timestamp}.
+ */
+ private final Timestamp start;
+
+ /**
+ * The end {@link Timestamp}.
+ */
+ private final Timestamp end;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param record the target record
+ * @param start the start {@link Timestamp}
+ * @param end the end {@link Timestamp}
+ */
+ RecordRangeState(long record, Timestamp start, Timestamp end) {
+ this.record = record;
+ this.start = start;
+ this.end = end;
+ }
+
+ /**
+ * Return the target record for this command.
+ *
+ * @return the record
+ */
+ public long record() {
+ return record;
+ }
+
+ /**
+ * Return the start {@link Timestamp} for this command.
+ *
+ * @return the start {@link Timestamp}
+ */
+ public Timestamp start() {
+ return start;
+ }
+
+ /**
+ * Return the end {@link Timestamp} for this command.
+ *
+ * @return the end {@link Timestamp}
+ */
+ public Timestamp end() {
+ return end;
+ }
+
+ @Override
+ public String ccl() {
+ StringBuilder sb = new StringBuilder("audit ");
+ sb.append(Long.toString(record));
+ CclRenderer.appendTimestamp(sb, start);
+ CclRenderer.appendTimestamp(sb, end);
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return ccl();
+ }
+
+ }
+
+ /**
+ * The terminal state for a key-scoped {@code audit} command that includes a
+ * start {@link Timestamp}. Supports an optional second {@code at} clause
+ * for an end timestamp.
+ */
+ public static final class KeyRecordTimestampState implements Command {
+
+ /**
+ * The key to audit.
+ */
+ private final String key;
+
+ /**
+ * The target record.
+ */
+ private final long record;
+
+ /**
+ * The start {@link Timestamp}.
+ */
+ private final Timestamp start;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param key the key
+ * @param record the target record
+ * @param start the start {@link Timestamp}
+ */
+ KeyRecordTimestampState(String key, long record, Timestamp start) {
+ this.key = key;
+ this.record = record;
+ this.start = start;
+ }
+
+ /**
+ * Specify the end {@link Timestamp} for this command.
+ *
+ * @param end the end {@link Timestamp}
+ * @return the next builder state
+ */
+ public KeyRecordRangeState at(Timestamp end) {
+ return new KeyRecordRangeState(key, record, start, end);
+ }
+
+ /**
+ * Return the key for this command.
+ *
+ * @return the key
+ */
+ public String key() {
+ return key;
+ }
+
+ /**
+ * Return the target record for this command.
+ *
+ * @return the record
+ */
+ public long record() {
+ return record;
+ }
+
+ /**
+ * Return the start {@link Timestamp} for this command.
+ *
+ * @return the start {@link Timestamp}
+ */
+ public Timestamp start() {
+ return start;
+ }
+
+ @Override
+ public String ccl() {
+ StringBuilder sb = new StringBuilder("audit ");
+ sb.append(key);
+ sb.append(" in ");
+ sb.append(Long.toString(record));
+ CclRenderer.appendTimestamp(sb, start);
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return ccl();
+ }
+
+ }
+
+ /**
+ * The terminal state for a key-scoped {@code audit} command that includes
+ * both a start and end {@link Timestamp}.
+ */
+ public static final class KeyRecordRangeState implements Command {
+
+ /**
+ * The key to audit.
+ */
+ private final String key;
+
+ /**
+ * The target record.
+ */
+ private final long record;
+
+ /**
+ * The start {@link Timestamp}.
+ */
+ private final Timestamp start;
+
+ /**
+ * The end {@link Timestamp}.
+ */
+ private final Timestamp end;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param key the key
+ * @param record the target record
+ * @param start the start {@link Timestamp}
+ * @param end the end {@link Timestamp}
+ */
+ KeyRecordRangeState(String key, long record, Timestamp start,
+ Timestamp end) {
+ this.key = key;
+ this.record = record;
+ this.start = start;
+ this.end = end;
+ }
+
+ /**
+ * Return the key for this command.
+ *
+ * @return the key
+ */
+ public String key() {
+ return key;
+ }
+
+ /**
+ * Return the target record for this command.
+ *
+ * @return the record
+ */
+ public long record() {
+ return record;
+ }
+
+ /**
+ * Return the start {@link Timestamp} for this command.
+ *
+ * @return the start {@link Timestamp}
+ */
+ public Timestamp start() {
+ return start;
+ }
+
+ /**
+ * Return the end {@link Timestamp} for this command.
+ *
+ * @return the end {@link Timestamp}
+ */
+ public Timestamp end() {
+ return end;
+ }
+
+ @Override
+ public String ccl() {
+ StringBuilder sb = new StringBuilder("audit ");
+ sb.append(key);
+ sb.append(" in ");
+ sb.append(Long.toString(record));
+ CclRenderer.appendTimestamp(sb, start);
+ CclRenderer.appendTimestamp(sb, end);
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return ccl();
+ }
+
+ }
+
+ private AuditCommand() {/* no-init */}
+
+}
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/BrowseCommand.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/BrowseCommand.java
new file mode 100644
index 000000000..8930c932b
--- /dev/null
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/BrowseCommand.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2013-2026 Cinchapi 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.cinchapi.concourse.lang.command;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import com.cinchapi.concourse.Timestamp;
+
+/**
+ * A {@link Command} builder for {@code browse} commands.
+ *
+ * {@code browse} retrieves the values indexed for one or more keys, optionally
+ * at a historical timestamp.
+ *
+ *
+ *
+ * browse <keys> [at timestamp]
+ *
+ *
+ * @author Jeff Nelson
+ */
+public final class BrowseCommand {
+
+ /**
+ * The terminal state for a {@code browse} command. This state is reached
+ * after specifying the keys to browse and supports an optional {@code at}
+ * clause for historical browsing.
+ */
+ public static final class State implements Command {
+
+ /**
+ * The keys to browse.
+ */
+ private final List keys;
+
+ /**
+ * The optional historical {@link Timestamp}.
+ */
+ @Nullable
+ private Timestamp timestamp;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param key the first key to browse
+ * @param moreKeys additional keys
+ */
+ State(String key, String... moreKeys) {
+ this.keys = CclRenderer.collectKeys(key, moreKeys);
+ }
+
+ /**
+ * Pin this command to a historical {@link Timestamp}.
+ *
+ * @param timestamp the {@link Timestamp}
+ * @return this state for further chaining
+ */
+ public State at(Timestamp timestamp) {
+ this.timestamp = timestamp;
+ return this;
+ }
+
+ /**
+ * Return the keys for this command.
+ *
+ * @return the keys
+ */
+ public List keys() {
+ return Collections.unmodifiableList(keys);
+ }
+
+ /**
+ * Return the historical {@link Timestamp}.
+ *
+ * @return the {@link Timestamp}, or {@code null}
+ */
+ @Nullable
+ public Timestamp timestamp() {
+ return timestamp;
+ }
+
+ @Override
+ public String ccl() {
+ StringBuilder sb = new StringBuilder("browse ");
+ sb.append(CclRenderer.keys(keys));
+ CclRenderer.appendTimestamp(sb, timestamp);
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return ccl();
+ }
+
+ }
+
+ private BrowseCommand() {/* no-init */}
+
+}
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/BuiltCommand.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/BuiltCommand.java
new file mode 100644
index 000000000..e6bdc106b
--- /dev/null
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/BuiltCommand.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013-2026 Cinchapi 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.cinchapi.concourse.lang.command;
+
+/**
+ * A simple {@link Command} implementation for nullary commands that have no
+ * parameters (e.g., {@code ping}, {@code stage}, {@code commit}, {@code abort},
+ * {@code inventory}).
+ *
+ * @author Jeff Nelson
+ */
+final class BuiltCommand implements Command {
+
+ /**
+ * The command verb.
+ */
+ private final String verb;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param verb the command verb
+ */
+ BuiltCommand(String verb) {
+ this.verb = verb;
+ }
+
+ @Override
+ public String ccl() {
+ return verb;
+ }
+
+ @Override
+ public String toString() {
+ return ccl();
+ }
+
+}
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CalculateCommand.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CalculateCommand.java
new file mode 100644
index 000000000..d7cd65b3f
--- /dev/null
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CalculateCommand.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2013-2026 Cinchapi 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.cinchapi.concourse.lang.command;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import com.cinchapi.concourse.Timestamp;
+import com.cinchapi.concourse.lang.Criteria;
+
+/**
+ * A {@link Command} builder for {@code calculate} commands.
+ *
+ * {@code calculate} applies an aggregation function to a key, optionally scoped
+ * to specific records or a condition, and optionally pinned to a historical
+ * timestamp.
+ *
+ *
+ *
+ * calculate <function> <key>
+ * calculate <function> <key> in <records>
+ * calculate <function> <key> where <condition>
+ * calculate <function> <key> [in|where] ... at <timestamp>
+ *
+ *
+ * @author Jeff Nelson
+ */
+public final class CalculateCommand {
+
+ /**
+ * The terminal state for a {@code calculate} command. Supports optional
+ * {@code in}, {@code where}, and {@code at} clauses that can be chained
+ * fluently.
+ */
+ public static final class State implements Command {
+
+ /**
+ * The aggregation function name.
+ */
+ private final String function;
+
+ /**
+ * The key to calculate.
+ */
+ private final String key;
+
+ /**
+ * The target records, or {@code null} if unscoped or condition-scoped.
+ */
+ @Nullable
+ private List records;
+
+ /**
+ * The structured {@link Criteria}, or {@code null}.
+ */
+ @Nullable
+ private Criteria criteria;
+
+ /**
+ * The raw CCL condition string, or {@code null}.
+ */
+ @Nullable
+ private String condition;
+
+ /**
+ * The optional historical {@link Timestamp}.
+ */
+ @Nullable
+ private Timestamp timestamp;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param function the aggregation function
+ * @param key the key to calculate
+ */
+ State(String function, String key) {
+ this.function = function;
+ this.key = key;
+ }
+
+ /**
+ * Scope this calculation to the specified {@code record}.
+ *
+ * @param record the target record
+ * @return this state for further chaining
+ */
+ public State in(long record) {
+ return in(record, new long[0]);
+ }
+
+ /**
+ * Scope this calculation to the specified records.
+ *
+ * @param record the first record
+ * @param moreRecords additional records
+ * @return this state for further chaining
+ */
+ public State in(long record, long... moreRecords) {
+ this.records = CclRenderer.collectRecords(record, moreRecords);
+ return this;
+ }
+
+ /**
+ * Alias for {@link #in(long)} to support alternate CCL dialects.
+ *
+ * @param record the target record
+ * @return this state for further chaining
+ */
+ public State from(long record) {
+ return in(record);
+ }
+
+ /**
+ * Alias for {@link #in(long, long...)} to support alternate CCL
+ * dialects.
+ *
+ * @param record the first record
+ * @param moreRecords additional records
+ * @return this state for further chaining
+ */
+ public State from(long record, long... moreRecords) {
+ return in(record, moreRecords);
+ }
+
+ /**
+ * Alias for {@link #in(long)} to support alternate CCL dialects.
+ *
+ * @param record the target record
+ * @return this state for further chaining
+ */
+ public State within(long record) {
+ return in(record);
+ }
+
+ /**
+ * Alias for {@link #in(long, long...)} to support alternate CCL
+ * dialects.
+ *
+ * @param record the first record
+ * @param moreRecords additional records
+ * @return this state for further chaining
+ */
+ public State within(long record, long... moreRecords) {
+ return in(record, moreRecords);
+ }
+
+ /**
+ * Scope this calculation to records matching the {@link Criteria}.
+ *
+ * @param criteria the {@link Criteria}
+ * @return this state for further chaining
+ */
+ public State where(Criteria criteria) {
+ this.criteria = criteria;
+ return this;
+ }
+
+ /**
+ * Scope this calculation to records matching the CCL condition string.
+ *
+ * @param ccl the CCL condition
+ * @return this state for further chaining
+ */
+ public State where(String ccl) {
+ this.condition = ccl;
+ return this;
+ }
+
+ /**
+ * Pin this calculation to a historical {@link Timestamp}.
+ *
+ * @param timestamp the {@link Timestamp}
+ * @return this state for further chaining
+ */
+ public State at(Timestamp timestamp) {
+ this.timestamp = timestamp;
+ return this;
+ }
+
+ /**
+ * Return the aggregation function for this command.
+ *
+ * @return the function name
+ */
+ public String function() {
+ return function;
+ }
+
+ /**
+ * Return the key for this command.
+ *
+ * @return the key
+ */
+ public String key() {
+ return key;
+ }
+
+ /**
+ * Return the target records for this command.
+ *
+ * @return the records, or {@code null}
+ */
+ @Nullable
+ public List records() {
+ return records != null ? Collections.unmodifiableList(records)
+ : null;
+ }
+
+ /**
+ * Return the {@link Criteria} for this command.
+ *
+ * @return the {@link Criteria}, or {@code null}
+ */
+ @Nullable
+ public Criteria criteria() {
+ return criteria;
+ }
+
+ /**
+ * Return the historical {@link Timestamp} for this command.
+ *
+ * @return the {@link Timestamp}, or {@code null}
+ */
+ @Nullable
+ public Timestamp timestamp() {
+ return timestamp;
+ }
+
+ @Override
+ public String ccl() {
+ StringBuilder sb = new StringBuilder("calculate ");
+ sb.append(function);
+ sb.append(" ");
+ sb.append(key);
+ if(records != null) {
+ sb.append(" in ");
+ sb.append(CclRenderer.records(records));
+ }
+ else {
+ CclRenderer.appendWhereClause(sb, criteria, condition);
+ }
+ CclRenderer.appendTimestamp(sb, timestamp);
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return ccl();
+ }
+
+ }
+
+ private CalculateCommand() {/* no-init */}
+
+}
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CclRenderer.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CclRenderer.java
new file mode 100644
index 000000000..eca1a46b4
--- /dev/null
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CclRenderer.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2013-2026 Cinchapi 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.cinchapi.concourse.lang.command;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import com.cinchapi.concourse.Timestamp;
+import com.cinchapi.concourse.lang.Criteria;
+import com.cinchapi.concourse.lang.paginate.Page;
+import com.cinchapi.concourse.lang.sort.Direction;
+import com.cinchapi.concourse.lang.sort.Order;
+import com.cinchapi.concourse.lang.sort.OrderComponent;
+import com.google.common.collect.Lists;
+
+/**
+ * Shared utilities for rendering {@link Command} components as CCL string
+ * fragments.
+ *
+ * @author Jeff Nelson
+ */
+public final class CclRenderer {
+
+ /**
+ * Render a list of keys as a CCL fragment. A single key is rendered bare;
+ * multiple keys are rendered as a bracketed, comma-separated list.
+ *
+ * @param keys the keys to render
+ * @return the CCL fragment
+ */
+ public static String keys(List keys) {
+ if(keys.size() == 1) {
+ return keys.get(0);
+ }
+ else {
+ return "[" + String.join(", ", keys) + "]";
+ }
+ }
+
+ /**
+ * Render a list of record identifiers as a CCL fragment. A single record is
+ * rendered bare; multiple records are rendered as a bracketed,
+ * comma-separated list.
+ *
+ * @param records the records to render
+ * @return the CCL fragment
+ */
+ public static String records(List records) {
+ if(records.size() == 1) {
+ return Long.toString(records.get(0));
+ }
+ else {
+ StringBuilder sb = new StringBuilder("[");
+ for (int i = 0; i < records.size(); ++i) {
+ if(i > 0) {
+ sb.append(", ");
+ }
+ sb.append(records.get(i));
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+ }
+
+ /**
+ * Render a value as a CCL fragment. Strings are double-quoted with internal
+ * double quotes escaped; numbers and other types are rendered as their
+ * string representation.
+ *
+ * @param value the value to render
+ * @return the CCL fragment
+ */
+ public static String value(Object value) {
+ if(value instanceof String) {
+ String escaped = ((String) value).replace("\\", "\\\\")
+ .replace("\"", "\\\"");
+ return "\"" + escaped + "\"";
+ }
+ else {
+ return value.toString();
+ }
+ }
+
+ /**
+ * Render a list of values as a CCL fragment, enclosed in brackets.
+ *
+ * @param values the values to render
+ * @return the CCL fragment
+ */
+ public static String values(List
*
* @author Jeff Nelson
@@ -127,10 +127,10 @@ public boolean includeIdentifier() {
public String ccl() {
StringBuilder sb = new StringBuilder("jsonify ");
sb.append(CclRenderer.records(records));
- CclRenderer.appendTimestamp(sb, timestamp);
if(identifier) {
- sb.append(" identifier");
+ sb.append(" with $id$");
}
+ CclRenderer.appendTimestamp(sb, timestamp);
return sb.toString();
}
diff --git a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandCompilationTest.java b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandCompilationTest.java
index 13c7c1ac4..639d586f4 100644
--- a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandCompilationTest.java
+++ b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandCompilationTest.java
@@ -1181,6 +1181,642 @@ public void testCalculateInRecordsCompiles() {
"CALCULATE");
}
+ /**
+ * Goal: Verify that a {@code jsonify} command with the
+ * identifier flag compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code jsonify} command for record {@code 1} with the
+ * identifier flag enabled.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code JSONIFY}.
+ */
+ @Test
+ public void testJsonifyWithIdentifierCompiles() {
+ assertCompiles(Command.jsonify(1).identifier().ccl(), "JSONIFY");
+ }
+
+ /**
+ * Goal: Verify that a {@code jsonify} command with the
+ * identifier flag and a timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code jsonify} command for record {@code 1} with the
+ * identifier flag and timestamp 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code JSONIFY}.
+ */
+ @Test
+ public void testJsonifyWithIdentifierAndTimestampCompiles() {
+ assertCompiles(Command.jsonify(1).identifier()
+ .at(Timestamp.fromMicros(12345)).ccl(), "JSONIFY");
+ }
+
+ /**
+ * Goal: Verify that a key-only {@code diff} command
+ * compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code diff} command for key {@code "name"} at timestamp
+ * 100.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code DIFF}.
+ */
+ @Test
+ public void testDiffKeyOnlyCompiles() {
+ assertCompiles(Command.diff("name").at(Timestamp.fromMicros(100)).ccl(),
+ "DIFF");
+ }
+
+ /**
+ * Goal: Verify that a key-only {@code diff} command with a
+ * range compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code diff} command for key {@code "name"} at start
+ * timestamp 100 and end timestamp 200.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code DIFF}.
+ */
+ @Test
+ public void testDiffKeyOnlyRangeCompiles() {
+ assertCompiles(Command.diff("name").at(Timestamp.fromMicros(100))
+ .at(Timestamp.fromMicros(200)).ccl(), "DIFF");
+ }
+
+ /**
+ * Goal: Verify that a {@code findOrInsert} command with a
+ * historical timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code findOrInsert} command with condition
+ * {@code "name = jeff"}, timestamp 12345, and JSON data.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code FIND_OR_INSERT}.
+ *
+ */
+ @Test
+ public void testFindOrInsertWithTimestampCompiles() {
+ assertCompiles(Command.findOrInsert("name = jeff")
+ .at(Timestamp.fromMicros(12345)).json("{\"name\":\"jeff\"}")
+ .ccl(), "FIND_OR_INSERT");
+ }
+
+ /**
+ * Goal: Verify that a {@code describe} command for all
+ * records with a timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code describeAll} command at timestamp 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code DESCRIBE}.
+ */
+ @Test
+ public void testDescribeAllWithTimestampCompiles() {
+ assertCompiles(
+ Command.describeAll().at(Timestamp.fromMicros(12345)).ccl(),
+ "DESCRIBE");
+ }
+
+ // ========== Temporal Variant Coverage ==========
+
+ /**
+ * Goal: Verify that a {@code diff} command for a record
+ * with a start and end timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code diff} command for record 1 at timestamps 100 and
+ * 200.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code DIFF}.
+ */
+ @Test
+ public void testDiffRecordRangeCompiles() {
+ assertCompiles(Command.diff(1L).at(Timestamp.fromMicros(100))
+ .at(Timestamp.fromMicros(200)).ccl(), "DIFF");
+ }
+
+ /**
+ * Goal: Verify that a {@code diff} command for a key in a
+ * record with a start and end timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code diff} command for key {@code "name"} in record 1 at
+ * timestamps 100 and 200.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code DIFF}.
+ */
+ @Test
+ public void testDiffKeyInRecordRangeCompiles() {
+ assertCompiles(Command.diff("name").in(1).at(Timestamp.fromMicros(100))
+ .at(Timestamp.fromMicros(200)).ccl(), "DIFF");
+ }
+
+ /**
+ * Goal: Verify that a {@code chronicle} command with a
+ * single timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code chronicle} command for key {@code "name"} in record 1
+ * at timestamp 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code CHRONICLE}.
+ */
+ @Test
+ public void testChronicleWithTimestampCompiles() {
+ assertCompiles(Command.chronicle("name").in(1)
+ .at(Timestamp.fromMicros(12345)).ccl(), "CHRONICLE");
+ }
+
+ /**
+ * Goal: Verify that an {@code audit} command for a record
+ * with a timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code audit} command for record 1 at timestamp 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code AUDIT}.
+ */
+ @Test
+ public void testAuditRecordWithTimestampCompiles() {
+ assertCompiles(Command.audit(1L).at(Timestamp.fromMicros(12345)).ccl(),
+ "AUDIT");
+ }
+
+ /**
+ * Goal: Verify that an {@code audit} command for a record
+ * with a start and end timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code audit} command for record 1 at timestamps 100 and
+ * 200.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code AUDIT}.
+ */
+ @Test
+ public void testAuditRecordRangeCompiles() {
+ assertCompiles(Command.audit(1L).at(Timestamp.fromMicros(100))
+ .at(Timestamp.fromMicros(200)).ccl(), "AUDIT");
+ }
+
+ /**
+ * Goal: Verify that an {@code audit} command for a key in
+ * a record with a timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code audit} command for key {@code "name"} in record 1 at
+ * timestamp 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code AUDIT}.
+ */
+ @Test
+ public void testAuditKeyInRecordWithTimestampCompiles() {
+ assertCompiles(Command.audit("name").in(1)
+ .at(Timestamp.fromMicros(12345)).ccl(), "AUDIT");
+ }
+
+ /**
+ * Goal: Verify that an {@code audit} command for a key in
+ * a record with a start and end timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code audit} command for key {@code "name"} in record 1 at
+ * timestamps 100 and 200.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code AUDIT}.
+ */
+ @Test
+ public void testAuditKeyInRecordRangeCompiles() {
+ assertCompiles(Command.audit("name").in(1).at(Timestamp.fromMicros(100))
+ .at(Timestamp.fromMicros(200)).ccl(), "AUDIT");
+ }
+
+ /**
+ * Goal: Verify that a {@code trace} command with a
+ * timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code trace} command for record 1 at timestamp 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code TRACE}.
+ */
+ @Test
+ public void testTraceWithTimestampCompiles() {
+ assertCompiles(Command.trace(1).at(Timestamp.fromMicros(12345)).ccl(),
+ "TRACE");
+ }
+
+ /**
+ * Goal: Verify that a {@code navigate} command with a
+ * timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code navigate} command for key {@code "friends.name"} from
+ * record 1 at timestamp 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code NAVIGATE}.
+ */
+ @Test
+ public void testNavigateWithTimestampCompiles() {
+ assertCompiles(Command.navigate("friends.name").from(1)
+ .at(Timestamp.fromMicros(12345)).ccl(), "NAVIGATE");
+ }
+
+ /**
+ * Goal: Verify that a {@code describe} command for a
+ * specific record with a timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code describe} command for record 1 at timestamp
+ * 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code DESCRIBE}.
+ */
+ @Test
+ public void testDescribeRecordWithTimestampCompiles() {
+ assertCompiles(
+ Command.describe(1).at(Timestamp.fromMicros(12345)).ccl(),
+ "DESCRIBE");
+ }
+
+ /**
+ * Goal: Verify that a {@code calculate} command with a
+ * timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code calculate} command for function {@code "sum"} on key
+ * {@code "salary"} at timestamp 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code CALCULATE}.
+ */
+ @Test
+ public void testCalculateWithTimestampCompiles() {
+ assertCompiles(Command.calculate("sum", "salary")
+ .at(Timestamp.fromMicros(12345)).ccl(), "CALCULATE");
+ }
+
+ /**
+ * Goal: Verify that a {@code jsonify} command with a
+ * timestamp (but no identifier) compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code jsonify} command for record 1 at timestamp 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code JSONIFY}.
+ */
+ @Test
+ public void testJsonifyWithTimestampCompiles() {
+ assertCompiles(Command.jsonify(1).at(Timestamp.fromMicros(12345)).ccl(),
+ "JSONIFY");
+ }
+
+ // ========== Order/Page Variant Coverage ==========
+
+ /**
+ * Goal: Verify that a {@code select} command with
+ * {@link Order} compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code select} command for key {@code "name"} from record 1
+ * with order by {@code "name"} ascending.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code SELECT}.
+ */
+ @Test
+ public void testSelectWithOrderCompiles() {
+ assertCompiles(Command.select("name").from(1)
+ .order(Order.by("name").build()).ccl(), "SELECT");
+ }
+
+ /**
+ * Goal: Verify that a {@code select} command with
+ * {@link Page} compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code select} command for key {@code "name"} where
+ * {@code "age > 30"} with page of size 10.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code SELECT}.
+ */
+ @Test
+ public void testSelectWithPageCompiles() {
+ assertCompiles(Command.select("name").where("age > 30")
+ .page(Page.sized(10)).ccl(), "SELECT");
+ }
+
+ /**
+ * Goal: Verify that a {@code select} command from a record
+ * with a timestamp compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code select} command for key {@code "name"} from record 1
+ * at timestamp 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code SELECT}.
+ */
+ @Test
+ public void testSelectFromRecordWithTimestampCompiles() {
+ assertCompiles(Command.select("name").from(1)
+ .at(Timestamp.fromMicros(12345)).ccl(), "SELECT");
+ }
+
+ // ========== Multi-Value Variant Coverage ==========
+
+ /**
+ * Goal: Verify that an {@code add} command targeting
+ * multiple records compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code add} command for key {@code "name"} with value
+ * {@code "jeff"} in records 1 and 2.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code ADD}.
+ */
+ @Test
+ public void testAddInMultipleRecordsCompiles() {
+ assertCompiles(Command.add("name").as("jeff").in(1, 2).ccl(), "ADD");
+ }
+
+ /**
+ * Goal: Verify that a {@code link} command with multiple
+ * destinations compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code link} command for key {@code "friends"} from record 1
+ * to records 2 and 3.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code LINK}.
+ */
+ @Test
+ public void testLinkMultipleDestinationsCompiles() {
+ assertCompiles(Command.link("friends").from(1).to(2, 3).ccl(), "LINK");
+ }
+
+ /**
+ * Goal: Verify that a {@code describe} command targeting
+ * multiple records compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code describe} command for records 1, 2, and 3.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code DESCRIBE}.
+ */
+ @Test
+ public void testDescribeMultipleRecordsCompiles() {
+ assertCompiles(Command.describe(1, 2, 3).ccl(), "DESCRIBE");
+ }
+
+ /**
+ * Goal: Verify that a {@code revert} command with multiple
+ * keys and records compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code revert} command for keys {@code "name"} and
+ * {@code "age"} in records 1 and 2 at timestamp 12345.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code REVERT}.
+ */
+ @Test
+ public void testRevertMultipleKeysAndRecordsCompiles() {
+ assertCompiles(Command.revert("name", "age").in(1, 2)
+ .to(Timestamp.fromMicros(12345)).ccl(), "REVERT");
+ }
+
+ // ========== All-Keys Variant Coverage ==========
+
+ /**
+ * Goal: Verify that a {@code select} all-keys command with
+ * a condition compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code selectAll} command with condition
+ * {@code "active = true"}.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code SELECT}.
+ */
+ @Test
+ public void testSelectAllWhereCompiles() {
+ assertCompiles(Command.selectAll().where("active = true").ccl(),
+ "SELECT");
+ }
+
+ /**
+ * Goal: Verify that a {@code get} all-keys command from a
+ * single record compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code getAll} command from record 1.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code GET}.
+ */
+ @Test
+ public void testGetAllFromRecordCompiles() {
+ assertCompiles(Command.getAll().from(1).ccl(), "GET");
+ }
+
+ /**
+ * Goal: Verify that a {@code get} all-keys command from
+ * multiple records compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code getAll} command from records 1 and 2.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code GET}.
+ */
+ @Test
+ public void testGetAllFromMultipleRecordsCompiles() {
+ assertCompiles(Command.getAll().from(1, 2).ccl(), "GET");
+ }
+
+ /**
+ * Goal: Verify that a {@code get} all-keys command with a
+ * condition compiles.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code getAll} command with condition
+ * {@code "active = true"}.
+ *
Compile the CCL output.
+ *
+ *
+ * Expected: The compiled tree is a {@link CommandTree} of
+ * type {@code GET}.
+ */
+ @Test
+ public void testGetAllWhereCompiles() {
+ assertCompiles(Command.getAll().where("active = true").ccl(), "GET");
+ }
+
// ========== Helper ==========
/**
diff --git a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/InspectionCommandTest.java b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/InspectionCommandTest.java
index cf1bbee0a..b27bdfe7e 100644
--- a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/InspectionCommandTest.java
+++ b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/InspectionCommandTest.java
@@ -285,26 +285,70 @@ public void testJsonify() {
}
/**
- * Goal: Verify that a {@code jsonify} command with a
- * timestamp and the {@code identifier} flag renders all three components.
+ * Goal: Verify that a {@code jsonify} command with the
+ * {@code identifier} flag and a timestamp renders both components in CCL
+ * grammar order ({@code with $id$} before {@code at}).
*
* Start state: No prior state needed.
*
* Workflow:
*
- *
Build a {@code jsonify} command for record {@code 1} at timestamp
- * 12345 with the identifier flag enabled.
+ *
Build a {@code jsonify} command for record {@code 1} with the
+ * identifier flag enabled and at timestamp 12345.
*
Call {@code ccl()}.
*
*
* Expected: The CCL string is
- * {@code "jsonify 1 at 12345 identifier"}.
+ * {@code "jsonify 1 with $id$ at 12345"}.
*/
@Test
public void testJsonifyWithTimestampAndIdentifier() {
- String ccl = Command.jsonify(1).at(Timestamp.fromMicros(12345))
- .identifier().ccl();
- Assert.assertEquals("jsonify 1 at 12345 identifier", ccl);
+ String ccl = Command.jsonify(1).identifier()
+ .at(Timestamp.fromMicros(12345)).ccl();
+ Assert.assertEquals("jsonify 1 with $id$ at 12345", ccl);
+ }
+
+ /**
+ * Goal: Verify that a {@code jsonify} command with only
+ * the {@code identifier} flag (no timestamp) renders correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code jsonify} command for record {@code 1} with the
+ * identifier flag enabled.
+ *
Call {@code ccl()}.
+ *
+ *
+ * Expected: The CCL string is
+ * {@code "jsonify 1 with $id$"}.
+ */
+ @Test
+ public void testJsonifyWithIdentifierOnly() {
+ String ccl = Command.jsonify(1).identifier().ccl();
+ Assert.assertEquals("jsonify 1 with $id$", ccl);
+ }
+
+ /**
+ * Goal: Verify that a {@code describe} command for all
+ * records with a historical timestamp renders the {@code at} clause.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code describeAll} command at timestamp 12345.
+ *
Call {@code ccl()}.
+ *
+ *
+ * Expected: The CCL string is {@code "describe at 12345"}.
+ */
+ @Test
+ public void testDescribeAllWithTimestamp() {
+ String ccl = Command.describeAll().at(Timestamp.fromMicros(12345))
+ .ccl();
+ Assert.assertEquals("describe at 12345", ccl);
}
/**
diff --git a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/LinkCommandTest.java b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/LinkCommandTest.java
index dfb1b3553..6e30e6d3b 100644
--- a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/LinkCommandTest.java
+++ b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/LinkCommandTest.java
@@ -305,4 +305,31 @@ public void testFindOrInsertWithCondition() {
Assert.assertEquals("findOrInsert name = jeff '" + json + "'", ccl);
}
+ /**
+ * Goal: Verify that a {@code findOrInsert} command with a
+ * historical timestamp renders the {@code at} clause between the condition
+ * and the JSON data.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code findOrInsert} command with condition
+ * {@code "name = jeff"}, timestamp 12345, and JSON
+ * {@code "{\"name\":\"jeff\"}"}.
+ *
Call {@code ccl()} on the resulting {@link Command}.
+ *
+ *
+ * Expected: The CCL string is {@code "findOrInsert name =
+ * jeff at 12345 '{\"name\":\"jeff\"}'"}.
+ */
+ @Test
+ public void testFindOrInsertWithTimestamp() {
+ String json = "{\"name\":\"jeff\"}";
+ String ccl = Command.findOrInsert("name = jeff")
+ .at(Timestamp.fromMicros(12345)).json(json).ccl();
+ Assert.assertEquals("findOrInsert name = jeff at 12345 '" + json + "'",
+ ccl);
+ }
+
}
diff --git a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/TemporalCommandTest.java b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/TemporalCommandTest.java
index 753f68c83..b60be5b9c 100644
--- a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/TemporalCommandTest.java
+++ b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/TemporalCommandTest.java
@@ -450,6 +450,50 @@ public void testChronicleWithinRecordAlias() {
Assert.assertEquals("chronicle name in 1", ccl);
}
+ /**
+ * Goal: Verify that a key-only {@code diff} command (no
+ * record) with a single timestamp renders correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code diff} command for key {@code "name"} at timestamp
+ * 100.
+ *
Call {@code ccl()}.
+ *
+ *
+ * Expected: The CCL string is {@code "diff name at 100"}.
+ */
+ @Test
+ public void testDiffKeyOnly() {
+ String ccl = Command.diff("name").at(Timestamp.fromMicros(100)).ccl();
+ Assert.assertEquals("diff name at 100", ccl);
+ }
+
+ /**
+ * Goal: Verify that a key-only {@code diff} command with a
+ * start and end timestamp renders both {@code at} clauses.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code diff} command for key {@code "name"} at start
+ * timestamp 100 and end timestamp 200.
+ *
Call {@code ccl()}.
+ *
+ *
+ * Expected: The CCL string is
+ * {@code "diff name at 100 at 200"}.
+ */
+ @Test
+ public void testDiffKeyOnlyRange() {
+ String ccl = Command.diff("name").at(Timestamp.fromMicros(100))
+ .at(Timestamp.fromMicros(200)).ccl();
+ Assert.assertEquals("diff name at 100 at 200", ccl);
+ }
+
/**
* Goal: Verify that the {@code within()} alias on
* {@code diff} produces the same CCL as {@code in()}.
From 87f27492621c2d5ffea0cff82d0e8697b91a79c6 Mon Sep 17 00:00:00 2001
From: Jeff Nelson
Date: Sat, 14 Mar 2026 19:51:58 -0400
Subject: [PATCH 04/13] fix failing test
---
.../cinchapi/concourse/lang/command/QueryCommandTest.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/QueryCommandTest.java b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/QueryCommandTest.java
index 3836db5a8..abf0665d2 100644
--- a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/QueryCommandTest.java
+++ b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/QueryCommandTest.java
@@ -196,12 +196,12 @@ public void testGetFromRecord() {
*
Call {@code ccl()} on the resulting command.
*
*
- * Expected: The CCL output is {@code "get from [1, 2]"}.
+ * Expected: The CCL output is {@code "get [1, 2]"}.
*/
@Test
public void testGetAllKeysFromRecords() {
String ccl = Command.getAll().from(1, 2).ccl();
- Assert.assertEquals("get from [1, 2]", ccl);
+ Assert.assertEquals("get [1, 2]", ccl);
}
/**
@@ -498,12 +498,12 @@ public void testGetKeyWithinRecordAlias() {
*
Call {@code ccl()} on the resulting command.
*
*
- * Expected: The CCL output is {@code "get from 1"}.
+ * Expected: The CCL output is {@code "get 1"}.
*/
@Test
public void testGetAllWithinRecordAlias() {
String ccl = Command.getAll().within(1).ccl();
- Assert.assertEquals("get from 1", ccl);
+ Assert.assertEquals("get 1", ccl);
}
/**
From 305fd495dba2f6be2c2f7770809917db2d8cb4b8 Mon Sep 17 00:00:00 2001
From: Jeff Nelson
Date: Sun, 15 Mar 2026 06:53:12 -0400
Subject: [PATCH 05/13] add conversion of command <-> tcommand (thrift
---
.../concourse/ForwardingConcourse.java | 1 -
.../lang/command/CalculateCommand.java | 10 +
.../concourse/lang/command/Command.java | 46 +-
.../lang/command/CommandSerializer.java | 1898 +++++++++++++
.../concourse/lang/command/GetCommand.java | 10 +
.../lang/command/NavigateCommand.java | 10 +
.../concourse/lang/command/SelectCommand.java | 10 +
.../cinchapi/concourse/thrift/TCommand.java | 2494 +++++++++++++++++
.../concourse/thrift/TCommandVerb.java | 152 +
.../command/CommandSerializationTest.java | 1611 +++++++++++
interface/data.thrift | 68 +
11 files changed, 6286 insertions(+), 24 deletions(-)
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CommandSerializer.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/thrift/TCommand.java
create mode 100644 concourse-driver-java/src/main/java/com/cinchapi/concourse/thrift/TCommandVerb.java
create mode 100644 concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/ForwardingConcourse.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/ForwardingConcourse.java
index 16786ef23..82a3f425f 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/ForwardingConcourse.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/ForwardingConcourse.java
@@ -39,7 +39,6 @@
*
* @author Jeff Nelson
*/
-@SuppressWarnings("deprecation")
public abstract class ForwardingConcourse extends Concourse {
/**
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CalculateCommand.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CalculateCommand.java
index d7cd65b3f..6b3c210de 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CalculateCommand.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CalculateCommand.java
@@ -232,6 +232,16 @@ public Criteria criteria() {
return criteria;
}
+ /**
+ * Return the raw CCL condition for this command.
+ *
+ * @return the condition string, or {@code null}
+ */
+ @Nullable
+ public String condition() {
+ return condition;
+ }
+
/**
* Return the historical {@link Timestamp} for this command.
*
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/Command.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/Command.java
index 772859cf4..6914fd1a0 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/Command.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/Command.java
@@ -16,11 +16,12 @@
package com.cinchapi.concourse.lang.command;
import com.cinchapi.concourse.lang.Criteria;
+import com.cinchapi.concourse.thrift.TCommand;
/**
* A {@link Command} encapsulates a complete CCL (Concourse Command Language)
- * statement that can be rendered as a CCL string and, in the future, serialized
- * for wire transport.
+ * statement that can be rendered as a CCL string or serialized as a
+ * {@link TCommand} for wire transport.
*
* {@link Command Commands} are constructed using the fluent static factory
* methods on this interface. Each factory returns a state object whose methods
@@ -55,7 +56,26 @@ public interface Command {
*/
public String ccl();
- // ---- QUERY COMMANDS ----
+ /**
+ * Return a {@link TCommand} Thrift representation of this {@link Command}
+ * suitable for wire transport.
+ *
+ * @return the {@link TCommand}
+ */
+ public default TCommand toThrift() {
+ return CommandSerializer.toThrift(this);
+ }
+
+ /**
+ * Reconstruct a {@link Command} from a {@link TCommand} received over the
+ * wire.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the {@link Command}
+ */
+ public static Command fromThrift(TCommand tc) {
+ return CommandSerializer.fromThrift(tc);
+ }
/**
* Start building a {@code find} {@link Command} using the provided
@@ -217,8 +237,6 @@ public static NavigateCommand.KeyState navigate(String key,
return new NavigateCommand.KeyState(key, moreKeys);
}
- // ---- WRITE COMMANDS ----
-
/**
* Start building an {@code add} {@link Command} for the specified
* {@code key}.
@@ -308,8 +326,6 @@ public static InsertCommand.JsonState insert(String json) {
return new InsertCommand.JsonState(json);
}
- // ---- LINK COMMANDS ----
-
/**
* Start building a {@code link} {@link Command} for the specified
* {@code key}.
@@ -332,8 +348,6 @@ public static UnlinkCommand.KeyState unlink(String key) {
return new UnlinkCommand.KeyState(key);
}
- // ---- VERIFY COMMANDS ----
-
/**
* Start building a {@code verify} {@link Command} for the specified
* {@code key}.
@@ -367,8 +381,6 @@ public static VerifyOrSetCommand.KeyState verifyOrSet(String key) {
return new VerifyOrSetCommand.KeyState(key);
}
- // ---- FIND-OR COMMANDS ----
-
/**
* Start building a {@code findOrAdd} {@link Command} for the specified
* {@code key}.
@@ -403,8 +415,6 @@ public static FindOrInsertCommand.ConditionState findOrInsert(String ccl) {
return new FindOrInsertCommand.ConditionState(null, ccl);
}
- // ---- SEARCH / BROWSE ----
-
/**
* Start building a {@code search} {@link Command} for the specified
* {@code key}.
@@ -439,8 +449,6 @@ public static BrowseCommand.State browse(String key, String... moreKeys) {
return new BrowseCommand.State(key, moreKeys);
}
- // ---- RECORD INSPECTION ----
-
/**
* Start building a {@code describe} {@link Command} for the specified
* {@code record}.
@@ -546,8 +554,6 @@ public static JsonifyCommand.State jsonify(long record,
return new JsonifyCommand.State(record, moreRecords);
}
- // ---- HISTORY / TEMPORAL ----
-
/**
* Start building a {@code chronicle} {@link Command} for the specified
* {@code key}.
@@ -627,8 +633,6 @@ public static RevertCommand.KeyState revert(String key,
return new RevertCommand.KeyState(key, moreKeys);
}
- // ---- OTHER ----
-
/**
* Start building a {@code reconcile} {@link Command} for the specified
* {@code key}.
@@ -667,8 +671,6 @@ public static CalculateCommand.State calculate(String function,
return new CalculateCommand.State(function, key);
}
- // ---- TRANSACTION ----
-
/**
* Return a {@code stage} {@link Command}.
*
@@ -696,8 +698,6 @@ public static Command abort() {
return new BuiltCommand("abort");
}
- // ---- UTILITY ----
-
/**
* Return a {@code ping} {@link Command}.
*
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CommandSerializer.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CommandSerializer.java
new file mode 100644
index 000000000..9a45ac255
--- /dev/null
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CommandSerializer.java
@@ -0,0 +1,1898 @@
+/*
+ * Copyright (c) 2013-2026 Cinchapi 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.cinchapi.concourse.lang.command;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nullable;
+
+import com.cinchapi.concourse.Timestamp;
+import com.cinchapi.concourse.lang.Criteria;
+import com.cinchapi.concourse.lang.Language;
+import com.cinchapi.concourse.lang.paginate.Page;
+import com.cinchapi.concourse.lang.sort.Order;
+import com.cinchapi.concourse.thrift.JavaThriftBridge;
+import com.cinchapi.concourse.thrift.TCommand;
+import com.cinchapi.concourse.thrift.TCommandVerb;
+import com.cinchapi.concourse.thrift.TObject;
+import com.cinchapi.concourse.util.Convert;
+
+/**
+ * Utility for converting {@link Command Commands} to and from {@link TCommand}
+ * Thrift representations.
+ *
+ * @author Jeff Nelson
+ */
+final class CommandSerializer {
+
+ /**
+ * Convert a {@link Command} to a {@link TCommand} suitable for wire
+ * transport.
+ *
+ * @param command the {@link Command} to serialize
+ * @return the {@link TCommand}
+ * @throws UnsupportedOperationException if the {@link Command} type is not
+ * recognized
+ */
+ public static TCommand toThrift(Command command) {
+ if(command instanceof BuiltCommand) {
+ return serializeBuiltCommand((BuiltCommand) command);
+ }
+ else if(command instanceof FindCommand.ConditionState) {
+ return serializeFindCommand((FindCommand.ConditionState) command);
+ }
+ else if(command instanceof SelectCommand.SourceState) {
+ return serializeSelectCommand((SelectCommand.SourceState) command);
+ }
+ else if(command instanceof GetCommand.SourceState) {
+ return serializeGetCommand((GetCommand.SourceState) command);
+ }
+ else if(command instanceof NavigateCommand.SourceState) {
+ return serializeNavigateCommand(
+ (NavigateCommand.SourceState) command);
+ }
+ else if(command instanceof AddCommand.RecordState) {
+ return serializeAddRecordCommand((AddCommand.RecordState) command);
+ }
+ else if(command instanceof AddCommand.ValueState) {
+ return serializeAddValueCommand((AddCommand.ValueState) command);
+ }
+ else if(command instanceof SetCommand.RecordState) {
+ return serializeSetCommand((SetCommand.RecordState) command);
+ }
+ else if(command instanceof RemoveCommand.RecordState) {
+ return serializeRemoveCommand((RemoveCommand.RecordState) command);
+ }
+ else if(command instanceof ClearCommand.RecordState) {
+ return serializeClearCommand((ClearCommand.RecordState) command);
+ }
+ else if(command instanceof InsertCommand.RecordState) {
+ return serializeInsertRecordCommand(
+ (InsertCommand.RecordState) command);
+ }
+ else if(command instanceof InsertCommand.JsonState) {
+ return serializeInsertJsonCommand(
+ (InsertCommand.JsonState) command);
+ }
+ else if(command instanceof LinkCommand.DestinationState) {
+ return serializeLinkCommand((LinkCommand.DestinationState) command);
+ }
+ else if(command instanceof UnlinkCommand.DestinationState) {
+ return serializeUnlinkCommand(
+ (UnlinkCommand.DestinationState) command);
+ }
+ else if(command instanceof VerifyCommand.TimestampState) {
+ return serializeVerifyTimestampCommand(
+ (VerifyCommand.TimestampState) command);
+ }
+ else if(command instanceof VerifyCommand.RecordState) {
+ return serializeVerifyCommand((VerifyCommand.RecordState) command);
+ }
+ else if(command instanceof VerifyAndSwapCommand.SwapState) {
+ return serializeVerifyAndSwapCommand(
+ (VerifyAndSwapCommand.SwapState) command);
+ }
+ else if(command instanceof VerifyOrSetCommand.RecordState) {
+ return serializeVerifyOrSetCommand(
+ (VerifyOrSetCommand.RecordState) command);
+ }
+ else if(command instanceof FindOrAddCommand.ValueState) {
+ return serializeFindOrAddCommand(
+ (FindOrAddCommand.ValueState) command);
+ }
+ else if(command instanceof FindOrInsertCommand.JsonState) {
+ return serializeFindOrInsertCommand(
+ (FindOrInsertCommand.JsonState) command);
+ }
+ else if(command instanceof SearchCommand.QueryState) {
+ return serializeSearchCommand((SearchCommand.QueryState) command);
+ }
+ else if(command instanceof BrowseCommand.State) {
+ return serializeBrowseCommand((BrowseCommand.State) command);
+ }
+ else if(command instanceof DescribeCommand.AllState) {
+ return serializeDescribeAllCommand(
+ (DescribeCommand.AllState) command);
+ }
+ else if(command instanceof DescribeCommand.State) {
+ return serializeDescribeCommand((DescribeCommand.State) command);
+ }
+ else if(command instanceof TraceCommand.State) {
+ return serializeTraceCommand((TraceCommand.State) command);
+ }
+ else if(command instanceof HoldsCommand.State) {
+ return serializeHoldsCommand((HoldsCommand.State) command);
+ }
+ else if(command instanceof JsonifyCommand.State) {
+ return serializeJsonifyCommand((JsonifyCommand.State) command);
+ }
+ else if(command instanceof ChronicleCommand.RangeState) {
+ return serializeChronicleRangeCommand(
+ (ChronicleCommand.RangeState) command);
+ }
+ else if(command instanceof ChronicleCommand.TimestampState) {
+ return serializeChronicleTimestampCommand(
+ (ChronicleCommand.TimestampState) command);
+ }
+ else if(command instanceof ChronicleCommand.RecordState) {
+ return serializeChronicleRecordCommand(
+ (ChronicleCommand.RecordState) command);
+ }
+ else if(command instanceof DiffCommand.KeyRecordRangeState) {
+ return serializeDiffCommand(
+ (DiffCommand.KeyRecordRangeState) command);
+ }
+ else if(command instanceof DiffCommand.KeyRecordTimestampState) {
+ return serializeDiffCommand(
+ (DiffCommand.KeyRecordTimestampState) command);
+ }
+ else if(command instanceof DiffCommand.KeyRangeState) {
+ return serializeDiffCommand((DiffCommand.KeyRangeState) command);
+ }
+ else if(command instanceof DiffCommand.KeyTimestampState) {
+ return serializeDiffCommand(
+ (DiffCommand.KeyTimestampState) command);
+ }
+ else if(command instanceof DiffCommand.RecordRangeState) {
+ return serializeDiffCommand((DiffCommand.RecordRangeState) command);
+ }
+ else if(command instanceof DiffCommand.RecordTimestampState) {
+ return serializeDiffCommand(
+ (DiffCommand.RecordTimestampState) command);
+ }
+ else if(command instanceof AuditCommand.KeyRecordRangeState) {
+ return serializeAuditCommand(
+ (AuditCommand.KeyRecordRangeState) command);
+ }
+ else if(command instanceof AuditCommand.KeyRecordTimestampState) {
+ return serializeAuditCommand(
+ (AuditCommand.KeyRecordTimestampState) command);
+ }
+ else if(command instanceof AuditCommand.RecordRangeState) {
+ return serializeAuditCommand(
+ (AuditCommand.RecordRangeState) command);
+ }
+ else if(command instanceof AuditCommand.RecordTimestampState) {
+ return serializeAuditCommand(
+ (AuditCommand.RecordTimestampState) command);
+ }
+ else if(command instanceof AuditCommand.KeyRecordState) {
+ return serializeAuditCommand((AuditCommand.KeyRecordState) command);
+ }
+ else if(command instanceof AuditCommand.RecordState) {
+ return serializeAuditCommand((AuditCommand.RecordState) command);
+ }
+ else if(command instanceof RevertCommand.TimestampState) {
+ return serializeRevertCommand(
+ (RevertCommand.TimestampState) command);
+ }
+ else if(command instanceof ReconcileCommand.ValuesState) {
+ return serializeReconcileCommand(
+ (ReconcileCommand.ValuesState) command);
+ }
+ else if(command instanceof ConsolidateCommand.State) {
+ return serializeConsolidateCommand(
+ (ConsolidateCommand.State) command);
+ }
+ else if(command instanceof CalculateCommand.State) {
+ return serializeCalculateCommand((CalculateCommand.State) command);
+ }
+ else {
+ throw new UnsupportedOperationException(
+ "Cannot serialize Command of type "
+ + command.getClass().getName());
+ }
+ }
+
+ /**
+ * Reconstruct a {@link Command} from a {@link TCommand} received over the
+ * wire.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the {@link Command}
+ * @throws UnsupportedOperationException if the verb is not recognized
+ */
+ public static Command fromThrift(TCommand tc) {
+ switch (tc.getVerb()) {
+ case PING:
+ case STAGE:
+ case COMMIT:
+ case ABORT:
+ case INVENTORY:
+ return new BuiltCommand(tc.getVerb().name().toLowerCase());
+ case FIND:
+ return deserializeFind(tc);
+ case SELECT:
+ return deserializeSelect(tc);
+ case GET:
+ return deserializeGet(tc);
+ case NAVIGATE:
+ return deserializeNavigate(tc);
+ case ADD:
+ return deserializeAdd(tc);
+ case SET:
+ return deserializeSet(tc);
+ case REMOVE:
+ return deserializeRemove(tc);
+ case CLEAR:
+ return deserializeClear(tc);
+ case INSERT:
+ return deserializeInsert(tc);
+ case LINK:
+ return deserializeLink(tc);
+ case UNLINK:
+ return deserializeUnlink(tc);
+ case VERIFY:
+ return deserializeVerify(tc);
+ case VERIFY_AND_SWAP:
+ return deserializeVerifyAndSwap(tc);
+ case VERIFY_OR_SET:
+ return deserializeVerifyOrSet(tc);
+ case FIND_OR_ADD:
+ return deserializeFindOrAdd(tc);
+ case FIND_OR_INSERT:
+ return deserializeFindOrInsert(tc);
+ case SEARCH:
+ return deserializeSearch(tc);
+ case BROWSE:
+ return deserializeBrowse(tc);
+ case DESCRIBE:
+ return deserializeDescribe(tc);
+ case TRACE:
+ return deserializeTrace(tc);
+ case HOLDS:
+ return deserializeHolds(tc);
+ case JSONIFY:
+ return deserializeJsonify(tc);
+ case CHRONICLE:
+ return deserializeChronicle(tc);
+ case DIFF:
+ return deserializeDiff(tc);
+ case AUDIT:
+ return deserializeAudit(tc);
+ case REVERT:
+ return deserializeRevert(tc);
+ case RECONCILE:
+ return deserializeReconcile(tc);
+ case CONSOLIDATE:
+ return deserializeConsolidate(tc);
+ case CALCULATE:
+ return deserializeCalculate(tc);
+ default:
+ throw new UnsupportedOperationException(
+ "Cannot deserialize TCommand with verb " + tc.getVerb());
+ }
+ }
+
+ /**
+ * Deserialize a {@code find} {@link TCommand} into a
+ * {@link FindCommand.ConditionState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeFind(TCommand tc) {
+ FindCommand.ConditionState state = new FindCommand.ConditionState(
+ getCriteria(tc), tc.getCondition());
+ applyTimestamp(state, tc);
+ applyOrder(state, tc);
+ applyPage(state, tc);
+ return state;
+ }
+
+ /**
+ * Deserialize a {@code select} {@link TCommand} into a
+ * {@link SelectCommand.SourceState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeSelect(TCommand tc) {
+ SelectCommand.SourceState state = new SelectCommand.SourceState(
+ getKeys(tc), getRecords(tc), getCriteria(tc),
+ tc.getCondition());
+ applyTimestamp(state, tc);
+ applyOrder(state, tc);
+ applyPage(state, tc);
+ return state;
+ }
+
+ /**
+ * Deserialize a {@code get} {@link TCommand} into a
+ * {@link GetCommand.SourceState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeGet(TCommand tc) {
+ GetCommand.SourceState state = new GetCommand.SourceState(getKeys(tc),
+ getRecords(tc), getCriteria(tc), tc.getCondition());
+ applyTimestamp(state, tc);
+ applyOrder(state, tc);
+ applyPage(state, tc);
+ return state;
+ }
+
+ /**
+ * Deserialize a {@code navigate} {@link TCommand} into a
+ * {@link NavigateCommand.SourceState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeNavigate(TCommand tc) {
+ NavigateCommand.SourceState state = new NavigateCommand.SourceState(
+ tc.getKeys(), getRecords(tc), getCriteria(tc),
+ tc.getCondition());
+ applyTimestamp(state, tc);
+ return state;
+ }
+
+ /**
+ * Deserialize an {@code add} {@link TCommand} into either an
+ * {@link AddCommand.RecordState} or {@link AddCommand.ValueState},
+ * depending on whether records are specified.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeAdd(TCommand tc) {
+ String key = tc.getKeys().get(0);
+ Object value = Convert.thriftToJava(tc.getValue());
+ if(tc.isSetRecords()) {
+ return new AddCommand.RecordState(key, value, tc.getRecords());
+ }
+ else {
+ return new AddCommand.ValueState(key, value);
+ }
+ }
+
+ /**
+ * Deserialize a {@code set} {@link TCommand} into a
+ * {@link SetCommand.RecordState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeSet(TCommand tc) {
+ return new SetCommand.RecordState(tc.getKeys().get(0),
+ Convert.thriftToJava(tc.getValue()), tc.getRecords());
+ }
+
+ /**
+ * Deserialize a {@code remove} {@link TCommand} into a
+ * {@link RemoveCommand.RecordState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeRemove(TCommand tc) {
+ Object value = tc.isSetValue() ? Convert.thriftToJava(tc.getValue())
+ : null;
+ return new RemoveCommand.RecordState(tc.getKeys().get(0), value,
+ tc.getRecords());
+ }
+
+ /**
+ * Deserialize a {@code clear} {@link TCommand} into a
+ * {@link ClearCommand.RecordState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeClear(TCommand tc) {
+ List keys = tc.isSetKeys() ? tc.getKeys() : null;
+ List records = tc.getRecords();
+ return new ClearCommand.RecordState(keys, records.get(0),
+ tail(records));
+ }
+
+ /**
+ * Deserialize an {@code insert} {@link TCommand} into either an
+ * {@link InsertCommand.RecordState} or {@link InsertCommand.JsonState},
+ * depending on whether records are specified.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeInsert(TCommand tc) {
+ if(tc.isSetRecords()) {
+ return new InsertCommand.RecordState(tc.getJson(), tc.getRecords());
+ }
+ else {
+ return new InsertCommand.JsonState(tc.getJson());
+ }
+ }
+
+ /**
+ * Deserialize a {@code link} {@link TCommand} into a
+ * {@link LinkCommand.DestinationState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeLink(TCommand tc) {
+ return new LinkCommand.DestinationState(tc.getKeys().get(0),
+ tc.getSourceRecord(), tc.getRecords());
+ }
+
+ /**
+ * Deserialize an {@code unlink} {@link TCommand} into an
+ * {@link UnlinkCommand.DestinationState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeUnlink(TCommand tc) {
+ return new UnlinkCommand.DestinationState(tc.getKeys().get(0),
+ tc.getSourceRecord(), tc.getRecords().get(0));
+ }
+
+ /**
+ * Deserialize a {@code verify} {@link TCommand} into either a
+ * {@link VerifyCommand.TimestampState} or
+ * {@link VerifyCommand.RecordState}, depending on whether a timestamp is
+ * specified.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeVerify(TCommand tc) {
+ String key = tc.getKeys().get(0);
+ Object value = Convert.thriftToJava(tc.getValue());
+ long record = tc.getRecords().get(0);
+ if(tc.isSetTimestamp()) {
+ return new VerifyCommand.TimestampState(key, value, record,
+ Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ else {
+ return new VerifyCommand.RecordState(key, value, record);
+ }
+ }
+
+ /**
+ * Deserialize a {@code verifyAndSwap} {@link TCommand} into a
+ * {@link VerifyAndSwapCommand.SwapState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeVerifyAndSwap(TCommand tc) {
+ return new VerifyAndSwapCommand.SwapState(tc.getKeys().get(0),
+ Convert.thriftToJava(tc.getValue()), tc.getRecords().get(0),
+ Convert.thriftToJava(tc.getReplacement()));
+ }
+
+ /**
+ * Deserialize a {@code verifyOrSet} {@link TCommand} into a
+ * {@link VerifyOrSetCommand.RecordState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeVerifyOrSet(TCommand tc) {
+ return new VerifyOrSetCommand.RecordState(tc.getKeys().get(0),
+ Convert.thriftToJava(tc.getValue()), tc.getRecords().get(0));
+ }
+
+ /**
+ * Deserialize a {@code findOrAdd} {@link TCommand} into a
+ * {@link FindOrAddCommand.ValueState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeFindOrAdd(TCommand tc) {
+ return new FindOrAddCommand.ValueState(tc.getKeys().get(0),
+ Convert.thriftToJava(tc.getValue()));
+ }
+
+ /**
+ * Deserialize a {@code findOrInsert} {@link TCommand} into a
+ * {@link FindOrInsertCommand.JsonState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeFindOrInsert(TCommand tc) {
+ Timestamp ts = tc.isSetTimestamp()
+ ? Timestamp.fromMicros(tc.getTimestamp())
+ : null;
+ return new FindOrInsertCommand.JsonState(getCriteria(tc),
+ tc.getCondition(), ts, tc.getJson());
+ }
+
+ /**
+ * Deserialize a {@code search} {@link TCommand} into a
+ * {@link SearchCommand.QueryState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeSearch(TCommand tc) {
+ return new SearchCommand.QueryState(tc.getKeys().get(0), tc.getQuery());
+ }
+
+ /**
+ * Deserialize a {@code browse} {@link TCommand} into a
+ * {@link BrowseCommand.State}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeBrowse(TCommand tc) {
+ List keys = tc.getKeys();
+ BrowseCommand.State state = new BrowseCommand.State(keys.get(0),
+ keys.subList(1, keys.size()).toArray(new String[0]));
+ applyTimestamp(state, tc);
+ return state;
+ }
+
+ /**
+ * Deserialize a {@code describe} {@link TCommand} into either a
+ * {@link DescribeCommand.State} or {@link DescribeCommand.AllState},
+ * depending on whether records are specified.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeDescribe(TCommand tc) {
+ if(tc.isSetRecords()) {
+ List records = tc.getRecords();
+ DescribeCommand.State state = new DescribeCommand.State(
+ records.get(0), tail(records));
+ applyTimestamp(state, tc);
+ return state;
+ }
+ else {
+ DescribeCommand.AllState state = new DescribeCommand.AllState();
+ applyTimestamp(state, tc);
+ return state;
+ }
+ }
+
+ /**
+ * Deserialize a {@code trace} {@link TCommand} into a
+ * {@link TraceCommand.State}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeTrace(TCommand tc) {
+ List records = tc.getRecords();
+ TraceCommand.State state = new TraceCommand.State(records.get(0),
+ tail(records));
+ applyTimestamp(state, tc);
+ return state;
+ }
+
+ /**
+ * Deserialize a {@code holds} {@link TCommand} into a
+ * {@link HoldsCommand.State}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeHolds(TCommand tc) {
+ List records = tc.getRecords();
+ return new HoldsCommand.State(records.get(0), tail(records));
+ }
+
+ /**
+ * Deserialize a {@code jsonify} {@link TCommand} into a
+ * {@link JsonifyCommand.State}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeJsonify(TCommand tc) {
+ List records = tc.getRecords();
+ JsonifyCommand.State state = new JsonifyCommand.State(records.get(0),
+ tail(records));
+ applyTimestamp(state, tc);
+ return state;
+ }
+
+ /**
+ * Deserialize a {@code chronicle} {@link TCommand} into the appropriate
+ * {@link ChronicleCommand} state, depending on which timestamp fields are
+ * set.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeChronicle(TCommand tc) {
+ String key = tc.getKeys().get(0);
+ long record = tc.getRecords().get(0);
+ if(tc.isSetEndTimestamp()) {
+ return new ChronicleCommand.RangeState(key, record,
+ Timestamp.fromMicros(tc.getTimestamp()),
+ Timestamp.fromMicros(tc.getEndTimestamp()));
+ }
+ else if(tc.isSetTimestamp()) {
+ return new ChronicleCommand.TimestampState(key, record,
+ Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ else {
+ return new ChronicleCommand.RecordState(key, record);
+ }
+ }
+
+ /**
+ * Deserialize a {@code diff} {@link TCommand} into the appropriate
+ * {@link DiffCommand} state, depending on which fields are set.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeDiff(TCommand tc) {
+ boolean hasKey = tc.isSetKeys();
+ boolean hasRecord = tc.isSetRecords();
+ boolean hasEnd = tc.isSetEndTimestamp();
+ Timestamp start = Timestamp.fromMicros(tc.getTimestamp());
+ if(hasKey && hasRecord && hasEnd) {
+ return new DiffCommand.KeyRecordRangeState(tc.getKeys().get(0),
+ tc.getRecords().get(0), start,
+ Timestamp.fromMicros(tc.getEndTimestamp()));
+ }
+ else if(hasKey && hasRecord) {
+ return new DiffCommand.KeyRecordTimestampState(tc.getKeys().get(0),
+ tc.getRecords().get(0), start);
+ }
+ else if(hasKey && hasEnd) {
+ return new DiffCommand.KeyRangeState(tc.getKeys().get(0), start,
+ Timestamp.fromMicros(tc.getEndTimestamp()));
+ }
+ else if(hasKey) {
+ return new DiffCommand.KeyTimestampState(tc.getKeys().get(0),
+ start);
+ }
+ else if(hasEnd) {
+ return new DiffCommand.RecordRangeState(tc.getRecords().get(0),
+ start, Timestamp.fromMicros(tc.getEndTimestamp()));
+ }
+ else {
+ return new DiffCommand.RecordTimestampState(tc.getRecords().get(0),
+ start);
+ }
+ }
+
+ /**
+ * Deserialize an {@code audit} {@link TCommand} into the appropriate
+ * {@link AuditCommand} state, depending on which fields are set.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeAudit(TCommand tc) {
+ boolean hasKey = tc.isSetKeys();
+ boolean hasTimestamp = tc.isSetTimestamp();
+ boolean hasEnd = tc.isSetEndTimestamp();
+ if(hasKey && hasTimestamp && hasEnd) {
+ return new AuditCommand.KeyRecordRangeState(tc.getKeys().get(0),
+ tc.getRecords().get(0),
+ Timestamp.fromMicros(tc.getTimestamp()),
+ Timestamp.fromMicros(tc.getEndTimestamp()));
+ }
+ else if(hasKey && hasTimestamp) {
+ return new AuditCommand.KeyRecordTimestampState(tc.getKeys().get(0),
+ tc.getRecords().get(0),
+ Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ else if(hasKey) {
+ return new AuditCommand.KeyRecordState(tc.getKeys().get(0),
+ tc.getRecords().get(0));
+ }
+ else if(hasTimestamp && hasEnd) {
+ return new AuditCommand.RecordRangeState(tc.getRecords().get(0),
+ Timestamp.fromMicros(tc.getTimestamp()),
+ Timestamp.fromMicros(tc.getEndTimestamp()));
+ }
+ else if(hasTimestamp) {
+ return new AuditCommand.RecordTimestampState(tc.getRecords().get(0),
+ Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ else {
+ return new AuditCommand.RecordState(tc.getRecords().get(0));
+ }
+ }
+
+ /**
+ * Deserialize a {@code revert} {@link TCommand} into a
+ * {@link RevertCommand.TimestampState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeRevert(TCommand tc) {
+ return new RevertCommand.TimestampState(tc.getKeys(), tc.getRecords(),
+ Timestamp.fromMicros(tc.getTimestamp()));
+ }
+
+ /**
+ * Deserialize a {@code reconcile} {@link TCommand} into a
+ * {@link ReconcileCommand.ValuesState}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeReconcile(TCommand tc) {
+ List values = tc.getValues().stream().map(Convert::thriftToJava)
+ .collect(Collectors.toList());
+ return new ReconcileCommand.ValuesState(tc.getKeys().get(0),
+ tc.getRecords().get(0), values);
+ }
+
+ /**
+ * Deserialize a {@code consolidate} {@link TCommand} into a
+ * {@link ConsolidateCommand.State}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeConsolidate(TCommand tc) {
+ List records = tc.getRecords();
+ return new ConsolidateCommand.State(records.get(0), records.get(1),
+ tail(records, 2));
+ }
+
+ /**
+ * Deserialize a {@code calculate} {@link TCommand} into a
+ * {@link CalculateCommand.State}.
+ *
+ * @param tc the {@link TCommand} to deserialize
+ * @return the deserialized {@link Command}
+ */
+ private static Command deserializeCalculate(TCommand tc) {
+ CalculateCommand.State state = new CalculateCommand.State(
+ tc.getFunction(), tc.getKeys().get(0));
+ if(tc.isSetRecords()) {
+ List records = tc.getRecords();
+ state.in(records.get(0), tail(records));
+ }
+ Criteria criteria = getCriteria(tc);
+ if(criteria != null) {
+ state.where(criteria);
+ }
+ else if(tc.isSetCondition()) {
+ state.where(tc.getCondition());
+ }
+ applyTimestamp(state, tc);
+ return state;
+ }
+
+ /**
+ * Return the {@link Criteria} from a {@link TCommand}, or {@code null} if
+ * not set.
+ *
+ * @param tc the {@link TCommand} to extract from
+ * @return the {@link Criteria}, or {@code null}
+ */
+ @Nullable
+ private static Criteria getCriteria(TCommand tc) {
+ return tc.isSetCriteria()
+ ? Language.translateFromThriftCriteria(tc.getCriteria())
+ : null;
+ }
+
+ /**
+ * Return the keys list from a {@link TCommand}, or {@code null} if not set.
+ *
+ * @param tc the {@link TCommand} to extract from
+ * @return the keys {@link List}, or {@code null}
+ */
+ @Nullable
+ private static List getKeys(TCommand tc) {
+ return tc.isSetKeys() ? tc.getKeys() : null;
+ }
+
+ /**
+ * Return the records list from a {@link TCommand}, or {@code null} if not
+ * set.
+ *
+ * @param tc the {@link TCommand} to extract from
+ * @return the records {@link List}, or {@code null}
+ */
+ @Nullable
+ private static List getRecords(TCommand tc) {
+ return tc.isSetRecords() ? tc.getRecords() : null;
+ }
+
+ /**
+ * Apply the optional timestamp from a {@link TCommand} to a
+ * {@link FindCommand.ConditionState}.
+ *
+ * @param state the {@link FindCommand.ConditionState} to modify
+ * @param tc the {@link TCommand} containing the timestamp
+ */
+ private static void applyTimestamp(FindCommand.ConditionState state,
+ TCommand tc) {
+ if(tc.isSetTimestamp()) {
+ state.at(Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ }
+
+ /**
+ * Apply the optional order from a {@link TCommand} to a
+ * {@link FindCommand.ConditionState}.
+ *
+ * @param state the {@link FindCommand.ConditionState} to modify
+ * @param tc the {@link TCommand} containing the order
+ */
+ private static void applyOrder(FindCommand.ConditionState state,
+ TCommand tc) {
+ if(tc.isSetOrder()) {
+ state.order(JavaThriftBridge.convert(tc.getOrder()));
+ }
+ }
+
+ /**
+ * Apply the optional page from a {@link TCommand} to a
+ * {@link FindCommand.ConditionState}.
+ *
+ * @param state the {@link FindCommand.ConditionState} to modify
+ * @param tc the {@link TCommand} containing the page
+ */
+ private static void applyPage(FindCommand.ConditionState state,
+ TCommand tc) {
+ if(tc.isSetPage()) {
+ state.page(JavaThriftBridge.convert(tc.getPage()));
+ }
+ }
+
+ /**
+ * Apply the optional timestamp from a {@link TCommand} to a
+ * {@link SelectCommand.SourceState}.
+ *
+ * @param state the {@link SelectCommand.SourceState} to modify
+ * @param tc the {@link TCommand} containing the timestamp
+ */
+ private static void applyTimestamp(SelectCommand.SourceState state,
+ TCommand tc) {
+ if(tc.isSetTimestamp()) {
+ state.at(Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ }
+
+ /**
+ * Apply the optional order from a {@link TCommand} to a
+ * {@link SelectCommand.SourceState}.
+ *
+ * @param state the {@link SelectCommand.SourceState} to modify
+ * @param tc the {@link TCommand} containing the order
+ */
+ private static void applyOrder(SelectCommand.SourceState state,
+ TCommand tc) {
+ if(tc.isSetOrder()) {
+ state.order(JavaThriftBridge.convert(tc.getOrder()));
+ }
+ }
+
+ /**
+ * Apply the optional page from a {@link TCommand} to a
+ * {@link SelectCommand.SourceState}.
+ *
+ * @param state the {@link SelectCommand.SourceState} to modify
+ * @param tc the {@link TCommand} containing the page
+ */
+ private static void applyPage(SelectCommand.SourceState state,
+ TCommand tc) {
+ if(tc.isSetPage()) {
+ state.page(JavaThriftBridge.convert(tc.getPage()));
+ }
+ }
+
+ /**
+ * Apply the optional timestamp from a {@link TCommand} to a
+ * {@link GetCommand.SourceState}.
+ *
+ * @param state the {@link GetCommand.SourceState} to modify
+ * @param tc the {@link TCommand} containing the timestamp
+ */
+ private static void applyTimestamp(GetCommand.SourceState state,
+ TCommand tc) {
+ if(tc.isSetTimestamp()) {
+ state.at(Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ }
+
+ /**
+ * Apply the optional order from a {@link TCommand} to a
+ * {@link GetCommand.SourceState}.
+ *
+ * @param state the {@link GetCommand.SourceState} to modify
+ * @param tc the {@link TCommand} containing the order
+ */
+ private static void applyOrder(GetCommand.SourceState state, TCommand tc) {
+ if(tc.isSetOrder()) {
+ state.order(JavaThriftBridge.convert(tc.getOrder()));
+ }
+ }
+
+ /**
+ * Apply the optional page from a {@link TCommand} to a
+ * {@link GetCommand.SourceState}.
+ *
+ * @param state the {@link GetCommand.SourceState} to modify
+ * @param tc the {@link TCommand} containing the page
+ */
+ private static void applyPage(GetCommand.SourceState state, TCommand tc) {
+ if(tc.isSetPage()) {
+ state.page(JavaThriftBridge.convert(tc.getPage()));
+ }
+ }
+
+ /**
+ * Apply the optional timestamp from a {@link TCommand} to a
+ * {@link NavigateCommand.SourceState}.
+ *
+ * @param state the {@link NavigateCommand.SourceState} to modify
+ * @param tc the {@link TCommand} containing the timestamp
+ */
+ private static void applyTimestamp(NavigateCommand.SourceState state,
+ TCommand tc) {
+ if(tc.isSetTimestamp()) {
+ state.at(Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ }
+
+ /**
+ * Apply the optional timestamp from a {@link TCommand} to a
+ * {@link BrowseCommand.State}.
+ *
+ * @param state the {@link BrowseCommand.State} to modify
+ * @param tc the {@link TCommand} containing the timestamp
+ */
+ private static void applyTimestamp(BrowseCommand.State state, TCommand tc) {
+ if(tc.isSetTimestamp()) {
+ state.at(Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ }
+
+ /**
+ * Apply the optional timestamp from a {@link TCommand} to a
+ * {@link DescribeCommand.State}.
+ *
+ * @param state the {@link DescribeCommand.State} to modify
+ * @param tc the {@link TCommand} containing the timestamp
+ */
+ private static void applyTimestamp(DescribeCommand.State state,
+ TCommand tc) {
+ if(tc.isSetTimestamp()) {
+ state.at(Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ }
+
+ /**
+ * Apply the optional timestamp from a {@link TCommand} to a
+ * {@link DescribeCommand.AllState}.
+ *
+ * @param state the {@link DescribeCommand.AllState} to modify
+ * @param tc the {@link TCommand} containing the timestamp
+ */
+ private static void applyTimestamp(DescribeCommand.AllState state,
+ TCommand tc) {
+ if(tc.isSetTimestamp()) {
+ state.at(Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ }
+
+ /**
+ * Apply the optional timestamp from a {@link TCommand} to a
+ * {@link TraceCommand.State}.
+ *
+ * @param state the {@link TraceCommand.State} to modify
+ * @param tc the {@link TCommand} containing the timestamp
+ */
+ private static void applyTimestamp(TraceCommand.State state, TCommand tc) {
+ if(tc.isSetTimestamp()) {
+ state.at(Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ }
+
+ /**
+ * Apply the optional timestamp from a {@link TCommand} to a
+ * {@link JsonifyCommand.State}.
+ *
+ * @param state the {@link JsonifyCommand.State} to modify
+ * @param tc the {@link TCommand} containing the timestamp
+ */
+ private static void applyTimestamp(JsonifyCommand.State state,
+ TCommand tc) {
+ if(tc.isSetTimestamp()) {
+ state.at(Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ }
+
+ /**
+ * Apply the optional timestamp from a {@link TCommand} to a
+ * {@link CalculateCommand.State}.
+ *
+ * @param state the {@link CalculateCommand.State} to modify
+ * @param tc the {@link TCommand} containing the timestamp
+ */
+ private static void applyTimestamp(CalculateCommand.State state,
+ TCommand tc) {
+ if(tc.isSetTimestamp()) {
+ state.at(Timestamp.fromMicros(tc.getTimestamp()));
+ }
+ }
+
+ /**
+ * Extract all elements after the first from a {@link List} of {@link Long
+ * Longs} as a {@code long} array.
+ *
+ * @param list the {@link List} to extract from
+ * @return the tail as a {@code long} array
+ */
+ private static long[] tail(List list) {
+ return tail(list, 1);
+ }
+
+ /**
+ * Extract all elements starting at {@code offset} from a {@link List} of
+ * {@link Long Longs} as a {@code long} array.
+ *
+ * @param list the {@link List} to extract from
+ * @param offset the starting index
+ * @return the sub-list as a {@code long} array
+ */
+ private static long[] tail(List list, int offset) {
+ long[] arr = new long[list.size() - offset];
+ for (int i = offset; i < list.size(); i++) {
+ arr[i - offset] = list.get(i);
+ }
+ return arr;
+ }
+
+ /**
+ * Serialize a nullary {@link BuiltCommand} into a {@link TCommand}.
+ *
+ * @param command the {@link BuiltCommand} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeBuiltCommand(BuiltCommand command) {
+ String verb = command.ccl().toUpperCase();
+ return new TCommand(TCommandVerb.valueOf(verb));
+ }
+
+ /**
+ * Serialize a {@code find} {@link FindCommand.ConditionState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link FindCommand.ConditionState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeFindCommand(
+ FindCommand.ConditionState state) {
+ TCommand tc = new TCommand(TCommandVerb.FIND);
+ setCondition(tc, state.criteria(), state.condition());
+ setTimestamp(tc, state.timestamp());
+ setOrder(tc, state.order());
+ setPage(tc, state.page());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code select} {@link SelectCommand.SourceState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link SelectCommand.SourceState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeSelectCommand(
+ SelectCommand.SourceState state) {
+ TCommand tc = new TCommand(TCommandVerb.SELECT);
+ setKeys(tc, state.keys());
+ setRecords(tc, state.records());
+ setCondition(tc, state.criteria(), state.condition());
+ setTimestamp(tc, state.timestamp());
+ setOrder(tc, state.order());
+ setPage(tc, state.page());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code get} {@link GetCommand.SourceState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link GetCommand.SourceState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeGetCommand(GetCommand.SourceState state) {
+ TCommand tc = new TCommand(TCommandVerb.GET);
+ setKeys(tc, state.keys());
+ setRecords(tc, state.records());
+ setCondition(tc, state.criteria(), state.condition());
+ setTimestamp(tc, state.timestamp());
+ setOrder(tc, state.order());
+ setPage(tc, state.page());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code navigate} {@link NavigateCommand.SourceState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link NavigateCommand.SourceState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeNavigateCommand(
+ NavigateCommand.SourceState state) {
+ TCommand tc = new TCommand(TCommandVerb.NAVIGATE);
+ setKeys(tc, state.keys());
+ setRecords(tc, state.records());
+ setCondition(tc, state.criteria(), state.condition());
+ setTimestamp(tc, state.timestamp());
+ return tc;
+ }
+
+ /**
+ * Serialize an {@code add} {@link AddCommand.RecordState} into a
+ * {@link TCommand} with record targets.
+ *
+ * @param state the {@link AddCommand.RecordState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeAddRecordCommand(
+ AddCommand.RecordState state) {
+ TCommand tc = new TCommand(TCommandVerb.ADD);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setValue(Convert.javaToThrift(state.value()));
+ tc.setRecords(state.records());
+ return tc;
+ }
+
+ /**
+ * Serialize an {@code add} {@link AddCommand.ValueState} into a
+ * {@link TCommand} without record targets.
+ *
+ * @param state the {@link AddCommand.ValueState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeAddValueCommand(
+ AddCommand.ValueState state) {
+ TCommand tc = new TCommand(TCommandVerb.ADD);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setValue(Convert.javaToThrift(state.value()));
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code set} {@link SetCommand.RecordState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link SetCommand.RecordState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeSetCommand(SetCommand.RecordState state) {
+ TCommand tc = new TCommand(TCommandVerb.SET);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setValue(Convert.javaToThrift(state.value()));
+ tc.setRecords(state.records());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code remove} {@link RemoveCommand.RecordState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link RemoveCommand.RecordState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeRemoveCommand(
+ RemoveCommand.RecordState state) {
+ TCommand tc = new TCommand(TCommandVerb.REMOVE);
+ tc.setKeys(Collections.singletonList(state.key()));
+ if(state.value() != null) {
+ tc.setValue(Convert.javaToThrift(state.value()));
+ }
+ tc.setRecords(state.records());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code clear} {@link ClearCommand.RecordState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link ClearCommand.RecordState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeClearCommand(
+ ClearCommand.RecordState state) {
+ TCommand tc = new TCommand(TCommandVerb.CLEAR);
+ if(state.keys() != null) {
+ tc.setKeys(state.keys());
+ }
+ tc.setRecords(state.records());
+ return tc;
+ }
+
+ /**
+ * Serialize an {@code insert} {@link InsertCommand.RecordState} into a
+ * {@link TCommand} with record targets.
+ *
+ * @param state the {@link InsertCommand.RecordState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeInsertRecordCommand(
+ InsertCommand.RecordState state) {
+ TCommand tc = new TCommand(TCommandVerb.INSERT);
+ tc.setJson(state.json());
+ tc.setRecords(state.records());
+ return tc;
+ }
+
+ /**
+ * Serialize an {@code insert} {@link InsertCommand.JsonState} into a
+ * {@link TCommand} without record targets.
+ *
+ * @param state the {@link InsertCommand.JsonState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeInsertJsonCommand(
+ InsertCommand.JsonState state) {
+ TCommand tc = new TCommand(TCommandVerb.INSERT);
+ tc.setJson(state.json());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code link} {@link LinkCommand.DestinationState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link LinkCommand.DestinationState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeLinkCommand(
+ LinkCommand.DestinationState state) {
+ TCommand tc = new TCommand(TCommandVerb.LINK);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setSourceRecord(state.source());
+ tc.setRecords(state.destinations());
+ return tc;
+ }
+
+ /**
+ * Serialize an {@code unlink} {@link UnlinkCommand.DestinationState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link UnlinkCommand.DestinationState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeUnlinkCommand(
+ UnlinkCommand.DestinationState state) {
+ TCommand tc = new TCommand(TCommandVerb.UNLINK);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setSourceRecord(state.source());
+ tc.setRecords(Collections.singletonList(state.destination()));
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code verify} {@link VerifyCommand.RecordState} into a
+ * {@link TCommand} without a timestamp.
+ *
+ * @param state the {@link VerifyCommand.RecordState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeVerifyCommand(
+ VerifyCommand.RecordState state) {
+ TCommand tc = new TCommand(TCommandVerb.VERIFY);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setValue(Convert.javaToThrift(state.value()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code verify} {@link VerifyCommand.TimestampState} into a
+ * {@link TCommand} with a timestamp.
+ *
+ * @param state the {@link VerifyCommand.TimestampState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeVerifyTimestampCommand(
+ VerifyCommand.TimestampState state) {
+ TCommand tc = new TCommand(TCommandVerb.VERIFY);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setValue(Convert.javaToThrift(state.value()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ tc.setTimestamp(state.timestamp().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code verifyAndSwap} {@link VerifyAndSwapCommand.SwapState}
+ * into a {@link TCommand}.
+ *
+ * @param state the {@link VerifyAndSwapCommand.SwapState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeVerifyAndSwapCommand(
+ VerifyAndSwapCommand.SwapState state) {
+ TCommand tc = new TCommand(TCommandVerb.VERIFY_AND_SWAP);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setValue(Convert.javaToThrift(state.expected()));
+ tc.setReplacement(Convert.javaToThrift(state.replacement()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code verifyOrSet} {@link VerifyOrSetCommand.RecordState}
+ * into a {@link TCommand}.
+ *
+ * @param state the {@link VerifyOrSetCommand.RecordState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeVerifyOrSetCommand(
+ VerifyOrSetCommand.RecordState state) {
+ TCommand tc = new TCommand(TCommandVerb.VERIFY_OR_SET);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setValue(Convert.javaToThrift(state.value()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code findOrAdd} {@link FindOrAddCommand.ValueState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link FindOrAddCommand.ValueState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeFindOrAddCommand(
+ FindOrAddCommand.ValueState state) {
+ TCommand tc = new TCommand(TCommandVerb.FIND_OR_ADD);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setValue(Convert.javaToThrift(state.value()));
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code findOrInsert} {@link FindOrInsertCommand.JsonState}
+ * into a {@link TCommand}.
+ *
+ * @param state the {@link FindOrInsertCommand.JsonState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeFindOrInsertCommand(
+ FindOrInsertCommand.JsonState state) {
+ TCommand tc = new TCommand(TCommandVerb.FIND_OR_INSERT);
+ setCondition(tc, state.criteria(), state.condition());
+ setTimestamp(tc, state.timestamp());
+ tc.setJson(state.json());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code search} {@link SearchCommand.QueryState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link SearchCommand.QueryState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeSearchCommand(
+ SearchCommand.QueryState state) {
+ TCommand tc = new TCommand(TCommandVerb.SEARCH);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setQuery(state.query());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code browse} {@link BrowseCommand.State} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link BrowseCommand.State} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeBrowseCommand(BrowseCommand.State state) {
+ TCommand tc = new TCommand(TCommandVerb.BROWSE);
+ tc.setKeys(state.keys());
+ setTimestamp(tc, state.timestamp());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code describe} {@link DescribeCommand.AllState} into a
+ * {@link TCommand} without records.
+ *
+ * @param state the {@link DescribeCommand.AllState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeDescribeAllCommand(
+ DescribeCommand.AllState state) {
+ TCommand tc = new TCommand(TCommandVerb.DESCRIBE);
+ setTimestamp(tc, state.timestamp());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code describe} {@link DescribeCommand.State} into a
+ * {@link TCommand} with records.
+ *
+ * @param state the {@link DescribeCommand.State} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeDescribeCommand(
+ DescribeCommand.State state) {
+ TCommand tc = new TCommand(TCommandVerb.DESCRIBE);
+ tc.setRecords(state.records());
+ setTimestamp(tc, state.timestamp());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code trace} {@link TraceCommand.State} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link TraceCommand.State} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeTraceCommand(TraceCommand.State state) {
+ TCommand tc = new TCommand(TCommandVerb.TRACE);
+ tc.setRecords(state.records());
+ setTimestamp(tc, state.timestamp());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code holds} {@link HoldsCommand.State} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link HoldsCommand.State} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeHoldsCommand(HoldsCommand.State state) {
+ TCommand tc = new TCommand(TCommandVerb.HOLDS);
+ tc.setRecords(state.records());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code jsonify} {@link JsonifyCommand.State} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link JsonifyCommand.State} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeJsonifyCommand(
+ JsonifyCommand.State state) {
+ TCommand tc = new TCommand(TCommandVerb.JSONIFY);
+ tc.setRecords(state.records());
+ setTimestamp(tc, state.timestamp());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code chronicle} {@link ChronicleCommand.RangeState} into a
+ * {@link TCommand} with a time range.
+ *
+ * @param state the {@link ChronicleCommand.RangeState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeChronicleRangeCommand(
+ ChronicleCommand.RangeState state) {
+ TCommand tc = new TCommand(TCommandVerb.CHRONICLE);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ tc.setTimestamp(state.start().getMicros());
+ tc.setEndTimestamp(state.end().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code chronicle} {@link ChronicleCommand.TimestampState}
+ * into a {@link TCommand} with a start timestamp.
+ *
+ * @param state the {@link ChronicleCommand.TimestampState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeChronicleTimestampCommand(
+ ChronicleCommand.TimestampState state) {
+ TCommand tc = new TCommand(TCommandVerb.CHRONICLE);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ tc.setTimestamp(state.start().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code chronicle} {@link ChronicleCommand.RecordState} into a
+ * {@link TCommand} without timestamps.
+ *
+ * @param state the {@link ChronicleCommand.RecordState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeChronicleRecordCommand(
+ ChronicleCommand.RecordState state) {
+ TCommand tc = new TCommand(TCommandVerb.CHRONICLE);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code diff} {@link DiffCommand.KeyRecordRangeState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link DiffCommand.KeyRecordRangeState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeDiffCommand(
+ DiffCommand.KeyRecordRangeState state) {
+ TCommand tc = new TCommand(TCommandVerb.DIFF);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ tc.setTimestamp(state.start().getMicros());
+ tc.setEndTimestamp(state.end().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code diff} {@link DiffCommand.KeyRecordTimestampState} into
+ * a {@link TCommand}.
+ *
+ * @param state the {@link DiffCommand.KeyRecordTimestampState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeDiffCommand(
+ DiffCommand.KeyRecordTimestampState state) {
+ TCommand tc = new TCommand(TCommandVerb.DIFF);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ tc.setTimestamp(state.start().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code diff} {@link DiffCommand.KeyRangeState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link DiffCommand.KeyRangeState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeDiffCommand(
+ DiffCommand.KeyRangeState state) {
+ TCommand tc = new TCommand(TCommandVerb.DIFF);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setTimestamp(state.start().getMicros());
+ tc.setEndTimestamp(state.end().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code diff} {@link DiffCommand.KeyTimestampState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link DiffCommand.KeyTimestampState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeDiffCommand(
+ DiffCommand.KeyTimestampState state) {
+ TCommand tc = new TCommand(TCommandVerb.DIFF);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setTimestamp(state.start().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code diff} {@link DiffCommand.RecordRangeState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link DiffCommand.RecordRangeState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeDiffCommand(
+ DiffCommand.RecordRangeState state) {
+ TCommand tc = new TCommand(TCommandVerb.DIFF);
+ tc.setRecords(Collections.singletonList(state.record()));
+ tc.setTimestamp(state.start().getMicros());
+ tc.setEndTimestamp(state.end().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code diff} {@link DiffCommand.RecordTimestampState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link DiffCommand.RecordTimestampState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeDiffCommand(
+ DiffCommand.RecordTimestampState state) {
+ TCommand tc = new TCommand(TCommandVerb.DIFF);
+ tc.setRecords(Collections.singletonList(state.record()));
+ tc.setTimestamp(state.start().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize an {@code audit} {@link AuditCommand.KeyRecordRangeState} into
+ * a {@link TCommand}.
+ *
+ * @param state the {@link AuditCommand.KeyRecordRangeState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeAuditCommand(
+ AuditCommand.KeyRecordRangeState state) {
+ TCommand tc = new TCommand(TCommandVerb.AUDIT);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ tc.setTimestamp(state.start().getMicros());
+ tc.setEndTimestamp(state.end().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize an {@code audit} {@link AuditCommand.KeyRecordTimestampState}
+ * into a {@link TCommand}.
+ *
+ * @param state the {@link AuditCommand.KeyRecordTimestampState} to
+ * serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeAuditCommand(
+ AuditCommand.KeyRecordTimestampState state) {
+ TCommand tc = new TCommand(TCommandVerb.AUDIT);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ tc.setTimestamp(state.start().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize an {@code audit} {@link AuditCommand.RecordRangeState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link AuditCommand.RecordRangeState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeAuditCommand(
+ AuditCommand.RecordRangeState state) {
+ TCommand tc = new TCommand(TCommandVerb.AUDIT);
+ tc.setRecords(Collections.singletonList(state.record()));
+ tc.setTimestamp(state.start().getMicros());
+ tc.setEndTimestamp(state.end().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize an {@code audit} {@link AuditCommand.RecordTimestampState} into
+ * a {@link TCommand}.
+ *
+ * @param state the {@link AuditCommand.RecordTimestampState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeAuditCommand(
+ AuditCommand.RecordTimestampState state) {
+ TCommand tc = new TCommand(TCommandVerb.AUDIT);
+ tc.setRecords(Collections.singletonList(state.record()));
+ tc.setTimestamp(state.start().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize an {@code audit} {@link AuditCommand.KeyRecordState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link AuditCommand.KeyRecordState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeAuditCommand(
+ AuditCommand.KeyRecordState state) {
+ TCommand tc = new TCommand(TCommandVerb.AUDIT);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ return tc;
+ }
+
+ /**
+ * Serialize an {@code audit} {@link AuditCommand.RecordState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link AuditCommand.RecordState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeAuditCommand(
+ AuditCommand.RecordState state) {
+ TCommand tc = new TCommand(TCommandVerb.AUDIT);
+ tc.setRecords(Collections.singletonList(state.record()));
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code revert} {@link RevertCommand.TimestampState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link RevertCommand.TimestampState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeRevertCommand(
+ RevertCommand.TimestampState state) {
+ TCommand tc = new TCommand(TCommandVerb.REVERT);
+ tc.setKeys(state.keys());
+ tc.setRecords(state.records());
+ tc.setTimestamp(state.timestamp().getMicros());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code reconcile} {@link ReconcileCommand.ValuesState} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link ReconcileCommand.ValuesState} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeReconcileCommand(
+ ReconcileCommand.ValuesState state) {
+ TCommand tc = new TCommand(TCommandVerb.RECONCILE);
+ tc.setKeys(Collections.singletonList(state.key()));
+ tc.setRecords(Collections.singletonList(state.record()));
+ List tvalues = state.values().stream()
+ .map(Convert::javaToThrift).collect(Collectors.toList());
+ tc.setValues(tvalues);
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code consolidate} {@link ConsolidateCommand.State} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link ConsolidateCommand.State} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeConsolidateCommand(
+ ConsolidateCommand.State state) {
+ TCommand tc = new TCommand(TCommandVerb.CONSOLIDATE);
+ tc.setRecords(state.records());
+ return tc;
+ }
+
+ /**
+ * Serialize a {@code calculate} {@link CalculateCommand.State} into a
+ * {@link TCommand}.
+ *
+ * @param state the {@link CalculateCommand.State} to serialize
+ * @return the {@link TCommand}
+ */
+ private static TCommand serializeCalculateCommand(
+ CalculateCommand.State state) {
+ TCommand tc = new TCommand(TCommandVerb.CALCULATE);
+ tc.setFunction(state.function());
+ tc.setKeys(Collections.singletonList(state.key()));
+ if(state.records() != null) {
+ tc.setRecords(state.records());
+ }
+ setCondition(tc, state.criteria(), state.condition());
+ setTimestamp(tc, state.timestamp());
+ return tc;
+ }
+
+ /**
+ * Set the condition fields on a {@link TCommand} from the given
+ * {@link Criteria} or CCL condition string.
+ *
+ * @param tc the {@link TCommand} to modify
+ * @param criteria the {@link Criteria}, or {@code null}
+ * @param condition the CCL condition string, or {@code null}
+ */
+ private static void setCondition(TCommand tc, @Nullable Criteria criteria,
+ @Nullable String condition) {
+ if(criteria != null) {
+ tc.setCriteria(Language.translateToThriftCriteria(criteria));
+ }
+ else if(condition != null) {
+ tc.setCondition(condition);
+ }
+ }
+
+ /**
+ * Set the timestamp field on a {@link TCommand} if the given
+ * {@link Timestamp} is not {@code null}.
+ *
+ * @param tc the {@link TCommand} to modify
+ * @param timestamp the {@link Timestamp}, or {@code null}
+ */
+ private static void setTimestamp(TCommand tc,
+ @Nullable Timestamp timestamp) {
+ if(timestamp != null) {
+ tc.setTimestamp(timestamp.getMicros());
+ }
+ }
+
+ /**
+ * Set the order field on a {@link TCommand} if the given {@link Order} is
+ * not {@code null}.
+ *
+ * @param tc the {@link TCommand} to modify
+ * @param order the {@link Order}, or {@code null}
+ */
+ private static void setOrder(TCommand tc, @Nullable Order order) {
+ if(order != null) {
+ tc.setOrder(JavaThriftBridge.convert(order));
+ }
+ }
+
+ /**
+ * Set the page field on a {@link TCommand} if the given {@link Page} is not
+ * {@code null}.
+ *
+ * @param tc the {@link TCommand} to modify
+ * @param page the {@link Page}, or {@code null}
+ */
+ private static void setPage(TCommand tc, @Nullable Page page) {
+ if(page != null) {
+ tc.setPage(JavaThriftBridge.convert(page));
+ }
+ }
+
+ /**
+ * Set the keys field on a {@link TCommand} from a list that may be
+ * {@code null} or empty (indicating all keys).
+ *
+ * @param tc the {@link TCommand} to modify
+ * @param keys the keys {@link List}, or {@code null}
+ */
+ private static void setKeys(TCommand tc, @Nullable List keys) {
+ if(keys != null && !keys.isEmpty()) {
+ tc.setKeys(keys);
+ }
+ }
+
+ /**
+ * Set the records field on a {@link TCommand} if the given list is not
+ * {@code null}.
+ *
+ * @param tc the {@link TCommand} to modify
+ * @param records the records {@link List}, or {@code null}
+ */
+ private static void setRecords(TCommand tc, @Nullable List records) {
+ if(records != null) {
+ tc.setRecords(records);
+ }
+ }
+
+ /**
+ * Construct a new {@link CommandSerializer}.
+ */
+ private CommandSerializer() {/* no-init */}
+
+}
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/GetCommand.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/GetCommand.java
index e04411b03..8602202cb 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/GetCommand.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/GetCommand.java
@@ -381,6 +381,16 @@ public Criteria criteria() {
return criteria;
}
+ /**
+ * Return the raw CCL condition for this command.
+ *
+ * @return the condition string, or {@code null}
+ */
+ @Nullable
+ public String condition() {
+ return condition;
+ }
+
/**
* Return the historical {@link Timestamp}.
*
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/NavigateCommand.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/NavigateCommand.java
index 9b8c5fad6..dfce1ae44 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/NavigateCommand.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/NavigateCommand.java
@@ -239,6 +239,16 @@ public Criteria criteria() {
return criteria;
}
+ /**
+ * Return the raw CCL condition for this command.
+ *
+ * @return the condition string, or {@code null}
+ */
+ @Nullable
+ public String condition() {
+ return condition;
+ }
+
/**
* Return the historical {@link Timestamp}.
*
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/SelectCommand.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/SelectCommand.java
index 0b2cb5e99..ccb6182ab 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/SelectCommand.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/SelectCommand.java
@@ -381,6 +381,16 @@ public Criteria criteria() {
return criteria;
}
+ /**
+ * Return the raw CCL condition for this command.
+ *
+ * @return the condition string, or {@code null}
+ */
+ @Nullable
+ public String condition() {
+ return condition;
+ }
+
/**
* Return the historical {@link Timestamp}.
*
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/thrift/TCommand.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/thrift/TCommand.java
new file mode 100644
index 000000000..65558dd29
--- /dev/null
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/thrift/TCommand.java
@@ -0,0 +1,2494 @@
+/*
+ * Copyright (c) 2013-2026 Cinchapi 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.cinchapi.concourse.thrift;
+
+/**
+ * A structured representation of a complete Concourse command that can be
+ * transmitted over the wire. Each command is identified by a required verb; the
+ * optional fields carry the parameters appropriate for that verb.
+ *
+ * Reuses existing types (TCriteria, TOrder, TPage, TObject) for condition,
+ * ordering, pagination, and values.
+ */
+@SuppressWarnings({ "cast", "rawtypes", "serial", "unchecked", "unused" })
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.20.0)", date = "2026-03-14")
+public class TCommand implements
+ org.apache.thrift.TBase,
+ java.io.Serializable,
+ Cloneable,
+ Comparable {
+ private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct(
+ "TCommand");
+
+ private static final org.apache.thrift.protocol.TField VERB_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "verb", org.apache.thrift.protocol.TType.I32, (short) 1);
+ private static final org.apache.thrift.protocol.TField KEYS_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "keys", org.apache.thrift.protocol.TType.LIST, (short) 2);
+ private static final org.apache.thrift.protocol.TField RECORDS_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "records", org.apache.thrift.protocol.TType.LIST, (short) 3);
+ private static final org.apache.thrift.protocol.TField CRITERIA_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "criteria", org.apache.thrift.protocol.TType.STRUCT, (short) 4);
+ private static final org.apache.thrift.protocol.TField CONDITION_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "condition", org.apache.thrift.protocol.TType.STRING, (short) 5);
+ private static final org.apache.thrift.protocol.TField TIMESTAMP_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "timestamp", org.apache.thrift.protocol.TType.I64, (short) 6);
+ private static final org.apache.thrift.protocol.TField END_TIMESTAMP_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "endTimestamp", org.apache.thrift.protocol.TType.I64, (short) 7);
+ private static final org.apache.thrift.protocol.TField ORDER_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "order", org.apache.thrift.protocol.TType.STRUCT, (short) 8);
+ private static final org.apache.thrift.protocol.TField PAGE_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "page", org.apache.thrift.protocol.TType.STRUCT, (short) 9);
+ private static final org.apache.thrift.protocol.TField VALUE_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "value", org.apache.thrift.protocol.TType.STRUCT, (short) 10);
+ private static final org.apache.thrift.protocol.TField REPLACEMENT_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "replacement", org.apache.thrift.protocol.TType.STRUCT, (short) 11);
+ private static final org.apache.thrift.protocol.TField VALUES_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "values", org.apache.thrift.protocol.TType.LIST, (short) 12);
+ private static final org.apache.thrift.protocol.TField JSON_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "json", org.apache.thrift.protocol.TType.STRING, (short) 13);
+ private static final org.apache.thrift.protocol.TField QUERY_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "query", org.apache.thrift.protocol.TType.STRING, (short) 14);
+ private static final org.apache.thrift.protocol.TField FUNCTION_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "function", org.apache.thrift.protocol.TType.STRING, (short) 15);
+ private static final org.apache.thrift.protocol.TField SOURCE_RECORD_FIELD_DESC = new org.apache.thrift.protocol.TField(
+ "sourceRecord", org.apache.thrift.protocol.TType.I64, (short) 16);
+
+ private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new TCommandStandardSchemeFactory();
+ private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new TCommandTupleSchemeFactory();
+
+ /**
+ *
+ * @see TCommandVerb
+ */
+ public @org.apache.thrift.annotation.Nullable TCommandVerb verb; // required
+ public @org.apache.thrift.annotation.Nullable java.util.List keys; // optional
+ public @org.apache.thrift.annotation.Nullable java.util.List records; // optional
+ public @org.apache.thrift.annotation.Nullable TCriteria criteria; // optional
+ public @org.apache.thrift.annotation.Nullable java.lang.String condition; // optional
+ public long timestamp; // optional
+ public long endTimestamp; // optional
+ public @org.apache.thrift.annotation.Nullable TOrder order; // optional
+ public @org.apache.thrift.annotation.Nullable TPage page; // optional
+ public @org.apache.thrift.annotation.Nullable TObject value; // optional
+ public @org.apache.thrift.annotation.Nullable TObject replacement; // optional
+ public @org.apache.thrift.annotation.Nullable java.util.List values; // optional
+ public @org.apache.thrift.annotation.Nullable java.lang.String json; // optional
+ public @org.apache.thrift.annotation.Nullable java.lang.String query; // optional
+ public @org.apache.thrift.annotation.Nullable java.lang.String function; // optional
+ public long sourceRecord; // optional
+
+ /**
+ * The set of fields this struct contains, along with convenience methods
+ * for finding and manipulating them.
+ */
+ public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+ /**
+ *
+ * @see TCommandVerb
+ */
+ VERB((short) 1, "verb"),
+ KEYS((short) 2, "keys"),
+ RECORDS((short) 3, "records"),
+ CRITERIA((short) 4, "criteria"),
+ CONDITION((short) 5, "condition"),
+ TIMESTAMP((short) 6, "timestamp"),
+ END_TIMESTAMP((short) 7, "endTimestamp"),
+ ORDER((short) 8, "order"),
+ PAGE((short) 9, "page"),
+ VALUE((short) 10, "value"),
+ REPLACEMENT((short) 11, "replacement"),
+ VALUES((short) 12, "values"),
+ JSON((short) 13, "json"),
+ QUERY((short) 14, "query"),
+ FUNCTION((short) 15, "function"),
+ SOURCE_RECORD((short) 16, "sourceRecord");
+
+ private static final java.util.Map byName = new java.util.HashMap();
+
+ static {
+ for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+ byName.put(field.getFieldName(), field);
+ }
+ }
+
+ /**
+ * Find the _Fields constant that matches fieldId, or null if its not
+ * found.
+ */
+ @org.apache.thrift.annotation.Nullable
+ public static _Fields findByThriftId(int fieldId) {
+ switch (fieldId) {
+ case 1: // VERB
+ return VERB;
+ case 2: // KEYS
+ return KEYS;
+ case 3: // RECORDS
+ return RECORDS;
+ case 4: // CRITERIA
+ return CRITERIA;
+ case 5: // CONDITION
+ return CONDITION;
+ case 6: // TIMESTAMP
+ return TIMESTAMP;
+ case 7: // END_TIMESTAMP
+ return END_TIMESTAMP;
+ case 8: // ORDER
+ return ORDER;
+ case 9: // PAGE
+ return PAGE;
+ case 10: // VALUE
+ return VALUE;
+ case 11: // REPLACEMENT
+ return REPLACEMENT;
+ case 12: // VALUES
+ return VALUES;
+ case 13: // JSON
+ return JSON;
+ case 14: // QUERY
+ return QUERY;
+ case 15: // FUNCTION
+ return FUNCTION;
+ case 16: // SOURCE_RECORD
+ return SOURCE_RECORD;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Find the _Fields constant that matches fieldId, throwing an exception
+ * if it is not found.
+ */
+ public static _Fields findByThriftIdOrThrow(int fieldId) {
+ _Fields fields = findByThriftId(fieldId);
+ if(fields == null)
+ throw new java.lang.IllegalArgumentException(
+ "Field " + fieldId + " doesn't exist!");
+ return fields;
+ }
+
+ /**
+ * Find the _Fields constant that matches name, or null if its not
+ * found.
+ */
+ @org.apache.thrift.annotation.Nullable
+ public static _Fields findByName(java.lang.String name) {
+ return byName.get(name);
+ }
+
+ private final short _thriftId;
+ private final java.lang.String _fieldName;
+
+ _Fields(short thriftId, java.lang.String fieldName) {
+ _thriftId = thriftId;
+ _fieldName = fieldName;
+ }
+
+ @Override
+ public short getThriftFieldId() {
+ return _thriftId;
+ }
+
+ @Override
+ public java.lang.String getFieldName() {
+ return _fieldName;
+ }
+ }
+
+ // isset id assignments
+ private static final int __TIMESTAMP_ISSET_ID = 0;
+ private static final int __ENDTIMESTAMP_ISSET_ID = 1;
+ private static final int __SOURCERECORD_ISSET_ID = 2;
+ private byte __isset_bitfield = 0;
+ private static final _Fields optionals[] = { _Fields.KEYS, _Fields.RECORDS,
+ _Fields.CRITERIA, _Fields.CONDITION, _Fields.TIMESTAMP,
+ _Fields.END_TIMESTAMP, _Fields.ORDER, _Fields.PAGE, _Fields.VALUE,
+ _Fields.REPLACEMENT, _Fields.VALUES, _Fields.JSON, _Fields.QUERY,
+ _Fields.FUNCTION, _Fields.SOURCE_RECORD };
+ public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+ static {
+ java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(
+ _Fields.class);
+ tmpMap.put(_Fields.VERB,
+ new org.apache.thrift.meta_data.FieldMetaData("verb",
+ org.apache.thrift.TFieldRequirementType.REQUIRED,
+ new org.apache.thrift.meta_data.EnumMetaData(
+ org.apache.thrift.protocol.TType.ENUM,
+ TCommandVerb.class)));
+ tmpMap.put(_Fields.KEYS, new org.apache.thrift.meta_data.FieldMetaData(
+ "keys", org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.ListMetaData(
+ org.apache.thrift.protocol.TType.LIST,
+ new org.apache.thrift.meta_data.FieldValueMetaData(
+ org.apache.thrift.protocol.TType.STRING))));
+ tmpMap.put(_Fields.RECORDS,
+ new org.apache.thrift.meta_data.FieldMetaData("records",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.ListMetaData(
+ org.apache.thrift.protocol.TType.LIST,
+ new org.apache.thrift.meta_data.FieldValueMetaData(
+ org.apache.thrift.protocol.TType.I64))));
+ tmpMap.put(_Fields.CRITERIA,
+ new org.apache.thrift.meta_data.FieldMetaData("criteria",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.StructMetaData(
+ org.apache.thrift.protocol.TType.STRUCT,
+ TCriteria.class)));
+ tmpMap.put(_Fields.CONDITION,
+ new org.apache.thrift.meta_data.FieldMetaData("condition",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.FieldValueMetaData(
+ org.apache.thrift.protocol.TType.STRING)));
+ tmpMap.put(_Fields.TIMESTAMP,
+ new org.apache.thrift.meta_data.FieldMetaData("timestamp",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.FieldValueMetaData(
+ org.apache.thrift.protocol.TType.I64)));
+ tmpMap.put(_Fields.END_TIMESTAMP,
+ new org.apache.thrift.meta_data.FieldMetaData("endTimestamp",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.FieldValueMetaData(
+ org.apache.thrift.protocol.TType.I64)));
+ tmpMap.put(_Fields.ORDER,
+ new org.apache.thrift.meta_data.FieldMetaData("order",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.StructMetaData(
+ org.apache.thrift.protocol.TType.STRUCT,
+ TOrder.class)));
+ tmpMap.put(_Fields.PAGE,
+ new org.apache.thrift.meta_data.FieldMetaData("page",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.StructMetaData(
+ org.apache.thrift.protocol.TType.STRUCT,
+ TPage.class)));
+ tmpMap.put(_Fields.VALUE,
+ new org.apache.thrift.meta_data.FieldMetaData("value",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.StructMetaData(
+ org.apache.thrift.protocol.TType.STRUCT,
+ TObject.class)));
+ tmpMap.put(_Fields.REPLACEMENT,
+ new org.apache.thrift.meta_data.FieldMetaData("replacement",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.StructMetaData(
+ org.apache.thrift.protocol.TType.STRUCT,
+ TObject.class)));
+ tmpMap.put(_Fields.VALUES,
+ new org.apache.thrift.meta_data.FieldMetaData("values",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.ListMetaData(
+ org.apache.thrift.protocol.TType.LIST,
+ new org.apache.thrift.meta_data.StructMetaData(
+ org.apache.thrift.protocol.TType.STRUCT,
+ TObject.class))));
+ tmpMap.put(_Fields.JSON,
+ new org.apache.thrift.meta_data.FieldMetaData("json",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.FieldValueMetaData(
+ org.apache.thrift.protocol.TType.STRING)));
+ tmpMap.put(_Fields.QUERY,
+ new org.apache.thrift.meta_data.FieldMetaData("query",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.FieldValueMetaData(
+ org.apache.thrift.protocol.TType.STRING)));
+ tmpMap.put(_Fields.FUNCTION,
+ new org.apache.thrift.meta_data.FieldMetaData("function",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.FieldValueMetaData(
+ org.apache.thrift.protocol.TType.STRING)));
+ tmpMap.put(_Fields.SOURCE_RECORD,
+ new org.apache.thrift.meta_data.FieldMetaData("sourceRecord",
+ org.apache.thrift.TFieldRequirementType.OPTIONAL,
+ new org.apache.thrift.meta_data.FieldValueMetaData(
+ org.apache.thrift.protocol.TType.I64)));
+ metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+ org.apache.thrift.meta_data.FieldMetaData
+ .addStructMetaDataMap(TCommand.class, metaDataMap);
+ }
+
+ public TCommand() {}
+
+ public TCommand(TCommandVerb verb) {
+ this();
+ this.verb = verb;
+ }
+
+ /**
+ * Performs a deep copy on other.
+ */
+ public TCommand(TCommand other) {
+ __isset_bitfield = other.__isset_bitfield;
+ if(other.isSetVerb()) {
+ this.verb = other.verb;
+ }
+ if(other.isSetKeys()) {
+ java.util.List __this__keys = new java.util.ArrayList(
+ other.keys);
+ this.keys = __this__keys;
+ }
+ if(other.isSetRecords()) {
+ java.util.List __this__records = new java.util.ArrayList(
+ other.records);
+ this.records = __this__records;
+ }
+ if(other.isSetCriteria()) {
+ this.criteria = new TCriteria(other.criteria);
+ }
+ if(other.isSetCondition()) {
+ this.condition = other.condition;
+ }
+ this.timestamp = other.timestamp;
+ this.endTimestamp = other.endTimestamp;
+ if(other.isSetOrder()) {
+ this.order = new TOrder(other.order);
+ }
+ if(other.isSetPage()) {
+ this.page = new TPage(other.page);
+ }
+ if(other.isSetValue()) {
+ this.value = new TObject(other.value);
+ }
+ if(other.isSetReplacement()) {
+ this.replacement = new TObject(other.replacement);
+ }
+ if(other.isSetValues()) {
+ java.util.List __this__values = new java.util.ArrayList(
+ other.values.size());
+ for (TObject other_element : other.values) {
+ __this__values.add(new TObject(other_element));
+ }
+ this.values = __this__values;
+ }
+ if(other.isSetJson()) {
+ this.json = other.json;
+ }
+ if(other.isSetQuery()) {
+ this.query = other.query;
+ }
+ if(other.isSetFunction()) {
+ this.function = other.function;
+ }
+ this.sourceRecord = other.sourceRecord;
+ }
+
+ @Override
+ public TCommand deepCopy() {
+ return new TCommand(this);
+ }
+
+ @Override
+ public void clear() {
+ this.verb = null;
+ this.keys = null;
+ this.records = null;
+ this.criteria = null;
+ this.condition = null;
+ setTimestampIsSet(false);
+ this.timestamp = 0;
+ setEndTimestampIsSet(false);
+ this.endTimestamp = 0;
+ this.order = null;
+ this.page = null;
+ this.value = null;
+ this.replacement = null;
+ this.values = null;
+ this.json = null;
+ this.query = null;
+ this.function = null;
+ setSourceRecordIsSet(false);
+ this.sourceRecord = 0;
+ }
+
+ /**
+ *
+ * @see TCommandVerb
+ */
+ @org.apache.thrift.annotation.Nullable
+ public TCommandVerb getVerb() {
+ return this.verb;
+ }
+
+ /**
+ *
+ * @see TCommandVerb
+ */
+ public TCommand setVerb(
+ @org.apache.thrift.annotation.Nullable TCommandVerb verb) {
+ this.verb = verb;
+ return this;
+ }
+
+ public void unsetVerb() {
+ this.verb = null;
+ }
+
+ /**
+ * Returns true if field verb is set (has been assigned a value) and false
+ * otherwise
+ */
+ public boolean isSetVerb() {
+ return this.verb != null;
+ }
+
+ public void setVerbIsSet(boolean value) {
+ if(!value) {
+ this.verb = null;
+ }
+ }
+
+ public int getKeysSize() {
+ return (this.keys == null) ? 0 : this.keys.size();
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public java.util.Iterator getKeysIterator() {
+ return (this.keys == null) ? null : this.keys.iterator();
+ }
+
+ public void addToKeys(java.lang.String elem) {
+ if(this.keys == null) {
+ this.keys = new java.util.ArrayList();
+ }
+ this.keys.add(elem);
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public java.util.List getKeys() {
+ return this.keys;
+ }
+
+ public TCommand setKeys(
+ @org.apache.thrift.annotation.Nullable java.util.List keys) {
+ this.keys = keys;
+ return this;
+ }
+
+ public void unsetKeys() {
+ this.keys = null;
+ }
+
+ /**
+ * Returns true if field keys is set (has been assigned a value) and false
+ * otherwise
+ */
+ public boolean isSetKeys() {
+ return this.keys != null;
+ }
+
+ public void setKeysIsSet(boolean value) {
+ if(!value) {
+ this.keys = null;
+ }
+ }
+
+ public int getRecordsSize() {
+ return (this.records == null) ? 0 : this.records.size();
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public java.util.Iterator getRecordsIterator() {
+ return (this.records == null) ? null : this.records.iterator();
+ }
+
+ public void addToRecords(long elem) {
+ if(this.records == null) {
+ this.records = new java.util.ArrayList();
+ }
+ this.records.add(elem);
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public java.util.List getRecords() {
+ return this.records;
+ }
+
+ public TCommand setRecords(
+ @org.apache.thrift.annotation.Nullable java.util.List records) {
+ this.records = records;
+ return this;
+ }
+
+ public void unsetRecords() {
+ this.records = null;
+ }
+
+ /**
+ * Returns true if field records is set (has been assigned a value) and
+ * false otherwise
+ */
+ public boolean isSetRecords() {
+ return this.records != null;
+ }
+
+ public void setRecordsIsSet(boolean value) {
+ if(!value) {
+ this.records = null;
+ }
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public TCriteria getCriteria() {
+ return this.criteria;
+ }
+
+ public TCommand setCriteria(
+ @org.apache.thrift.annotation.Nullable TCriteria criteria) {
+ this.criteria = criteria;
+ return this;
+ }
+
+ public void unsetCriteria() {
+ this.criteria = null;
+ }
+
+ /**
+ * Returns true if field criteria is set (has been assigned a value) and
+ * false otherwise
+ */
+ public boolean isSetCriteria() {
+ return this.criteria != null;
+ }
+
+ public void setCriteriaIsSet(boolean value) {
+ if(!value) {
+ this.criteria = null;
+ }
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public java.lang.String getCondition() {
+ return this.condition;
+ }
+
+ public TCommand setCondition(
+ @org.apache.thrift.annotation.Nullable java.lang.String condition) {
+ this.condition = condition;
+ return this;
+ }
+
+ public void unsetCondition() {
+ this.condition = null;
+ }
+
+ /**
+ * Returns true if field condition is set (has been assigned a value) and
+ * false otherwise
+ */
+ public boolean isSetCondition() {
+ return this.condition != null;
+ }
+
+ public void setConditionIsSet(boolean value) {
+ if(!value) {
+ this.condition = null;
+ }
+ }
+
+ public long getTimestamp() {
+ return this.timestamp;
+ }
+
+ public TCommand setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ setTimestampIsSet(true);
+ return this;
+ }
+
+ public void unsetTimestamp() {
+ __isset_bitfield = org.apache.thrift.EncodingUtils
+ .clearBit(__isset_bitfield, __TIMESTAMP_ISSET_ID);
+ }
+
+ /**
+ * Returns true if field timestamp is set (has been assigned a value) and
+ * false otherwise
+ */
+ public boolean isSetTimestamp() {
+ return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield,
+ __TIMESTAMP_ISSET_ID);
+ }
+
+ public void setTimestampIsSet(boolean value) {
+ __isset_bitfield = org.apache.thrift.EncodingUtils
+ .setBit(__isset_bitfield, __TIMESTAMP_ISSET_ID, value);
+ }
+
+ public long getEndTimestamp() {
+ return this.endTimestamp;
+ }
+
+ public TCommand setEndTimestamp(long endTimestamp) {
+ this.endTimestamp = endTimestamp;
+ setEndTimestampIsSet(true);
+ return this;
+ }
+
+ public void unsetEndTimestamp() {
+ __isset_bitfield = org.apache.thrift.EncodingUtils
+ .clearBit(__isset_bitfield, __ENDTIMESTAMP_ISSET_ID);
+ }
+
+ /**
+ * Returns true if field endTimestamp is set (has been assigned a value) and
+ * false otherwise
+ */
+ public boolean isSetEndTimestamp() {
+ return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield,
+ __ENDTIMESTAMP_ISSET_ID);
+ }
+
+ public void setEndTimestampIsSet(boolean value) {
+ __isset_bitfield = org.apache.thrift.EncodingUtils
+ .setBit(__isset_bitfield, __ENDTIMESTAMP_ISSET_ID, value);
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public TOrder getOrder() {
+ return this.order;
+ }
+
+ public TCommand setOrder(
+ @org.apache.thrift.annotation.Nullable TOrder order) {
+ this.order = order;
+ return this;
+ }
+
+ public void unsetOrder() {
+ this.order = null;
+ }
+
+ /**
+ * Returns true if field order is set (has been assigned a value) and false
+ * otherwise
+ */
+ public boolean isSetOrder() {
+ return this.order != null;
+ }
+
+ public void setOrderIsSet(boolean value) {
+ if(!value) {
+ this.order = null;
+ }
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public TPage getPage() {
+ return this.page;
+ }
+
+ public TCommand setPage(@org.apache.thrift.annotation.Nullable TPage page) {
+ this.page = page;
+ return this;
+ }
+
+ public void unsetPage() {
+ this.page = null;
+ }
+
+ /**
+ * Returns true if field page is set (has been assigned a value) and false
+ * otherwise
+ */
+ public boolean isSetPage() {
+ return this.page != null;
+ }
+
+ public void setPageIsSet(boolean value) {
+ if(!value) {
+ this.page = null;
+ }
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public TObject getValue() {
+ return this.value;
+ }
+
+ public TCommand setValue(
+ @org.apache.thrift.annotation.Nullable TObject value) {
+ this.value = value;
+ return this;
+ }
+
+ public void unsetValue() {
+ this.value = null;
+ }
+
+ /**
+ * Returns true if field value is set (has been assigned a value) and false
+ * otherwise
+ */
+ public boolean isSetValue() {
+ return this.value != null;
+ }
+
+ public void setValueIsSet(boolean value) {
+ if(!value) {
+ this.value = null;
+ }
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public TObject getReplacement() {
+ return this.replacement;
+ }
+
+ public TCommand setReplacement(
+ @org.apache.thrift.annotation.Nullable TObject replacement) {
+ this.replacement = replacement;
+ return this;
+ }
+
+ public void unsetReplacement() {
+ this.replacement = null;
+ }
+
+ /**
+ * Returns true if field replacement is set (has been assigned a value) and
+ * false otherwise
+ */
+ public boolean isSetReplacement() {
+ return this.replacement != null;
+ }
+
+ public void setReplacementIsSet(boolean value) {
+ if(!value) {
+ this.replacement = null;
+ }
+ }
+
+ public int getValuesSize() {
+ return (this.values == null) ? 0 : this.values.size();
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public java.util.Iterator getValuesIterator() {
+ return (this.values == null) ? null : this.values.iterator();
+ }
+
+ public void addToValues(TObject elem) {
+ if(this.values == null) {
+ this.values = new java.util.ArrayList();
+ }
+ this.values.add(elem);
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public java.util.List getValues() {
+ return this.values;
+ }
+
+ public TCommand setValues(
+ @org.apache.thrift.annotation.Nullable java.util.List values) {
+ this.values = values;
+ return this;
+ }
+
+ public void unsetValues() {
+ this.values = null;
+ }
+
+ /**
+ * Returns true if field values is set (has been assigned a value) and false
+ * otherwise
+ */
+ public boolean isSetValues() {
+ return this.values != null;
+ }
+
+ public void setValuesIsSet(boolean value) {
+ if(!value) {
+ this.values = null;
+ }
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public java.lang.String getJson() {
+ return this.json;
+ }
+
+ public TCommand setJson(
+ @org.apache.thrift.annotation.Nullable java.lang.String json) {
+ this.json = json;
+ return this;
+ }
+
+ public void unsetJson() {
+ this.json = null;
+ }
+
+ /**
+ * Returns true if field json is set (has been assigned a value) and false
+ * otherwise
+ */
+ public boolean isSetJson() {
+ return this.json != null;
+ }
+
+ public void setJsonIsSet(boolean value) {
+ if(!value) {
+ this.json = null;
+ }
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public java.lang.String getQuery() {
+ return this.query;
+ }
+
+ public TCommand setQuery(
+ @org.apache.thrift.annotation.Nullable java.lang.String query) {
+ this.query = query;
+ return this;
+ }
+
+ public void unsetQuery() {
+ this.query = null;
+ }
+
+ /**
+ * Returns true if field query is set (has been assigned a value) and false
+ * otherwise
+ */
+ public boolean isSetQuery() {
+ return this.query != null;
+ }
+
+ public void setQueryIsSet(boolean value) {
+ if(!value) {
+ this.query = null;
+ }
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ public java.lang.String getFunction() {
+ return this.function;
+ }
+
+ public TCommand setFunction(
+ @org.apache.thrift.annotation.Nullable java.lang.String function) {
+ this.function = function;
+ return this;
+ }
+
+ public void unsetFunction() {
+ this.function = null;
+ }
+
+ /**
+ * Returns true if field function is set (has been assigned a value) and
+ * false otherwise
+ */
+ public boolean isSetFunction() {
+ return this.function != null;
+ }
+
+ public void setFunctionIsSet(boolean value) {
+ if(!value) {
+ this.function = null;
+ }
+ }
+
+ public long getSourceRecord() {
+ return this.sourceRecord;
+ }
+
+ public TCommand setSourceRecord(long sourceRecord) {
+ this.sourceRecord = sourceRecord;
+ setSourceRecordIsSet(true);
+ return this;
+ }
+
+ public void unsetSourceRecord() {
+ __isset_bitfield = org.apache.thrift.EncodingUtils
+ .clearBit(__isset_bitfield, __SOURCERECORD_ISSET_ID);
+ }
+
+ /**
+ * Returns true if field sourceRecord is set (has been assigned a value) and
+ * false otherwise
+ */
+ public boolean isSetSourceRecord() {
+ return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield,
+ __SOURCERECORD_ISSET_ID);
+ }
+
+ public void setSourceRecordIsSet(boolean value) {
+ __isset_bitfield = org.apache.thrift.EncodingUtils
+ .setBit(__isset_bitfield, __SOURCERECORD_ISSET_ID, value);
+ }
+
+ @Override
+ public void setFieldValue(_Fields field,
+ @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+ switch (field) {
+ case VERB:
+ if(value == null) {
+ unsetVerb();
+ }
+ else {
+ setVerb((TCommandVerb) value);
+ }
+ break;
+
+ case KEYS:
+ if(value == null) {
+ unsetKeys();
+ }
+ else {
+ setKeys((java.util.List) value);
+ }
+ break;
+
+ case RECORDS:
+ if(value == null) {
+ unsetRecords();
+ }
+ else {
+ setRecords((java.util.List) value);
+ }
+ break;
+
+ case CRITERIA:
+ if(value == null) {
+ unsetCriteria();
+ }
+ else {
+ setCriteria((TCriteria) value);
+ }
+ break;
+
+ case CONDITION:
+ if(value == null) {
+ unsetCondition();
+ }
+ else {
+ setCondition((java.lang.String) value);
+ }
+ break;
+
+ case TIMESTAMP:
+ if(value == null) {
+ unsetTimestamp();
+ }
+ else {
+ setTimestamp((java.lang.Long) value);
+ }
+ break;
+
+ case END_TIMESTAMP:
+ if(value == null) {
+ unsetEndTimestamp();
+ }
+ else {
+ setEndTimestamp((java.lang.Long) value);
+ }
+ break;
+
+ case ORDER:
+ if(value == null) {
+ unsetOrder();
+ }
+ else {
+ setOrder((TOrder) value);
+ }
+ break;
+
+ case PAGE:
+ if(value == null) {
+ unsetPage();
+ }
+ else {
+ setPage((TPage) value);
+ }
+ break;
+
+ case VALUE:
+ if(value == null) {
+ unsetValue();
+ }
+ else {
+ setValue((TObject) value);
+ }
+ break;
+
+ case REPLACEMENT:
+ if(value == null) {
+ unsetReplacement();
+ }
+ else {
+ setReplacement((TObject) value);
+ }
+ break;
+
+ case VALUES:
+ if(value == null) {
+ unsetValues();
+ }
+ else {
+ setValues((java.util.List) value);
+ }
+ break;
+
+ case JSON:
+ if(value == null) {
+ unsetJson();
+ }
+ else {
+ setJson((java.lang.String) value);
+ }
+ break;
+
+ case QUERY:
+ if(value == null) {
+ unsetQuery();
+ }
+ else {
+ setQuery((java.lang.String) value);
+ }
+ break;
+
+ case FUNCTION:
+ if(value == null) {
+ unsetFunction();
+ }
+ else {
+ setFunction((java.lang.String) value);
+ }
+ break;
+
+ case SOURCE_RECORD:
+ if(value == null) {
+ unsetSourceRecord();
+ }
+ else {
+ setSourceRecord((java.lang.Long) value);
+ }
+ break;
+
+ }
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ @Override
+ public java.lang.Object getFieldValue(_Fields field) {
+ switch (field) {
+ case VERB:
+ return getVerb();
+
+ case KEYS:
+ return getKeys();
+
+ case RECORDS:
+ return getRecords();
+
+ case CRITERIA:
+ return getCriteria();
+
+ case CONDITION:
+ return getCondition();
+
+ case TIMESTAMP:
+ return getTimestamp();
+
+ case END_TIMESTAMP:
+ return getEndTimestamp();
+
+ case ORDER:
+ return getOrder();
+
+ case PAGE:
+ return getPage();
+
+ case VALUE:
+ return getValue();
+
+ case REPLACEMENT:
+ return getReplacement();
+
+ case VALUES:
+ return getValues();
+
+ case JSON:
+ return getJson();
+
+ case QUERY:
+ return getQuery();
+
+ case FUNCTION:
+ return getFunction();
+
+ case SOURCE_RECORD:
+ return getSourceRecord();
+
+ }
+ throw new java.lang.IllegalStateException();
+ }
+
+ /**
+ * Returns true if field corresponding to fieldID is set (has been assigned
+ * a value) and false otherwise
+ */
+ @Override
+ public boolean isSet(_Fields field) {
+ if(field == null) {
+ throw new java.lang.IllegalArgumentException();
+ }
+
+ switch (field) {
+ case VERB:
+ return isSetVerb();
+ case KEYS:
+ return isSetKeys();
+ case RECORDS:
+ return isSetRecords();
+ case CRITERIA:
+ return isSetCriteria();
+ case CONDITION:
+ return isSetCondition();
+ case TIMESTAMP:
+ return isSetTimestamp();
+ case END_TIMESTAMP:
+ return isSetEndTimestamp();
+ case ORDER:
+ return isSetOrder();
+ case PAGE:
+ return isSetPage();
+ case VALUE:
+ return isSetValue();
+ case REPLACEMENT:
+ return isSetReplacement();
+ case VALUES:
+ return isSetValues();
+ case JSON:
+ return isSetJson();
+ case QUERY:
+ return isSetQuery();
+ case FUNCTION:
+ return isSetFunction();
+ case SOURCE_RECORD:
+ return isSetSourceRecord();
+ }
+ throw new java.lang.IllegalStateException();
+ }
+
+ @Override
+ public boolean equals(java.lang.Object that) {
+ if(that instanceof TCommand)
+ return this.equals((TCommand) that);
+ return false;
+ }
+
+ public boolean equals(TCommand that) {
+ if(that == null)
+ return false;
+ if(this == that)
+ return true;
+
+ boolean this_present_verb = true && this.isSetVerb();
+ boolean that_present_verb = true && that.isSetVerb();
+ if(this_present_verb || that_present_verb) {
+ if(!(this_present_verb && that_present_verb))
+ return false;
+ if(!this.verb.equals(that.verb))
+ return false;
+ }
+
+ boolean this_present_keys = true && this.isSetKeys();
+ boolean that_present_keys = true && that.isSetKeys();
+ if(this_present_keys || that_present_keys) {
+ if(!(this_present_keys && that_present_keys))
+ return false;
+ if(!this.keys.equals(that.keys))
+ return false;
+ }
+
+ boolean this_present_records = true && this.isSetRecords();
+ boolean that_present_records = true && that.isSetRecords();
+ if(this_present_records || that_present_records) {
+ if(!(this_present_records && that_present_records))
+ return false;
+ if(!this.records.equals(that.records))
+ return false;
+ }
+
+ boolean this_present_criteria = true && this.isSetCriteria();
+ boolean that_present_criteria = true && that.isSetCriteria();
+ if(this_present_criteria || that_present_criteria) {
+ if(!(this_present_criteria && that_present_criteria))
+ return false;
+ if(!this.criteria.equals(that.criteria))
+ return false;
+ }
+
+ boolean this_present_condition = true && this.isSetCondition();
+ boolean that_present_condition = true && that.isSetCondition();
+ if(this_present_condition || that_present_condition) {
+ if(!(this_present_condition && that_present_condition))
+ return false;
+ if(!this.condition.equals(that.condition))
+ return false;
+ }
+
+ boolean this_present_timestamp = true && this.isSetTimestamp();
+ boolean that_present_timestamp = true && that.isSetTimestamp();
+ if(this_present_timestamp || that_present_timestamp) {
+ if(!(this_present_timestamp && that_present_timestamp))
+ return false;
+ if(this.timestamp != that.timestamp)
+ return false;
+ }
+
+ boolean this_present_endTimestamp = true && this.isSetEndTimestamp();
+ boolean that_present_endTimestamp = true && that.isSetEndTimestamp();
+ if(this_present_endTimestamp || that_present_endTimestamp) {
+ if(!(this_present_endTimestamp && that_present_endTimestamp))
+ return false;
+ if(this.endTimestamp != that.endTimestamp)
+ return false;
+ }
+
+ boolean this_present_order = true && this.isSetOrder();
+ boolean that_present_order = true && that.isSetOrder();
+ if(this_present_order || that_present_order) {
+ if(!(this_present_order && that_present_order))
+ return false;
+ if(!this.order.equals(that.order))
+ return false;
+ }
+
+ boolean this_present_page = true && this.isSetPage();
+ boolean that_present_page = true && that.isSetPage();
+ if(this_present_page || that_present_page) {
+ if(!(this_present_page && that_present_page))
+ return false;
+ if(!this.page.equals(that.page))
+ return false;
+ }
+
+ boolean this_present_value = true && this.isSetValue();
+ boolean that_present_value = true && that.isSetValue();
+ if(this_present_value || that_present_value) {
+ if(!(this_present_value && that_present_value))
+ return false;
+ if(!this.value.equals(that.value))
+ return false;
+ }
+
+ boolean this_present_replacement = true && this.isSetReplacement();
+ boolean that_present_replacement = true && that.isSetReplacement();
+ if(this_present_replacement || that_present_replacement) {
+ if(!(this_present_replacement && that_present_replacement))
+ return false;
+ if(!this.replacement.equals(that.replacement))
+ return false;
+ }
+
+ boolean this_present_values = true && this.isSetValues();
+ boolean that_present_values = true && that.isSetValues();
+ if(this_present_values || that_present_values) {
+ if(!(this_present_values && that_present_values))
+ return false;
+ if(!this.values.equals(that.values))
+ return false;
+ }
+
+ boolean this_present_json = true && this.isSetJson();
+ boolean that_present_json = true && that.isSetJson();
+ if(this_present_json || that_present_json) {
+ if(!(this_present_json && that_present_json))
+ return false;
+ if(!this.json.equals(that.json))
+ return false;
+ }
+
+ boolean this_present_query = true && this.isSetQuery();
+ boolean that_present_query = true && that.isSetQuery();
+ if(this_present_query || that_present_query) {
+ if(!(this_present_query && that_present_query))
+ return false;
+ if(!this.query.equals(that.query))
+ return false;
+ }
+
+ boolean this_present_function = true && this.isSetFunction();
+ boolean that_present_function = true && that.isSetFunction();
+ if(this_present_function || that_present_function) {
+ if(!(this_present_function && that_present_function))
+ return false;
+ if(!this.function.equals(that.function))
+ return false;
+ }
+
+ boolean this_present_sourceRecord = true && this.isSetSourceRecord();
+ boolean that_present_sourceRecord = true && that.isSetSourceRecord();
+ if(this_present_sourceRecord || that_present_sourceRecord) {
+ if(!(this_present_sourceRecord && that_present_sourceRecord))
+ return false;
+ if(this.sourceRecord != that.sourceRecord)
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = 1;
+
+ hashCode = hashCode * 8191 + ((isSetVerb()) ? 131071 : 524287);
+ if(isSetVerb())
+ hashCode = hashCode * 8191 + verb.getValue();
+
+ hashCode = hashCode * 8191 + ((isSetKeys()) ? 131071 : 524287);
+ if(isSetKeys())
+ hashCode = hashCode * 8191 + keys.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetRecords()) ? 131071 : 524287);
+ if(isSetRecords())
+ hashCode = hashCode * 8191 + records.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetCriteria()) ? 131071 : 524287);
+ if(isSetCriteria())
+ hashCode = hashCode * 8191 + criteria.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetCondition()) ? 131071 : 524287);
+ if(isSetCondition())
+ hashCode = hashCode * 8191 + condition.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetTimestamp()) ? 131071 : 524287);
+ if(isSetTimestamp())
+ hashCode = hashCode * 8191
+ + org.apache.thrift.TBaseHelper.hashCode(timestamp);
+
+ hashCode = hashCode * 8191 + ((isSetEndTimestamp()) ? 131071 : 524287);
+ if(isSetEndTimestamp())
+ hashCode = hashCode * 8191
+ + org.apache.thrift.TBaseHelper.hashCode(endTimestamp);
+
+ hashCode = hashCode * 8191 + ((isSetOrder()) ? 131071 : 524287);
+ if(isSetOrder())
+ hashCode = hashCode * 8191 + order.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetPage()) ? 131071 : 524287);
+ if(isSetPage())
+ hashCode = hashCode * 8191 + page.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetValue()) ? 131071 : 524287);
+ if(isSetValue())
+ hashCode = hashCode * 8191 + value.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetReplacement()) ? 131071 : 524287);
+ if(isSetReplacement())
+ hashCode = hashCode * 8191 + replacement.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetValues()) ? 131071 : 524287);
+ if(isSetValues())
+ hashCode = hashCode * 8191 + values.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetJson()) ? 131071 : 524287);
+ if(isSetJson())
+ hashCode = hashCode * 8191 + json.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetQuery()) ? 131071 : 524287);
+ if(isSetQuery())
+ hashCode = hashCode * 8191 + query.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetFunction()) ? 131071 : 524287);
+ if(isSetFunction())
+ hashCode = hashCode * 8191 + function.hashCode();
+
+ hashCode = hashCode * 8191 + ((isSetSourceRecord()) ? 131071 : 524287);
+ if(isSetSourceRecord())
+ hashCode = hashCode * 8191
+ + org.apache.thrift.TBaseHelper.hashCode(sourceRecord);
+
+ return hashCode;
+ }
+
+ @Override
+ public int compareTo(TCommand other) {
+ if(!getClass().equals(other.getClass())) {
+ return getClass().getName().compareTo(other.getClass().getName());
+ }
+
+ int lastComparison = 0;
+
+ lastComparison = java.lang.Boolean.compare(isSetVerb(),
+ other.isSetVerb());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetVerb()) {
+ lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.verb,
+ other.verb);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetKeys(),
+ other.isSetKeys());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetKeys()) {
+ lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.keys,
+ other.keys);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetRecords(),
+ other.isSetRecords());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetRecords()) {
+ lastComparison = org.apache.thrift.TBaseHelper
+ .compareTo(this.records, other.records);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetCriteria(),
+ other.isSetCriteria());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetCriteria()) {
+ lastComparison = org.apache.thrift.TBaseHelper
+ .compareTo(this.criteria, other.criteria);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetCondition(),
+ other.isSetCondition());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetCondition()) {
+ lastComparison = org.apache.thrift.TBaseHelper
+ .compareTo(this.condition, other.condition);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetTimestamp(),
+ other.isSetTimestamp());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetTimestamp()) {
+ lastComparison = org.apache.thrift.TBaseHelper
+ .compareTo(this.timestamp, other.timestamp);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetEndTimestamp(),
+ other.isSetEndTimestamp());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetEndTimestamp()) {
+ lastComparison = org.apache.thrift.TBaseHelper
+ .compareTo(this.endTimestamp, other.endTimestamp);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetOrder(),
+ other.isSetOrder());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetOrder()) {
+ lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.order,
+ other.order);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetPage(),
+ other.isSetPage());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetPage()) {
+ lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.page,
+ other.page);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetValue(),
+ other.isSetValue());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetValue()) {
+ lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.value,
+ other.value);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetReplacement(),
+ other.isSetReplacement());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetReplacement()) {
+ lastComparison = org.apache.thrift.TBaseHelper
+ .compareTo(this.replacement, other.replacement);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetValues(),
+ other.isSetValues());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetValues()) {
+ lastComparison = org.apache.thrift.TBaseHelper
+ .compareTo(this.values, other.values);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetJson(),
+ other.isSetJson());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetJson()) {
+ lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.json,
+ other.json);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetQuery(),
+ other.isSetQuery());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetQuery()) {
+ lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.query,
+ other.query);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetFunction(),
+ other.isSetFunction());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetFunction()) {
+ lastComparison = org.apache.thrift.TBaseHelper
+ .compareTo(this.function, other.function);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ lastComparison = java.lang.Boolean.compare(isSetSourceRecord(),
+ other.isSetSourceRecord());
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ if(isSetSourceRecord()) {
+ lastComparison = org.apache.thrift.TBaseHelper
+ .compareTo(this.sourceRecord, other.sourceRecord);
+ if(lastComparison != 0) {
+ return lastComparison;
+ }
+ }
+ return 0;
+ }
+
+ @org.apache.thrift.annotation.Nullable
+ @Override
+ public _Fields fieldForId(int fieldId) {
+ return _Fields.findByThriftId(fieldId);
+ }
+
+ @Override
+ public void read(org.apache.thrift.protocol.TProtocol iprot)
+ throws org.apache.thrift.TException {
+ scheme(iprot).read(iprot, this);
+ }
+
+ @Override
+ public void write(org.apache.thrift.protocol.TProtocol oprot)
+ throws org.apache.thrift.TException {
+ scheme(oprot).write(oprot, this);
+ }
+
+ @Override
+ public java.lang.String toString() {
+ java.lang.StringBuilder sb = new java.lang.StringBuilder("TCommand(");
+ boolean first = true;
+
+ sb.append("verb:");
+ if(this.verb == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.verb);
+ }
+ first = false;
+ if(isSetKeys()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("keys:");
+ if(this.keys == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.keys);
+ }
+ first = false;
+ }
+ if(isSetRecords()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("records:");
+ if(this.records == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.records);
+ }
+ first = false;
+ }
+ if(isSetCriteria()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("criteria:");
+ if(this.criteria == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.criteria);
+ }
+ first = false;
+ }
+ if(isSetCondition()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("condition:");
+ if(this.condition == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.condition);
+ }
+ first = false;
+ }
+ if(isSetTimestamp()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("timestamp:");
+ sb.append(this.timestamp);
+ first = false;
+ }
+ if(isSetEndTimestamp()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("endTimestamp:");
+ sb.append(this.endTimestamp);
+ first = false;
+ }
+ if(isSetOrder()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("order:");
+ if(this.order == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.order);
+ }
+ first = false;
+ }
+ if(isSetPage()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("page:");
+ if(this.page == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.page);
+ }
+ first = false;
+ }
+ if(isSetValue()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("value:");
+ if(this.value == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.value);
+ }
+ first = false;
+ }
+ if(isSetReplacement()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("replacement:");
+ if(this.replacement == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.replacement);
+ }
+ first = false;
+ }
+ if(isSetValues()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("values:");
+ if(this.values == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.values);
+ }
+ first = false;
+ }
+ if(isSetJson()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("json:");
+ if(this.json == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.json);
+ }
+ first = false;
+ }
+ if(isSetQuery()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("query:");
+ if(this.query == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.query);
+ }
+ first = false;
+ }
+ if(isSetFunction()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("function:");
+ if(this.function == null) {
+ sb.append("null");
+ }
+ else {
+ sb.append(this.function);
+ }
+ first = false;
+ }
+ if(isSetSourceRecord()) {
+ if(!first)
+ sb.append(", ");
+ sb.append("sourceRecord:");
+ sb.append(this.sourceRecord);
+ first = false;
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ public void validate() throws org.apache.thrift.TException {
+ // check for required fields
+ if(verb == null) {
+ throw new org.apache.thrift.protocol.TProtocolException(
+ "Required field 'verb' was not present! Struct: "
+ + toString());
+ }
+ // check for sub-struct validity
+ if(criteria != null) {
+ criteria.validate();
+ }
+ if(order != null) {
+ order.validate();
+ }
+ if(page != null) {
+ page.validate();
+ }
+ if(value != null) {
+ value.validate();
+ }
+ if(replacement != null) {
+ replacement.validate();
+ }
+ }
+
+ private void writeObject(java.io.ObjectOutputStream out)
+ throws java.io.IOException {
+ try {
+ write(new org.apache.thrift.protocol.TCompactProtocol(
+ new org.apache.thrift.transport.TIOStreamTransport(out)));
+ }
+ catch (org.apache.thrift.TException te) {
+ throw new java.io.IOException(te);
+ }
+ }
+
+ private void readObject(java.io.ObjectInputStream in)
+ throws java.io.IOException, java.lang.ClassNotFoundException {
+ try {
+ // it doesn't seem like you should have to do this, but java
+ // serialization is wacky, and doesn't call the default constructor.
+ __isset_bitfield = 0;
+ read(new org.apache.thrift.protocol.TCompactProtocol(
+ new org.apache.thrift.transport.TIOStreamTransport(in)));
+ }
+ catch (org.apache.thrift.TException te) {
+ throw new java.io.IOException(te);
+ }
+ }
+
+ private static class TCommandStandardSchemeFactory implements
+ org.apache.thrift.scheme.SchemeFactory {
+ @Override
+ public TCommandStandardScheme getScheme() {
+ return new TCommandStandardScheme();
+ }
+ }
+
+ private static class TCommandStandardScheme
+ extends org.apache.thrift.scheme.StandardScheme {
+
+ @Override
+ public void read(org.apache.thrift.protocol.TProtocol iprot,
+ TCommand struct) throws org.apache.thrift.TException {
+ org.apache.thrift.protocol.TField schemeField;
+ iprot.readStructBegin();
+ while (true) {
+ schemeField = iprot.readFieldBegin();
+ if(schemeField.type == org.apache.thrift.protocol.TType.STOP) {
+ break;
+ }
+ switch (schemeField.id) {
+ case 1: // VERB
+ if(schemeField.type == org.apache.thrift.protocol.TType.I32) {
+ struct.verb = com.cinchapi.concourse.thrift.TCommandVerb
+ .findByValue(iprot.readI32());
+ struct.setVerbIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 2: // KEYS
+ if(schemeField.type == org.apache.thrift.protocol.TType.LIST) {
+ {
+ org.apache.thrift.protocol.TList _list16 = iprot
+ .readListBegin();
+ struct.keys = new java.util.ArrayList(
+ _list16.size);
+ @org.apache.thrift.annotation.Nullable java.lang.String _elem17;
+ for (int _i18 = 0; _i18 < _list16.size; ++_i18) {
+ _elem17 = iprot.readString();
+ struct.keys.add(_elem17);
+ }
+ iprot.readListEnd();
+ }
+ struct.setKeysIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 3: // RECORDS
+ if(schemeField.type == org.apache.thrift.protocol.TType.LIST) {
+ {
+ org.apache.thrift.protocol.TList _list19 = iprot
+ .readListBegin();
+ struct.records = new java.util.ArrayList(
+ _list19.size);
+ long _elem20;
+ for (int _i21 = 0; _i21 < _list19.size; ++_i21) {
+ _elem20 = iprot.readI64();
+ struct.records.add(_elem20);
+ }
+ iprot.readListEnd();
+ }
+ struct.setRecordsIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 4: // CRITERIA
+ if(schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+ struct.criteria = new TCriteria();
+ struct.criteria.read(iprot);
+ struct.setCriteriaIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 5: // CONDITION
+ if(schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+ struct.condition = iprot.readString();
+ struct.setConditionIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 6: // TIMESTAMP
+ if(schemeField.type == org.apache.thrift.protocol.TType.I64) {
+ struct.timestamp = iprot.readI64();
+ struct.setTimestampIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 7: // END_TIMESTAMP
+ if(schemeField.type == org.apache.thrift.protocol.TType.I64) {
+ struct.endTimestamp = iprot.readI64();
+ struct.setEndTimestampIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 8: // ORDER
+ if(schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+ struct.order = new TOrder();
+ struct.order.read(iprot);
+ struct.setOrderIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 9: // PAGE
+ if(schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+ struct.page = new TPage();
+ struct.page.read(iprot);
+ struct.setPageIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 10: // VALUE
+ if(schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+ struct.value = new TObject();
+ struct.value.read(iprot);
+ struct.setValueIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 11: // REPLACEMENT
+ if(schemeField.type == org.apache.thrift.protocol.TType.STRUCT) {
+ struct.replacement = new TObject();
+ struct.replacement.read(iprot);
+ struct.setReplacementIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 12: // VALUES
+ if(schemeField.type == org.apache.thrift.protocol.TType.LIST) {
+ {
+ org.apache.thrift.protocol.TList _list22 = iprot
+ .readListBegin();
+ struct.values = new java.util.ArrayList(
+ _list22.size);
+ @org.apache.thrift.annotation.Nullable TObject _elem23;
+ for (int _i24 = 0; _i24 < _list22.size; ++_i24) {
+ _elem23 = new TObject();
+ _elem23.read(iprot);
+ struct.values.add(_elem23);
+ }
+ iprot.readListEnd();
+ }
+ struct.setValuesIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 13: // JSON
+ if(schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+ struct.json = iprot.readString();
+ struct.setJsonIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 14: // QUERY
+ if(schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+ struct.query = iprot.readString();
+ struct.setQueryIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 15: // FUNCTION
+ if(schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+ struct.function = iprot.readString();
+ struct.setFunctionIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ case 16: // SOURCE_RECORD
+ if(schemeField.type == org.apache.thrift.protocol.TType.I64) {
+ struct.sourceRecord = iprot.readI64();
+ struct.setSourceRecordIsSet(true);
+ }
+ else {
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ break;
+ default:
+ org.apache.thrift.protocol.TProtocolUtil.skip(iprot,
+ schemeField.type);
+ }
+ iprot.readFieldEnd();
+ }
+ iprot.readStructEnd();
+
+ // check for required fields of primitive type, which can't be
+ // checked in the validate method
+ struct.validate();
+ }
+
+ @Override
+ public void write(org.apache.thrift.protocol.TProtocol oprot,
+ TCommand struct) throws org.apache.thrift.TException {
+ struct.validate();
+
+ oprot.writeStructBegin(STRUCT_DESC);
+ if(struct.verb != null) {
+ oprot.writeFieldBegin(VERB_FIELD_DESC);
+ oprot.writeI32(struct.verb.getValue());
+ oprot.writeFieldEnd();
+ }
+ if(struct.keys != null) {
+ if(struct.isSetKeys()) {
+ oprot.writeFieldBegin(KEYS_FIELD_DESC);
+ {
+ oprot.writeListBegin(
+ new org.apache.thrift.protocol.TList(
+ org.apache.thrift.protocol.TType.STRING,
+ struct.keys.size()));
+ for (java.lang.String _iter25 : struct.keys) {
+ oprot.writeString(_iter25);
+ }
+ oprot.writeListEnd();
+ }
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.records != null) {
+ if(struct.isSetRecords()) {
+ oprot.writeFieldBegin(RECORDS_FIELD_DESC);
+ {
+ oprot.writeListBegin(
+ new org.apache.thrift.protocol.TList(
+ org.apache.thrift.protocol.TType.I64,
+ struct.records.size()));
+ for (long _iter26 : struct.records) {
+ oprot.writeI64(_iter26);
+ }
+ oprot.writeListEnd();
+ }
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.criteria != null) {
+ if(struct.isSetCriteria()) {
+ oprot.writeFieldBegin(CRITERIA_FIELD_DESC);
+ struct.criteria.write(oprot);
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.condition != null) {
+ if(struct.isSetCondition()) {
+ oprot.writeFieldBegin(CONDITION_FIELD_DESC);
+ oprot.writeString(struct.condition);
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.isSetTimestamp()) {
+ oprot.writeFieldBegin(TIMESTAMP_FIELD_DESC);
+ oprot.writeI64(struct.timestamp);
+ oprot.writeFieldEnd();
+ }
+ if(struct.isSetEndTimestamp()) {
+ oprot.writeFieldBegin(END_TIMESTAMP_FIELD_DESC);
+ oprot.writeI64(struct.endTimestamp);
+ oprot.writeFieldEnd();
+ }
+ if(struct.order != null) {
+ if(struct.isSetOrder()) {
+ oprot.writeFieldBegin(ORDER_FIELD_DESC);
+ struct.order.write(oprot);
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.page != null) {
+ if(struct.isSetPage()) {
+ oprot.writeFieldBegin(PAGE_FIELD_DESC);
+ struct.page.write(oprot);
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.value != null) {
+ if(struct.isSetValue()) {
+ oprot.writeFieldBegin(VALUE_FIELD_DESC);
+ struct.value.write(oprot);
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.replacement != null) {
+ if(struct.isSetReplacement()) {
+ oprot.writeFieldBegin(REPLACEMENT_FIELD_DESC);
+ struct.replacement.write(oprot);
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.values != null) {
+ if(struct.isSetValues()) {
+ oprot.writeFieldBegin(VALUES_FIELD_DESC);
+ {
+ oprot.writeListBegin(
+ new org.apache.thrift.protocol.TList(
+ org.apache.thrift.protocol.TType.STRUCT,
+ struct.values.size()));
+ for (TObject _iter27 : struct.values) {
+ _iter27.write(oprot);
+ }
+ oprot.writeListEnd();
+ }
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.json != null) {
+ if(struct.isSetJson()) {
+ oprot.writeFieldBegin(JSON_FIELD_DESC);
+ oprot.writeString(struct.json);
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.query != null) {
+ if(struct.isSetQuery()) {
+ oprot.writeFieldBegin(QUERY_FIELD_DESC);
+ oprot.writeString(struct.query);
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.function != null) {
+ if(struct.isSetFunction()) {
+ oprot.writeFieldBegin(FUNCTION_FIELD_DESC);
+ oprot.writeString(struct.function);
+ oprot.writeFieldEnd();
+ }
+ }
+ if(struct.isSetSourceRecord()) {
+ oprot.writeFieldBegin(SOURCE_RECORD_FIELD_DESC);
+ oprot.writeI64(struct.sourceRecord);
+ oprot.writeFieldEnd();
+ }
+ oprot.writeFieldStop();
+ oprot.writeStructEnd();
+ }
+
+ }
+
+ private static class TCommandTupleSchemeFactory implements
+ org.apache.thrift.scheme.SchemeFactory {
+ @Override
+ public TCommandTupleScheme getScheme() {
+ return new TCommandTupleScheme();
+ }
+ }
+
+ private static class TCommandTupleScheme
+ extends org.apache.thrift.scheme.TupleScheme {
+
+ @Override
+ public void write(org.apache.thrift.protocol.TProtocol prot,
+ TCommand struct) throws org.apache.thrift.TException {
+ org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+ oprot.writeI32(struct.verb.getValue());
+ java.util.BitSet optionals = new java.util.BitSet();
+ if(struct.isSetKeys()) {
+ optionals.set(0);
+ }
+ if(struct.isSetRecords()) {
+ optionals.set(1);
+ }
+ if(struct.isSetCriteria()) {
+ optionals.set(2);
+ }
+ if(struct.isSetCondition()) {
+ optionals.set(3);
+ }
+ if(struct.isSetTimestamp()) {
+ optionals.set(4);
+ }
+ if(struct.isSetEndTimestamp()) {
+ optionals.set(5);
+ }
+ if(struct.isSetOrder()) {
+ optionals.set(6);
+ }
+ if(struct.isSetPage()) {
+ optionals.set(7);
+ }
+ if(struct.isSetValue()) {
+ optionals.set(8);
+ }
+ if(struct.isSetReplacement()) {
+ optionals.set(9);
+ }
+ if(struct.isSetValues()) {
+ optionals.set(10);
+ }
+ if(struct.isSetJson()) {
+ optionals.set(11);
+ }
+ if(struct.isSetQuery()) {
+ optionals.set(12);
+ }
+ if(struct.isSetFunction()) {
+ optionals.set(13);
+ }
+ if(struct.isSetSourceRecord()) {
+ optionals.set(14);
+ }
+ oprot.writeBitSet(optionals, 15);
+ if(struct.isSetKeys()) {
+ {
+ oprot.writeI32(struct.keys.size());
+ for (java.lang.String _iter28 : struct.keys) {
+ oprot.writeString(_iter28);
+ }
+ }
+ }
+ if(struct.isSetRecords()) {
+ {
+ oprot.writeI32(struct.records.size());
+ for (long _iter29 : struct.records) {
+ oprot.writeI64(_iter29);
+ }
+ }
+ }
+ if(struct.isSetCriteria()) {
+ struct.criteria.write(oprot);
+ }
+ if(struct.isSetCondition()) {
+ oprot.writeString(struct.condition);
+ }
+ if(struct.isSetTimestamp()) {
+ oprot.writeI64(struct.timestamp);
+ }
+ if(struct.isSetEndTimestamp()) {
+ oprot.writeI64(struct.endTimestamp);
+ }
+ if(struct.isSetOrder()) {
+ struct.order.write(oprot);
+ }
+ if(struct.isSetPage()) {
+ struct.page.write(oprot);
+ }
+ if(struct.isSetValue()) {
+ struct.value.write(oprot);
+ }
+ if(struct.isSetReplacement()) {
+ struct.replacement.write(oprot);
+ }
+ if(struct.isSetValues()) {
+ {
+ oprot.writeI32(struct.values.size());
+ for (TObject _iter30 : struct.values) {
+ _iter30.write(oprot);
+ }
+ }
+ }
+ if(struct.isSetJson()) {
+ oprot.writeString(struct.json);
+ }
+ if(struct.isSetQuery()) {
+ oprot.writeString(struct.query);
+ }
+ if(struct.isSetFunction()) {
+ oprot.writeString(struct.function);
+ }
+ if(struct.isSetSourceRecord()) {
+ oprot.writeI64(struct.sourceRecord);
+ }
+ }
+
+ @Override
+ public void read(org.apache.thrift.protocol.TProtocol prot,
+ TCommand struct) throws org.apache.thrift.TException {
+ org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+ struct.verb = com.cinchapi.concourse.thrift.TCommandVerb
+ .findByValue(iprot.readI32());
+ struct.setVerbIsSet(true);
+ java.util.BitSet incoming = iprot.readBitSet(15);
+ if(incoming.get(0)) {
+ {
+ org.apache.thrift.protocol.TList _list31 = iprot
+ .readListBegin(
+ org.apache.thrift.protocol.TType.STRING);
+ struct.keys = new java.util.ArrayList(
+ _list31.size);
+ @org.apache.thrift.annotation.Nullable java.lang.String _elem32;
+ for (int _i33 = 0; _i33 < _list31.size; ++_i33) {
+ _elem32 = iprot.readString();
+ struct.keys.add(_elem32);
+ }
+ }
+ struct.setKeysIsSet(true);
+ }
+ if(incoming.get(1)) {
+ {
+ org.apache.thrift.protocol.TList _list34 = iprot
+ .readListBegin(
+ org.apache.thrift.protocol.TType.I64);
+ struct.records = new java.util.ArrayList(
+ _list34.size);
+ long _elem35;
+ for (int _i36 = 0; _i36 < _list34.size; ++_i36) {
+ _elem35 = iprot.readI64();
+ struct.records.add(_elem35);
+ }
+ }
+ struct.setRecordsIsSet(true);
+ }
+ if(incoming.get(2)) {
+ struct.criteria = new TCriteria();
+ struct.criteria.read(iprot);
+ struct.setCriteriaIsSet(true);
+ }
+ if(incoming.get(3)) {
+ struct.condition = iprot.readString();
+ struct.setConditionIsSet(true);
+ }
+ if(incoming.get(4)) {
+ struct.timestamp = iprot.readI64();
+ struct.setTimestampIsSet(true);
+ }
+ if(incoming.get(5)) {
+ struct.endTimestamp = iprot.readI64();
+ struct.setEndTimestampIsSet(true);
+ }
+ if(incoming.get(6)) {
+ struct.order = new TOrder();
+ struct.order.read(iprot);
+ struct.setOrderIsSet(true);
+ }
+ if(incoming.get(7)) {
+ struct.page = new TPage();
+ struct.page.read(iprot);
+ struct.setPageIsSet(true);
+ }
+ if(incoming.get(8)) {
+ struct.value = new TObject();
+ struct.value.read(iprot);
+ struct.setValueIsSet(true);
+ }
+ if(incoming.get(9)) {
+ struct.replacement = new TObject();
+ struct.replacement.read(iprot);
+ struct.setReplacementIsSet(true);
+ }
+ if(incoming.get(10)) {
+ {
+ org.apache.thrift.protocol.TList _list37 = iprot
+ .readListBegin(
+ org.apache.thrift.protocol.TType.STRUCT);
+ struct.values = new java.util.ArrayList(
+ _list37.size);
+ @org.apache.thrift.annotation.Nullable TObject _elem38;
+ for (int _i39 = 0; _i39 < _list37.size; ++_i39) {
+ _elem38 = new TObject();
+ _elem38.read(iprot);
+ struct.values.add(_elem38);
+ }
+ }
+ struct.setValuesIsSet(true);
+ }
+ if(incoming.get(11)) {
+ struct.json = iprot.readString();
+ struct.setJsonIsSet(true);
+ }
+ if(incoming.get(12)) {
+ struct.query = iprot.readString();
+ struct.setQueryIsSet(true);
+ }
+ if(incoming.get(13)) {
+ struct.function = iprot.readString();
+ struct.setFunctionIsSet(true);
+ }
+ if(incoming.get(14)) {
+ struct.sourceRecord = iprot.readI64();
+ struct.setSourceRecordIsSet(true);
+ }
+ }
+ }
+
+ private static S scheme(
+ org.apache.thrift.protocol.TProtocol proto) {
+ return (org.apache.thrift.scheme.StandardScheme.class
+ .equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY
+ : TUPLE_SCHEME_FACTORY).getScheme();
+ }
+}
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/thrift/TCommandVerb.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/thrift/TCommandVerb.java
new file mode 100644
index 000000000..637532126
--- /dev/null
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/thrift/TCommandVerb.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2013-2026 Cinchapi 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.cinchapi.concourse.thrift;
+
+/**
+ * The verb identifying which operation a TCommand represents.
+ */
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.20.0)", date = "2026-03-14")
+public enum TCommandVerb implements org.apache.thrift.TEnum {
+ FIND(1),
+ SELECT(2),
+ GET(3),
+ NAVIGATE(4),
+ ADD(5),
+ SET(6),
+ REMOVE(7),
+ CLEAR(8),
+ INSERT(9),
+ LINK(10),
+ UNLINK(11),
+ VERIFY(12),
+ VERIFY_AND_SWAP(13),
+ VERIFY_OR_SET(14),
+ FIND_OR_ADD(15),
+ FIND_OR_INSERT(16),
+ SEARCH(17),
+ BROWSE(18),
+ DESCRIBE(19),
+ TRACE(20),
+ HOLDS(21),
+ JSONIFY(22),
+ CHRONICLE(23),
+ DIFF(24),
+ AUDIT(25),
+ REVERT(26),
+ RECONCILE(27),
+ CONSOLIDATE(28),
+ CALCULATE(29),
+ STAGE(30),
+ COMMIT(31),
+ ABORT(32),
+ PING(33),
+ INVENTORY(34);
+
+ private final int value;
+
+ private TCommandVerb(int value) {
+ this.value = value;
+ }
+
+ /**
+ * Get the integer value of this enum value, as defined in the Thrift IDL.
+ */
+ @Override
+ public int getValue() {
+ return value;
+ }
+
+ /**
+ * Find a the enum type by its integer value, as defined in the Thrift IDL.
+ *
+ * @return null if the value is not found.
+ */
+ @org.apache.thrift.annotation.Nullable
+ public static TCommandVerb findByValue(int value) {
+ switch (value) {
+ case 1:
+ return FIND;
+ case 2:
+ return SELECT;
+ case 3:
+ return GET;
+ case 4:
+ return NAVIGATE;
+ case 5:
+ return ADD;
+ case 6:
+ return SET;
+ case 7:
+ return REMOVE;
+ case 8:
+ return CLEAR;
+ case 9:
+ return INSERT;
+ case 10:
+ return LINK;
+ case 11:
+ return UNLINK;
+ case 12:
+ return VERIFY;
+ case 13:
+ return VERIFY_AND_SWAP;
+ case 14:
+ return VERIFY_OR_SET;
+ case 15:
+ return FIND_OR_ADD;
+ case 16:
+ return FIND_OR_INSERT;
+ case 17:
+ return SEARCH;
+ case 18:
+ return BROWSE;
+ case 19:
+ return DESCRIBE;
+ case 20:
+ return TRACE;
+ case 21:
+ return HOLDS;
+ case 22:
+ return JSONIFY;
+ case 23:
+ return CHRONICLE;
+ case 24:
+ return DIFF;
+ case 25:
+ return AUDIT;
+ case 26:
+ return REVERT;
+ case 27:
+ return RECONCILE;
+ case 28:
+ return CONSOLIDATE;
+ case 29:
+ return CALCULATE;
+ case 30:
+ return STAGE;
+ case 31:
+ return COMMIT;
+ case 32:
+ return ABORT;
+ case 33:
+ return PING;
+ case 34:
+ return INVENTORY;
+ default:
+ return null;
+ }
+ }
+}
diff --git a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java
new file mode 100644
index 000000000..69946e706
--- /dev/null
+++ b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java
@@ -0,0 +1,1611 @@
+/*
+ * Copyright (c) 2013-2026 Cinchapi 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.cinchapi.concourse.lang.command;
+
+import java.util.Arrays;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.cinchapi.concourse.Timestamp;
+import com.cinchapi.concourse.lang.paginate.Page;
+import com.cinchapi.concourse.lang.sort.Order;
+import com.cinchapi.concourse.thrift.TCommand;
+import com.cinchapi.concourse.thrift.TCommandVerb;
+
+/**
+ * Unit tests verifying round-trip serialization and deserialization of
+ * {@link Command Commands} through {@link TCommand}.
+ *
+ * Each test builds a {@link Command} via the fluent API, serializes it to a
+ * {@link TCommand}, then deserializes back and asserts that the resulting
+ * {@code ccl()} output matches the original.
+ *
+ *
+ * @author Jeff Nelson
+ */
+public class CommandSerializationTest {
+
+ /**
+ * Goal: Verify that a {@code ping} command round-trips
+ * through {@link TCommand} serialization.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code ping} command.
+ *
Serialize to {@link TCommand} and verify the verb.
+ *
Deserialize back and compare {@code ccl()} output.
+ *
+ *
+ * Expected: The verb is {@code PING} and the round-tripped
+ * CCL matches the original.
+ */
+ @Test
+ public void testPingRoundTrip() {
+ Command cmd = Command.ping();
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.PING, tc.getVerb());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code stage} command round-trips
+ * through {@link TCommand} serialization.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code stage} command.
+ *
Serialize to {@link TCommand} and verify the verb.
+ *
Deserialize back and compare {@code ccl()} output.
+ *
+ *
+ * Expected: The verb is {@code STAGE} and the
+ * round-tripped CCL matches the original.
+ */
+ @Test
+ public void testStageRoundTrip() {
+ Command cmd = Command.stage();
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.STAGE, tc.getVerb());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code commit} command round-trips
+ * through {@link TCommand} serialization.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code commit} command.
+ *
Serialize to {@link TCommand} and verify the verb.
+ *
Deserialize back and compare {@code ccl()} output.
+ *
+ *
+ * Expected: The verb is {@code COMMIT} and the
+ * round-tripped CCL matches the original.
+ */
+ @Test
+ public void testCommitRoundTrip() {
+ Command cmd = Command.commit();
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.COMMIT, tc.getVerb());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that an {@code abort} command round-trips
+ * through {@link TCommand} serialization.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code abort} command.
+ *
Serialize to {@link TCommand} and verify the verb.
+ *
Deserialize back and compare {@code ccl()} output.
+ *
+ *
+ * Expected: The verb is {@code ABORT} and the
+ * round-tripped CCL matches the original.
+ */
+ @Test
+ public void testAbortRoundTrip() {
+ Command cmd = Command.abort();
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.ABORT, tc.getVerb());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that an {@code inventory} command
+ * round-trips through {@link TCommand} serialization.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code inventory} command.
+ *
Serialize to {@link TCommand} and verify the verb.
+ *
Deserialize back and compare {@code ccl()} output.
+ *
+ *
+ * Expected: The verb is {@code INVENTORY} and the
+ * round-tripped CCL matches the original.
+ */
+ @Test
+ public void testInventoryRoundTrip() {
+ Command cmd = Command.inventory();
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.INVENTORY, tc.getVerb());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code find} command with a CCL
+ * condition round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code find} command with condition {@code "age > 30"}.
+ *
Serialize, verify verb is {@code FIND}, and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "find age > 30"}.
+ */
+ @Test
+ public void testFindWithConditionRoundTrip() {
+ Command cmd = Command.find("age > 30");
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.FIND, tc.getVerb());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code find} command with a
+ * timestamp round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code find} command with condition {@code "age > 30"} and a
+ * historical timestamp.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL includes the {@code at}
+ * clause.
+ */
+ @Test
+ public void testFindWithTimestampRoundTrip() {
+ Command cmd = Command.find("age > 30").at(Timestamp.fromMicros(12345));
+ TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetTimestamp());
+ Assert.assertEquals(12345, tc.getTimestamp());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code find} command with order and
+ * page round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code find} command with condition, order, and page.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL includes
+ * {@code order by} and {@code page} clauses.
+ */
+ @Test
+ public void testFindWithOrderAndPageRoundTrip() {
+ Command cmd = Command.find("age > 30").order(Order.by("name").build())
+ .page(Page.sized(10));
+ TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetOrder());
+ Assert.assertTrue(tc.isSetPage());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code select} command with keys and
+ * records round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code select} command for keys {@code "name"} and
+ * {@code "age"} from records {@code 1}, {@code 2}, {@code 3}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "select [name, age] from [1, 2, 3]"}.
+ */
+ @Test
+ public void testSelectKeysFromRecordsRoundTrip() {
+ Command cmd = Command.select("name", "age").from(1, 2, 3);
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.SELECT, tc.getVerb());
+ Assert.assertEquals(Arrays.asList("name", "age"), tc.getKeys());
+ Assert.assertEquals(Arrays.asList(1L, 2L, 3L), tc.getRecords());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code selectAll} command from a
+ * record round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code selectAll} command from record {@code 1}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is {@code "select 1"}.
+ */
+ @Test
+ public void testSelectAllFromRecordRoundTrip() {
+ Command cmd = Command.selectAll().from(1);
+ TCommand tc = cmd.toThrift();
+ Assert.assertFalse(tc.isSetKeys());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code select} command with a CCL
+ * condition round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code select} command for key {@code "name"} with condition
+ * {@code "status = active"}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "select name where status = active"}.
+ */
+ @Test
+ public void testSelectWithConditionRoundTrip() {
+ Command cmd = Command.select("name").where("status = active");
+ TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetCondition());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code select} command with
+ * timestamp, order, and page round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code select} with keys, records, timestamp, order, and
+ * page.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL includes all clauses.
+ */
+ @Test
+ public void testSelectWithAllOptionsRoundTrip() {
+ Command cmd = Command.select("name").from(1)
+ .at(Timestamp.fromMicros(5000)).order(Order.by("name").build())
+ .page(Page.sized(5));
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code get} command with a key and
+ * record round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code get} command for key {@code "name"} from record
+ * {@code 1}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "get name from 1"}.
+ */
+ @Test
+ public void testGetFromRecordRoundTrip() {
+ Command cmd = Command.get("name").from(1);
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.GET, tc.getVerb());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code getAll} command with a
+ * condition round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code getAll} command with condition
+ * {@code "active = true"}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "get where active = true"}.
+ */
+ @Test
+ public void testGetAllWithConditionRoundTrip() {
+ Command cmd = Command.getAll().where("active = true");
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code navigate} command from a
+ * record round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code navigate} command for key {@code "friends.name"} from
+ * record {@code 1}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "navigate friends.name from 1"}.
+ */
+ @Test
+ public void testNavigateFromRecordRoundTrip() {
+ Command cmd = Command.navigate("friends.name").from(1);
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.NAVIGATE, tc.getVerb());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code navigate} command with a
+ * condition and timestamp round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code navigate} command with a condition and historical
+ * timestamp.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL includes both the
+ * {@code where} and {@code at} clauses.
+ */
+ @Test
+ public void testNavigateWithConditionAndTimestampRoundTrip() {
+ Command cmd = Command.navigate("friends.name").where("active = true")
+ .at(Timestamp.fromMicros(9999));
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that an {@code add} command with key and
+ * value round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code add} command with key {@code "name"} and value
+ * {@code "jeff"}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "add name as \"jeff\""}.
+ */
+ @Test
+ public void testAddKeyValueRoundTrip() {
+ Command cmd = Command.add("name").as("jeff");
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.ADD, tc.getVerb());
+ Assert.assertFalse(tc.isSetRecords());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that an {@code add} command with key,
+ * value, and records round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code add} command with key {@code "name"}, value
+ * {@code "jeff"}, and records {@code 1}, {@code 2}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "add name as \"jeff\" in [1, 2]"}.
+ */
+ @Test
+ public void testAddKeyValueInRecordsRoundTrip() {
+ Command cmd = Command.add("name").as("jeff").in(1, 2);
+ TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetRecords());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that an {@code add} command with a numeric
+ * value round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code add} command with key {@code "age"} and integer value
+ * {@code 30}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "add age as 30"}.
+ */
+ @Test
+ public void testAddNumericValueRoundTrip() {
+ Command cmd = Command.add("age").as(30);
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code set} command round-trips
+ * correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code set} command with key {@code "name"}, value
+ * {@code "jeff"}, and record {@code 1}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "set name as \"jeff\" in 1"}.
+ */
+ @Test
+ public void testSetRoundTrip() {
+ Command cmd = Command.set("name").as("jeff").in(1);
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.SET, tc.getVerb());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code remove} command round-trips
+ * correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code remove} command with key {@code "name"}, value
+ * {@code "jeff"}, and record {@code 1}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "remove name as \"jeff\" from 1"}.
+ */
+ @Test
+ public void testRemoveRoundTrip() {
+ Command cmd = Command.remove("name").as("jeff").from(1);
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.REMOVE, tc.getVerb());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code clear} command with keys and
+ * records round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code clear} command with keys {@code "name"} and
+ * {@code "age"} from records {@code 1} and {@code 2}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "clear [name, age] from [1, 2]"}.
+ */
+ @Test
+ public void testClearKeysFromRecordsRoundTrip() {
+ Command cmd = Command.clear("name", "age").from(1, 2);
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.CLEAR, tc.getVerb());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code clear} command with records
+ * only (no keys) round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code clear} command targeting records {@code 1} and
+ * {@code 2}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL is
+ * {@code "clear [1, 2]"}.
+ */
+ @Test
+ public void testClearRecordsOnlyRoundTrip() {
+ Command cmd = Command.clear(1, 2);
+ TCommand tc = cmd.toThrift();
+ Assert.assertFalse(tc.isSetKeys());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that an {@code insert} command with JSON
+ * round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code insert} command with JSON
+ * {@code "{\"name\":\"jeff\"}"}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL matches the original.
+ */
+ @Test
+ public void testInsertJsonRoundTrip() {
+ Command cmd = Command.insert("{\"name\":\"jeff\"}");
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.INSERT, tc.getVerb());
+ Assert.assertFalse(tc.isSetRecords());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that an {@code insert} command with JSON
+ * and a record target round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build an {@code insert} command with JSON targeting record
+ * {@code 1}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL includes {@code "in 1"}.
+ */
+ @Test
+ public void testInsertJsonInRecordRoundTrip() {
+ Command cmd = Command.insert("{\"name\":\"jeff\"}").in(1);
+ TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetRecords());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code link} command round-trips
+ * correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code link} command for key {@code "friends"} from source
+ * record {@code 1} to destination {@code 2}.
Build a {@code consolidate} command for records {@code 1}, {@code 2},
+ * and {@code 3}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL matches the original.
+ */
+ @Test
+ public void testConsolidateRoundTrip() {
+ Command cmd = Command.consolidate(1, 2, 3);
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.CONSOLIDATE, tc.getVerb());
+ Assert.assertEquals(Arrays.asList(1L, 2L, 3L), tc.getRecords());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code calculate} command with
+ * records round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code calculate} command with function {@code "count"} for
+ * key {@code "name"} in records {@code 1} and {@code 2}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL matches the original.
+ */
+ @Test
+ public void testCalculateWithRecordsRoundTrip() {
+ Command cmd = Command.calculate("count", "name").in(1, 2);
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.CALCULATE, tc.getVerb());
+ Assert.assertEquals("count", tc.getFunction());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code calculate} command with a
+ * condition round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code calculate} command with function {@code "count"} for
+ * key {@code "name"} with condition {@code "active = true"}.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL matches the original.
+ */
+ @Test
+ public void testCalculateWithConditionRoundTrip() {
+ Command cmd = Command.calculate("count", "name").where("active = true");
+ TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetCondition());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code calculate} command with a
+ * condition and timestamp round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code calculate} command with function, key, condition, and
+ * timestamp.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL includes both the
+ * condition and timestamp.
+ */
+ @Test
+ public void testCalculateWithConditionAndTimestampRoundTrip() {
+ Command cmd = Command.calculate("count", "name").where("active = true")
+ .at(Timestamp.fromMicros(5000));
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+}
diff --git a/interface/data.thrift b/interface/data.thrift
index 850923bc9..c78cac4ac 100644
--- a/interface/data.thrift
+++ b/interface/data.thrift
@@ -104,3 +104,71 @@ struct TPage {
1:required i32 skip,
2:required i32 limit
}
+
+/**
+ * The verb identifying which operation a TCommand represents.
+ */
+enum TCommandVerb {
+ FIND = 1,
+ SELECT = 2,
+ GET = 3,
+ NAVIGATE = 4,
+ ADD = 5,
+ SET = 6,
+ REMOVE = 7,
+ CLEAR = 8,
+ INSERT = 9,
+ LINK = 10,
+ UNLINK = 11,
+ VERIFY = 12,
+ VERIFY_AND_SWAP = 13,
+ VERIFY_OR_SET = 14,
+ FIND_OR_ADD = 15,
+ FIND_OR_INSERT = 16,
+ SEARCH = 17,
+ BROWSE = 18,
+ DESCRIBE = 19,
+ TRACE = 20,
+ HOLDS = 21,
+ JSONIFY = 22,
+ CHRONICLE = 23,
+ DIFF = 24,
+ AUDIT = 25,
+ REVERT = 26,
+ RECONCILE = 27,
+ CONSOLIDATE = 28,
+ CALCULATE = 29,
+ STAGE = 30,
+ COMMIT = 31,
+ ABORT = 32,
+ PING = 33,
+ INVENTORY = 34,
+}
+
+/**
+ * A structured representation of a complete Concourse command that can
+ * be transmitted over the wire. Each command is identified by a required
+ * verb; the optional fields carry the parameters appropriate for that
+ * verb.
+ *
+ * Reuses existing types (TCriteria, TOrder, TPage, TObject) for
+ * condition, ordering, pagination, and values.
+ */
+struct TCommand {
+ 1: required TCommandVerb verb,
+ 2: optional list keys,
+ 3: optional list records,
+ 4: optional TCriteria criteria,
+ 5: optional string condition,
+ 6: optional i64 timestamp,
+ 7: optional i64 endTimestamp,
+ 8: optional TOrder order,
+ 9: optional TPage page,
+ 10: optional TObject value,
+ 11: optional TObject replacement,
+ 12: optional list values,
+ 13: optional string json,
+ 14: optional string query,
+ 15: optional string function,
+ 16: optional i64 sourceRecord,
+}
From 8d0a6855fdeb6f6f783481122db145b7af95cd7a Mon Sep 17 00:00:00 2001
From: Jeff Nelson
Date: Sun, 15 Mar 2026 07:02:39 -0400
Subject: [PATCH 06/13] more test cases
---
.../command/CommandSerializationTest.java | 119 ++++++++++++++++++
1 file changed, 119 insertions(+)
diff --git a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java
index 69946e706..ae5423bcf 100644
--- a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java
+++ b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java
@@ -21,8 +21,10 @@
import org.junit.Test;
import com.cinchapi.concourse.Timestamp;
+import com.cinchapi.concourse.lang.Criteria;
import com.cinchapi.concourse.lang.paginate.Page;
import com.cinchapi.concourse.lang.sort.Order;
+import com.cinchapi.concourse.thrift.Operator;
import com.cinchapi.concourse.thrift.TCommand;
import com.cinchapi.concourse.thrift.TCommandVerb;
@@ -235,6 +237,38 @@ public void testFindWithOrderAndPageRoundTrip() {
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
+ /**
+ * Goal: Verify that a {@code find} command built with a
+ * structured {@link Criteria} object round-trips correctly through
+ * {@link TCommand} serialization.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@link Criteria} with {@code age GREATER_THAN 30}.
+ *
Build a {@code find} command using that {@link Criteria}.
+ *
Serialize to {@link TCommand} and verify the {@code criteria} field
+ * is set instead of {@code condition}.
+ *
Deserialize and compare {@code ccl()} output.
+ *
+ *
+ * Expected: The {@link TCommand} has
+ * {@code isSetCriteria() == true} and {@code isSetCondition() == false},
+ * and the round-tripped CCL matches the original.
+ */
+ @Test
+ public void testFindWithCriteriaRoundTrip() {
+ Criteria criteria = Criteria.where().key("age")
+ .operator(Operator.GREATER_THAN).value(30).build();
+ Command cmd = Command.find(criteria);
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(TCommandVerb.FIND, tc.getVerb());
+ Assert.assertTrue(tc.isSetCriteria());
+ Assert.assertFalse(tc.isSetCondition());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
/**
* Goal: Verify that a {@code select} command with keys and
* records round-trips correctly.
@@ -384,6 +418,61 @@ public void testGetAllWithConditionRoundTrip() {
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
+ /**
+ * Goal: Verify that a {@code get} command with a timestamp
+ * round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code get} command for key {@code "name"} from record
+ * {@code 1} at a historical timestamp.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL includes the {@code at}
+ * clause.
+ */
+ @Test
+ public void testGetWithTimestampRoundTrip() {
+ Command cmd = Command.get("name").from(1)
+ .at(Timestamp.fromMicros(5000));
+ TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetTimestamp());
+ Assert.assertEquals(5000, tc.getTimestamp());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
+ /**
+ * Goal: Verify that a {@code get} command with timestamp,
+ * order, and page round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code get} command for key {@code "name"} from record
+ * {@code 1} with a timestamp, order, and page.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The round-tripped CCL includes the {@code at},
+ * {@code order by}, and {@code page} clauses.
+ */
+ @Test
+ public void testGetWithAllOptionsRoundTrip() {
+ Command cmd = Command.get("name").from(1).at(Timestamp.fromMicros(5000))
+ .order(Order.by("name").build()).page(Page.sized(5));
+ TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetTimestamp());
+ Assert.assertTrue(tc.isSetOrder());
+ Assert.assertTrue(tc.isSetPage());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
/**
* Goal: Verify that a {@code navigate} command from a
* record round-trips correctly.
@@ -1267,6 +1356,36 @@ public void testDiffKeyTimestampRoundTrip() {
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
+ /**
+ * Goal: Verify that a {@code diff} command for a key
+ * between two timestamps (without a record) round-trips correctly.
+ *
+ * Start state: No prior state needed.
+ *
+ * Workflow:
+ *
+ *
Build a {@code diff} command for key {@code "name"} with start and
+ * end timestamps.
+ *
Serialize and deserialize.
+ *
Compare {@code ccl()} output.
+ *
+ *
+ * Expected: The {@link TCommand} has keys and both
+ * timestamp fields set but no records, and the round-tripped CCL matches
+ * the original.
+ */
+ @Test
+ public void testDiffKeyRangeRoundTrip() {
+ Command cmd = Command.diff("name").at(Timestamp.fromMicros(1000))
+ .at(Timestamp.fromMicros(2000));
+ TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetKeys());
+ Assert.assertFalse(tc.isSetRecords());
+ Assert.assertTrue(tc.isSetTimestamp());
+ Assert.assertTrue(tc.isSetEndTimestamp());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
+
/**
* Goal: Verify that a {@code diff} command for a key and
* record at a timestamp round-trips correctly.
From b0c9b7fa78a969832dddc4116f01b5e87eaa6c68 Mon Sep 17 00:00:00 2001
From: Jeff Nelson
Date: Sun, 15 Mar 2026 07:22:57 -0400
Subject: [PATCH 07/13] fix of the unit tests again
---
.../command/CommandSerializationTest.java | 260 ++++++++----------
1 file changed, 113 insertions(+), 147 deletions(-)
diff --git a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java
index ae5423bcf..1a8a55b0d 100644
--- a/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java
+++ b/concourse-driver-java/src/test/java/com/cinchapi/concourse/lang/command/CommandSerializationTest.java
@@ -42,123 +42,33 @@
public class CommandSerializationTest {
/**
- * Goal: Verify that a {@code ping} command round-trips
- * through {@link TCommand} serialization.
+ * Goal: Verify that all nullary commands (no parameters)
+ * round-trip through {@link TCommand} serialization.
*
* Start state: No prior state needed.
*
* Workflow:
*
- *
Build a {@code ping} command.
- *
Serialize to {@link TCommand} and verify the verb.
Serialize to {@link TCommand} and verify the verb matches the CCL
+ * verb name.
*
Deserialize back and compare {@code ccl()} output.
*
*
- * Expected: The verb is {@code PING} and the round-tripped
- * CCL matches the original.
+ * Expected: Each command's verb maps correctly and the
+ * round-tripped CCL matches the original. All five share the same
+ * serialization path, so one test covers the mechanism.
*/
@Test
- public void testPingRoundTrip() {
- Command cmd = Command.ping();
- TCommand tc = cmd.toThrift();
- Assert.assertEquals(TCommandVerb.PING, tc.getVerb());
- Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
- }
-
- /**
- * Goal: Verify that a {@code stage} command round-trips
- * through {@link TCommand} serialization.
- *
- * Start state: No prior state needed.
- *
- * Workflow:
- *
- *
Build a {@code stage} command.
- *
Serialize to {@link TCommand} and verify the verb.
- *
Deserialize back and compare {@code ccl()} output.
- *
- *
- * Expected: The verb is {@code STAGE} and the
- * round-tripped CCL matches the original.
- */
- @Test
- public void testStageRoundTrip() {
- Command cmd = Command.stage();
- TCommand tc = cmd.toThrift();
- Assert.assertEquals(TCommandVerb.STAGE, tc.getVerb());
- Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
- }
-
- /**
- * Goal: Verify that a {@code commit} command round-trips
- * through {@link TCommand} serialization.
- *
- * Start state: No prior state needed.
- *
- * Workflow:
- *
- *
Build a {@code commit} command.
- *
Serialize to {@link TCommand} and verify the verb.
- *
Deserialize back and compare {@code ccl()} output.
- *
- *
- * Expected: The verb is {@code COMMIT} and the
- * round-tripped CCL matches the original.
- */
- @Test
- public void testCommitRoundTrip() {
- Command cmd = Command.commit();
- TCommand tc = cmd.toThrift();
- Assert.assertEquals(TCommandVerb.COMMIT, tc.getVerb());
- Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
- }
-
- /**
- * Goal: Verify that an {@code abort} command round-trips
- * through {@link TCommand} serialization.
- *
- * Start state: No prior state needed.
- *
- * Workflow:
- *
- *
Build an {@code abort} command.
- *
Serialize to {@link TCommand} and verify the verb.
- *
Deserialize back and compare {@code ccl()} output.
- *
- *
- * Expected: The verb is {@code ABORT} and the
- * round-tripped CCL matches the original.
- */
- @Test
- public void testAbortRoundTrip() {
- Command cmd = Command.abort();
- TCommand tc = cmd.toThrift();
- Assert.assertEquals(TCommandVerb.ABORT, tc.getVerb());
- Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
- }
-
- /**
- * Goal: Verify that an {@code inventory} command
- * round-trips through {@link TCommand} serialization.
- *
- * Start state: No prior state needed.
- *
- * Workflow:
- *
- *
Build an {@code inventory} command.
- *
Serialize to {@link TCommand} and verify the verb.
- *
Deserialize back and compare {@code ccl()} output.
- *
- *
- * Expected: The verb is {@code INVENTORY} and the
- * round-tripped CCL matches the original.
- */
- @Test
- public void testInventoryRoundTrip() {
- Command cmd = Command.inventory();
- TCommand tc = cmd.toThrift();
- Assert.assertEquals(TCommandVerb.INVENTORY, tc.getVerb());
- Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ public void testNullaryCommandsRoundTrip() {
+ Command[] commands = { Command.ping(), Command.stage(),
+ Command.commit(), Command.abort(), Command.inventory() };
+ for (Command cmd : commands) {
+ TCommand tc = cmd.toThrift();
+ Assert.assertEquals(cmd.ccl(), tc.getVerb().name().toLowerCase());
+ Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
+ }
}
/**
@@ -358,7 +268,8 @@ public void testSelectWithConditionRoundTrip() {
*
Compare {@code ccl()} output.
*
*
- * Expected: The round-tripped CCL includes all clauses.
+ * Expected: The {@link TCommand} has timestamp, order, and
+ * page fields set, and the round-tripped CCL matches.
*/
@Test
public void testSelectWithAllOptionsRoundTrip() {
@@ -366,6 +277,9 @@ public void testSelectWithAllOptionsRoundTrip() {
.at(Timestamp.fromMicros(5000)).order(Order.by("name").build())
.page(Page.sized(5));
TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetTimestamp());
+ Assert.assertTrue(tc.isSetOrder());
+ Assert.assertTrue(tc.isSetPage());
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
@@ -408,13 +322,15 @@ public void testGetFromRecordRoundTrip() {
*
Compare {@code ccl()} output.
*
*
- * Expected: The round-tripped CCL is
- * {@code "get where active = true"}.
+ * Expected: The {@link TCommand} has the condition field
+ * set, no keys, and the round-tripped CCL matches.
*/
@Test
public void testGetAllWithConditionRoundTrip() {
Command cmd = Command.getAll().where("active = true");
TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetCondition());
+ Assert.assertFalse(tc.isSetKeys());
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
@@ -512,14 +428,17 @@ public void testNavigateFromRecordRoundTrip() {
*
Compare {@code ccl()} output.
*
*
- * Expected: The round-tripped CCL includes both the
- * {@code where} and {@code at} clauses.
+ * Expected: The {@link TCommand} has both condition and
+ * timestamp fields set, and the round-tripped CCL matches.
*/
@Test
public void testNavigateWithConditionAndTimestampRoundTrip() {
Command cmd = Command.navigate("friends.name").where("active = true")
.at(Timestamp.fromMicros(9999));
TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetCondition());
+ Assert.assertTrue(tc.isSetTimestamp());
+ Assert.assertEquals(9999, tc.getTimestamp());
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
@@ -574,30 +493,6 @@ public void testAddKeyValueInRecordsRoundTrip() {
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
- /**
- * Goal: Verify that an {@code add} command with a numeric
- * value round-trips correctly.
- *
- * Start state: No prior state needed.
- *
- * Workflow:
- *
- *
Build an {@code add} command with key {@code "age"} and integer value
- * {@code 30}.
- *
Serialize and deserialize.
- *
Compare {@code ccl()} output.
- *
- *
- * Expected: The round-tripped CCL is
- * {@code "add age as 30"}.
- */
- @Test
- public void testAddNumericValueRoundTrip() {
- Command cmd = Command.add("age").as(30);
- TCommand tc = cmd.toThrift();
- Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
- }
-
/**
* Goal: Verify that a {@code set} command round-trips
* correctly.
@@ -637,14 +532,17 @@ public void testSetRoundTrip() {
*
Compare {@code ccl()} output.
*
*
- * Expected: The round-tripped CCL is
- * {@code "remove name as \"jeff\" from 1"}.
+ * Expected: The {@link TCommand} has key, value, and
+ * records fields correctly populated.
*/
@Test
public void testRemoveRoundTrip() {
Command cmd = Command.remove("name").as("jeff").from(1);
TCommand tc = cmd.toThrift();
Assert.assertEquals(TCommandVerb.REMOVE, tc.getVerb());
+ Assert.assertTrue(tc.isSetValue());
+ Assert.assertEquals(Arrays.asList("name"), tc.getKeys());
+ Assert.assertEquals(Arrays.asList(1L), tc.getRecords());
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
@@ -786,13 +684,16 @@ public void testLinkRoundTrip() {
*
Compare {@code ccl()} output.
*
*
- * Expected: The round-tripped CCL matches the original.
+ * Expected: The {@link TCommand} has the source record and
+ * destination record correctly mapped.
*/
@Test
public void testUnlinkRoundTrip() {
Command cmd = Command.unlink("friends").from(1).to(2);
TCommand tc = cmd.toThrift();
Assert.assertEquals(TCommandVerb.UNLINK, tc.getVerb());
+ Assert.assertEquals(1, tc.getSourceRecord());
+ Assert.assertEquals(Arrays.asList(2L), tc.getRecords());
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
@@ -887,13 +788,16 @@ public void testVerifyAndSwapRoundTrip() {
*
Compare {@code ccl()} output.
*
*
- * Expected: The round-tripped CCL matches the original.
+ * Expected: The {@link TCommand} has key, value, and
+ * record fields populated.
*/
@Test
public void testVerifyOrSetRoundTrip() {
Command cmd = Command.verifyOrSet("name").as("jeff").in(1);
TCommand tc = cmd.toThrift();
Assert.assertEquals(TCommandVerb.VERIFY_OR_SET, tc.getVerb());
+ Assert.assertTrue(tc.isSetValue());
+ Assert.assertEquals(Arrays.asList(1L), tc.getRecords());
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
@@ -911,13 +815,17 @@ public void testVerifyOrSetRoundTrip() {
*
Compare {@code ccl()} output.
*
*
- * Expected: The round-tripped CCL matches the original.
+ * Expected: The {@link TCommand} has key and value fields
+ * populated but no records.
*/
@Test
public void testFindOrAddRoundTrip() {
Command cmd = Command.findOrAdd("name").as("jeff");
TCommand tc = cmd.toThrift();
Assert.assertEquals(TCommandVerb.FIND_OR_ADD, tc.getVerb());
+ Assert.assertTrue(tc.isSetValue());
+ Assert.assertEquals(Arrays.asList("name"), tc.getKeys());
+ Assert.assertFalse(tc.isSetRecords());
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
@@ -935,7 +843,8 @@ public void testFindOrAddRoundTrip() {
*
Compare {@code ccl()} output.
*
*
- * Expected: The round-tripped CCL matches the original.
+ * Expected: The {@link TCommand} has condition and json
+ * fields populated.
*/
@Test
public void testFindOrInsertRoundTrip() {
@@ -943,6 +852,8 @@ public void testFindOrInsertRoundTrip() {
.json("{\"name\":\"jeff\"}");
TCommand tc = cmd.toThrift();
Assert.assertEquals(TCommandVerb.FIND_OR_INSERT, tc.getVerb());
+ Assert.assertTrue(tc.isSetCondition());
+ Assert.assertTrue(tc.isSetJson());
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
@@ -1078,13 +989,15 @@ public void testDescribeAllRoundTrip() {
*
Compare {@code ccl()} output.
*
*
- * Expected: The round-tripped CCL includes the {@code at}
- * clause.
+ * Expected: The {@link TCommand} has a timestamp but no
+ * records, and the round-tripped CCL matches.
*/
@Test
public void testDescribeAllWithTimestampRoundTrip() {
Command cmd = Command.describeAll().at(Timestamp.fromMicros(5000));
TCommand tc = cmd.toThrift();
+ Assert.assertTrue(tc.isSetTimestamp());
+ Assert.assertFalse(tc.isSetRecords());
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
@@ -1102,13 +1015,16 @@ public void testDescribeAllWithTimestampRoundTrip() {
*
Compare {@code ccl()} output.
*
*
- * Expected: The round-tripped CCL matches the original.
+ * Expected: The {@link TCommand} has the records list
+ * populated and the round-tripped CCL matches.
*/
@Test
public void testTraceRoundTrip() {
Command cmd = Command.trace(1, 2);
TCommand tc = cmd.toThrift();
Assert.assertEquals(TCommandVerb.TRACE, tc.getVerb());
+ Assert.assertEquals(Arrays.asList(1L, 2L), tc.getRecords());
+ Assert.assertFalse(tc.isSetTimestamp());
Assert.assertEquals(cmd.ccl(), Command.fromThrift(tc).ccl());
}
@@ -1125,13 +1041,15 @@ public void testTraceRoundTrip() {
*
+ * If the {@link Command} fails, the exception is propagated immediately.
+ *
+ *
+ * @param command the {@link Command} to execute
+ * @return the result of the {@link Command}
+ */
+ public abstract Object exec(Command command);
+
+ /**
+ * Execute two or more {@link Command Commands} and return the result of the
+ * last one.
+ *
+ * {@link Command Commands} are executed sequentially. If any
+ * {@link Command} fails, execution stops and the exception is propagated
+ * immediately.
+ *
+ *
+ * @param command the first {@link Command} to execute
+ * @param more additional {@link Command Commands} to execute
+ * @return the result of the last {@link Command}
+ */
+ public abstract Object exec(Command command, Command... more);
+
+ /**
+ * Execute a list of {@link Command Commands} and return the result of the
+ * last one.
+ *
+ * {@link Command Commands} are executed sequentially. If any
+ * {@link Command} fails, execution stops and the exception is propagated
+ * immediately.
+ *
+ *
+ * @param commands the {@link Command Commands} to execute
+ * @return the result of the last {@link Command}
+ */
+ public abstract Object exec(List commands);
+
+ /**
+ * Submit a single {@link Command} and return a {@link List} containing its
+ * result.
+ *
+ * If the {@link Command} fails, the exception is propagated immediately.
+ *
+ *
+ * @param command the {@link Command} to submit
+ * @return a {@link List} containing the result
+ */
+ public abstract List submit(Command command);
+
+ /**
+ * Submit two or more {@link Command Commands} and return a {@link List} of
+ * results corresponding to each {@link Command}.
+ *
+ * {@link Command Commands} are executed sequentially on the server in a
+ * single round trip. If any {@link Command} fails, execution stops and the
+ * exception is propagated.
+ *
+ *
+ * @param command the first {@link Command} to submit
+ * @param more additional {@link Command Commands} to submit
+ * @return a {@link List} of results, one per {@link Command}
+ */
+ public abstract List submit(Command command, Command... more);
+
+ /**
+ * Submit a list of {@link Command Commands} and return a {@link List} of
+ * results corresponding to each {@link Command}.
+ *
+ * {@link Command Commands} are executed sequentially on the server in a
+ * single round trip. If any {@link Command} fails, execution stops and the
+ * exception is propagated.
+ *
+ *
+ * @param commands the {@link Command Commands} to submit
+ * @return a {@link List} of results, one per {@link Command}
+ */
+ public abstract List submit(List commands);
+
+ /**
+ * Submit all the {@link Command Commands} that have been collected by the
+ * {@code group} and return a {@link List} of results corresponding to each
+ * {@link Command}.
+ *
+ * {@link Command Commands} are executed sequentially on the server in a
+ * single round trip. If any {@link Command} fails, execution stops and the
+ * exception is propagated.
+ *
+ *
+ * @param group the {@link CommandGroup} containing the {@link Command
+ * Commands} to submit
+ * @return a {@link List} of results, one per {@link Command}
+ */
+ public abstract List submit(CommandGroup group);
+
+ /**
+ * Return a new {@link CommandGroup} that can be used to collect
+ * {@link Command Commands} for batch submission.
+ *
+ * Call methods on the returned {@link CommandGroup} to record operations.
+ * Then pass the {@link CommandGroup} to {@link #submit(CommandGroup)} to
+ * execute all the recorded operations in a single round trip.
+ *
+ *
+ * @return a new {@link CommandGroup}
+ */
+ public abstract CommandGroup group();
+
/**
* Return a {@link Timestamp} that represents the current instant according
* to the server.
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/ConcourseThriftDriver.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/ConcourseThriftDriver.java
index 31702188c..709b41cb6 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/ConcourseThriftDriver.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/ConcourseThriftDriver.java
@@ -48,6 +48,9 @@
import com.cinchapi.concourse.data.transform.DataTable;
import com.cinchapi.concourse.lang.Criteria;
import com.cinchapi.concourse.lang.Language;
+import com.cinchapi.concourse.lang.command.Command;
+import com.cinchapi.concourse.lang.command.CommandGroup;
+import com.cinchapi.concourse.lang.command.DefaultCommandGroup;
import com.cinchapi.concourse.lang.paginate.Page;
import com.cinchapi.concourse.lang.sort.Order;
import com.cinchapi.concourse.security.ClientSecurity;
@@ -60,6 +63,7 @@
import com.cinchapi.concourse.thrift.JavaThriftBridge;
import com.cinchapi.concourse.thrift.Operator;
import com.cinchapi.concourse.thrift.SecurityException;
+import com.cinchapi.concourse.thrift.TCommand;
import com.cinchapi.concourse.thrift.TObject;
import com.cinchapi.concourse.thrift.TransactionToken;
import com.cinchapi.concourse.util.Collections;
@@ -4063,6 +4067,61 @@ public void stage() throws TransactionException {
});
}
+ @Override
+ public Object exec(Command command) {
+ return exec(Lists.newArrayList(command));
+ }
+
+ @Override
+ public Object exec(Command command, Command... more) {
+ List commands = Lists.newArrayList(command);
+ java.util.Collections.addAll(commands, more);
+ return exec(commands);
+ }
+
+ @Override
+ public Object exec(List commands) {
+ return execute(() -> {
+ List tcommands = commands.stream().map(Command::toThrift)
+ .collect(Collectors.toList());
+ return core.exec(tcommands, creds, transaction, environment)
+ .getJavaObject();
+ });
+ }
+
+ @Override
+ public List submit(Command command) {
+ return submit(Lists.newArrayList(command));
+ }
+
+ @Override
+ public List submit(Command command, Command... more) {
+ List commands = Lists.newArrayList(command);
+ java.util.Collections.addAll(commands, more);
+ return submit(commands);
+ }
+
+ @Override
+ public List submit(List commands) {
+ return execute(() -> {
+ List tcommands = commands.stream().map(Command::toThrift)
+ .collect(Collectors.toList());
+ return core.submit(tcommands, creds, transaction, environment)
+ .stream().map(ComplexTObject::getJavaObject)
+ .collect(Collectors.toList());
+ });
+ }
+
+ @Override
+ public List submit(CommandGroup group) {
+ return submit(group.commands());
+ }
+
+ @Override
+ public CommandGroup group() {
+ return new DefaultCommandGroup();
+ }
+
@Override
public Timestamp time() {
return execute(() -> Timestamp
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/ForwardingConcourse.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/ForwardingConcourse.java
index 82a3f425f..f363e06a9 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/ForwardingConcourse.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/ForwardingConcourse.java
@@ -21,6 +21,8 @@
import java.util.Set;
import com.cinchapi.concourse.lang.Criteria;
+import com.cinchapi.concourse.lang.command.Command;
+import com.cinchapi.concourse.lang.command.CommandGroup;
import com.cinchapi.concourse.lang.paginate.Page;
import com.cinchapi.concourse.lang.sort.Order;
import com.cinchapi.concourse.thrift.Diff;
@@ -1710,6 +1712,46 @@ public void verifyOrSet(String key, Object value, long record) {
concourse.verifyOrSet(key, value, record);
}
+ @Override
+ public Object exec(Command command) {
+ return concourse.exec(command);
+ }
+
+ @Override
+ public Object exec(Command command, Command... more) {
+ return concourse.exec(command, more);
+ }
+
+ @Override
+ public Object exec(List commands) {
+ return concourse.exec(commands);
+ }
+
+ @Override
+ public List submit(Command command) {
+ return concourse.submit(command);
+ }
+
+ @Override
+ public List submit(Command command, Command... more) {
+ return concourse.submit(command, more);
+ }
+
+ @Override
+ public List submit(List commands) {
+ return concourse.submit(commands);
+ }
+
+ @Override
+ public List submit(CommandGroup group) {
+ return concourse.submit(group);
+ }
+
+ @Override
+ public CommandGroup group() {
+ return concourse.group();
+ }
+
@Override
boolean failed() {
return concourse.failed();
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/NoOpConcourse.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/NoOpConcourse.java
index 547e387c5..483edb558 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/NoOpConcourse.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/NoOpConcourse.java
@@ -21,6 +21,8 @@
import java.util.Set;
import com.cinchapi.concourse.lang.Criteria;
+import com.cinchapi.concourse.lang.command.Command;
+import com.cinchapi.concourse.lang.command.CommandGroup;
import com.cinchapi.concourse.lang.paginate.Page;
import com.cinchapi.concourse.lang.sort.Order;
import com.cinchapi.concourse.thrift.Diff;
@@ -1696,6 +1698,46 @@ public void verifyOrSet(String key, Object value, long record) {
throw new UnsupportedOperationException();
}
+ @Override
+ public Object exec(Command command) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object exec(Command command, Command... more) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object exec(List commands) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List submit(Command command) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List submit(Command command, Command... more) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List submit(List commands) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List submit(CommandGroup group) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public CommandGroup group() {
+ throw new UnsupportedOperationException();
+ }
+
@Override
protected Concourse copyConnection() {
throw new UnsupportedOperationException();
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/Command.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/Command.java
index 6914fd1a0..221e3ff6f 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/Command.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/Command.java
@@ -716,4 +716,24 @@ public static Command inventory() {
return new BuiltCommand("inventory");
}
+ /**
+ * Return a {@code time} {@link Command}.
+ *
+ * @return the {@link Command}
+ */
+ public static Command time() {
+ return new BuiltCommand("time");
+ }
+
+ /**
+ * Return a {@code time} {@link Command} that resolves the given
+ * {@code phrase} to a timestamp.
+ *
+ * @param phrase the natural language time phrase
+ * @return the {@link Command}
+ */
+ public static Command time(String phrase) {
+ return new BuiltCommand("time " + phrase);
+ }
+
}
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CommandGroup.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CommandGroup.java
new file mode 100644
index 000000000..120f594b0
--- /dev/null
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/command/CommandGroup.java
@@ -0,0 +1,929 @@
+/*
+ * Copyright (c) 2013-2026 Cinchapi 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.cinchapi.concourse.lang.command;
+
+import java.util.List;
+import java.util.Set;
+
+import com.cinchapi.concourse.lang.Criteria;
+import com.cinchapi.concourse.lang.paginate.Page;
+import com.cinchapi.concourse.lang.sort.Order;
+import com.cinchapi.concourse.thrift.Operator;
+
+/**
+ * An interface that mirrors the Concourse API with void-returning methods.
+ * Implementations collect the method invocations as {@link Command Commands}
+ * for batch submission via {@code Concourse#submit(CommandGroup)}.
+ */
+public interface CommandGroup {
+
+ /**
+ * Return the collected {@link Command Commands}.
+ *
+ * @return the {@link Command Commands}
+ */
+ List commands();
+
+ void abort();
+
+ void add(String key, Object value);
+
+ void add(String key, Object value, long record);
+
+ void add(String key, Object value, List records);
+
+ void audit(long record);
+
+ void audit(long record, long start);
+
+ void audit(long record, String start);
+
+ void audit(long record, long start, long tend);
+
+ void audit(long record, String start, String tend);
+
+ void audit(String key, long record);
+
+ void audit(String key, long record, long start);
+
+ void audit(String key, long record, String start);
+
+ void audit(String key, long record, long start, long tend);
+
+ void audit(String key, long record, String start, String tend);
+
+ void browse(String key);
+
+ void browse(List keys);
+
+ void browse(String key, long timestamp);
+
+ void browse(String key, String timestamp);
+
+ void browse(List keys, long timestamp);
+
+ void browse(List keys, String timestamp);
+
+ void chronicle(String key, long record);
+
+ void chronicle(String key, long record, long start);
+
+ void chronicle(String key, long record, String start);
+
+ void chronicle(String key, long record, long start, long tend);
+
+ void chronicle(String key, long record, String start, String tend);
+
+ void clear(long record);
+
+ void clear(List records);
+
+ void clear(String key, long record);
+
+ void clear(List keys, long record);
+
+ void clear(String key, List records);
+
+ void clear(List keys, List records);
+
+ void commit();
+
+ void describe();
+
+ void describe(long timestamp);
+
+ void describe(String timestamp);
+
+ void describe(long record, long timestamp);
+
+ void describe(long record, String timestamp);
+
+ void describe(List records);
+
+ void describe(List records, long timestamp);
+
+ void describe(List records, String timestamp);
+
+ void diff(long record, long start);
+
+ void diff(long record, String start);
+
+ void diff(long record, long start, long tend);
+
+ void diff(long record, String start, String tend);
+
+ void diff(String key, long record, long start);
+
+ void diff(String key, long record, String start);
+
+ void diff(String key, long record, long start, long tend);
+
+ void diff(String key, long record, String start, String tend);
+
+ void diff(String key, long start);
+
+ void diff(String key, String start);
+
+ void diff(String key, String start, String tend);
+
+ void stage();
+
+ void insert(String json);
+
+ void insert(String json, long record);
+
+ void insert(String json, List records);
+
+ void remove(String key, Object value, long record);
+
+ void remove(String key, Object value, List records);
+
+ void set(String key, Object value, long record);
+
+ void set(String key, Object value);
+
+ void set(String key, Object value, List records);
+
+ void reconcile(String key, long record, Set values);
+
+ void inventory();
+
+ void select(long record);
+
+ void select(List records);
+
+ void select(List records, Page page);
+
+ void select(List records, Order order);
+
+ void select(List records, Order order, Page page);
+
+ void select(long record, long timestamp);
+
+ void select(long record, String timestamp);
+
+ void select(List records, long timestamp);
+
+ void select(List records, long timestamp, Page page);
+
+ void select(List records, long timestamp, Order order);
+
+ void select(List records, long timestamp, Order order, Page page);
+
+ void select(List records, String timestamp);
+
+ void select(List records, String timestamp, Page page);
+
+ void select(List records, String timestamp, Order order);
+
+ void select(List records, String timestamp, Order order, Page page);
+
+ void select(String key, long record);
+
+ void select(String key, long record, long timestamp);
+
+ void select(String key, long record, String timestamp);
+
+ void select(List keys, long record, long timestamp);
+
+ void select(List keys, long record, String timestamp);
+
+ void select(List keys, List records);
+
+ void select(List keys, List records, Page page);
+
+ void select(List keys, List records, Order order);
+
+ void select(List keys, List records, Order order, Page page);
+
+ void select(String key, List records);
+
+ void select(String key, List records, Page page);
+
+ void select(String key, List records, Order order);
+
+ void select(String key, List records, Order order, Page page);
+
+ void select(String key, List records, long timestamp);
+
+ void select(String key, List records, long timestamp, Page page);
+
+ void select(String key, List records, long timestamp, Order order);
+
+ void select(String key, List records, long timestamp, Order order,
+ Page page);
+
+ void select(String key, List records, String timestamp);
+
+ void select(String key, List records, String timestamp, Page page);
+
+ void select(String key, List records, String timestamp, Order order);
+
+ void select(String key, List records, String timestamp, Order order,
+ Page page);
+
+ void select(List keys, List records, long timestamp);
+
+ void select(List keys, List records, long timestamp,
+ Page page);
+
+ void select(List keys, List records, long timestamp,
+ Order order);
+
+ void select(List keys, List records, long timestamp,
+ Order order, Page page);
+
+ void select(List keys, List records, String timestamp);
+
+ void select(List keys, List records, String timestamp,
+ Page page);
+
+ void select(List keys, List records, String timestamp,
+ Order order);
+
+ void select(List keys, List records, String timestamp,
+ Order order, Page page);
+
+ void select(Criteria criteria);
+
+ void select(Criteria criteria, Page page);
+
+ void select(Criteria criteria, Order order);
+
+ void select(Criteria criteria, Order order, Page page);
+
+ void select(String ccl);
+
+ void select(String ccl, Page page);
+
+ void select(String ccl, Order order);
+
+ void select(String ccl, Order order, Page page);
+
+ void select(Criteria criteria, long timestamp);
+
+ void select(Criteria criteria, long timestamp, Page page);
+
+ void select(Criteria criteria, long timestamp, Order order);
+
+ void select(Criteria criteria, long timestamp, Order order, Page page);
+
+ void select(Criteria criteria, String timestamp);
+
+ void select(Criteria criteria, String timestamp, Page page);
+
+ void select(Criteria criteria, String timestamp, Order order);
+
+ void select(Criteria criteria, String timestamp, Order order, Page page);
+
+ void select(String ccl, long timestamp, Page page);
+
+ void select(String ccl, long timestamp, Order order);
+
+ void select(String ccl, long timestamp, Order order, Page page);
+
+ void select(String ccl, String timestamp);
+
+ void select(String ccl, String timestamp, Page page);
+
+ void select(String ccl, String timestamp, Order order);
+
+ void select(String ccl, String timestamp, Order order, Page page);
+
+ void select(String key, Criteria criteria);
+
+ void select(String key, Criteria criteria, Page page);
+
+ void select(String key, Criteria criteria, Order order);
+
+ void select(String key, Criteria criteria, Order order, Page page);
+
+ void select(String key, Criteria criteria, long timestamp);
+
+ void select(String key, Criteria criteria, long timestamp, Page page);
+
+ void select(String key, Criteria criteria, long timestamp, Order order);
+
+ void select(String key, Criteria criteria, long timestamp, Order order,
+ Page page);
+
+ void select(String key, Criteria criteria, String timestamp);
+
+ void select(String key, Criteria criteria, String timestamp, Page page);
+
+ void select(String key, Criteria criteria, String timestamp, Order order);
+
+ void select(String key, Criteria criteria, String timestamp, Order order,
+ Page page);
+
+ void select(String key, String ccl, long timestamp);
+
+ void select(String key, String ccl, long timestamp, Page page);
+
+ void select(String key, String ccl, long timestamp, Order order);
+
+ void select(String key, String ccl, long timestamp, Order order, Page page);
+
+ void select(String key, String ccl, String timestamp);
+
+ void select(String key, String ccl, String timestamp, Page page);
+
+ void select(String key, String ccl, String timestamp, Order order);
+
+ void select(String key, String ccl, String timestamp, Order order,
+ Page page);
+
+ void select(List keys, Criteria criteria);
+
+ void select(List keys, Criteria criteria, Page page);
+
+ void select(List keys, Criteria criteria, Order order);
+
+ void select(List keys, Criteria criteria, Order order, Page page);
+
+ void select(List keys, Criteria criteria, long timestamp);
+
+ void select(List keys, Criteria criteria, long timestamp,
+ Page page);
+
+ void select(List keys, Criteria criteria, long timestamp,
+ Order order);
+
+ void select(List keys, Criteria criteria, long timestamp,
+ Order order, Page page);
+
+ void select(List keys, Criteria criteria, String timestamp);
+
+ void select(List keys, Criteria criteria, String timestamp,
+ Page page);
+
+ void select(List keys, Criteria criteria, String timestamp,
+ Order order);
+
+ void select(List keys, Criteria criteria, String timestamp,
+ Order order, Page page);
+
+ void select(List keys, String ccl, long timestamp);
+
+ void select(List keys, String ccl, long timestamp, Page page);
+
+ void select(List keys, String ccl, long timestamp, Order order);
+
+ void select(List keys, String ccl, long timestamp, Order order,
+ Page page);
+
+ void select(List keys, String ccl, String timestamp);
+
+ void select(List keys, String ccl, String timestamp, Page page);
+
+ void select(List keys, String ccl, String timestamp, Order order);
+
+ void select(List keys, String ccl, String timestamp, Order order,
+ Page page);
+
+ void get(String key, long record);
+
+ void get(String key, long record, long timestamp);
+
+ void get(String key, long record, String timestamp);
+
+ void get(List keys, long record);
+
+ void get(List keys, long record, long timestamp);
+
+ void get(List keys, long record, String timestamp);
+
+ void get(List keys, List records);
+
+ void get(List keys, List records, Page page);
+
+ void get(List keys, List records, Order order);
+
+ void get(List keys, List records, Order order, Page page);
+
+ void get(String key, List records);
+
+ void get(String key, List records, Page page);
+
+ void get(String key, List records, Order order);
+
+ void get(String key, List records, Order order, Page page);
+
+ void get(String key, List records, long timestamp);
+
+ void get(String key, List records, long timestamp, Page page);
+
+ void get(String key, List records, long timestamp, Order order);
+
+ void get(String key, List records, long timestamp, Order order,
+ Page page);
+
+ void get(String key, List records, String timestamp);
+
+ void get(String key, List records, String timestamp, Page page);
+
+ void get(String key, List records, String timestamp, Order order);
+
+ void get(String key, List records, String timestamp, Order order,
+ Page page);
+
+ void get(List keys, List records, long timestamp);
+
+ void get(List keys, List records, long timestamp, Page page);
+
+ void get(List keys, List records, long timestamp,
+ Order order);
+
+ void get(List keys, List records, long timestamp, Order order,
+ Page page);
+
+ void get(List keys, List records, String timestamp);
+
+ void get(List keys, List records, String timestamp,
+ Page page);
+
+ void get(List keys, List records, String timestamp,
+ Order order);
+
+ void get(List keys, List records, String timestamp,
+ Order order, Page page);
+
+ void get(String key, Criteria criteria);
+
+ void get(String key, Criteria criteria, Page page);
+
+ void get(String key, Criteria criteria, Order order);
+
+ void get(String key, Criteria criteria, Order order, Page page);
+
+ void get(Criteria criteria);
+
+ void get(Criteria criteria, Page page);
+
+ void get(Criteria criteria, Order order);
+
+ void get(Criteria criteria, Order order, Page page);
+
+ void get(String ccl);
+
+ void get(String ccl, Page page);
+
+ void get(String ccl, Order order);
+
+ void get(String ccl, Order order, Page page);
+
+ void get(Criteria criteria, long timestamp);
+
+ void get(Criteria criteria, long timestamp, Page page);
+
+ void get(Criteria criteria, long timestamp, Order order);
+
+ void get(Criteria criteria, long timestamp, Order order, Page page);
+
+ void get(Criteria criteria, String timestamp);
+
+ void get(Criteria criteria, String timestamp, Page page);
+
+ void get(Criteria criteria, String timestamp, Order order);
+
+ void get(Criteria criteria, String timestamp, Order order, Page page);
+
+ void get(String ccl, long timestamp, Page page);
+
+ void get(String ccl, long timestamp, Order order);
+
+ void get(String ccl, long timestamp, Order order, Page page);
+
+ void get(String ccl, String timestamp);
+
+ void get(String ccl, String timestamp, Page page);
+
+ void get(String ccl, String timestamp, Order order);
+
+ void get(String ccl, String timestamp, Order order, Page page);
+
+ void get(String key, Criteria criteria, long timestamp);
+
+ void get(String key, Criteria criteria, long timestamp, Page page);
+
+ void get(String key, Criteria criteria, long timestamp, Order order);
+
+ void get(String key, Criteria criteria, long timestamp, Order order,
+ Page page);
+
+ void get(String key, Criteria criteria, String timestamp);
+
+ void get(String key, Criteria criteria, String timestamp, Page page);
+
+ void get(String key, Criteria criteria, String timestamp, Order order);
+
+ void get(String key, Criteria criteria, String timestamp, Order order,
+ Page page);
+
+ void get(String key, String ccl, long timestamp);
+
+ void get(String key, String ccl, long timestamp, Page page);
+
+ void get(String key, String ccl, long timestamp, Order order);
+
+ void get(String key, String ccl, long timestamp, Order order, Page page);
+
+ void get(String key, String ccl, String timestamp);
+
+ void get(String key, String ccl, String timestamp, Page page);
+
+ void get(String key, String ccl, String timestamp, Order order);
+
+ void get(String key, String ccl, String timestamp, Order order, Page page);
+
+ void get(List keys, Criteria criteria);
+
+ void get(List keys, Criteria criteria, Page page);
+
+ void get(List keys, Criteria criteria, Order order);
+
+ void get(List keys, Criteria criteria, Order order, Page page);
+
+ void get(List keys, String ccl);
+
+ void get(List keys, String ccl, Page page);
+
+ void get(List keys, String ccl, Order order);
+
+ void get(List keys, String ccl, Order order, Page page);
+
+ void get(List keys, Criteria criteria, long timestamp);
+
+ void get(List keys, Criteria criteria, long timestamp, Page page);
+
+ void get(List keys, Criteria criteria, long timestamp, Order order);
+
+ void get(List keys, Criteria criteria, long timestamp, Order order,
+ Page page);
+
+ void get(List keys, Criteria criteria, String timestamp);
+
+ void get(List keys, Criteria criteria, String timestamp, Page page);
+
+ void get(List keys, Criteria criteria, String timestamp,
+ Order order);
+
+ void get(List keys, Criteria criteria, String timestamp,
+ Order order, Page page);
+
+ void get(List keys, String ccl, long timestamp);
+
+ void get(List keys, String ccl, long timestamp, Page page);
+
+ void get(List keys, String ccl, long timestamp, Order order);
+
+ void get(List keys, String ccl, long timestamp, Order order,
+ Page page);
+
+ void get(List keys, String ccl, String timestamp);
+
+ void get(List keys, String ccl, String timestamp, Page page);
+
+ void get(List keys, String ccl, String timestamp, Order order);
+
+ void get(List keys, String ccl, String timestamp, Order order,
+ Page page);
+
+ void verify(String key, Object value, long record);
+
+ void verify(String key, Object value, long record, long timestamp);
+
+ void verify(String key, Object value, long record, String timestamp);
+
+ void jsonify(List records, boolean identifier);
+
+ void jsonify(List records, long timestamp, boolean identifier);
+
+ void jsonify(List records, String timestamp, boolean identifier);
+
+ void find(Criteria criteria);
+
+ void find(Criteria criteria, Page page);
+
+ void find(Criteria criteria, Order order);
+
+ void find(Criteria criteria, Order order, Page page);
+
+ void find(String ccl);
+
+ void find(String ccl, Page page);
+
+ void find(String ccl, Order order);
+
+ void find(String ccl, Order order, Page page);
+
+ void find(String key, Operator operator, List values);
+
+ void find(String key, Operator operator, List values, Page page);
+
+ void find(String key, Operator operator, List values, Order order);
+
+ void find(String key, Operator operator, List values, Order order,
+ Page page);
+
+ void find(String key, Operator operator, List values,
+ long timestamp);
+
+ void find(String key, Operator operator, List values,
+ long timestamp, Page page);
+
+ void find(String key, Operator operator, List values,
+ long timestamp, Order order);
+
+ void find(String key, Operator operator, List