use of com.cinchapi.ccl.type.function.KeyConditionFunction in project concourse by cinchapi.
the class Stores method find.
/**
* Find the records that contain values that are stored for {@code key} and
* satisfy {@code operator} in relation to the specified {@code values} at
* {@code timestamp}.
* <p>
* If the {@code key} is primitive, the store lookup is usually a simple
* {@link Store#find(String, Operator, TObject[]) find}. However, if the key
* is a navigation key, this method will process it by
* {@link #browse(Store, String) browsing} the destination values and
* checking the operator validity of each if and only if the {@code store}
* is an {@link AtomicOperation} or {@link AtomicSupport supports} starting
* one.
* </p>
*
* @param store
* @param timestamp
* @param key
* @param operator
* @param values
* @return the records that satisfy the query
*/
public static Set<Long> find(Store store, long timestamp, String key, Operator operator, TObject... values) {
for (int i = 0; i < values.length; ++i) {
TObject value = values[i];
if (value.getType() == Type.FUNCTION) {
Function function = (Function) Convert.thriftToJava(value);
TemporalFunction func = (TemporalFunction) function;
String method = Calculations.alias(function.operation());
ArrayBuilder<Object> args = ArrayBuilder.builder();
method += "Key";
args.add(function.key());
if (function instanceof KeyRecordsFunction || function instanceof KeyConditionFunction) {
method += "Records";
Collection<Long> records = function instanceof KeyRecordsFunction ? ((KeyRecordsFunction) function).source() : Finder.instance().visit(((KeyConditionFunction) function).source(), store);
args.add(records);
} else if (!(function instanceof IndexFunction)) {
throw new IllegalStateException("Invalid function value");
}
method += "Atomic";
args.add(func.timestamp());
args.add(store);
values[i] = Convert.javaToThrift(Reflection.callStatic(Operations.class, method, args.build()));
}
}
if (Keys.isNavigationKey(key)) {
Map<TObject, Set<Long>> index = timestamp == Time.NONE ? browse(store, key) : browse(store, key, timestamp);
Set<Long> records = index.entrySet().stream().filter(e -> e.getKey().is(operator, values)).map(e -> e.getValue()).flatMap(Set::stream).collect(Collectors.toCollection(LinkedHashSet::new));
return records;
} else if (Keys.isFunctionKey(key)) {
Set<Long> records = Sets.newLinkedHashSet();
for (long record : store.getAllRecords()) {
Set<TObject> aggregate = select(store, key, record, timestamp);
for (TObject tobject : aggregate) {
if (tobject.is(operator, values)) {
records.add(record);
break;
}
}
}
return records;
} else {
return timestamp == Time.NONE ? store.find(key, operator, values) : store.find(timestamp, key, operator, values);
}
}
use of com.cinchapi.ccl.type.function.KeyConditionFunction in project concourse by cinchapi.
the class ConvertTest method testConvertKeyConditionFunctionToThriftRoundTrip.
@Test
public void testConvertKeyConditionFunctionToThriftRoundTrip() {
KeyConditionFunction expected = new KeyConditionFunction("average", "age", (ConditionTree) ConcourseCompiler.get().parse("name = jeff or (age > 30 and (email like '%gmail.com%' or employed = true) or foo = bar)"));
KeyConditionFunction actual = (KeyConditionFunction) Convert.thriftToJava(Convert.javaToThrift(expected));
Assert.assertEquals(expected, actual);
}
use of com.cinchapi.ccl.type.function.KeyConditionFunction in project concourse by cinchapi.
the class Convert method javaToThrift.
/**
* Return the Thrift Object that represents {@code object}.
*
* @param object
* @return the TObject
*/
public static TObject javaToThrift(Object object) {
if (object == null) {
return TObject.NULL;
} else {
ByteBuffer bytes;
Type type = null;
if (object instanceof Boolean) {
bytes = ByteBuffer.allocate(1);
bytes.put((boolean) object ? (byte) 1 : (byte) 0);
type = Type.BOOLEAN;
} else if (object instanceof Double) {
bytes = ByteBuffer.allocate(8);
bytes.putDouble((double) object);
type = Type.DOUBLE;
} else if (object instanceof Float) {
bytes = ByteBuffer.allocate(4);
bytes.putFloat((float) object);
type = Type.FLOAT;
} else if (object instanceof Link) {
bytes = ByteBuffer.allocate(8);
bytes.putLong(((Link) object).longValue());
type = Type.LINK;
} else if (object instanceof Long) {
bytes = ByteBuffer.allocate(8);
bytes.putLong((long) object);
type = Type.LONG;
} else if (object instanceof Integer) {
bytes = ByteBuffer.allocate(4);
bytes.putInt((int) object);
type = Type.INTEGER;
} else if (object instanceof BigDecimal) {
bytes = ByteBuffer.allocate(8);
bytes.putDouble((double) ((BigDecimal) object).doubleValue());
type = Type.DOUBLE;
} else if (object instanceof Tag) {
bytes = ByteBuffer.wrap(object.toString().getBytes(StandardCharsets.UTF_8));
type = Type.TAG;
} else if (object instanceof Timestamp) {
try {
bytes = ByteBuffer.allocate(8);
bytes.putLong(((Timestamp) object).getMicros());
type = Type.TIMESTAMP;
} catch (IllegalStateException e) {
throw new UnsupportedOperationException("Cannot convert string based Timestamp to a TObject");
}
} else if (object instanceof Function) {
type = Type.FUNCTION;
Function function = (Function) object;
byte[] nameBytes = function.operation().getBytes(StandardCharsets.UTF_8);
byte[] keyBytes = function.key().getBytes(StandardCharsets.UTF_8);
if (function instanceof IndexFunction) {
/*
* Schema:
* | type (1) | timestamp(8) | nameLength (4) | name
* (nameLength) | key |
*/
bytes = ByteBuffer.allocate(1 + 8 + 4 + nameBytes.length + keyBytes.length);
bytes.put((byte) FunctionType.INDEX.ordinal());
bytes.putLong(((TemporalFunction) function).timestamp());
bytes.putInt(nameBytes.length);
bytes.put(nameBytes);
bytes.put(keyBytes);
} else if (function instanceof KeyRecordsFunction) {
/*
* Schema:
* | type (1) | timestamp(8) | nameLength (4) | name
* (nameLength) | keyLength (4) | key (keyLength) | records
* (8 each) |
*/
KeyRecordsFunction func = (KeyRecordsFunction) function;
bytes = ByteBuffer.allocate(1 + 8 + 4 + nameBytes.length + 4 + keyBytes.length + 8 * func.source().size());
bytes.put((byte) FunctionType.KEY_RECORDS.ordinal());
bytes.putLong(((TemporalFunction) function).timestamp());
bytes.putInt(nameBytes.length);
bytes.put(nameBytes);
bytes.putInt(keyBytes.length);
bytes.put(keyBytes);
for (long record : func.source()) {
bytes.putLong(record);
}
} else if (function instanceof KeyConditionFunction) {
/*
* Schema:
* | type (1) | timestamp(8) | nameLength (4) | name
* (nameLength) | keyLength (4) | key (keyLength) |
* condition |
*/
KeyConditionFunction func = (KeyConditionFunction) function;
String condition = ConcourseCompiler.get().tokenize(func.source()).stream().map(Symbol::toString).collect(Collectors.joining(" "));
bytes = ByteBuffer.allocate(1 + 9 + 4 + nameBytes.length + 4 + keyBytes.length + condition.length());
bytes.put((byte) FunctionType.KEY_CONDITION.ordinal());
bytes.putLong(((TemporalFunction) function).timestamp());
bytes.putInt(nameBytes.length);
bytes.put(nameBytes);
bytes.putInt(keyBytes.length);
bytes.put(keyBytes);
bytes.put(condition.getBytes(StandardCharsets.UTF_8));
} else {
throw new UnsupportedOperationException("Cannot convert the following function to a TObject: " + function);
}
} else {
bytes = ByteBuffer.wrap(object.toString().getBytes(StandardCharsets.UTF_8));
type = Type.STRING;
}
bytes.rewind();
return new TObject(bytes, type).setJavaFormat(object);
}
}
use of com.cinchapi.ccl.type.function.KeyConditionFunction in project concourse by cinchapi.
the class Convert method thriftToJava.
/**
* Return the Java Object that represents {@code object}.
*
* @param object
* @return the Object
*/
public static Object thriftToJava(TObject object) {
Preconditions.checkState(object.getType() != null, "Cannot read value because it has been " + "created with a newer version of Concourse " + "Server. Please upgrade this client.");
Object java = object.getJavaFormat();
if (java == null) {
ByteBuffer buffer = object.bufferForData();
switch(object.getType()) {
case BOOLEAN:
java = ByteBuffers.getBoolean(buffer);
break;
case DOUBLE:
java = buffer.getDouble();
break;
case FLOAT:
java = buffer.getFloat();
break;
case INTEGER:
java = buffer.getInt();
break;
case LINK:
java = Link.to(buffer.getLong());
break;
case LONG:
java = buffer.getLong();
break;
case TAG:
java = ByteBuffers.getUtf8String(buffer);
break;
case TIMESTAMP:
java = Timestamp.fromMicros(buffer.getLong());
break;
case FUNCTION:
FunctionType type = Enums.parseIgnoreCase(FunctionType.class, buffer.get());
long timestamp = buffer.getLong();
int nameLength = buffer.getInt();
String name = ByteBuffers.getUtf8String(ByteBuffers.get(buffer, nameLength));
int keyLength;
String key;
switch(type) {
case INDEX:
key = ByteBuffers.getUtf8String(buffer);
java = new IndexFunction(name, key, timestamp);
break;
case KEY_RECORDS:
keyLength = buffer.getInt();
key = ByteBuffers.getUtf8String(ByteBuffers.get(buffer, keyLength));
ArrayBuilder<Long> ab = ArrayBuilder.builder();
while (buffer.hasRemaining()) {
long record = buffer.getLong();
ab.add(record);
}
java = new KeyRecordsFunction(timestamp, name, key, ab.build());
break;
case KEY_CONDITION:
keyLength = buffer.getInt();
key = ByteBuffers.getUtf8String(ByteBuffers.get(buffer, keyLength));
String condition = ByteBuffers.getUtf8String(buffer);
ConditionTree tree = (ConditionTree) ConcourseCompiler.get().parse(condition);
java = new KeyConditionFunction(name, key, tree, timestamp);
break;
}
break;
case NULL:
java = null;
break;
default:
java = ByteBuffers.getUtf8String(buffer);
break;
}
buffer.rewind();
}
return java;
}
Aggregations