aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2018-06-03 13:59:26 +0200
committerGitHub <noreply@github.com>2018-06-03 13:59:26 +0200
commitb42b350a9892d2ca4fd2d2c3ef022e4e8565a8f4 (patch)
tree89c962e41535ea2de52bb370ff7c6846616f6397
parenta98edada487056d6d155e7ab419734809acd20ef (diff)
parente30aeab40c5a7e0f6265f41a812d07175227b90b (diff)
Merge pull request #6063 from vespa-engine/balder/allow-dot-nested-fieldnames-in-yql
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.java13
2 files changed, 39 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..8bbe43ee3d4 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,17 @@ public class YqlParserTestCase {
}
@Test
+ public void testDottedFieldNames() {
+ assertParse("select foo from bar where my.nested.title contains \"madonna\";",
+ "my.nested.title:madonna");
+ }
+ @Test
+ public void testDottedNestedFieldNames() {
+ 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 +277,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