Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 183 additions & 2 deletions client/src/com/aerospike/client/cdt/CTX.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
package com.aerospike.client.cdt;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.aerospike.client.AerospikeException;
Expand Down Expand Up @@ -153,6 +155,184 @@ public static CTX mapValue(Value key) {
return new CTX(0x23, key);
}

/**
* Select map entries whose keys are contained in the provided string keys.
* <p>
* This context selects a subset of a map by matching its keys against
* the given keys. Only entries with keys present in {@code keys} are
* included. Can be combined with {@link #andFilter(Exp)} to apply
* additional filtering on the selected entries.
*
* <pre>{@code
* // Given map: {alpha: 10, beta: 20, gamma: 30, delta: 40}
* // Select only the "alpha" and "gamma" entries.
* CTX ctx = CTX.mapKeysIn("alpha", "gamma");
* Operation op = CdtOperation.selectByPath("myBin", SelectFlags.VALUE, ctx);
* Record result = client.operate(null, key, op);
* // result: [10, 30]
* }</pre>
*
* @param keys string map keys to select
* @return a map key-list context
* @see #andFilter(Exp)
* @see CdtOperation#selectByPath(String, int, CTX...)
*/
public static CTX mapKeysIn(String... keys) {
return new CTX(0x2a, Value.get(Arrays.asList(keys)));
}

/**
* Select map entries whose keys are contained in the provided integer keys.
*
* <pre>{@code
* CTX ctx = CTX.mapKeysIn(1, 2, 3);
* }</pre>
*
* @param keys integer map keys to select
* @return a map key-list context
* @see #mapKeysIn(String...)
*/
public static CTX mapKeysIn(int... keys) {
// Manual boxing required: Arrays.asList() on a primitive array wraps it as a single element, not per-element.
List<Integer> list = new ArrayList<>(keys.length);
for (int k : keys) {
list.add(k);
}
return new CTX(0x2a, Value.get(list));
}

/**
* Select map entries whose keys are contained in the provided long keys.
*
* <pre>{@code
* CTX ctx = CTX.mapKeysIn(1L, 2L, 3L);
* }</pre>
*
* @param keys long map keys to select
* @return a map key-list context
* @see #mapKeysIn(String...)
*/
public static CTX mapKeysIn(long... keys) {
// Manual boxing required: Arrays.asList() on a primitive array wraps it as a single element, not per-element.
List<Long> list = new ArrayList<>(keys.length);
for (long k : keys) {
list.add(k);
}
return new CTX(0x2a, Value.get(list));
}

/**
* Select map entries whose keys are contained in the provided byte keys.
*
* @param keys byte map keys to select
* @return a map key-list context
* @see #mapKeysIn(String...)
*/
public static CTX mapKeysIn(byte... keys) {
// Manual boxing required: Arrays.asList() on a primitive array wraps it as a single element, not per-element.
List<Byte> list = new ArrayList<>(keys.length);
for (byte k : keys) {
list.add(k);
}
return new CTX(0x2a, Value.get(list));
}

/**
* Select map entries whose keys are contained in the provided short keys.
*
* @param keys short map keys to select
* @return a map key-list context
* @see #mapKeysIn(String...)
*/
public static CTX mapKeysIn(short... keys) {
// Manual boxing required: Arrays.asList() on a primitive array wraps it as a single element, not per-element.
List<Short> list = new ArrayList<>(keys.length);
for (short k : keys) {
list.add(k);
}
return new CTX(0x2a, Value.get(list));
}

/**
* Select map entries whose keys are contained in the provided double keys.
*
* @param keys double map keys to select
* @return a map key-list context
* @see #mapKeysIn(String...)
*/
public static CTX mapKeysIn(double... keys) {
// Manual boxing required: Arrays.asList() on a primitive array wraps it as a single element, not per-element.
List<Double> list = new ArrayList<>(keys.length);
for (double k : keys) {
list.add(k);
}
return new CTX(0x2a, Value.get(list));
}

/**
* Select map entries whose keys are contained in the provided float keys.
*
* @param keys float map keys to select
* @return a map key-list context
* @see #mapKeysIn(String...)
*/
public static CTX mapKeysIn(float... keys) {
// Manual boxing required: Arrays.asList() on a primitive array wraps it as a single element, not per-element.
List<Float> list = new ArrayList<>(keys.length);
for (float k : keys) {
list.add(k);
}
return new CTX(0x2a, Value.get(list));
}

