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
19 changes: 19 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf

[*.java]
indent_style = space
indent_size = 4
insert_final_newline = true
max_line_length = 120
ij_java_wrap_long_lines = true
ij_java_wrap_comments = true
ij_java_method_call_chain_wrap = normal
ij_java_blank_lines_after_class_header = 1
ij_java_class_count_to_use_import_on_demand = 10
ij_java_names_count_to_use_import_on_demand = 10
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,17 @@ out/
*.ipr
*.iws

## Static Analysis
static-analysis/

## OS X
.DS_Store

## Cursor
.cursor/

## Local
tdd/
pmd-ruleset.xml
spotbugs-exclude.xml
pom-analysis.xml
11 changes: 9 additions & 2 deletions src/main/antlr4/com/aerospike/dsl/Condition.g4
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ comparisonExpression
| bitwiseExpression '<=' bitwiseExpression # LessThanOrEqualExpression
| bitwiseExpression '==' bitwiseExpression # EqualityExpression
| bitwiseExpression '!=' bitwiseExpression # InequalityExpression
| bitwiseExpression IN bitwiseExpression # InExpression
| bitwiseExpression # BitwiseExpressionWrapper
;

Expand Down Expand Up @@ -129,7 +130,9 @@ stringOperand: QUOTED_STRING;

QUOTED_STRING: ('\'' (~'\'')* '\'') | ('"' (~'"')* '"');

listConstant: '[' unaryExpression? (',' unaryExpression)* ']';
// LIST_TYPE_DESIGNATOR is needed here because the lexer tokenizes '[]' as a single token,
// preventing the parser from matching it as '[' ']' for empty list literals.
listConstant: '[' unaryExpression? (',' unaryExpression)* ']' | LIST_TYPE_DESIGNATOR;
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The addition of LIST_TYPE_DESIGNATOR as an alternative in the listConstant rule appears unrelated to the IN operation support. The LIST_TYPE_DESIGNATOR token (defined as '[]' on line 417) is already used in the listPart rule for path operations. Adding it here would allow '[]' to be parsed as a list literal, but there are no tests demonstrating this functionality or explaining its purpose in relation to the IN operation. Consider removing this addition if it's not needed for the IN operation, or add tests and documentation if it's intentional.

Suggested change
listConstant: '[' unaryExpression? (',' unaryExpression)* ']' | LIST_TYPE_DESIGNATOR;
listConstant: '[' unaryExpression? (',' unaryExpression)* ']';

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done to handle empty list, added a comment


orderedMapConstant: '{' mapPairConstant? (',' mapPairConstant)* '}';

Expand Down Expand Up @@ -215,7 +218,7 @@ PATH_FUNCTION_CDT_RETURN_TYPE
| 'REVERSE_RANK'
;

binPart: NAME_IDENTIFIER;
binPart: NAME_IDENTIFIER | IN;

mapPart
: MAP_TYPE_DESIGNATOR
Expand All @@ -238,6 +241,7 @@ MAP_TYPE_DESIGNATOR: '{}';
mapKey
: NAME_IDENTIFIER
| QUOTED_STRING
| IN
;

Comment on lines +244 to 246
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding IN as an alternative in the mapKey rule (and using ctx.IN() in MapKey.from()) is correct. However, MapKeyRange and MapKeyList (which also use mapKey) have not been updated to handle the IN token. When the IN keyword is used as a key in a range expression (like $.mapBin.{in-z}) or a key list ($.mapBin.{in,z}), the existing code in MapKeyRange.from() and MapKeyList.from() will throw a NullPointerException because it only checks for NAME_IDENTIFIER() and QUOTED_STRING(), not IN(). These classes should be updated with the same fix applied to MapKey.from() in this PR.

Suggested change
| IN
;
;

Copilot uses AI. Check for mistakes.
mapValue: '{=' valueIdentifier '}';
Expand Down Expand Up @@ -490,6 +494,7 @@ valueIdentifier
: NAME_IDENTIFIER
| QUOTED_STRING
| signedInt
| IN
;

valueListIdentifier: valueIdentifier ',' valueIdentifier (',' valueIdentifier)*;
Expand Down Expand Up @@ -532,6 +537,8 @@ pathFunctionParams: pathFunctionParam (',' pathFunctionParam)*?;

pathFunctionParam: pathFunctionParamName ':' pathFunctionParamValue;

IN: [iI][nN];

NAME_IDENTIFIER: [a-zA-Z0-9_]+;

WS: [ \t\r\n]+ -> skip;
23 changes: 22 additions & 1 deletion src/main/java/com/aerospike/dsl/parts/ExpressionContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import lombok.Setter;
import lombok.experimental.Accessors;

