forked from jirutka/rsql-parser
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
feat: Add support for operators without arguments `=null=`, `=notnull=`.
- Loading branch information
Showing
15 changed files
with
420 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* | ||
* The MIT License | ||
* | ||
* Copyright 2024 Edgar Asatryan <[email protected]>. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
* THE SOFTWARE. | ||
*/ | ||
package cz.jirutka.rsql.parser.ast; | ||
|
||
/** | ||
* The arity of an operator. | ||
* | ||
* @since 2.3.0 | ||
*/ | ||
public interface Arity { | ||
|
||
/** | ||
* The minimum number of arguments operator can receive. | ||
* | ||
* @return The minimum number of arguments operator can receive. Positive or zero. | ||
* @apiNote The minimum values is always less than or equal to {@linkplain #max()} | ||
*/ | ||
int min(); | ||
|
||
/** | ||
* The maximum number of arguments operator can receive. | ||
* | ||
* @return The maximum number of arguments operator can receive. Positive or zero. | ||
* @apiNote The maximum values is always greater than or equal to {@linkplain #min()}. For practically unlimited | ||
* arity the implementations should return {@link Integer#MAX_VALUE}. | ||
*/ | ||
int max(); | ||
|
||
/** | ||
* Creates arity with given {@code min} and {@code max}. | ||
* | ||
* @param min The minimum number of arguments. Must be zero or positive. | ||
* @param max The maximum number of arguments. Must be zero or positive and greater than or equal to {@code min}. | ||
* @return the created arity | ||
*/ | ||
static Arity of(int min, int max) { | ||
return new DynamicArity(min, max); | ||
} | ||
|
||
/** | ||
* Creates N-ary object. | ||
* | ||
* @param n The N. | ||
* @return the created arity | ||
*/ | ||
static Arity nary(int n) { | ||
return new NAry(n); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
* The MIT License | ||
* | ||
* Copyright 2013-2014 Jakub Jirutka <[email protected]>. | ||
* Copyright 2024 Edgar Asatryan <[email protected]>. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
|
@@ -23,12 +24,11 @@ | |
*/ | ||
package cz.jirutka.rsql.parser.ast; | ||
|
||
import net.jcip.annotations.Immutable; | ||
import static cz.jirutka.rsql.parser.ast.StringUtils.join; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import static cz.jirutka.rsql.parser.ast.StringUtils.join; | ||
import net.jcip.annotations.Immutable; | ||
|
||
/** | ||
* This node represents a comparison with operator, selector and arguments, | ||
|
@@ -54,9 +54,8 @@ public final class ComparisonNode extends AbstractNode { | |
public ComparisonNode(ComparisonOperator operator, String selector, List<String> arguments) { | ||
Assert.notNull(operator, "operator must not be null"); | ||
Assert.notBlank(selector, "selector must not be blank"); | ||
Assert.notEmpty(arguments, "arguments list must not be empty"); | ||
Assert.isTrue(operator.isMultiValue() || arguments.size() == 1, | ||
"operator %s expects single argument, but multiple values given", operator); | ||
Assert.notNull(arguments, "arguments must not be null"); | ||
validate(operator, arguments.size()); | ||
|
||
this.operator = operator; | ||
this.selector = selector; | ||
|
@@ -118,9 +117,28 @@ public ComparisonNode withArguments(List<String> newArguments) { | |
return new ComparisonNode(operator, selector, newArguments); | ||
} | ||
|
||
private static void validate(ComparisonOperator operator, int argc) { | ||
Arity arity = operator.getArity(); | ||
int min = arity.min(); | ||
int max = arity.max(); | ||
|
||
if (argc < min || argc > max) { | ||
final String message; | ||
if (min == max) { | ||
message = String.format("operator '%s' can have exactly %d argument(s), but got %d", | ||
operator.getSymbol(), max, argc); | ||
} else { | ||
message = String.format("operator '%s' can have from %d to %d argument(s), but got %d", | ||
operator.getSymbol(), min, max, argc); | ||
} | ||
|
||
throw new IllegalArgumentException(message); | ||
} | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
String args = operator.isMultiValue() | ||
String args = operator.getArity().max() > 1 | ||
? join(arguments, "','", "('", "')") | ||
: "'" + arguments.get(0) + "'"; | ||
return selector + operator + args; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
* The MIT License | ||
* | ||
* Copyright 2013-2014 Jakub Jirutka <[email protected]>. | ||
* Copyright 2024 Edgar Asatryan <[email protected]>. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
|
@@ -36,8 +37,7 @@ public final class ComparisonOperator { | |
|
||
private final String[] symbols; | ||
|
||
private final boolean multiValue; | ||
|
||
private final Arity arity; | ||
|
||
/** | ||
* @param symbols Textual representation of this operator (e.g. <tt>=gt=</tt>); the first item | ||
|
@@ -47,13 +47,30 @@ public final class ComparisonOperator { | |
* validated in {@link NodesFactory}. | ||
* @throws IllegalArgumentException If the {@code symbols} is either <tt>null</tt>, empty, | ||
* or contain illegal symbols. | ||
* @see #ComparisonOperator(String[], Arity) | ||
* @deprecated in favor of {@linkplain #ComparisonOperator(String[], Arity)} | ||
*/ | ||
@Deprecated | ||
public ComparisonOperator(String[] symbols, boolean multiValue) { | ||
this(symbols, multiValue ? Arity.of(1, Integer.MAX_VALUE) : Arity.nary(1)); | ||
} | ||
|
||
/** | ||
* @param symbols Textual representation of this operator (e.g. <tt>=gt=</tt>); the first item is primary | ||
* representation, any others are alternatives. Must match {@literal =[a-zA-Z]*=|[><]=?|!=}. | ||
* @param arity Arity of this operator. | ||
* @throws IllegalArgumentException If the {@code symbols} is either <tt>null</tt>, empty, or contain illegal | ||
* symbols. | ||
* @since 2.3.0 | ||
*/ | ||
public ComparisonOperator(String[] symbols, Arity arity) { | ||
Assert.notEmpty(symbols, "symbols must not be null or empty"); | ||
Assert.notNull(arity, "arity must not be null"); | ||
for (String sym : symbols) { | ||
Assert.isTrue(isValidOperatorSymbol(sym), "symbol must match: %s", SYMBOL_PATTERN); | ||
} | ||
this.multiValue = multiValue; | ||
|
||
this.arity = arity; | ||
this.symbols = symbols.clone(); | ||
} | ||
|
||
|
@@ -63,22 +80,48 @@ public ComparisonOperator(String[] symbols, boolean multiValue) { | |
* @param multiValue Whether this operator may be used with multiple arguments. This is then | ||
* validated in {@link NodesFactory}. | ||
* @see #ComparisonOperator(String[], boolean) | ||
* @deprecated in favor of {@linkplain #ComparisonOperator(String, Arity)} | ||
*/ | ||
@Deprecated | ||
public ComparisonOperator(String symbol, boolean multiValue) { | ||
this(new String[]{symbol}, multiValue); | ||
} | ||
|
||
/** | ||
* @param symbol Textual representation of this operator (e.g. <tt>=gt=</tt>); Must match | ||
* {@literal =[a-zA-Z]*=|[><]=?|!=}. | ||
* @param arity Arity of this operator. | ||
* @see #ComparisonOperator(String[], boolean) | ||
* @since 2.3.0 | ||
*/ | ||
public ComparisonOperator(String symbol, Arity arity) { | ||
this(new String[]{symbol}, arity); | ||
} | ||
|
||
/** | ||
* @param symbol Textual representation of this operator (e.g. <tt>=gt=</tt>); Must match | ||
* {@literal =[a-zA-Z]*=|[><]=?|!=}. | ||
* @param altSymbol Alternative representation for {@code symbol}. | ||
* @param multiValue Whether this operator may be used with multiple arguments. This is then | ||
* @see #ComparisonOperator(String[], boolean) | ||
* @deprecated in favor of {@linkplain #ComparisonOperator(String, String, Arity)} | ||
*/ | ||
public ComparisonOperator(String symbol, String altSymbol, boolean multiValue) { | ||
this(new String[]{symbol, altSymbol}, multiValue); | ||
} | ||
|
||
/** | ||
* @param symbol Textual representation of this operator (e.g. <tt>=gt=</tt>); Must match | ||
* {@literal =[a-zA-Z]*=|[><]=?|!=}. | ||
* @param altSymbol Alternative representation for {@code symbol}. | ||
* @param arity Arity of this operator. | ||
* @see #ComparisonOperator(String[], boolean) | ||
* @since 2.3.0 | ||
*/ | ||
public ComparisonOperator(String symbol, String altSymbol, Arity arity) { | ||
this(new String[]{symbol, altSymbol}, arity); | ||
} | ||
|
||
/** | ||
* @param symbols Textual representation of this operator (e.g. <tt>=gt=</tt>); the first item | ||
* is primary representation, any others are alternatives. Must match {@literal =[a-zA-Z]*=|[><]=?|!=}. | ||
|
@@ -112,11 +155,22 @@ public String[] getSymbols() { | |
* Whether this operator may be used with multiple arguments. | ||
* | ||
* @return Whether this operator may be used with multiple arguments. | ||
* @deprecated use {@linkplain #getArity()} | ||
*/ | ||
@Deprecated | ||
public boolean isMultiValue() { | ||
return multiValue; | ||
return arity.max() > 1; | ||
} | ||
|
||
/** | ||
* Returns the arity of this operator. | ||
* | ||
* @return the arity of this operator. | ||
* @since 2.3.0 | ||
*/ | ||
public Arity getArity() { | ||
return arity; | ||
} | ||
|
||
/** | ||
* Whether the given string can represent an operator. | ||
|
55 changes: 55 additions & 0 deletions
55
src/main/java/cz/jirutka/rsql/parser/ast/DynamicArity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* | ||
* The MIT License | ||
* | ||
* Copyright 2024 Edgar Asatryan <[email protected]>. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
* THE SOFTWARE. | ||
*/ | ||
package cz.jirutka.rsql.parser.ast; | ||
|
||
final class DynamicArity implements Arity { | ||
|
||
private final int min; | ||
private final int max; | ||
|
||
DynamicArity(int min, int max) { | ||
if (min < 0) { | ||
throw new IllegalArgumentException("min must be positive or zero"); | ||
} | ||
if (max < 0) { | ||
throw new IllegalArgumentException("max must be positive or zero"); | ||
} | ||
if (min > max) { | ||
throw new IllegalArgumentException("min must be less than or equal to max"); | ||
} | ||
|
||
this.min = min; | ||
this.max = max; | ||
} | ||
|
||
@Override | ||
public int min() { | ||
return min; | ||
} | ||
|
||
@Override | ||
public int max() { | ||
return max; | ||
} | ||
} |
Oops, something went wrong.