Skip to content

Commit

Permalink
fix: Parsing of YQL queries is not caseinsensitive
Browse files Browse the repository at this point in the history
  • Loading branch information
theodorklauritzen committed Nov 22, 2024
1 parent 1b96c65 commit a5b1b3f
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ TOKEN :
| < EQ: '=' >
| < LIKE: 'like' >
| < CONTAINS: 'contains' >
| < NOTLIKE: 'not like' >
| < NOTLIKE: 'not ' <LIKE> >
| < MATCHES: 'matches' >
| < NOTMATCHES: 'not matches' >
| < NOTMATCHES: 'not ' <MATCHES> >

| < PLUS: '+' >
| < MINUS: '-' >
Expand All @@ -89,8 +89,8 @@ TOKEN :

// effectively unary operators
| < NULL: 'null' >
| < IS_NULL: 'is' <NULL> >
| < IS_NOT_NULL: 'is not' <NULL> >
| < IS_NULL: 'is ' <NULL> >
| < IS_NOT_NULL: 'is not ' <NULL> >

// dereference
| < DOT: '.' >
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,8 @@ public void updateFileContent(String content, Integer version) {
updateFileContent(content);
}

private static YQLPartParseResult parseYQLPart(CharSequence content, ClientLogger logger, Position offset, int charOffset) {
// CharSequence charSequence = content.toLowerCase();
YQLPlusParser parser = new YQLPlusParser(content);
private static YQLPartParseResult parseYQLPart(String content, ClientLogger logger, Position offset, int charOffset) {
YQLPlusParser parser = new YQLPlusParser(content.toLowerCase());

try {
parser.statement();
Expand All @@ -110,7 +109,7 @@ private static YQLPartParseResult parseYQLPart(CharSequence content, ClientLogge
if (charsRead == 0) return new YQLPartParseResult(List.of(), Optional.empty(), charsRead);

ai.vespa.schemals.parser.yqlplus.Node node = parser.rootNode();
YQLNode retNode = new YQLNode(node, offset, charOffset);
YQLNode retNode = new YQLNode(node, offset, charOffset, content);
// YQLUtils.printTree(logger, node);

return new YQLPartParseResult(List.of(), Optional.of(retNode), charsRead);
Expand Down Expand Up @@ -215,6 +214,8 @@ public static ParseResult parseContent(ParseContext context) {
YQLNode ret = new YQLNode(StringUtils.getStringRange(content));
ArrayList<Diagnostic> diagnostics = new ArrayList<>();

if (content.trim().length() == 0) return new ParseResult(diagnostics, Optional.of(ret));

int charsRead = 0;
int linesRead = 0;

Expand Down Expand Up @@ -243,7 +244,7 @@ public static ParseResult parseContent(ParseContext context) {
charsRead = newOffset;
}

YQLUtils.printTree(context.logger(), ret);
// YQLUtils.printTree(context.logger(), ret);

return new ParseResult(diagnostics, Optional.of(ret));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ public class YQLNode extends ai.vespa.schemals.tree.Node {
private String customText;
private int startCharOffset;

public YQLNode(Node node, Position offset, int startCharOffset, String originalString) {
super(LanguageType.YQLPlus, CSTUtils.addPositionToRange(offset, YQLUtils.getNodeRange(node)), node.isDirty());
originalYQLNode = node;
this.startCharOffset = startCharOffset;
this.customText = originalString.substring(node.getBeginOffset(), node.getEndOffset());

for (Node child : node.children()) {
addChild(new YQLNode(child, offset, startCharOffset, originalString));
}
}

public YQLNode(Node node, Position offset, int startCharOffset) {
super(LanguageType.YQLPlus, CSTUtils.addPositionToRange(offset, YQLUtils.getNodeRange(node)), node.isDirty());
originalYQLNode = node;
Expand Down Expand Up @@ -53,6 +64,7 @@ public Range setRange(Range range) {

public String getText() {
if (language == LanguageType.YQLPlus) {
if (customText != null) return customText;
return originalYQLNode.getSource();
}

Expand All @@ -76,6 +88,7 @@ public String getText() {
var child = get(i);
ret += " " + child.getText();
}
if (ret.length() == 0) return "";

return ret.substring(1);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ Stream<DynamicTest> generateGoodTests() {
"select * from music where myUrlField.hostname contains uri(\"vespa.ai\")",
"select * from music where myUrlField.hostname contains ({startAnchor: true}uri(\"vespa.ai\"))",
"select * from music where title contains ({weight:200}\"heads\")",
"select * from sources * where ({stem: false}(foo contains \"a\" and bar contains \"b\")) or foo contains {stem: false}\"c\"",
"select * from sources * where ({stem: false}(foo contains \"a\" and bar contains \"b\")) or foo contains ({stem: false}\"c\")",
"select * from sources * where foo contains @animal and foo contains phrase(@animal, @syntaxExample, @animal)",
"select * from sources * where sddocname contains 'purchase' | all(group(customer) each(output(sum(price))))",
};
Expand Down

0 comments on commit a5b1b3f

Please sign in to comment.