/**
* Apply an additional expression filter at the current context level.
* <p>
* This creates an AND filter that combines with the preceding context.
* Entries must satisfy both the preceding context and this filter expression
* to be included in the result. Typically used after {@link #mapKeysIn(String...)}
* or other selection contexts to further narrow the results.
*
* <pre>{@code
* // Given map: {a: 5, b: 15, c: 25, d: 35}
* // Select keys "a", "b", "c" AND keep only entries where value > 10.
* CTX keys = CTX.mapKeysIn("a", "b", "c");
* CTX filter = CTX.andFilter(
* Exp.gt(Exp.intLoopVar(LoopVarPart.VALUE), Exp.val(10))
* );
* Operation op = CdtOperation.selectByPath("myBin", SelectFlags.MAP_KEY_VALUE, keys, filter);
* Record result = client.operate(null, key, op);
* // result: {b: 15, c: 25}
* }</pre>
*
* @param exp filter expression; entries that evaluate to false are excluded
* @return an AND filter context
* @see #mapKeysIn(String...)
* @see CdtOperation#selectByPath(String, int, CTX...)
*/
public static CTX andFilter(Exp exp) {
Expression expression = Exp.build(exp);
return new CTX(Exp.CTX_AND | Exp.CTX_EXP, expression);
}

/**
* Apply an additional expression filter at the current context level.
* <p>
* This creates an AND filter that combines with the preceding context.
* Entries must satisfy both the preceding context and this filter expression
* to be included in the result. Typically used after {@link #mapKeysIn(String...)}
* or other selection contexts to further narrow the results.
*
* @param exp compiled filter expression; entries that evaluate to false are excluded
* @return an AND filter context
* @see #andFilter(Exp)
* @see #mapKeysIn(String...)
* @see CdtOperation#selectByPath(String, int, CTX...)
*/
public static CTX andFilter(Expression exp) {
return new CTX(Exp.CTX_AND | Exp.CTX_EXP, exp);
}

/**
* Serialize context array to bytes.
*/
Expand All @@ -178,8 +358,9 @@ public static CTX[] fromBytes(byte[] bytes) {
}

