Skip to content

Commit

Permalink
Add support for casting (cast(field_name to ip)) and remove existin…
Browse files Browse the repository at this point in the history
…g unused sorting syntax.

Signed-off-by: currantw <[email protected]>
  • Loading branch information
currantw committed Nov 28, 2024
1 parent 944c9d9 commit e4fb3e7
Show file tree
Hide file tree
Showing 16 changed files with 138 additions and 110 deletions.
2 changes: 1 addition & 1 deletion core/src/main/java/org/opensearch/sql/ast/dsl/AstDSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ public static List<Argument> sortOptions() {
}

public static List<Argument> defaultSortFieldArgs() {
return exprList(argument("asc", booleanLiteral(true)), argument("type", nullLiteral()));
return exprList(argument("asc", booleanLiteral(true)));
}

public static Span span(UnresolvedExpression field, UnresolvedExpression value, SpanUnit unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_DOUBLE;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_FLOAT;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_INT;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_IP;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_LONG;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_SHORT;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_STRING;
Expand Down Expand Up @@ -54,6 +55,7 @@ public class Cast extends UnresolvedExpression {
.put("time", CAST_TO_TIME.getName())
.put("timestamp", CAST_TO_TIMESTAMP.getName())
.put("datetime", CAST_TO_DATETIME.getName())
.put("ip", CAST_TO_IP.getName())
.build();

/** The source expression cast from. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@ public ExprType type() {

@Override
public int compare(ExprValue other) {
return value.compareTo(((ExprIpValue) other).value);
IPAddress otherValue = ((ExprIpValue) other).value;
return value.compareTo(otherValue);
}

@Override
public boolean equal(ExprValue other) {
return value.equals(((ExprIpValue) other).value);
IPAddress otherValue = ((ExprIpValue) other).value;
return value.equals(otherValue);
}

@Override
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/org/opensearch/sql/expression/DSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,10 @@ public static FunctionExpression castTimestamp(Expression value) {
return compile(FunctionProperties.None, BuiltinFunctionName.CAST_TO_TIMESTAMP, value);
}

public static FunctionExpression castIp(Expression value) {
return compile(FunctionProperties.None, BuiltinFunctionName.CAST_TO_IP, value);
}

public static FunctionExpression typeof(Expression value) {
return compile(FunctionProperties.None, BuiltinFunctionName.TYPEOF, value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ public enum BuiltinFunctionName {
CAST_TO_TIME(FunctionName.of("cast_to_time")),
CAST_TO_TIMESTAMP(FunctionName.of("cast_to_timestamp")),
CAST_TO_DATETIME(FunctionName.of("cast_to_datetime")),
CAST_TO_IP(FunctionName.of("cast_to_ip")),
TYPEOF(FunctionName.of("typeof")),

/** Relevance Function. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static org.opensearch.sql.data.type.ExprCoreType.DOUBLE;
import static org.opensearch.sql.data.type.ExprCoreType.FLOAT;
import static org.opensearch.sql.data.type.ExprCoreType.INTEGER;
import static org.opensearch.sql.data.type.ExprCoreType.IP;
import static org.opensearch.sql.data.type.ExprCoreType.LONG;
import static org.opensearch.sql.data.type.ExprCoreType.SHORT;
import static org.opensearch.sql.data.type.ExprCoreType.STRING;
Expand All @@ -31,6 +32,7 @@
import org.opensearch.sql.data.model.ExprDoubleValue;
import org.opensearch.sql.data.model.ExprFloatValue;
import org.opensearch.sql.data.model.ExprIntegerValue;
import org.opensearch.sql.data.model.ExprIpValue;
import org.opensearch.sql.data.model.ExprLongValue;
import org.opensearch.sql.data.model.ExprShortValue;
import org.opensearch.sql.data.model.ExprStringValue;
Expand All @@ -53,6 +55,7 @@ public static void register(BuiltinFunctionRepository repository) {
repository.register(castToFloat());
repository.register(castToDouble());
repository.register(castToBoolean());
repository.register(castToIp());
repository.register(castToDate());
repository.register(castToTime());
repository.register(castToTimestamp());
Expand Down Expand Up @@ -172,6 +175,13 @@ private static DefaultFunctionResolver castToBoolean() {
impl(nullMissingHandling((v) -> v), BOOLEAN, BOOLEAN));
}

private static DefaultFunctionResolver castToIp() {
return FunctionDSL.define(
BuiltinFunctionName.CAST_TO_IP.getName(),
impl(nullMissingHandling((v) -> v), IP, IP),
impl(nullMissingHandling((v) -> new ExprIpValue(v.stringValue())), IP, STRING));
}

private static DefaultFunctionResolver castToDate() {
return FunctionDSL.define(
BuiltinFunctionName.CAST_TO_DATE.getName(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.opensearch.sql.data.type.ExprCoreType.BOOLEAN;
import static org.opensearch.sql.data.type.ExprCoreType.BYTE;
import static org.opensearch.sql.data.type.ExprCoreType.DATE;
import static org.opensearch.sql.data.type.ExprCoreType.DOUBLE;
import static org.opensearch.sql.data.type.ExprCoreType.FLOAT;
import static org.opensearch.sql.data.type.ExprCoreType.INTEGER;
import static org.opensearch.sql.data.type.ExprCoreType.IP;
import static org.opensearch.sql.data.type.ExprCoreType.LONG;
import static org.opensearch.sql.data.type.ExprCoreType.SHORT;
import static org.opensearch.sql.data.type.ExprCoreType.STRING;
Expand All @@ -29,12 +31,17 @@
import org.opensearch.sql.data.model.ExprDoubleValue;
import org.opensearch.sql.data.model.ExprFloatValue;
import org.opensearch.sql.data.model.ExprIntegerValue;
import org.opensearch.sql.data.model.ExprIpValue;
import org.opensearch.sql.data.model.ExprLongValue;
import org.opensearch.sql.data.model.ExprMissingValue;
import org.opensearch.sql.data.model.ExprNullValue;
import org.opensearch.sql.data.model.ExprShortValue;
import org.opensearch.sql.data.model.ExprStringValue;
import org.opensearch.sql.data.model.ExprTimeValue;
import org.opensearch.sql.data.model.ExprTimestampValue;
import org.opensearch.sql.data.model.ExprValue;
import org.opensearch.sql.exception.ExpressionEvaluationException;
import org.opensearch.sql.exception.SemanticCheckException;
import org.opensearch.sql.expression.DSL;
import org.opensearch.sql.expression.FunctionExpression;

Expand Down Expand Up @@ -316,10 +323,6 @@ void castToTime() {
assertEquals(TIME, expression.type());
assertEquals(new ExprTimeValue("01:01:01"), expression.valueOf());

expression = DSL.castTime(DSL.literal(new ExprTimestampValue("2012-08-07 01:01:01")));
assertEquals(TIME, expression.type());
assertEquals(new ExprTimeValue("01:01:01"), expression.valueOf());

expression = DSL.castTime(DSL.literal(new ExprTimeValue("01:01:01")));
assertEquals(TIME, expression.type());
assertEquals(new ExprTimeValue("01:01:01"), expression.valueOf());
Expand All @@ -334,9 +337,59 @@ void castToTimestamp() {
expression = DSL.castTimestamp(DSL.literal(new ExprTimestampValue("2012-08-07 01:01:01")));
assertEquals(TIMESTAMP, expression.type());
assertEquals(new ExprTimestampValue("2012-08-07 01:01:01"), expression.valueOf());
}

expression = DSL.castTimestamp(DSL.literal(new ExprTimestampValue("2012-08-07 01:01:01")));
assertEquals(TIMESTAMP, expression.type());
assertEquals(new ExprTimestampValue("2012-08-07 01:01:01"), expression.valueOf());
@Test
void castToIp() {
FunctionExpression exp;

String expectedMsg;
String actualMsg;

final String ipv4String = "1.2.3.4";
final String ipv6String = "2001:db7::ff00:42:8329";
final String ipInvalidString = "INVALID";

final ExprValue exprIpv4Value = new ExprIpValue(ipv4String);
final ExprValue exprIpv6Value = new ExprIpValue(ipv6String);

// From string
exp = DSL.castIp(DSL.literal(ipv4String));
assertEquals(IP, exp.type());
assertEquals(exprIpv4Value, exp.valueOf());

exp = DSL.castIp(DSL.literal(ipv6String));
assertEquals(IP, exp.type());
assertEquals(exprIpv6Value, exp.valueOf());

exp = DSL.castIp(DSL.literal(ipInvalidString));
actualMsg = assertThrows(SemanticCheckException.class, exp::valueOf).getMessage();
expectedMsg = String.format("IP address '%s' is not valid. Error details: .*", ipInvalidString);
assertTrue(actualMsg.matches(expectedMsg));

// From IP address
exp = DSL.castIp(DSL.literal(exprIpv4Value));
assertEquals(IP, exp.type());
assertEquals(exprIpv4Value, exp.valueOf());

exp = DSL.castIp(DSL.literal(exprIpv6Value));
assertEquals(IP, exp.type());
assertEquals(exprIpv6Value, exp.valueOf());

// From invalid type
actualMsg =
assertThrows(ExpressionEvaluationException.class, () -> DSL.castIp(DSL.literal(0)))
.getMessage();
expectedMsg = "cast_to_ip function expected {[IP],[STRING]}, but get [INTEGER]";
assertEquals(expectedMsg, actualMsg);

// From null or missing value
exp = DSL.castIp(DSL.literal(ExprNullValue.of()));
assertEquals(IP, exp.type());
assertTrue(exp.valueOf().isNull());

exp = DSL.castIp(DSL.literal(ExprMissingValue.of()));
assertEquals(IP, exp.type());
assertTrue(exp.valueOf().isMissing());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.opensearch.sql.data.model.ExprDoubleValue;
import org.opensearch.sql.data.model.ExprFloatValue;
import org.opensearch.sql.data.model.ExprIntegerValue;
import org.opensearch.sql.data.model.ExprIpValue;
import org.opensearch.sql.data.model.ExprLongValue;
import org.opensearch.sql.data.model.ExprShortValue;
import org.opensearch.sql.data.model.ExprStringValue;
Expand Down Expand Up @@ -211,6 +212,14 @@ private ExprValue cast(FunctionExpression castFunction, ReferenceExpression ref)
return expr.valueOf();
}
})
.put(
BuiltinFunctionName.CAST_TO_IP.getName(),
(expr, ref) -> {
ExprValue value = expr.valueOf();
return value.type().equals(ExprCoreType.IP)
? value
: new ExprIpValue(value.stringValue());
})
.put(
BuiltinFunctionName.CAST_TO_DATE.getName(),
(expr, ref) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import static org.opensearch.sql.data.type.ExprCoreType.DOUBLE;
import static org.opensearch.sql.data.type.ExprCoreType.FLOAT;
import static org.opensearch.sql.data.type.ExprCoreType.INTEGER;
import static org.opensearch.sql.data.type.ExprCoreType.IP;
import static org.opensearch.sql.data.type.ExprCoreType.LONG;
import static org.opensearch.sql.data.type.ExprCoreType.SHORT;
import static org.opensearch.sql.data.type.ExprCoreType.STRING;
Expand Down Expand Up @@ -59,6 +60,10 @@
@ExtendWith(MockitoExtension.class)
class FilterQueryBuilderTest {

private static Stream<LiteralExpression> ipCastSource() {
return Stream.of(literal("1.2.3.4"), literal("2001:db7::ff00:42:8329"));
}

private static Stream<LiteralExpression> numericCastSource() {
return Stream.of(
literal((byte) 1),
Expand Down Expand Up @@ -1715,6 +1720,24 @@ void cast_to_boolean_false_in_filter(LiteralExpression expr) {
json, buildQuery(DSL.equal(ref("boolean_value", BOOLEAN), DSL.castBoolean(expr))));
}

@ParameterizedTest(name = "castIp({0})")
@MethodSource({"ipCastSource"})
void cast_to_ip_in_filter(LiteralExpression expr) {
String json =
String.format(
"{\n"
+ " \"term\" : {\n"
+ " \"ip_value\" : {\n"
+ " \"value\" : \"%s\",\n"
+ " \"boost\" : 1.0\n"
+ " }\n"
+ " }\n"
+ "}",
expr.valueOf().stringValue());

assertJsonEquals(json, buildQuery(DSL.equal(ref("ip_value", IP), DSL.castIp(expr))));
}

@Test
void cast_from_boolean() {
Expression booleanExpr = literal(false);
Expand Down
7 changes: 1 addition & 6 deletions ppl/src/main/antlr/OpenSearchPPLLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,6 @@ DATASOURCES: 'DATASOURCES';
// CLAUSE KEYWORDS
SORTBY: 'SORTBY';

// FIELD KEYWORDS
AUTO: 'AUTO';
STR: 'STR';
IP: 'IP';
NUM: 'NUM';

// ARGUMENT KEYWORDS
KEEPEMPTY: 'KEEPEMPTY';
CONSECUTIVE: 'CONSECUTIVE';
Expand Down Expand Up @@ -135,6 +129,7 @@ LONG: 'LONG';
FLOAT: 'FLOAT';
STRING: 'STRING';
BOOLEAN: 'BOOLEAN';
IP: 'IP';

// SPECIAL CHARACTERS AND OPERATORS
PIPE: '|';
Expand Down
15 changes: 2 additions & 13 deletions ppl/src/main/antlr/OpenSearchPPLParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -332,15 +332,7 @@ wcFieldList
;

sortField
: (PLUS | MINUS)? sortFieldExpression
;

sortFieldExpression
: fieldExpression
| AUTO LT_PRTHS fieldExpression RT_PRTHS
| STR LT_PRTHS fieldExpression RT_PRTHS
| IP LT_PRTHS fieldExpression RT_PRTHS
| NUM LT_PRTHS fieldExpression RT_PRTHS
: (PLUS | MINUS)? fieldExpression
;

fieldExpression
Expand Down Expand Up @@ -377,6 +369,7 @@ convertedDataType
| typeName = FLOAT
| typeName = STRING
| typeName = BOOLEAN
| typeName = IP
;

evalFunctionName
Expand Down Expand Up @@ -862,10 +855,6 @@ keywordsCanBeId
| DATASOURCES
// CLAUSEKEYWORDS
| SORTBY
// FIELDKEYWORDSAUTO
| STR
| IP
| NUM
// ARGUMENT KEYWORDS
| KEEPEMPTY
| CONSECUTIVE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,7 @@ public UnresolvedExpression visitWcFieldExpression(WcFieldExpressionContext ctx)
@Override
public UnresolvedExpression visitSortField(SortFieldContext ctx) {
return new Field(
visit(ctx.sortFieldExpression().fieldExpression().qualifiedName()),
ArgumentFactory.getArgumentList(ctx));
visit(ctx.fieldExpression().qualifiedName()), ArgumentFactory.getArgumentList(ctx));
}

/** Aggregation function. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,10 @@ public static List<Argument> getArgumentList(DedupCommandContext ctx) {
* @return the list of arguments fetched from the sort field in sort command
*/
public static List<Argument> getArgumentList(SortFieldContext ctx) {
return Arrays.asList(
return List.of(
ctx.MINUS() != null
? new Argument("asc", new Literal(false, DataType.BOOLEAN))
: new Argument("asc", new Literal(true, DataType.BOOLEAN)),
ctx.sortFieldExpression().AUTO() != null
? new Argument("type", new Literal("auto", DataType.STRING))
: ctx.sortFieldExpression().IP() != null
? new Argument("type", new Literal("ip", DataType.STRING))
: ctx.sortFieldExpression().NUM() != null
? new Argument("type", new Literal("num", DataType.STRING))
: ctx.sortFieldExpression().STR() != null
? new Argument("type", new Literal("str", DataType.STRING))
: new Argument("type", new Literal(null, DataType.NULL)));
: new Argument("asc", new Literal(true, DataType.BOOLEAN)));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import static org.opensearch.sql.ast.dsl.AstDSL.intLiteral;
import static org.opensearch.sql.ast.dsl.AstDSL.let;
import static org.opensearch.sql.ast.dsl.AstDSL.map;
import static org.opensearch.sql.ast.dsl.AstDSL.nullLiteral;
import static org.opensearch.sql.ast.dsl.AstDSL.parse;
import static org.opensearch.sql.ast.dsl.AstDSL.projectWithArg;
import static org.opensearch.sql.ast.dsl.AstDSL.qualifiedName;
Expand Down Expand Up @@ -424,9 +423,7 @@ public void testSortCommandWithOptions() {
"source=t | sort - f1, + f2",
sort(
relation("t"),
field(
"f1",
exprList(argument("asc", booleanLiteral(false)), argument("type", nullLiteral()))),
field("f1", exprList(argument("asc", booleanLiteral(false)))),
field("f2", defaultSortFieldArgs())));
}

Expand Down
Loading

0 comments on commit e4fb3e7

Please sign in to comment.