aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2018-06-03 00:02:35 +0200
committerHenning Baldersheim <balder@yahoo-inc.com>2018-06-03 00:02:35 +0200
commit1dbfe269c9a90fb8ad9a59a1fd5e2eafd6abbd7e (patch)
tree6e0d3bcd87bbb9cdf3ba3ecfa6a31fc989569fdf
parent53f3d3d5b06ad034a0f8a0f0e457b0d10033d574 (diff)
Allow nested fieldnames using '.' in yql.
-rw-r--r--container-search/src/main/java/com/yahoo/search/yql/YqlParser.java44
-rw-r--r--container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java8
2 files changed, 34 insertions, 18 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
index 38a87f3b7bc..0b9f79537d0 100644
--- a/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
+++ b/container-search/src/main/java/com/yahoo/search/yql/YqlParser.java
@@ -915,8 +915,16 @@ public class YqlParser implements Parser {
@NonNull
private static String fetchFieldRead(OperatorNode<ExpressionOperator> ast) {
- assertHasOperator(ast, ExpressionOperator.READ_FIELD);
- return ast.getArgument(1);
+ switch (ast.getOperator()) {
+ case READ_FIELD:
+ return ast.getArgument(1);
+ case PROPREF:
+ return new StringBuilder(fetchFieldRead(ast.getArgument(0)))
+ .append('.').append(ast.getArgument(1).toString()).toString();
+ default:
+ throw newUnexpectedArgumentException(ast.getOperator(),
+ ExpressionOperator.READ_FIELD, ExpressionOperator.PROPREF);
+ }
}
@NonNull
@@ -986,14 +994,12 @@ public class YqlParser implements Parser {
OperatorNode<ExpressionOperator> lhs = ast.getArgument(0);
OperatorNode<ExpressionOperator> rhs = ast.getArgument(1);
if (lhs.getOperator() == ExpressionOperator.LITERAL || lhs.getOperator() == ExpressionOperator.NEGATE) {
- assertHasOperator(rhs, ExpressionOperator.READ_FIELD);
return getIndex(rhs);
}
if (rhs.getOperator() == ExpressionOperator.LITERAL || rhs.getOperator() == ExpressionOperator.NEGATE) {
- assertHasOperator(lhs, ExpressionOperator.READ_FIELD);
return getIndex(lhs);
}
- throw new IllegalArgumentException("Expected LITERAL and READ_FIELD, got " + lhs.getOperator() +
+ throw new IllegalArgumentException("Expected LITERAL and READ_FIELD/PROPREF, got " + lhs.getOperator() +
" and " + rhs.getOperator() + ".");
}
@@ -1009,28 +1015,24 @@ public class YqlParser implements Parser {
}
@NonNull
- private static String fetchConditionWord(
- OperatorNode<ExpressionOperator> ast) {
+ private static String fetchConditionWord(OperatorNode<ExpressionOperator> ast) {
OperatorNode<ExpressionOperator> lhs = ast.getArgument(0);
OperatorNode<ExpressionOperator> rhs = ast.getArgument(1);
- if (lhs.getOperator() == ExpressionOperator.LITERAL
- || lhs.getOperator() == ExpressionOperator.NEGATE) {
- assertHasOperator(rhs, ExpressionOperator.READ_FIELD);
+ if (lhs.getOperator() == ExpressionOperator.LITERAL || lhs.getOperator() == ExpressionOperator.NEGATE) {
+ assertFieldName(rhs);
return getNumberAsString(lhs);
}
- if (rhs.getOperator() == ExpressionOperator.LITERAL
- || rhs.getOperator() == ExpressionOperator.NEGATE) {
- assertHasOperator(lhs, ExpressionOperator.READ_FIELD);
+ if (rhs.getOperator() == ExpressionOperator.LITERAL || rhs.getOperator() == ExpressionOperator.NEGATE) {
+ assertFieldName(lhs);
return getNumberAsString(rhs);
}
- throw new IllegalArgumentException(
- "Expected LITERAL/NEGATE and READ_FIELD, got "
+ throw new IllegalArgumentException("Expected LITERAL/NEGATE and READ_FIELD/PROPREF, got "
+ lhs.getOperator() + " and " + rhs.getOperator() + ".");
}
- private static boolean isIndexOnLeftHandSide(
- OperatorNode<ExpressionOperator> ast) {
- return ast.getArgument(0, OperatorNode.class).getOperator() == ExpressionOperator.READ_FIELD;
+ private static boolean isIndexOnLeftHandSide(OperatorNode<ExpressionOperator> ast) {
+ OperatorNode node = ast.getArgument(0, OperatorNode.class);
+ return node.getOperator() == ExpressionOperator.READ_FIELD || node.getOperator() == ExpressionOperator.PROPREF;
}
@NonNull
@@ -1558,6 +1560,12 @@ public class YqlParser implements Parser {
expectedFunctionName, names.get(0));
}
+ private static void assertFieldName(OperatorNode<?> ast) {
+ Preconditions.checkArgument(ast.getOperator() == ExpressionOperator.READ_FIELD ||
+ ast.getOperator() == ExpressionOperator.PROPREF,
+ "Expected operator READ_FIELD or PRPPREF, got %s.", ast.getOperator());
+ }
+
private static void addItems(OperatorNode<ExpressionOperator> ast, WeightedSetItem out) {
switch (ast.getOperator()) {
case MAP:
diff --git a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
index ac1969701ca..20c864a7ee5 100644
--- a/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/yql/YqlParserTestCase.java
@@ -118,6 +118,12 @@ public class YqlParserTestCase {
}
@Test
+ public void testDottedFieldNames() {
+ assertParse("select foo from bar where my.title contains \"madonna\";",
+ "my.title:madonna");
+ }
+
+ @Test
public void testOr() {
assertParse("select foo from bar where title contains \"madonna\" or title contains \"saint\";",
"OR title:madonna title:saint");
@@ -266,6 +272,8 @@ public class YqlParserTestCase {
"baz:{f1:a f2:b}");
assertParse("select foo from bar where baz contains sameElement(f1 contains \"a\", f2 = 10);",
"baz:{f1:a f2:10}");
+ assertParse("select foo from bar where baz contains sameElement(key contains \"a\", value.f2 = 10);",
+ "baz:{key:a value.f2:10}");
}
@Test