Object obj = list.get(i);
// Check if this is an expression context based on the id
if (id == Exp.CTX_EXP) {
// Check if this is an expression context based on the low nibble of the id.
// Mask with 0x0f so AND|EXP contexts (0x204) are correctly detected.
if ((id & 0x0f) == Exp.CTX_EXP) {
Expression exp = Exp.build(Exp.get(obj));
ctx[count++] = new CTX(id, exp);
} else {
Expand Down
2 changes: 1 addition & 1 deletion client/src/com/aerospike/client/exp/CdtExp.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class CdtExp {
/**
* The modify flag for CDT expressions.
*/
public static final int MODIFY = 0x40;
private static final int MODIFY = 0x40;

/**
* The type of CDT expression.
Expand Down
67 changes: 57 additions & 10 deletions client/src/com/aerospike/client/exp/Exp.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,18 @@ public enum Type {
}
}

/**
* @hidden
* Internal context type flag for expression-based contexts.
*/
public static final int CTX_EXP = 0x04;

/**
* @hidden
* Internal context type flag for AND filter contexts.
*/
public static final int CTX_AND = 0x200;

//--------------------------------------------------
// Build
//--------------------------------------------------
Expand Down Expand Up @@ -1182,7 +1192,7 @@ public static Exp var(String name) {
* Requires server version 8.1.1
*
* <pre>{@code
* Exp.stringLoopVar(LoopVarPart.MAP_KEY | LoopVarPart.VALUE | INDEX)
* Exp.stringLoopVar(LoopVarPart.MAP_KEY)
* }</pre>
*/
public static Exp stringLoopVar(LoopVarPart part) {
Expand All @@ -1194,7 +1204,7 @@ public static Exp stringLoopVar(LoopVarPart part) {
* Requires server version 8.1.1
*
* <pre>{@code
* Exp.boolLoopVar(LoopVarPart.MAP_KEY | LoopVarPart.VALUE | INDEX)
* Exp.boolLoopVar(LoopVarPart.MAP_KEY)
* }</pre>
*/
public static Exp boolLoopVar(LoopVarPart part) {
Expand All @@ -1206,7 +1216,7 @@ public static Exp boolLoopVar(LoopVarPart part) {
* Requires server version 8.1.1
*
* <pre>{@code
* Exp.hllLoopVar(LoopVarPart.MAP_KEY | LoopVarPart.VALUE | INDEX)
* Exp.hllLoopVar(LoopVarPart.MAP_KEY)
* }</pre>
*/
public static Exp hllLoopVar(LoopVarPart part) {
Expand All @@ -1218,7 +1228,7 @@ public static Exp hllLoopVar(LoopVarPart part) {
* Requires server version 8.1.1
*
* <pre>{@code
* Exp.intLoopVar(LoopVarPart.MAP_KEY | LoopVarPart.VALUE | INDEX)
* Exp.intLoopVar(LoopVarPart.MAP_KEY)
* }</pre>
*/
public static Exp intLoopVar(LoopVarPart part) {
Expand All @@ -1230,7 +1240,7 @@ public static Exp intLoopVar(LoopVarPart part) {
* Requires server version 8.1.1
*
* <pre>{@code
* Exp.floatLoopVar(LoopVarPart.MAP_KEY | LoopVarPart.VALUE | INDEX)
* Exp.floatLoopVar(LoopVarPart.MAP_KEY)
* }</pre>
*/
public static Exp floatLoopVar(LoopVarPart part) {
Expand All @@ -1242,7 +1252,7 @@ public static Exp floatLoopVar(LoopVarPart part) {
* Requires server version 8.1.1
*
* <pre>{@code
* Exp.listLoopVar(LoopVarPart.MAP_KEY | LoopVarPart.VALUE | INDEX)
* Exp.listLoopVar(LoopVarPart.MAP_KEY)
* }</pre>
*/
public static Exp listLoopVar(LoopVarPart part) {
Expand All @@ -1254,7 +1264,7 @@ public static Exp listLoopVar(LoopVarPart part) {
* Requires server version 8.1.1
*
* <pre>{@code
* Exp.mapLoopVar(LoopVarPart.MAP_KEY | LoopVarPart.VALUE | INDEX)
* Exp.mapLoopVar(LoopVarPart.MAP_KEY)
* }</pre>
*/
public static Exp mapLoopVar(LoopVarPart part) {
Expand All @@ -1266,7 +1276,7 @@ public static Exp mapLoopVar(LoopVarPart part) {
* Requires server version 8.1.1
*
* <pre>{@code
* Exp.blobLoopVar(LoopVarPart.MAP_KEY | LoopVarPart.VALUE | INDEX)
* Exp.blobLoopVar(LoopVarPart.MAP_KEY)
* }</pre>
*/
public static Exp blobLoopVar(LoopVarPart part) {
Expand All @@ -1278,7 +1288,7 @@ public static Exp blobLoopVar(LoopVarPart part) {
* Requires server version 8.1.1
*
* <pre>{@code
* Exp.nilLoopVar(LoopVarPart.MAP_KEY | LoopVarPart.VALUE | INDEX)
* Exp.nilLoopVar(LoopVarPart.MAP_KEY)
* }</pre>
*/
public static Exp nilLoopVar(LoopVarPart part) {
Expand All @@ -1290,13 +1300,47 @@ public static Exp nilLoopVar(LoopVarPart part) {
* Requires server version 8.1.1
*
* <pre>{@code
* Exp.geoJsonLoopVar(LoopVarPart.MAP_KEY | LoopVarPart.VALUE | INDEX)
* Exp.geoJsonLoopVar(LoopVarPart.MAP_KEY)
* }</pre>
*/
public static Exp geoJsonLoopVar(LoopVarPart part) {
return new Var(Type.GEO.code, part.id);
}

/**
* Create expression that checks if a value is contained in a list.
*
* <pre>{@code
* // Check if bin "color" value is in the list ["red", "blue", "green"]
* Exp.inList(Exp.stringBin("color"), Exp.val(List.of("red", "blue", "green")))
* }</pre>
*/
public static Exp inList(Exp value, Exp list) {
return new CmdExp(IN_LIST, value, list);
}

/**
* Create expression that extracts all keys from a map as a list.
*
* <pre>{@code
* Exp.mapKeysIn(Exp.mapBin("myMap"))
* }</pre>
*/
public static Exp mapKeysIn(Exp map) {
return new CmdExp(MAP_KEYS, map);
}

/**
* Create expression that extracts all values from a map as a list.
*
* <pre>{@code
* Exp.mapValues(Exp.mapBin("myMap"))
* }</pre>
*/
public static Exp mapValuesIn(Exp map) {
return new CmdExp(MAP_VALUES, map);
}

/**
* Creates a remove result expression.
* Requires server version 8.1.1+.
Expand Down Expand Up @@ -1403,7 +1447,10 @@ public static Exp expr(Expression e) {
private static final int KEY = 80;
private static final int BIN = 81;
private static final int BIN_TYPE = 82;
private static final int IN_LIST = 9;
private static final int RESULT_REMOVE = 100;
private static final int MAP_KEYS = 101;
private static final int MAP_VALUES = 102;
private static final int VAR_BUILTIN = 122;
private static final int COND = 123;
private static final int VAR = 124;
Expand Down
1 change: 1 addition & 0 deletions examples/src/com/aerospike/examples/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public class Main extends JPanel {
"OperateBit",
"OperateList",
"OperateMap",
"PathExpression",
"ScanPage",
"ScanParallel",
"ScanResume",
Expand Down
Loading
Loading