import java.util.EnumSet;

@Getter
public class ExpressionContainer extends AbstractPart {

Expand Down Expand Up @@ -78,10 +80,29 @@ public enum ExprPartsOperation {
GTEQ,
LT,
LTEQ,
IN,
WITH_STRUCTURE, // unary
WHEN_STRUCTURE, // unary
EXCLUSIVE_STRUCTURE, // unary
AND_STRUCTURE,
OR_STRUCTURE
OR_STRUCTURE;

// New values not in this set default to "might produce a list" (no false positives).
private static final EnumSet<ExprPartsOperation> SCALAR = EnumSet.of(
ADD, SUB, MUL, DIV, MOD, POW,
INT_AND, INT_OR, INT_XOR, INT_NOT,
L_SHIFT, R_SHIFT, LOGICAL_R_SHIFT,
ABS, CEIL, FLOOR, LOG,
MIN_FUNC, MAX_FUNC,
COUNT_ONE_BITS, FIND_BIT_LEFT, FIND_BIT_RIGHT,
TO_INT, TO_FLOAT,
EQ, NOTEQ, GT, GTEQ, LT, LTEQ,
IN, NOT, AND, OR,
AND_STRUCTURE, OR_STRUCTURE, EXCLUSIVE_STRUCTURE
);

public boolean isScalar() {
return SCALAR.contains(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
import com.aerospike.dsl.client.exp.ListExp;
import com.aerospike.dsl.parts.path.BasePath;

import com.aerospike.dsl.util.ParsingUtils;

import static com.aerospike.dsl.util.ParsingUtils.parseSignedInt;
import static com.aerospike.dsl.util.ParsingUtils.subtractNullable;
import static com.aerospike.dsl.util.ParsingUtils.unquote;

public class ListRankRangeRelative extends ListPart {
private final boolean isInverted;
Expand Down Expand Up @@ -43,17 +44,9 @@ public static ListRankRangeRelative from(ConditionParser.ListRankRangeRelativeCo
}

Object relativeValue = null;

if (range.relativeRankEnd().relativeValue() != null) {
ConditionParser.ValueIdentifierContext valueIdentifierContext
= range.relativeRankEnd().relativeValue().valueIdentifier();
if (valueIdentifierContext.signedInt() != null) {
relativeValue = parseSignedInt(valueIdentifierContext.signedInt());
} else if (valueIdentifierContext.NAME_IDENTIFIER() != null) {
relativeValue = valueIdentifierContext.NAME_IDENTIFIER().getText();
} else if (valueIdentifierContext.QUOTED_STRING() != null) {
relativeValue = unquote(valueIdentifierContext.QUOTED_STRING().getText());
}
relativeValue = ParsingUtils.parseValueIdentifier(
range.relativeRankEnd().relativeValue().valueIdentifier());
}

return new ListRankRangeRelative(isInverted, start, end, relativeValue);
Expand Down
13 changes: 2 additions & 11 deletions src/main/java/com/aerospike/dsl/parts/cdt/list/ListValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
import com.aerospike.dsl.client.exp.ListExp;
import com.aerospike.dsl.parts.path.BasePath;

import static com.aerospike.dsl.util.ParsingUtils.parseSignedInt;
import static com.aerospike.dsl.util.ParsingUtils.unquote;
import static com.aerospike.dsl.util.ParsingUtils.parseValueIdentifier;

public class ListValue extends ListPart {
private final Object value;
Expand All @@ -19,15 +18,7 @@ public ListValue(Object value) {
}

public static ListValue from(ConditionParser.ListValueContext ctx) {
Object listValue = null;
if (ctx.valueIdentifier().NAME_IDENTIFIER() != null) {
listValue = ctx.valueIdentifier().NAME_IDENTIFIER().getText();
} else if (ctx.valueIdentifier().QUOTED_STRING() != null) {
listValue = unquote(ctx.valueIdentifier().QUOTED_STRING().getText());
} else if (ctx.valueIdentifier().signedInt() != null) {
listValue = parseSignedInt(ctx.valueIdentifier().signedInt());
}
return new ListValue(listValue);
return new ListValue(parseValueIdentifier(ctx.valueIdentifier()));
}

@Override
Expand Down
18 changes: 5 additions & 13 deletions src/main/java/com/aerospike/dsl/parts/cdt/list/ListValueList.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@
import com.aerospike.dsl.client.exp.ListExp;
import com.aerospike.dsl.parts.path.BasePath;

import java.util.List;
import com.aerospike.dsl.util.ParsingUtils;

import static com.aerospike.dsl.util.ParsingUtils.parseSignedInt;
import static com.aerospike.dsl.util.ParsingUtils.unquote;
import java.util.List;

public class ListValueList extends ListPart {
private final boolean isInverted;
Expand All @@ -32,16 +31,9 @@ public static ListValueList from(ConditionParser.ListValueListContext ctx) {
valueList != null ? valueList.valueListIdentifier() : invertedValueList.valueListIdentifier();
boolean isInverted = valueList == null;

List<?> valueListObjects = list.valueIdentifier().stream().map(
listValue -> {
if (listValue.NAME_IDENTIFIER() != null) {
return listValue.NAME_IDENTIFIER().getText();
} else if (listValue.QUOTED_STRING() != null) {
return unquote(listValue.QUOTED_STRING().getText());
}
return parseSignedInt(listValue.signedInt());
}
).toList();
List<?> valueListObjects = list.valueIdentifier().stream()
.map(ParsingUtils::parseValueIdentifier)
.toList();

return new ListValueList(isInverted, valueListObjects);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import com.aerospike.dsl.client.exp.ListExp;
import com.aerospike.dsl.parts.path.BasePath;

import static com.aerospike.dsl.util.ParsingUtils.parseSignedInt;
import static com.aerospike.dsl.util.ParsingUtils.requireIntValueIdentifier;

public class ListValueRange extends ListPart {
private final boolean isInverted;
Expand All @@ -31,12 +31,11 @@ public static ListValueRange from(ConditionParser.ListValueRangeContext ctx) {
valueRange != null ? valueRange.valueRangeIdentifier() : invertedValueRange.valueRangeIdentifier();
boolean isInverted = valueRange == null;

Integer startValue = parseSignedInt(range.valueIdentifier(0).signedInt());
Integer startValue = requireIntValueIdentifier(range.valueIdentifier(0));

Integer endValue = null;

if (range.valueIdentifier(1) != null && range.valueIdentifier(1).signedInt() != null) {
endValue = parseSignedInt(range.valueIdentifier(1).signedInt());
if (range.valueIdentifier(1) != null) {
endValue = requireIntValueIdentifier(range.valueIdentifier(1));
}

return new ListValueRange(isInverted, startValue, endValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
import com.aerospike.dsl.client.exp.MapExp;
import com.aerospike.dsl.parts.path.BasePath;

import com.aerospike.dsl.util.ParsingUtils;

import static com.aerospike.dsl.util.ParsingUtils.parseSignedInt;
import static com.aerospike.dsl.util.ParsingUtils.subtractNullable;
import static com.aerospike.dsl.util.ParsingUtils.unquote;

public class MapIndexRangeRelative extends MapPart {
private final boolean isInverted;
Expand Down Expand Up @@ -44,12 +45,7 @@ public static MapIndexRangeRelative from(ConditionParser.MapIndexRangeRelativeCo

String relativeKey = null;
if (range.relativeKeyEnd().mapKey() != null) {
ConditionParser.MapKeyContext mapKeyContext = range.relativeKeyEnd().mapKey();
if (mapKeyContext.NAME_IDENTIFIER() != null) {
relativeKey = mapKeyContext.NAME_IDENTIFIER().getText();
} else if (mapKeyContext.QUOTED_STRING() != null) {
relativeKey = unquote(mapKeyContext.QUOTED_STRING().getText());
}
relativeKey = ParsingUtils.parseMapKey(range.relativeKeyEnd().mapKey());
}
return new MapIndexRangeRelative(isInverted, start, end, relativeKey);
}
Expand Down
12 changes: 2 additions & 10 deletions src/main/java/com/aerospike/dsl/parts/cdt/map/MapKey.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package com.aerospike.dsl.parts.cdt.map;

import com.aerospike.dsl.ConditionParser;
import com.aerospike.dsl.DslParseException;
import com.aerospike.dsl.client.Value;
import com.aerospike.dsl.client.cdt.CTX;
import com.aerospike.dsl.client.exp.Exp;
import com.aerospike.dsl.client.exp.MapExp;
import com.aerospike.dsl.parts.path.BasePath;

import static com.aerospike.dsl.util.ParsingUtils.unquote;
import com.aerospike.dsl.util.ParsingUtils;

public class MapKey extends MapPart {
private final String key;
Expand All @@ -19,13 +17,7 @@ public MapKey(String key) {
}

public static MapKey from(ConditionParser.MapKeyContext ctx) {
if (ctx.QUOTED_STRING() != null) {
return new MapKey(unquote(ctx.QUOTED_STRING().getText()));
}
if (ctx.NAME_IDENTIFIER() != null) {
return new MapKey(ctx.NAME_IDENTIFIER().getText());
}
throw new DslParseException("Could not translate MapKey from ctx: %s".formatted(ctx));
return new MapKey(ParsingUtils.parseMapKey(ctx));
}

@Override
Expand Down
16 changes: 5 additions & 11 deletions src/main/java/com/aerospike/dsl/parts/cdt/map/MapKeyList.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import com.aerospike.dsl.client.exp.MapExp;
import com.aerospike.dsl.parts.path.BasePath;

import java.util.List;
import com.aerospike.dsl.util.ParsingUtils;

import static com.aerospike.dsl.util.ParsingUtils.unquote;
import java.util.List;

public class MapKeyList extends MapPart {
private final boolean isInverted;
Expand All @@ -31,15 +31,9 @@ public static MapKeyList from(ConditionParser.MapKeyListContext ctx) {
keyList != null ? keyList.keyListIdentifier() : invertedKeyList.keyListIdentifier();
boolean isInverted = keyList == null;

List<String> keyListStrings = list.mapKey().stream().map(
mapKey -> {
if (mapKey.NAME_IDENTIFIER() != null) {
return mapKey.NAME_IDENTIFIER().getText();
} else {
return unquote(mapKey.QUOTED_STRING().getText());
}
}
).toList();
List<String> keyListStrings = list.mapKey().stream()
.map(ParsingUtils::parseMapKey)
.toList();

return new MapKeyList(isInverted, keyListStrings);
}
Expand Down
12 changes: 4 additions & 8 deletions src/main/java/com/aerospike/dsl/parts/cdt/map/MapKeyRange.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import com.aerospike.dsl.client.exp.MapExp;
import com.aerospike.dsl.parts.path.BasePath;

import java.util.Optional;
import com.aerospike.dsl.util.ParsingUtils;

import static com.aerospike.dsl.util.ParsingUtils.unquote;
import java.util.Optional;

public class MapKeyRange extends MapPart {
private final boolean isInverted;
Expand All @@ -33,14 +33,10 @@ public static MapKeyRange from(ConditionParser.MapKeyRangeContext ctx) {
keyRange != null ? keyRange.keyRangeIdentifier() : invertedKeyRange.keyRangeIdentifier();
boolean isInverted = keyRange == null;

String startKey = range.mapKey(0).NAME_IDENTIFIER() != null
? range.mapKey(0).NAME_IDENTIFIER().getText()
: unquote(range.mapKey(0).QUOTED_STRING().getText());
String startKey = ParsingUtils.parseMapKey(range.mapKey(0));

String endKey = Optional.ofNullable(range.mapKey(1))
.map(keyCtx -> keyCtx.NAME_IDENTIFIER() != null
? keyCtx.NAME_IDENTIFIER().getText()
: unquote(keyCtx.QUOTED_STRING().getText()))
.map(ParsingUtils::parseMapKey)
.orElse(null);

return new MapKeyRange(isInverted, startKey, endKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
import com.aerospike.dsl.client.exp.MapExp;
import com.aerospike.dsl.parts.path.BasePath;

import com.aerospike.dsl.util.ParsingUtils;

import static com.aerospike.dsl.util.ParsingUtils.parseSignedInt;
import static com.aerospike.dsl.util.ParsingUtils.subtractNullable;
import static com.aerospike.dsl.util.ParsingUtils.unquote;

public class MapRankRangeRelative extends MapPart {
private final boolean isInverted;
Expand Down Expand Up @@ -44,15 +45,8 @@ public static MapRankRangeRelative from(ConditionParser.MapRankRangeRelativeCont

Object relativeValue = null;
if (range.relativeRankEnd().relativeValue() != null) {
ConditionParser.ValueIdentifierContext valueIdentifierContext
= range.relativeRankEnd().relativeValue().valueIdentifier();
if (valueIdentifierContext.signedInt() != null) {
relativeValue = parseSignedInt(valueIdentifierContext.signedInt());
} else if (valueIdentifierContext.NAME_IDENTIFIER() != null) {
relativeValue = valueIdentifierContext.NAME_IDENTIFIER().getText();
} else if (valueIdentifierContext.QUOTED_STRING() != null) {
relativeValue = unquote(valueIdentifierContext.QUOTED_STRING().getText());
}
relativeValue = ParsingUtils.parseValueIdentifier(
range.relativeRankEnd().relativeValue().valueIdentifier());
}

return new MapRankRangeRelative(isInverted, start, end, relativeValue);
Expand Down
Loading
Loading