Skip to content

Commit

Permalink
Add AllowLeadingWildcards validation option. Fix ! being used as a fi…
Browse files Browse the repository at this point in the history
…eld prefix. Fixes #73, Fixes #72
  • Loading branch information
ejsmith committed Jan 21, 2022
1 parent 3371108 commit 5ef9244
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static bool IsExcluded(this IFieldQueryNode node) {
if (node == null)
return false;

return (node.IsNegated.HasValue && node.IsNegated.Value == true) || (!String.IsNullOrEmpty(node.Prefix) && node.Prefix == "-");
return (node.IsNegated.HasValue && node.IsNegated.Value == true) || (!String.IsNullOrEmpty(node.Prefix) && (node.Prefix == "-" || node.Prefix == "!"));
}

public static bool IsRequired(this IFieldQueryNode node) {
Expand Down Expand Up @@ -113,7 +113,7 @@ public static IQueryNode InvertGroupNegation(this GroupNode node, IQueryVisitorC
public static void InvertNegation(this IFieldQueryNode node) {
if (node.IsNegated.HasValue)
node.IsNegated = !node.IsNegated.Value;
else if (!String.IsNullOrEmpty(node.Prefix) && node.Prefix == "-")
else if (!String.IsNullOrEmpty(node.Prefix) && (node.Prefix == "-" || node.Prefix == "!"))
node.Prefix = null;
else
node.IsNegated = true;
Expand Down
1 change: 1 addition & 0 deletions src/Foundatio.Parsers.LuceneQueries/LuceneQueryParser.peg
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ prefix_operator_exp
prefix_operator -lexical
= '+'
/ '-'
/ '!'

_
= [ \t\r\n\f]+
Expand Down
12 changes: 12 additions & 0 deletions src/Foundatio.Parsers.LuceneQueries/Visitors/ValidationVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public override void Visit(TermNode node, IQueryVisitorContext context) {
AddField(validationInfo, node, context);
AddOperation(validationInfo, node.GetOperationType(), node.Field);

var validationOptions = context.GetValidationOptions();
if (validationOptions != null && !validationOptions.AllowLeadingWildcards && node.Term != null && (node.Term.StartsWith("*") || node.Term.StartsWith("?")))
validationInfo.MarkInvalid("Terms must not start with a wildcard: " + node.Term);

// aggregations must have a field
if (context.QueryType == QueryType.Aggregation && String.IsNullOrEmpty(node.Field))
validationInfo.MarkInvalid("Aggregations must have a field");
Expand All @@ -39,7 +43,14 @@ public override void Visit(TermRangeNode node, IQueryVisitorContext context) {
var validationInfo = context.GetValidationInfo();
AddField(validationInfo, node, context);
AddOperation(validationInfo, node.GetOperationType(), node.Field);

var validationOptions = context.GetValidationOptions();
if (validationOptions != null && !validationOptions.AllowLeadingWildcards && node.Min != null && (node.Min.StartsWith("*") || node.Min.StartsWith("?")))
validationInfo.MarkInvalid("Terms must not start with a wildcard: " + node.Min);

if (validationOptions != null && !validationOptions.AllowLeadingWildcards && node.Max != null && (node.Max.StartsWith("*") || node.Max.StartsWith("?")))
validationInfo.MarkInvalid("Terms must not start with a wildcard: " + node.Max);

// aggregations must have a field
if (context.QueryType == QueryType.Aggregation && String.IsNullOrEmpty(node.Field))
validationInfo.MarkInvalid("Aggregations must have a field");
Expand Down Expand Up @@ -182,6 +193,7 @@ public class QueryValidationOptions {
public bool ShouldThrow { get; set; }
public ICollection<string> AllowedFields { get; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
public bool ShouldResolveFields { get; set; }
public bool AllowLeadingWildcards { get; set; }
public bool AllowUnresolvedFields {
get => _allowUnresolvedFields;
set {
Expand Down
32 changes: 32 additions & 0 deletions tests/Foundatio.Parsers.LuceneQueries.Tests/QueryParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Threading.Tasks;
using Foundatio.Parsers.LuceneQueries.Extensions;
using Foundatio.Parsers.LuceneQueries.Nodes;
using Foundatio.Parsers.LuceneQueries.Visitors;
using Foundatio.Xunit;
Expand Down Expand Up @@ -167,6 +168,37 @@ public void CanParseNotBeforeParens() {
Assert.True((result.Left as GroupNode).IsNegated);
}

[Fact]
public void CanParsePrefix() {
var sut = new LuceneQueryParser();

var result = sut.Parse(@"""jakarta apache"" !""Apache Lucene""");
var ast = DebugQueryVisitor.Run(result);

var left = result.Left as TermNode;
var right = result.Right as TermNode;
Assert.NotNull(left);
Assert.NotNull(right);
Assert.Equal("jakarta apache", left.Term);
Assert.Null(left.Prefix);
Assert.False(left.IsExcluded());
Assert.Equal("Apache Lucene", right.Term);
Assert.Equal("!", right.Prefix);
Assert.True(right.IsExcluded());

result = sut.Parse(@"""jakarta apache"" -""Apache Lucene""");
ast = DebugQueryVisitor.Run(result);

left = result.Left as TermNode;
right = result.Right as TermNode;
Assert.NotNull(left);
Assert.NotNull(right);
Assert.Equal("jakarta apache", left.Term);
Assert.Equal("Apache Lucene", right.Term);
Assert.Equal("-", right.Prefix);
Assert.True(right.IsExcluded());
}

[Fact]
public void CanParseRanges() {
var sut = new LuceneQueryParser();
Expand Down
13 changes: 13 additions & 0 deletions tests/Foundatio.Parsers.LuceneQueries.Tests/QueryValidatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ public async Task AllowedFields() {
Assert.True(info.IsValid);
}

[Fact]
public async Task AllowLeadingWildcards() {
var options = new QueryValidationOptions();
options.AllowLeadingWildcards = false;
var info = await QueryValidator.ValidateQueryAsync(@"blah allowedfield:*alue", options);
Assert.False(info.IsValid);
Assert.Contains("wildcard", info.Message);

options.AllowLeadingWildcards = true;
info = await QueryValidator.ValidateQueryAsync(@"blah allowedfield:*alue", options);
Assert.True(info.IsValid);
}

[Fact]
public async Task AllowedOperations() {
var options = new QueryValidationOptions();
Expand Down

0 comments on commit 5ef9244

Please sign in to comment.