com.aerospike.client.exp.Exp Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2012-2023 Aerospike, Inc.
*
* Portions may be licensed to Aerospike, Inc. under one or more contributor
* license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
*
* 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.aerospike.client.exp;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import com.aerospike.client.util.Packer;
/**
* Expression generator.
*/
public abstract class Exp {
/**
* Expression type.
*/
public enum Type {
NIL(0),
BOOL(1),
INT(2),
STRING(3),
LIST(4),
MAP(5),
BLOB(6),
FLOAT(7),
GEO(8),
HLL(9);
public final int code;
Type(int code) {
this.code = code;
}
}
//--------------------------------------------------
// Build
//--------------------------------------------------
/**
* Create final expression that contains packed byte instructions used in the wire protocol.
*/
public static Expression build(Exp exp) {
return new Expression(exp);
}
//--------------------------------------------------
// Record Key
//--------------------------------------------------
/**
* Create record key expression of specified type.
*
* {@code
* // Integer record key >= 100000
* Exp.ge(Exp.key(Type.INT), Exp.val(100000))
* }
*/
public static Exp key(Type type) {
return new CmdInt(KEY, type.code);
}
/**
* Create expression that returns if the primary key is stored in the record meta data
* as a boolean expression. This would occur when {@link com.aerospike.client.policy.Policy#sendKey}
* is true on record write. This expression usually evaluates quickly because record
* meta data is cached in memory.
*
* {@code
* // Key exists in record meta data
* Exp.keyExists()
* }
*/
public static Exp keyExists() {
return new Cmd(KEY_EXISTS);
}
//--------------------------------------------------
// Record Bin
//--------------------------------------------------
/**
* Create bin expression of specified type.
*
* {@code
* // String bin "a" == "views"
* Exp.eq(Exp.bin("a", Type.STRING), Exp.val("views"))
* }
*/
public static Exp bin(String name, Type type) {
return new Bin(name, type);
}
/**
* Create 64 bit integer bin expression.
*
* {@code
* // Integer bin "a" == 200
* Exp.eq(Exp.intBin("a"), Exp.val(200))
* }
*/
public static Exp intBin(String name) {
return new Bin(name, Type.INT);
}
/**
* Create 64 bit float bin expression.
*
* {@code
* // Float bin "a" >= 1.5
* Exp.ge(Exp.floatBin("a"), Exp.val(1.5))
* }
*/
public static Exp floatBin(String name) {
return new Bin(name, Type.FLOAT);
}
/**
* Create string bin expression.
*
* {@code
* // String bin "a" == "views"
* Exp.eq(Exp.stringBin("a"), Exp.val("views"))
* }
*/
public static Exp stringBin(String name) {
return new Bin(name, Type.STRING);
}
/**
* Create boolean bin expression.
*
* {@code
* // Boolean bin "a" == true
* Exp.eq(Exp.boolBin("a"), Exp.val(true))
* }
*/
public static Exp boolBin(String name) {
return new Bin(name, Type.BOOL);
}
/**
* Create byte[] bin expression.
*
* {@code
* // Blob bin "a" == [1,2,3]
* Exp.eq(Exp.blobBin("a"), Exp.val(new byte[] {1, 2, 3}))
* }
*/
public static Exp blobBin(String name) {
return new Bin(name, Type.BLOB);
}
/**
* Create geospatial bin expression.
*
* {@code
* // Geo bin "a" == region
* String region = "{ \"type\": \"AeroCircle\", \"coordinates\": [[-122.0, 37.5], 50000.0] }";
* Exp.geoCompare(Exp.geoBin("loc"), Exp.geo(region))
* }
*/
public static Exp geoBin(String name) {
return new Bin(name, Type.GEO);
}
/**
* Create list bin expression.
*
* {@code
* // Bin a[2] == 3
* Exp.eq(ListExp.getByIndex(ListReturnType.VALUE, Type.INT, Exp.val(2), Exp.listBin("a")), Exp.val(3))
* }
*/
public static Exp listBin(String name) {
return new Bin(name, Type.LIST);
}
/**
* Create map bin expression.
*
* {@code
* // Bin a["key"] == "value"
* Exp.eq(
* MapExp.getByKey(MapReturnType.VALUE, Type.STRING, Exp.val("key"), Exp.mapBin("a")),
* Exp.val("value"));
* }
*/
public static Exp mapBin(String name) {
return new Bin(name, Type.MAP);
}
/**
* Create hll bin expression.
*
* {@code
* // HLL bin "a" count > 7
* Exp.gt(HLLExp.getCount(Exp.hllBin("a")), Exp.val(7))
* }
*/
public static Exp hllBin(String name) {
return new Bin(name, Type.HLL);
}
/**
* Create expression that returns if bin of specified name exists.
*
* {@code
* // Bin "a" exists in record
* Exp.binExists("a")
* }
*/
public static Exp binExists(String name) {
return Exp.ne(Exp.binType(name), Exp.val(0));
}
/**
* Create expression that returns bin's integer particle type.
* See {@link com.aerospike.client.command.ParticleType}.
*
* {@code
* // Bin "a" particle type is a list
* Exp.eq(Exp.binType("a"), Exp.val(ParticleType.LIST))
* }
*/
public static Exp binType(String name) {
return new CmdStr(BIN_TYPE, name);
}
//--------------------------------------------------
// Misc
//--------------------------------------------------
/**
* Create expression that returns record set name string. This expression usually
* evaluates quickly because record meta data is cached in memory.
*
* {@code
* // Record set name == "myset"
* Exp.eq(Exp.setName(), Exp.val("myset"))
* }
*/
public static Exp setName() {
return new Cmd(SET_NAME);
}
/**
* Create expression that returns record size on disk. If server storage-engine is
* memory, then zero is returned. This expression usually evaluates quickly because
* record meta data is cached in memory.
*
* {@code
* // Record device size >= 100 KB
* Exp.ge(Exp.deviceSize(), Exp.val(100 * 1024))
* }
*/
public static Exp deviceSize() {
return new Cmd(DEVICE_SIZE);
}
/**
* Create expression that returns record size in memory. If server storage-engine is
* not memory nor data-in-memory, then zero is returned. This expression usually evaluates
* quickly because record meta data is cached in memory.
*
* Requires server version 5.3.0+
*
*
{@code
* // Record memory size >= 100 KB
* Exp.ge(Exp.memorySize(), Exp.val(100 * 1024))
* }
*/
public static Exp memorySize() {
return new Cmd(MEMORY_SIZE);
}
/**
* Create expression that returns record last update time expressed as 64 bit integer
* nanoseconds since 1970-01-01 epoch. This expression usually evaluates quickly because
* record meta data is cached in memory.
*
* {@code
* // Record last update time >= 2020-01-15
* Exp.ge(Exp.lastUpdate(), Exp.val(new GregorianCalendar(2020, 0, 15)))
* }
*/
public static Exp lastUpdate() {
return new Cmd(LAST_UPDATE);
}
/**
* Create expression that returns milliseconds since the record was last updated.
* This expression usually evaluates quickly because record meta data is cached in memory.
*
* {@code
* // Record last updated more than 2 hours ago
* Exp.gt(Exp.sinceUpdate(), Exp.val(2 * 60 * 60 * 1000))
* }
*/
public static Exp sinceUpdate() {
return new Cmd(SINCE_UPDATE);
}
/**
* Create expression that returns record expiration time expressed as 64 bit integer
* nanoseconds since 1970-01-01 epoch. This expression usually evaluates quickly because
* record meta data is cached in memory.
*
* {@code
* // Record expires on 2021-01-01
* Exp.and(
* Exp.ge(Exp.voidTime(), Exp.val(new GregorianCalendar(2021, 0, 1))),
* Exp.lt(Exp.voidTime(), Exp.val(new GregorianCalendar(2021, 0, 2))))
* }
*/
public static Exp voidTime() {
return new Cmd(VOID_TIME);
}
/**
* Create expression that returns record expiration time (time to live) in integer seconds.
* This expression usually evaluates quickly because record meta data is cached in memory.
*
* {@code
* // Record expires in less than 1 hour
* Exp.lt(Exp.ttl(), Exp.val(60 * 60))
* }
*/
public static Exp ttl() {
return new Cmd(TTL);
}
/**
* Create expression that returns if record has been deleted and is still in tombstone state.
* This expression usually evaluates quickly because record meta data is cached in memory.
*
* {@code
* // Deleted records that are in tombstone state.
* Exp.isTombstone()
* }
*/
public static Exp isTombstone() {
return new Cmd(IS_TOMBSTONE);
}
/**
* Create expression that returns record digest modulo as integer. This expression usually
* evaluates quickly because record meta data is cached in memory.
*
* {@code
* // Records that have digest(key) % 3 == 1
* Exp.eq(Exp.digestModulo(3), Exp.val(1))
* }
*/
public static Exp digestModulo(int mod) {
return new CmdInt(DIGEST_MODULO, mod);
}
/**
* Create expression that performs a regex match on a string bin or string value expression.
*
* {@code
* // Select string bin "a" that starts with "prefix" and ends with "suffix".
* // Ignore case and do not match newline.
* Exp.regexCompare("prefix.*suffix", RegexFlag.ICASE | RegexFlag.NEWLINE, Exp.stringBin("a"))
* }
*
* @param regex regular expression string
* @param flags regular expression bit flags. See {@link com.aerospike.client.query.RegexFlag}
* @param bin string bin or string value expression
*/
public static Exp regexCompare(String regex, int flags, Exp bin) {
return new Regex(bin, regex, flags);
}
//--------------------------------------------------
// GEO Spatial
//--------------------------------------------------
/**
* Create compare geospatial operation.
*
* {@code
* // Query region within coordinates.
* String region =
* "{ " +
* " \"type\": \"Polygon\", " +
* " \"coordinates\": [ " +
* " [[-122.500000, 37.000000],[-121.000000, 37.000000], " +
* " [-121.000000, 38.080000],[-122.500000, 38.080000], " +
* " [-122.500000, 37.000000]] " +
* " ] " +
* "}";
* Exp.geoCompare(Exp.geoBin("a"), Exp.geo(region))
* }
*/
public static Exp geoCompare(Exp left, Exp right) {
return new CmdExp(GEO, left, right);
}
/**
* Create geospatial json string value.
*/
public static Exp geo(String val) {
return new Geo(val);
}
//--------------------------------------------------
// Value
//--------------------------------------------------
/**
* Create boolean value.
*/
public static Exp val(boolean val) {
return new Bool(val);
}
/**
* Create 64 bit integer value.
*/
public static Exp val(long val) {
return new Int(val);
}
/**
* Create Calendar value expressed in nanoseconds since 1970-01-01 epoch as 64 bit integer.
*/
public static Exp val(Calendar val) {
return new Int(val.getTimeInMillis() * NANOS_PER_MILLIS);
}
/**
* Create 64 bit floating point value.
*/
public static Exp val(double val) {
return new Float(val);
}
/**
* Create string value.
*/
public static Exp val(String val) {
return new Str(val);
}
/**
* Create blob byte[] value.
*/
public static Exp val(byte[] val) {
return new Blob(val);
}
/**
* Create list value.
*/
public static Exp val(List> list) {
return new ListVal(list);
}
/**
* Create map value. For ordered maps, pass in a TreeMap or a map that implements the SortedMap
* interface. For unordered maps, pass in a HashMap.
*/
public static Exp val(Map,?> map) {
return new MapVal(map);
}
/**
* Create nil value.
*/
public static Exp nil() {
return new Nil();
}
/**
* Create infinity value for use in CDT range expressions.
*/
public static Exp inf() {
return new Infinity();
}
/**
* Create wildcard value for use in CDT expressions.
*/
public static Exp wildcard() {
return new Wildcard();
}
//--------------------------------------------------
// Boolean Operator
//--------------------------------------------------
/**
* Create "not" operator expression.
*
* {@code
* // ! (a == 0 || a == 10)
* Exp.not(
* Exp.or(
* Exp.eq(Exp.intBin("a"), Exp.val(0)),
* Exp.eq(Exp.intBin("a"), Exp.val(10))))
* }
*/
public static Exp not(Exp exp) {
return new CmdExp(NOT, exp);
}
/**
* Create "and" (&&) operator that applies to a variable number of expressions.
*
* {@code
* // (a > 5 || a == 0) && b < 3
* Exp.and(
* Exp.or(
* Exp.gt(Exp.intBin("a"), Exp.val(5)),
* Exp.eq(Exp.intBin("a"), Exp.val(0))),
* Exp.lt(Exp.intBin("b"), Exp.val(3)))
* }
*/
public static Exp and(Exp... exps) {
return new CmdExp(AND, exps);
}
/**
* Create "or" (||) operator that applies to a variable number of expressions.
*
* {@code
* // a == 0 || b == 0
* Exp.or(
* Exp.eq(Exp.intBin("a"), Exp.val(0)),
* Exp.eq(Exp.intBin("b"), Exp.val(0)));
* }
*/
public static Exp or(Exp... exps) {
return new CmdExp(OR, exps);
}
/**
* Create expression that returns true if only one of the expressions are true.
* Requires server version 5.6.0+.
*
* {@code
* // exclusive(a == 0, b == 0)
* Exp.exclusive(
* Exp.eq(Exp.intBin("a"), Exp.val(0)),
* Exp.eq(Exp.intBin("b"), Exp.val(0)));
* }
*/
public static Exp exclusive(Exp... exps) {
return new CmdExp(EXCLUSIVE, exps);
}
/**
* Create equal (==) expression.
*
* {@code
* // a == 11
* Exp.eq(Exp.intBin("a"), Exp.val(11))
* }
*/
public static Exp eq(Exp left, Exp right) {
return new CmdExp(EQ, left, right);
}
/**
* Create not equal (!=) expression
*
* {@code
* // a != 13
* Exp.ne(Exp.intBin("a"), Exp.val(13))
* }
*/
public static Exp ne(Exp left, Exp right) {
return new CmdExp(NE, left, right);
}
/**
* Create greater than (>) operation.
*
* {@code
* // a > 8
* Exp.gt(Exp.intBin("a"), Exp.val(8))
* }
*/
public static Exp gt(Exp left, Exp right) {
return new CmdExp(GT, left, right);
}
/**
* Create greater than or equal (>=) operation.
*
* {@code
* // a >= 88
* Exp.ge(Exp.intBin("a"), Exp.val(88))
* }
*/
public static Exp ge(Exp left, Exp right) {
return new CmdExp(GE, left, right);
}
/**
* Create less than (<) operation.
*
* {@code
* // a < 1000
* Exp.lt(Exp.intBin("a"), Exp.val(1000))
* }
*/
public static Exp lt(Exp left, Exp right) {
return new CmdExp(LT, left, right);
}
/**
* Create less than or equals (<=) operation.
*
* {@code
* // a <= 1
* Exp.le(Exp.intBin("a"), Exp.val(1))
* }
*/
public static Exp le(Exp left, Exp right) {
return new CmdExp(LE, left, right);
}
//--------------------------------------------------
// Number Operator
//--------------------------------------------------
/**
* Create "add" (+) operator that applies to a variable number of expressions.
* Return sum of all arguments. All arguments must resolve to the same type (integer or float).
* Requires server version 5.6.0+.
*
* {@code
* // a + b + c == 10
* Exp.eq(
* Exp.add(Exp.intBin("a"), Exp.intBin("b"), Exp.intBin("c")),
* Exp.val(10));
* }
*/
public static Exp add(Exp... exps) {
return new CmdExp(ADD, exps);
}
/**
* Create "subtract" (-) operator that applies to a variable number of expressions.
* If only one argument is provided, return the negation of that argument.
* Otherwise, return the sum of the 2nd to Nth argument subtracted from the 1st
* argument. All arguments must resolve to the same type (integer or float).
* Requires server version 5.6.0+.
*
* {@code
* // a - b - c > 10
* Exp.gt(
* Exp.sub(Exp.intBin("a"), Exp.intBin("b"), Exp.intBin("c")),
* Exp.val(10));
* }
*/
public static Exp sub(Exp... exps) {
return new CmdExp(SUB, exps);
}
/**
* Create "multiply" (*) operator that applies to a variable number of expressions.
* Return the product of all arguments. If only one argument is supplied, return
* that argument. All arguments must resolve to the same type (integer or float).
* Requires server version 5.6.0+.
*
* {@code
* // a * b * c < 100
* Exp.lt(
* Exp.mul(Exp.intBin("a"), Exp.intBin("b"), Exp.intBin("c")),
* Exp.val(100));
* }
*/
public static Exp mul(Exp... exps) {
return new CmdExp(MUL, exps);
}
/**
* Create "divide" (/) operator that applies to a variable number of expressions.
* If there is only one argument, returns the reciprocal for that argument.
* Otherwise, return the first argument divided by the product of the rest.
* All arguments must resolve to the same type (integer or float).
* Requires server version 5.6.0+.
*
* {@code
* // a / b / c > 1
* Exp.gt(
* Exp.div(Exp.intBin("a"), Exp.intBin("b"), Exp.intBin("c")),
* Exp.val(1));
* }
*/
public static Exp div(Exp... exps) {
return new CmdExp(DIV, exps);
}
/**
* Create "power" operator that raises a "base" to the "exponent" power.
* All arguments must resolve to floats.
* Requires server version 5.6.0+.
*
* {@code
* // pow(a, 2.0) == 4.0
* Exp.eq(
* Exp.pow(Exp.floatBin("a"), Exp.val(2.0)),
* Exp.val(4.0));
* }
*/
public static Exp pow(Exp base, Exp exponent) {
return new CmdExp(POW, base, exponent);
}
/**
* Create "log" operator for logarithm of "num" with base "base".
* All arguments must resolve to floats.
* Requires server version 5.6.0+.
*
* {@code
* // log(a, 2.0) == 4.0
* Exp.eq(
* Exp.log(Exp.floatBin("a"), Exp.val(2.0)),
* Exp.val(4.0));
* }
*/
public static Exp log(Exp num, Exp base) {
return new CmdExp(LOG, num, base);
}
/**
* Create "modulo" (%) operator that determines the remainder of "numerator"
* divided by "denominator". All arguments must resolve to integers.
* Requires server version 5.6.0+.
*
* {@code
* // a % 10 == 0
* Exp.eq(
* Exp.mod(Exp.intBin("a"), Exp.val(10)),
* Exp.val(0));
* }
*/
public static Exp mod(Exp numerator, Exp denominator) {
return new CmdExp(MOD, numerator, denominator);
}
/**
* Create operator that returns absolute value of a number.
* All arguments must resolve to integer or float.
* Requires server version 5.6.0+.
*
* {@code
* // abs(a) == 1
* Exp.eq(
* Exp.abs(Exp.intBin("a")),
* Exp.val(1));
* }
*/
public static Exp abs(Exp value) {
return new CmdExp(ABS, value);
}
/**
* Create expression that rounds a floating point number down to the closest integer value.
* The return type is float. Requires server version 5.6.0+.
*
* {@code
* // floor(2.95) == 2.0
* Exp.eq(
* Exp.floor(Exp.val(2.95)),
* Exp.val(2.0));
* }
*/
public static Exp floor(Exp num) {
return new CmdExp(FLOOR, num);
}
/**
* Create expression that rounds a floating point number up to the closest integer value.
* The return type is float. Requires server version 5.6.0+.
*
* {@code
* // ceil(2.15) >= 3.0
* Exp.ge(
* Exp.ceil(Exp.val(2.15)),
* Exp.val(3.0));
* }
*/
public static Exp ceil(Exp num) {
return new CmdExp(CEIL, num);
}
/**
* Create expression that converts a float to an integer.
* Requires server version 5.6.0+.
*
* {@code
* // int(2.5) == 2
* Exp.eq(
* Exp.toInt(Exp.val(2.5)),
* Exp.val(2));
* }
*/
public static Exp toInt(Exp num) {
return new CmdExp(TO_INT, num);
}
/**
* Create expression that converts an integer to a float.
* Requires server version 5.6.0+.
*
* {@code
* // float(2) == 2.0
* Exp.eq(
* Exp.toFloat(Exp.val(2))),
* Exp.val(2.0));
* }
*/
public static Exp toFloat(Exp num) {
return new CmdExp(TO_FLOAT, num);
}
/**
* Create integer "and" (&) operator that is applied to two or more integers.
* All arguments must resolve to integers.
* Requires server version 5.6.0+.
*
* {@code
* // a & 0xff == 0x11
* Exp.eq(
* Exp.intAnd(Exp.intBin("a"), Exp.val(0xff)),
* Exp.val(0x11));
* }
*/
public static Exp intAnd(Exp... exps) {
return new CmdExp(INT_AND, exps);
}
/**
* Create integer "or" (|) operator that is applied to two or more integers.
* All arguments must resolve to integers.
* Requires server version 5.6.0+.
*
* {@code
* // a | 0x10 != 0
* Exp.ne(
* Exp.intOr(Exp.intBin("a"), Exp.val(0x10)),
* Exp.val(0));
* }
*/
public static Exp intOr(Exp... exps) {
return new CmdExp(INT_OR, exps);
}
/**
* Create integer "xor" (^) operator that is applied to two or more integers.
* All arguments must resolve to integers.
* Requires server version 5.6.0+.
*
* {@code
* // a ^ b == 16
* Exp.eq(
* Exp.intXor(Exp.intBin("a"), Exp.intBin("b")),
* Exp.val(16));
* }
*/
public static Exp intXor(Exp... exps) {
return new CmdExp(INT_XOR, exps);
}
/**
* Create integer "not" (~) operator.
* Requires server version 5.6.0+.
*
* {@code
* // ~a == 7
* Exp.eq(
* Exp.intNot(Exp.intBin("a")),
* Exp.val(7));
* }
*/
public static Exp intNot(Exp exp) {
return new CmdExp(INT_NOT, exp);
}
/**
* Create integer "left shift" (<<) operator.
* Requires server version 5.6.0+.
*
* {@code
* // a << 8 > 0xff
* Exp.gt(
* Exp.lshift(Exp.intBin("a"), Exp.val(8)),
* Exp.val(0xff));
* }
*/
public static Exp lshift(Exp value, Exp shift) {
return new CmdExp(INT_LSHIFT, value, shift);
}
/**
* Create integer "logical right shift" (>>>) operator.
* Requires server version 5.6.0+.
*
* {@code
* // a >>> 8 > 0xff
* Exp.gt(
* Exp.rshift(Exp.intBin("a"), Exp.val(8)),
* Exp.val(0xff));
* }
*/
public static Exp rshift(Exp value, Exp shift) {
return new CmdExp(INT_RSHIFT, value, shift);
}
/**
* Create integer "arithmetic right shift" (>>) operator.
* Requires server version 5.6.0+.
*
* {@code
* // a >> 8 > 0xff
* Exp.gt(
* Exp.arshift(Exp.intBin("a"), Exp.val(8)),
* Exp.val(0xff));
* }
*/
public static Exp arshift(Exp value, Exp shift) {
return new CmdExp(INT_ARSHIFT, value, shift);
}
/**
* Create expression that returns count of integer bits that are set to 1.
* Requires server version 5.6.0+.
*
* {@code
* // count(a) == 4
* Exp.eq(
* Exp.count(Exp.intBin("a")),
* Exp.val(4));
* }
*/
public static Exp count(Exp exp) {
return new CmdExp(INT_COUNT, exp);
}
/**
* Create expression that scans integer bits from left (most significant bit) to
* right (least significant bit), looking for a search bit value. When the
* search value is found, the index of that bit (where the most significant bit is
* index 0) is returned. If "search" is true, the scan will search for the bit
* value 1. If "search" is false it will search for bit value 0.
* Requires server version 5.6.0+.
*
* {@code
* // lscan(a, true) == 4
* Exp.eq(
* Exp.lscan(Exp.intBin("a"), Exp.val(true)),
* Exp.val(4));
* }
*/
public static Exp lscan(Exp value, Exp search) {
return new CmdExp(INT_LSCAN, value, search);
}
/**
* Create expression that scans integer bits from right (least significant bit) to
* left (most significant bit), looking for a search bit value. When the
* search value is found, the index of that bit (where the most significant bit is
* index 0) is returned. If "search" is true, the scan will search for the bit
* value 1. If "search" is false it will search for bit value 0.
* Requires server version 5.6.0+.
*
* {@code
* // rscan(a, true) == 4
* Exp.eq(
* Exp.rscan(Exp.intBin("a"), Exp.val(true)),
* Exp.val(4));
* }
*/
public static Exp rscan(Exp value, Exp search) {
return new CmdExp(INT_RSCAN, value, search);
}
/**
* Create expression that returns the minimum value in a variable number of expressions.
* All arguments must be the same type (integer or float).
* Requires server version 5.6.0+.
*
* {@code
* // min(a, b, c) > 0
* Exp.gt(
* Exp.min(Exp.intBin("a"), Exp.intBin("b"), Exp.intBin("c")),
* Exp.val(0));
* }
*/
public static Exp min(Exp... exps) {
return new CmdExp(MIN, exps);
}
/**
* Create expression that returns the maximum value in a variable number of expressions.
* All arguments must be the same type (integer or float).
* Requires server version 5.6.0+.
*
* {@code
* // max(a, b, c) > 100
* Exp.gt(
* Exp.max(Exp.intBin("a"), Exp.intBin("b"), Exp.intBin("c")),
* Exp.val(100));
* }
*/
public static Exp max(Exp... exps) {
return new CmdExp(MAX, exps);
}
//--------------------------------------------------
// Variables
//--------------------------------------------------
/**
* Conditionally select an expression from a variable number of expression pairs
* followed by default expression action. Requires server version 5.6.0+.
*
* {@code
* Args Format: bool exp1, action exp1, bool exp2, action exp2, ..., action-default
*
* // Apply operator based on type.
* Exp.cond(
* Exp.eq(Exp.intBin("type"), Exp.val(0)), Exp.add(Exp.intBin("val1"), Exp.intBin("val2")),
* Exp.eq(Exp.intBin("type"), Exp.val(1)), Exp.sub(Exp.intBin("val1"), Exp.intBin("val2")),
* Exp.eq(Exp.intBin("type"), Exp.val(2)), Exp.mul(Exp.intBin("val1"), Exp.intBin("val2")),
* Exp.val(-1));
* }
*/
public static Exp cond(Exp... exps) {
return new CmdExp(COND, exps);
}
/**
* Define variables and expressions in scope.
* Requires server version 5.6.0+.
*
* {@code
* Args Format: , , ...,
* def: {@link Exp#def(String, Exp)}
* exp: Scoped expression
* }
*
* {@code
* // 5 < a < 10
* Exp.let(
* Exp.def("x", Exp.intBin("a")),
* Exp.and(
* Exp.lt(Exp.val(5), Exp.var("x")),
* Exp.lt(Exp.var("x"), Exp.val(10))));
* }
*/
public static Exp let(Exp... exps) {
return new Let(exps);
}
/**
* Assign variable to a {@link Exp#let(Exp...)} expression that can be accessed later.
* Requires server version 5.6.0+.
*
* {@code
* // 5 < a < 10
* Exp.let(
* Exp.def("x", Exp.intBin("a")),
* Exp.and(
* Exp.lt(Exp.val(5), Exp.var("x")),
* Exp.lt(Exp.var("x"), Exp.val(10))));
* }
*/
public static Exp def(String name, Exp value) {
return new Def(name, value);
}
/**
* Retrieve expression value from a variable.
* Requires server version 5.6.0+.
*
* {@code
* // 5 < a < 10
* Exp.let(
* Exp.def("x", Exp.intBin("a")),
* Exp.and(
* Exp.lt(Exp.val(5), Exp.var("x")),
* Exp.lt(Exp.var("x"), Exp.val(10))));
* }
*/
public static Exp var(String name) {
return new CmdStr(VAR, name);
}
//--------------------------------------------------
// Miscellaneous
//--------------------------------------------------
/**
* Create unknown value. Used to intentionally fail an expression.
* The failure can be ignored with {@link com.aerospike.client.exp.ExpWriteFlags#EVAL_NO_FAIL}
* or {@link com.aerospike.client.exp.ExpReadFlags#EVAL_NO_FAIL}.
* Requires server version 5.6.0+.
*
* {@code
* // double v = balance - 100.0;
* // return (v > 0.0)? v : unknown;
* Exp.let(
* Exp.def("v", Exp.sub(Exp.floatBin("balance"), Exp.val(100.0))),
* Exp.cond(
* Exp.ge(Exp.var("v"), Exp.val(0.0)), Exp.var("v"),
* Exp.unknown()));
* }
*/
public static Exp unknown() {
return new Cmd(UNKNOWN);
}
/**
* Merge precompiled expression into a new expression tree.
* Useful for storing common precompiled expressions and then reusing
* these expressions as part of a greater expression.
*
* {@code
* // Merge precompiled expression into new expression.
* Expression e = Exp.build(Exp.eq(Exp.intBin("a"), Exp.val(200)));
* Expression merged = Exp.build(Exp.and(Exp.expr(e), Exp.eq(Exp.intBin("b"), Exp.val(100))));
* }
*/
public static Exp expr(Expression e) {
return new ExpBytes(e);
}
//--------------------------------------------------
// Internal
//--------------------------------------------------
private static final int UNKNOWN = 0;
private static final int EQ = 1;
private static final int NE = 2;
private static final int GT = 3;
private static final int GE = 4;
private static final int LT = 5;
private static final int LE = 6;
private static final int REGEX = 7;
private static final int GEO = 8;
private static final int AND = 16;
private static final int OR = 17;
private static final int NOT = 18;
private static final int EXCLUSIVE = 19;
private static final int ADD = 20;
private static final int SUB = 21;
private static final int MUL = 22;
private static final int DIV = 23;
private static final int POW = 24;
private static final int LOG = 25;
private static final int MOD = 26;
private static final int ABS = 27;
private static final int FLOOR = 28;
private static final int CEIL = 29;
private static final int TO_INT = 30;
private static final int TO_FLOAT = 31;
private static final int INT_AND = 32;
private static final int INT_OR = 33;
private static final int INT_XOR = 34;
private static final int INT_NOT = 35;
private static final int INT_LSHIFT = 36;
private static final int INT_RSHIFT = 37;
private static final int INT_ARSHIFT = 38;
private static final int INT_COUNT = 39;
private static final int INT_LSCAN = 40;
private static final int INT_RSCAN = 41;
private static final int MIN = 50;
private static final int MAX = 51;
private static final int DIGEST_MODULO = 64;
private static final int DEVICE_SIZE = 65;
private static final int LAST_UPDATE = 66;
private static final int SINCE_UPDATE = 67;
private static final int VOID_TIME = 68;
private static final int TTL = 69;
private static final int SET_NAME = 70;
private static final int KEY_EXISTS = 71;
private static final int IS_TOMBSTONE = 72;
private static final int MEMORY_SIZE = 73;
private static final int KEY = 80;
private static final int BIN = 81;
private static final int BIN_TYPE = 82;
private static final int COND = 123;
private static final int VAR = 124;
private static final int LET = 125;
private static final int QUOTED = 126;
private static final int CALL = 127;
public static final int MODIFY = 0x40;
private static final long NANOS_PER_MILLIS = 1000000L;
public abstract void pack(Packer packer);
/**
* For internal use only.
*/
static class Module extends Exp {
private final Exp bin;
private final byte[] bytes;
private final int retType;
private final int module;
public Module(Exp bin, byte[] bytes, int retType, int module) {
this.bin = bin;
this.bytes = bytes;
this.retType = retType;
this.module = module;
}
@Override
public void pack(Packer packer) {
packer.packArrayBegin(5);
packer.packInt(Exp.CALL);
packer.packInt(retType);
packer.packInt(module);
packer.packByteArray(bytes, 0, bytes.length);
bin.pack(packer);
}
}
private static final class Bin extends Exp {
private final String name;
private final Type type;
public Bin(String name, Type type) {
this.name = name;
this.type = type;
}
@Override
public void pack(Packer packer) {
packer.packArrayBegin(3);
packer.packInt(BIN);
packer.packInt(type.code);
packer.packString(name);
}
}
private static final class Regex extends Exp {
private final Exp bin;
private final String regex;
private final int flags;
private Regex(Exp bin, String regex, int flags) {
this.bin = bin;
this.regex = regex;
this.flags = flags;
}
@Override
public void pack(Packer packer) {
packer.packArrayBegin(4);
packer.packInt(REGEX);
packer.packInt(flags);
packer.packString(regex);
bin.pack(packer);
}
}
private static final class Let extends Exp {
private final Exp[] exps;
private Let(Exp... exps) {
this.exps = exps;
}
@Override
public void pack(Packer packer) {
// Let wire format: LET , , , , ...,
int count = (exps.length - 1) * 2 + 2;
packer.packArrayBegin(count);
packer.packInt(LET);
for (Exp exp : exps) {
exp.pack(packer);
}
}
}
private static final class Def extends Exp {
private final String name;
private final Exp exp;
private Def(String name, Exp exp) {
this.name = name;
this.exp = exp;
}
@Override
public void pack(Packer packer) {
packer.packString(name);
exp.pack(packer);
}
}
private static final class CmdExp extends Exp {
private final Exp[] exps;
private final int cmd;
private CmdExp(int cmd, Exp... exps) {
this.exps = exps;
this.cmd = cmd;
}
@Override
public void pack(Packer packer) {
packer.packArrayBegin(exps.length + 1);
packer.packInt(cmd);
for (Exp exp : exps) {
exp.pack(packer);
}
}
}
private static final class CmdInt extends Exp {
private final int cmd;
private final int val;
private CmdInt(int cmd, int val) {
this.cmd = cmd;
this.val = val;
}
@Override
public void pack(Packer packer) {
packer.packArrayBegin(2);
packer.packInt(cmd);
packer.packInt(val);
}
}
private static final class CmdStr extends Exp {
private final String str;
private final int cmd;
private CmdStr(int cmd, String str) {
this.str = str;
this.cmd = cmd;
}
@Override
public void pack(Packer packer) {
packer.packArrayBegin(2);
packer.packInt(cmd);
packer.packString(str);
}
}
private static final class Cmd extends Exp {
private final int cmd;
private Cmd(int cmd) {
this.cmd = cmd;
}
@Override
public void pack(Packer packer) {
packer.packArrayBegin(1);
packer.packInt(cmd);
}
}
private static final class Bool extends Exp {
private final boolean val;
private Bool(boolean val) {
this.val = val;
}
@Override
public void pack(Packer packer) {
packer.packBoolean(val);
}
}
private static final class Int extends Exp {
private final long val;
private Int(long val) {
this.val = val;
}
@Override
public void pack(Packer packer) {
packer.packLong(val);
}
}
private static final class Float extends Exp {
private final double val;
private Float(double val) {
this.val = val;
}
@Override
public void pack(Packer packer) {
packer.packDouble(val);
}
}
private static final class Str extends Exp {
private final String val;
private Str(String val) {
this.val = val;
}
@Override
public void pack(Packer packer) {
packer.packParticleString(val);
}
}
private static final class Geo extends Exp {
private final String val;
private Geo(String val) {
this.val = val;
}
@Override
public void pack(Packer packer) {
packer.packGeoJSON(val);
}
}
private static final class Blob extends Exp {
private final byte[] val;
private Blob(byte[] val) {
this.val = val;
}
@Override
public void pack(Packer packer) {
packer.packParticleBytes(val);
}
}
private static final class ListVal extends Exp {
private final List> list;
private ListVal(List> list) {
this.list = list;
}
@Override
public void pack(Packer packer) {
// List values need an extra array and QUOTED in order to distinguish
// between a multiple argument array call and a local list.
packer.packArrayBegin(2);
packer.packInt(QUOTED);
packer.packList(list);
}
}
private static final class MapVal extends Exp {
private final Map,?> map;
private MapVal(Map,?> map) {
this.map = map;
}
@Override
public void pack(Packer packer) {
packer.packMap(map);
}
}
private static final class Nil extends Exp {
@Override
public void pack(Packer packer) {
packer.packNil();
}
}
private static final class Infinity extends Exp {
@Override
public void pack(Packer packer) {
packer.packInfinity();
}
}
private static final class Wildcard extends Exp {
@Override
public void pack(Packer packer) {
packer.packWildcard();
}
}
private static final class ExpBytes extends Exp
{
private final byte[] bytes;
private ExpBytes(Expression e)
{
this.bytes = e.getBytes();
}
@Override
public void pack(Packer packer) {
packer.packByteArray(bytes, 0, bytes.length);
}
}
}