Skip to content

Commit

Permalink
feat: adds negated patterns (#6)
Browse files Browse the repository at this point in the history
* feat: adds negated patterns

* fix: fixed parser
  • Loading branch information
valmoz committed Oct 17, 2022
1 parent 08c3c4a commit 534f013
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 31 deletions.
2 changes: 1 addition & 1 deletion grammar/ApiFilter.g4
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ comparisonop: EQ | GT | GTE | LT | LTE | NEQ;
value: (BOOL | STRING | integer | decimal);

pattern: FIELD patternop STRING;
patternop: LIKE | CONTAINS | STARTSWITH | ENDSWITH;
patternop: LIKE | CONTAINS | NOT LIKE | NOT CONTAINS | STARTSWITH | ENDSWITH;

integer: INT;
decimal: INT DOT INT;
Expand Down
2 changes: 2 additions & 0 deletions src/ApiFilter/Filter/Operator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ abstract class Operator
const LTE = "<=";
const NEQ = "<>";
const LIKE = "like";
const NOT_LIKE = "not like";
const NOT_CONTAINS = "not contains";
const CONTAINS = "contains";
const STARTS_WITH = "starts with";
const ENDS_WITH = "ends with";
Expand Down
8 changes: 7 additions & 1 deletion src/ApiFilter/FilterFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,13 @@ public function visitPattern(Context\PatternContext $context): Condition
public function visitPatternop(Context\PatternopContext $context)
{
$op = null;
if ($context->LIKE()) {
if ($context->NOT()) {
if ($context->LIKE()) {
$op = Operator::NOT_LIKE;
} elseif ($context->CONTAINS()) {
$op = Operator::NOT_CONTAINS;
}
} elseif ($context->LIKE()) {
$op = Operator::LIKE;
} elseif ($context->CONTAINS()) {
$op = Operator::CONTAINS;
Expand Down
2 changes: 1 addition & 1 deletion src/ApiFilter/Parser/ApiFilter.interp
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ decimal


atn:
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 28, 91, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 37, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 45, 10, 3, 12, 3, 14, 3, 48, 11, 3, 3, 4, 3, 4, 3, 4, 5, 4, 53, 10, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 67, 10, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 5, 9, 77, 10, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 2, 3, 4, 14, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 2, 5, 4, 2, 3, 3, 20, 20, 3, 2, 3, 8, 3, 2, 9, 12, 2, 88, 2, 26, 3, 2, 2, 2, 4, 36, 3, 2, 2, 2, 6, 52, 3, 2, 2, 2, 8, 54, 3, 2, 2, 2, 10, 58, 3, 2, 2, 2, 12, 62, 3, 2, 2, 2, 14, 70, 3, 2, 2, 2, 16, 76, 3, 2, 2, 2, 18, 78, 3, 2, 2, 2, 20, 82, 3, 2, 2, 2, 22, 84, 3, 2, 2, 2, 24, 86, 3, 2, 2, 2, 26, 27, 5, 4, 3, 2, 27, 28, 7, 2, 2, 3, 28, 3, 3, 2, 2, 2, 29, 30, 8, 3, 1, 2, 30, 37, 5, 6, 4, 2, 31, 37, 5, 18, 10, 2, 32, 33, 7, 23, 2, 2, 33, 34, 5, 4, 3, 2, 34, 35, 7, 24, 2, 2, 35, 37, 3, 2, 2, 2, 36, 29, 3, 2, 2, 2, 36, 31, 3, 2, 2, 2, 36, 32, 3, 2, 2, 2, 37, 46, 3, 2, 2, 2, 38, 39, 12, 4, 2, 2, 39, 40, 7, 18, 2, 2, 40, 45, 5, 4, 3, 5, 41, 42, 12, 3, 2, 2, 42, 43, 7, 19, 2, 2, 43, 45, 5, 4, 3, 4, 44, 38, 3, 2, 2, 2, 44, 41, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 5, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 53, 5, 8, 5, 2, 50, 53, 5, 10, 6, 2, 51, 53, 5, 12, 7, 2, 52, 49, 3, 2, 2, 2, 52, 50, 3, 2, 2, 2, 52, 51, 3, 2, 2, 2, 53, 7, 3, 2, 2, 2, 54, 55, 7, 27, 2, 2, 55, 56, 5, 14, 8, 2, 56, 57, 5, 16, 9, 2, 57, 9, 3, 2, 2, 2, 58, 59, 7, 27, 2, 2, 59, 60, 9, 2, 2, 2, 60, 61, 7, 21, 2, 2, 61, 11, 3, 2, 2, 2, 62, 66, 7, 27, 2, 2, 63, 67, 7, 8, 2, 2, 64, 65, 7, 20, 2, 2, 65, 67, 7, 22, 2, 2, 66, 63, 3, 2, 2, 2, 66, 64, 3, 2, 2, 2, 67, 68, 3, 2, 2, 2, 68, 69, 7, 21, 2, 2, 69, 13, 3, 2, 2, 2, 70, 71, 9, 3, 2, 2, 71, 15, 3, 2, 2, 2, 72, 77, 7, 16, 2, 2, 73, 77, 7, 17, 2, 2, 74, 77, 5, 22, 12, 2, 75, 77, 5, 24, 13, 2, 76, 72, 3, 2, 2, 2, 76, 73, 3, 2, 2, 2, 76, 74, 3, 2, 2, 2, 76, 75, 3, 2, 2, 2, 77, 17, 3, 2, 2, 2, 78, 79, 7, 27, 2, 2, 79, 80, 5, 20, 11, 2, 80, 81, 7, 17, 2, 2, 81, 19, 3, 2, 2, 2, 82, 83, 9, 4, 2, 2, 83, 21, 3, 2, 2, 2, 84, 85, 7, 25, 2, 2, 85, 23, 3, 2, 2, 2, 86, 87, 7, 25, 2, 2, 87, 88, 7, 26, 2, 2, 88, 89, 7, 25, 2, 2, 89, 25, 3, 2, 2, 2, 8, 36, 44, 46, 52, 66, 76]
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 28, 99, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 37, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 45, 10, 3, 12, 3, 14, 3, 48, 11, 3, 3, 4, 3, 4, 3, 4, 5, 4, 53, 10, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 67, 10, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 5, 9, 77, 10, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 5, 11, 91, 10, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 2, 3, 4, 14, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 2, 4, 4, 2, 3, 3, 20, 20, 3, 2, 3, 8, 2, 101, 2, 26, 3, 2, 2, 2, 4, 36, 3, 2, 2, 2, 6, 52, 3, 2, 2, 2, 8, 54, 3, 2, 2, 2, 10, 58, 3, 2, 2, 2, 12, 62, 3, 2, 2, 2, 14, 70, 3, 2, 2, 2, 16, 76, 3, 2, 2, 2, 18, 78, 3, 2, 2, 2, 20, 90, 3, 2, 2, 2, 22, 92, 3, 2, 2, 2, 24, 94, 3, 2, 2, 2, 26, 27, 5, 4, 3, 2, 27, 28, 7, 2, 2, 3, 28, 3, 3, 2, 2, 2, 29, 30, 8, 3, 1, 2, 30, 37, 5, 6, 4, 2, 31, 37, 5, 18, 10, 2, 32, 33, 7, 23, 2, 2, 33, 34, 5, 4, 3, 2, 34, 35, 7, 24, 2, 2, 35, 37, 3, 2, 2, 2, 36, 29, 3, 2, 2, 2, 36, 31, 3, 2, 2, 2, 36, 32, 3, 2, 2, 2, 37, 46, 3, 2, 2, 2, 38, 39, 12, 4, 2, 2, 39, 40, 7, 18, 2, 2, 40, 45, 5, 4, 3, 5, 41, 42, 12, 3, 2, 2, 42, 43, 7, 19, 2, 2, 43, 45, 5, 4, 3, 4, 44, 38, 3, 2, 2, 2, 44, 41, 3, 2, 2, 2, 45, 48, 3, 2, 2, 2, 46, 44, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 5, 3, 2, 2, 2, 48, 46, 3, 2, 2, 2, 49, 53, 5, 8, 5, 2, 50, 53, 5, 10, 6, 2, 51, 53, 5, 12, 7, 2, 52, 49, 3, 2, 2, 2, 52, 50, 3, 2, 2, 2, 52, 51, 3, 2, 2, 2, 53, 7, 3, 2, 2, 2, 54, 55, 7, 27, 2, 2, 55, 56, 5, 14, 8, 2, 56, 57, 5, 16, 9, 2, 57, 9, 3, 2, 2, 2, 58, 59, 7, 27, 2, 2, 59, 60, 9, 2, 2, 2, 60, 61, 7, 21, 2, 2, 61, 11, 3, 2, 2, 2, 62, 66, 7, 27, 2, 2, 63, 67, 7, 8, 2, 2, 64, 65, 7, 20, 2, 2, 65, 67, 7, 22, 2, 2, 66, 63, 3, 2, 2, 2, 66, 64, 3, 2, 2, 2, 67, 68, 3, 2, 2, 2, 68, 69, 7, 21, 2, 2, 69, 13, 3, 2, 2, 2, 70, 71, 9, 3, 2, 2, 71, 15, 3, 2, 2, 2, 72, 77, 7, 16, 2, 2, 73, 77, 7, 17, 2, 2, 74, 77, 5, 22, 12, 2, 75, 77, 5, 24, 13, 2, 76, 72, 3, 2, 2, 2, 76, 73, 3, 2, 2, 2, 76, 74, 3, 2, 2, 2, 76, 75, 3, 2, 2, 2, 77, 17, 3, 2, 2, 2, 78, 79, 7, 27, 2, 2, 79, 80, 5, 20, 11, 2, 80, 81, 7, 17, 2, 2, 81, 19, 3, 2, 2, 2, 82, 91, 7, 9, 2, 2, 83, 91, 7, 10, 2, 2, 84, 85, 7, 22, 2, 2, 85, 91, 7, 9, 2, 2, 86, 87, 7, 22, 2, 2, 87, 91, 7, 10, 2, 2, 88, 91, 7, 11, 2, 2, 89, 91, 7, 12, 2, 2, 90, 82, 3, 2, 2, 2, 90, 83, 3, 2, 2, 2, 90, 84, 3, 2, 2, 2, 90, 86, 3, 2, 2, 2, 90, 88, 3, 2, 2, 2, 90, 89, 3, 2, 2, 2, 91, 21, 3, 2, 2, 2, 92, 93, 7, 25, 2, 2, 93, 23, 3, 2, 2, 2, 94, 95, 7, 25, 2, 2, 95, 96, 7, 26, 2, 2, 96, 97, 7, 25, 2, 2, 97, 25, 3, 2, 2, 2, 9, 36, 44, 46, 52, 66, 76, 90]
97 changes: 69 additions & 28 deletions src/ApiFilter/Parser/ApiFilterParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ final class ApiFilterParser extends Parser
*/
private const SERIALIZED_ATN =
"\u{3}\u{608B}\u{A72A}\u{8133}\u{B9ED}\u{417C}\u{3BE7}\u{7786}\u{5964}" .
"\u{3}\u{1C}\u{5B}\u{4}\u{2}\u{9}\u{2}\u{4}\u{3}\u{9}\u{3}\u{4}\u{4}" .
"\u{3}\u{1C}\u{63}\u{4}\u{2}\u{9}\u{2}\u{4}\u{3}\u{9}\u{3}\u{4}\u{4}" .
"\u{9}\u{4}\u{4}\u{5}\u{9}\u{5}\u{4}\u{6}\u{9}\u{6}\u{4}\u{7}\u{9}" .
"\u{7}\u{4}\u{8}\u{9}\u{8}\u{4}\u{9}\u{9}\u{9}\u{4}\u{A}\u{9}\u{A}" .
"\u{4}\u{B}\u{9}\u{B}\u{4}\u{C}\u{9}\u{C}\u{4}\u{D}\u{9}\u{D}\u{3}" .
Expand All @@ -79,16 +79,17 @@ final class ApiFilterParser extends Parser
"\u{7}\u{3}\u{7}\u{3}\u{7}\u{5}\u{7}\u{43}\u{A}\u{7}\u{3}\u{7}\u{3}" .
"\u{7}\u{3}\u{8}\u{3}\u{8}\u{3}\u{9}\u{3}\u{9}\u{3}\u{9}\u{3}\u{9}" .
"\u{5}\u{9}\u{4D}\u{A}\u{9}\u{3}\u{A}\u{3}\u{A}\u{3}\u{A}\u{3}\u{A}" .
"\u{3}\u{B}\u{3}\u{B}\u{3}\u{C}\u{3}\u{C}\u{3}\u{D}\u{3}\u{D}\u{3}" .
"\u{D}\u{3}\u{D}\u{3}\u{D}\u{2}\u{3}\u{4}\u{E}\u{2}\u{4}\u{6}\u{8}" .
"\u{A}\u{C}\u{E}\u{10}\u{12}\u{14}\u{16}\u{18}\u{2}\u{5}\u{4}\u{2}" .
"\u{3}\u{3}\u{14}\u{14}\u{3}\u{2}\u{3}\u{8}\u{3}\u{2}\u{9}\u{C}\u{2}" .
"\u{58}\u{2}\u{1A}\u{3}\u{2}\u{2}\u{2}\u{4}\u{24}\u{3}\u{2}\u{2}\u{2}" .
"\u{3}\u{B}\u{3}\u{B}\u{3}\u{B}\u{3}\u{B}\u{3}\u{B}\u{3}\u{B}\u{3}" .
"\u{B}\u{3}\u{B}\u{5}\u{B}\u{5B}\u{A}\u{B}\u{3}\u{C}\u{3}\u{C}\u{3}" .
"\u{D}\u{3}\u{D}\u{3}\u{D}\u{3}\u{D}\u{3}\u{D}\u{2}\u{3}\u{4}\u{E}" .
"\u{2}\u{4}\u{6}\u{8}\u{A}\u{C}\u{E}\u{10}\u{12}\u{14}\u{16}\u{18}" .
"\u{2}\u{4}\u{4}\u{2}\u{3}\u{3}\u{14}\u{14}\u{3}\u{2}\u{3}\u{8}\u{2}" .
"\u{65}\u{2}\u{1A}\u{3}\u{2}\u{2}\u{2}\u{4}\u{24}\u{3}\u{2}\u{2}\u{2}" .
"\u{6}\u{34}\u{3}\u{2}\u{2}\u{2}\u{8}\u{36}\u{3}\u{2}\u{2}\u{2}\u{A}" .
"\u{3A}\u{3}\u{2}\u{2}\u{2}\u{C}\u{3E}\u{3}\u{2}\u{2}\u{2}\u{E}\u{46}" .
"\u{3}\u{2}\u{2}\u{2}\u{10}\u{4C}\u{3}\u{2}\u{2}\u{2}\u{12}\u{4E}\u{3}" .
"\u{2}\u{2}\u{2}\u{14}\u{52}\u{3}\u{2}\u{2}\u{2}\u{16}\u{54}\u{3}\u{2}" .
"\u{2}\u{2}\u{18}\u{56}\u{3}\u{2}\u{2}\u{2}\u{1A}\u{1B}\u{5}\u{4}\u{3}" .
"\u{2}\u{2}\u{2}\u{14}\u{5A}\u{3}\u{2}\u{2}\u{2}\u{16}\u{5C}\u{3}\u{2}" .
"\u{2}\u{2}\u{18}\u{5E}\u{3}\u{2}\u{2}\u{2}\u{1A}\u{1B}\u{5}\u{4}\u{3}" .
"\u{2}\u{1B}\u{1C}\u{7}\u{2}\u{2}\u{3}\u{1C}\u{3}\u{3}\u{2}\u{2}\u{2}" .
"\u{1D}\u{1E}\u{8}\u{3}\u{1}\u{2}\u{1E}\u{25}\u{5}\u{6}\u{4}\u{2}\u{1F}" .
"\u{25}\u{5}\u{12}\u{A}\u{2}\u{20}\u{21}\u{7}\u{17}\u{2}\u{2}\u{21}" .
Expand Down Expand Up @@ -120,11 +121,17 @@ final class ApiFilterParser extends Parser
"\u{4C}\u{4B}\u{3}\u{2}\u{2}\u{2}\u{4D}\u{11}\u{3}\u{2}\u{2}\u{2}\u{4E}" .
"\u{4F}\u{7}\u{1B}\u{2}\u{2}\u{4F}\u{50}\u{5}\u{14}\u{B}\u{2}\u{50}" .
"\u{51}\u{7}\u{11}\u{2}\u{2}\u{51}\u{13}\u{3}\u{2}\u{2}\u{2}\u{52}" .
"\u{53}\u{9}\u{4}\u{2}\u{2}\u{53}\u{15}\u{3}\u{2}\u{2}\u{2}\u{54}\u{55}" .
"\u{7}\u{19}\u{2}\u{2}\u{55}\u{17}\u{3}\u{2}\u{2}\u{2}\u{56}\u{57}" .
"\u{7}\u{19}\u{2}\u{2}\u{57}\u{58}\u{7}\u{1A}\u{2}\u{2}\u{58}\u{59}" .
"\u{7}\u{19}\u{2}\u{2}\u{59}\u{19}\u{3}\u{2}\u{2}\u{2}\u{8}\u{24}\u{2C}" .
"\u{2E}\u{34}\u{42}\u{4C}";
"\u{5B}\u{7}\u{9}\u{2}\u{2}\u{53}\u{5B}\u{7}\u{A}\u{2}\u{2}\u{54}\u{55}" .
"\u{7}\u{16}\u{2}\u{2}\u{55}\u{5B}\u{7}\u{9}\u{2}\u{2}\u{56}\u{57}" .
"\u{7}\u{16}\u{2}\u{2}\u{57}\u{5B}\u{7}\u{A}\u{2}\u{2}\u{58}\u{5B}" .
"\u{7}\u{B}\u{2}\u{2}\u{59}\u{5B}\u{7}\u{C}\u{2}\u{2}\u{5A}\u{52}\u{3}" .
"\u{2}\u{2}\u{2}\u{5A}\u{53}\u{3}\u{2}\u{2}\u{2}\u{5A}\u{54}\u{3}\u{2}" .
"\u{2}\u{2}\u{5A}\u{56}\u{3}\u{2}\u{2}\u{2}\u{5A}\u{58}\u{3}\u{2}\u{2}" .
"\u{2}\u{5A}\u{59}\u{3}\u{2}\u{2}\u{2}\u{5B}\u{15}\u{3}\u{2}\u{2}\u{2}" .
"\u{5C}\u{5D}\u{7}\u{19}\u{2}\u{2}\u{5D}\u{17}\u{3}\u{2}\u{2}\u{2}" .
"\u{5E}\u{5F}\u{7}\u{19}\u{2}\u{2}\u{5F}\u{60}\u{7}\u{1A}\u{2}\u{2}" .
"\u{60}\u{61}\u{7}\u{19}\u{2}\u{2}\u{61}\u{19}\u{3}\u{2}\u{2}\u{2}" .
"\u{9}\u{24}\u{2C}\u{2E}\u{34}\u{42}\u{4C}\u{5A}";

protected static $atn;
protected static $decisionToDFA;
Expand Down Expand Up @@ -609,20 +616,49 @@ public function patternop() : Context\PatternopContext
$this->enterRule($localContext, 18, self::RULE_patternop);

try {
$this->enterOuterAlt($localContext, 1);
$this->setState(80);
$this->setState(88);
$this->errorHandler->sync($this);

$_la = $this->input->LA(1);
switch ($this->getInterpreter()->adaptivePredict($this->input, 6, $this->ctx)) {
case 1:
$this->enterOuterAlt($localContext, 1);
$this->setState(80);
$this->match(self::LIKE);
break;

if (!(((($_la) & ~0x3f) === 0 && ((1 << $_la) & ((1 << self::LIKE) | (1 << self::CONTAINS) | (1 << self::STARTSWITH) | (1 << self::ENDSWITH))) !== 0))) {
$this->errorHandler->recoverInline($this);
} else {
if ($this->input->LA(1) === Token::EOF) {
$this->matchedEOF = true;
}
case 2:
$this->enterOuterAlt($localContext, 2);
$this->setState(81);
$this->match(self::CONTAINS);
break;

$this->errorHandler->reportMatch($this);
$this->consume();
case 3:
$this->enterOuterAlt($localContext, 3);
$this->setState(82);
$this->match(self::NOT);
$this->setState(83);
$this->match(self::LIKE);
break;

case 4:
$this->enterOuterAlt($localContext, 4);
$this->setState(84);
$this->match(self::NOT);
$this->setState(85);
$this->match(self::CONTAINS);
break;

case 5:
$this->enterOuterAlt($localContext, 5);
$this->setState(86);
$this->match(self::STARTSWITH);
break;

case 6:
$this->enterOuterAlt($localContext, 6);
$this->setState(87);
$this->match(self::ENDSWITH);
break;
}
} catch (RecognitionException $exception) {
$localContext->exception = $exception;
Expand All @@ -646,7 +682,7 @@ public function integer() : Context\IntegerContext

try {
$this->enterOuterAlt($localContext, 1);
$this->setState(82);
$this->setState(90);
$this->match(self::INT);
} catch (RecognitionException $exception) {
$localContext->exception = $exception;
Expand All @@ -670,11 +706,11 @@ public function decimal() : Context\DecimalContext

try {
$this->enterOuterAlt($localContext, 1);
$this->setState(84);
$this->setState(92);
$this->match(self::INT);
$this->setState(85);
$this->setState(93);
$this->match(self::DOT);
$this->setState(86);
$this->setState(94);
$this->match(self::INT);
} catch (RecognitionException $exception) {
$localContext->exception = $exception;
Expand Down Expand Up @@ -1297,6 +1333,11 @@ public function CONTAINS() : ?TerminalNode
return $this->getToken(ApiFilterParser::CONTAINS, 0);
}

public function NOT() : ?TerminalNode
{
return $this->getToken(ApiFilterParser::NOT, 0);
}

public function STARTSWITH() : ?TerminalNode
{
return $this->getToken(ApiFilterParser::STARTSWITH, 0);
Expand Down
9 changes: 9 additions & 0 deletions tests/ApiFilter/Filter/ConditionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ public function testOperator()
$condition->setOp(Operator::CONTAINS);
$this->assertEquals(Operator::CONTAINS, $condition->getOp());

$condition->setOp(Operator::NOT_LIKE);
$this->assertEquals(Operator::NOT_LIKE, $condition->getOp());

$condition->setOp(Operator::NOT_CONTAINS);
$this->assertEquals(Operator::NOT_CONTAINS, $condition->getOp());

$condition->setOp(Operator::STARTS_WITH);
$this->assertEquals(Operator::STARTS_WITH, $condition->getOp());

Expand All @@ -116,5 +122,8 @@ public function testToString()

$condition = new Condition("city", Operator::LIKE, "%aco");
$this->assertEquals("city like %aco", (string)$condition);

$condition = new Condition("city", Operator::NOT_LIKE, "%aco");
$this->assertEquals("city not like %aco", (string)$condition);
}
}
46 changes: 46 additions & 0 deletions tests/ApiFilter/FilterFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,34 @@ public function testContainsOp()
$this->assertEquals($expected2, $filter2);
}

/**
* Test 'not like' operator
*/
public function testNotLikeOp()
{
$filter1 = $this->factory->initFilter("name not like '%ergam%'");
$expected1 = new Filter(new Condition("name", Operator::NOT_LIKE, "%ergam%"));
$this->assertEquals($expected1, $filter1);

$filter2 = $this->factory->initFilter("name NOT LIKE '%ergam%'");
$expected2 = new Filter(new Condition("name", Operator::NOT_LIKE, "%ergam%"));
$this->assertEquals($expected2, $filter2);
}

/**
* Test 'not contains' operator
*/
public function testNotContainsOp()
{
$filter1 = $this->factory->initFilter("name not contains 'ergam'");
$expected1 = new Filter(new Condition("name", Operator::NOT_CONTAINS, "ergam"));
$this->assertEquals($expected1, $filter1);

$filter2 = $this->factory->initFilter("name NOT CONTAINS 'ergam'");
$expected2 = new Filter(new Condition("name", Operator::NOT_CONTAINS, "ergam"));
$this->assertEquals($expected2, $filter2);
}

/**
* Test 'starts with' operator
*/
Expand Down Expand Up @@ -203,6 +231,24 @@ public function testEndsWithOp()
$this->assertEquals($expected6, $filter6);
}

/**
* Test no not starts with operator
*/
public function testNoNotStartsWithOperator()
{
$this->expectException(ParseCancellationException::class);
$this->factory->initFilter("name not starts with 'Mariano'");
}

/**
* Test no not ends with operator
*/
public function testNoNotEndsWithOperator()
{
$this->expectException(ParseCancellationException::class);
$this->factory->initFilter("name not ends with 'Mariano'");
}

/**
* Test no starts operator
*/
Expand Down

0 comments on commit 534f013

Please sign in to comment.