
com.aerospike.client.exp.Exp Maven / Gradle / Ivy
/*
* Copyright 2012-2021 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;
}
}
/**
* Create final expression that contains packed byte instructions used in the wire protocol.
*/
public static Expression build(Exp exp) {
return new Expression(exp);
}
/**
* 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);
}
/**
* 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 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.val(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);
}
/**
* 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.
*
* This method requires Aerospike 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);
}
/**
* 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);
}
/**
* 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.
*/
public static Exp val(Map,?> map) {
return new MapVal(map);
}
/**
* Create nil value.
*/
public static Exp nil() {
return new Nil();
}
/**
* 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 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);
}
//--------------------------------------------------
// Internal
//--------------------------------------------------
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 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 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 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();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy