Skip to content

Commit

Permalink
feat: added string patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
valmoz committed Dec 9, 2021
1 parent 04025eb commit 30794dd
Show file tree
Hide file tree
Showing 21 changed files with 1,141 additions and 444 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,19 @@ The **op** is one of the following (unquoted):
- _Less than_: '<'
- _Less than or equal to_: '<='
- _Not equal_: '<>', '!='
- _Like_: 'like', 'LIKE'

The **value** can be one of:
- _String_: 'value'
- _Booleam_: true, false
- _Int_: 46
- _Double_: 12.34

It is also possible to **match a String against a Pattern** using one of those operators:
- _Like_: 'like', 'LIKE'
- _Contains_: 'contains', 'CONTAINS'
- _Starts With_: 'starts with', 'STARTS WITH'
- _Ends With_: 'ends with', 'ENDS WITH'

Additionally, it is possible to check if field has a value or not, using NULL:
- _Null field_: 'IS NULL', 'is null', '= null', '= NULL'
- _Not Null field_: 'IS NOT NULL', 'is not null', '<> null', '!= null', '<> NULL', '!= NULL'
Expand All @@ -60,7 +65,7 @@ Parenthesis can be used to compose complex expressions.

For example:
```
city = 'Bergamo' and (age < 30 or (dev = true and (name = 'Giorgio' and name is not null)))
city = 'Bergamo' and (age < 30 or (dev = true and (name = 'Giorgio' and surname is not null) or employer starts with 'Fatture'))
```

## Testing
Expand Down
2 changes: 2 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
wget https://www.antlr.org/download/antlr-4.9.2-complete.jar
export CLASSPATH=".:./antlr-4.9.2-complete.jar:$CLASSPATH"

rm -rf /parser/*

java -jar ./antlr-4.9.2-complete.jar -Dlanguage=PHP /grammar/ApiFilter.g4 -o /parser -package FattureInCloud\\ApiFilter\\Parser -visitor -no-listener
27 changes: 20 additions & 7 deletions grammar/ApiFilter.g4
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,26 @@ filter: expression EOF;

expression:
condition # conditionExp
| pattern # patternExp
| OPEN_PAR expression CLOSE_PAR # parenthesisExp
| expression AND expression # conjunctionExp
| expression OR expression # disjunctionExp;

condition:
comparison # comparisonCondition
| emptyfield # emptyCondition
comparison # comparisonCondition
| emptyfield # emptyCondition
| filledfield # filledCondition;

comparison: FIELD op value;
comparison: FIELD comparisonop value;
emptyfield: FIELD (EQ | IS) NULL;
filledfield: FIELD (NEQ | IS NOT) NULL;

op: EQ | GT | GTE | LT | LTE | NEQ | LIKE;
comparisonop: EQ | GT | GTE | LT | LTE | NEQ;
value: (BOOL | STRING | integer | decimal);

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

integer: INT;
decimal: INT DOT INT;

Expand All @@ -37,26 +41,35 @@ GTE: '>=';
LT: '<';
LTE: '<=';
NEQ: ('<>' | '!=');

LIKE: ('like' | 'LIKE');
CONTAINS: ('contains' | 'CONTAINS');
STARTSWITH: STARTS ' '* WITH;
ENDSWITH: ENDS ' '* WITH;

STARTS: ('starts' | 'STARTS');
ENDS: ('ends' | 'ENDS');
WITH: ('with' | 'WITH');

BOOL: ('true' | 'false');
STRING: '\'' ( ~'\'' | '\'\'')+ '\'';

AND: ('and' | 'AND');
OR: ('or' | 'OR');
NOT: ('not' | 'NOT');

IS: ('is' | 'IS');
NULL: ('null' | 'NULL');
NOT: ('not' | 'NOT');

OPEN_PAR: '(';
CLOSE_PAR: ')';

INT: (DIGIT)+;

DOT: '.';

INT: (DIGIT)+;
FIELD: LOWERCASE (( LOWERCASE | '_' | DOT)* LOWERCASE)?;

FIELD: LOWERCASE (( LOWERCASE | '_' | '.')* LOWERCASE)?;

fragment LOWERCASE: [a-z];
fragment UPPERCASE: [A-Z];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@

namespace FattureInCloud\ApiFilter\Filter;

abstract class Operator
abstract class ComparisonOperator
{
const EQ = "=";
const GT = ">";
const GTE = ">=";
const LT = "<";
const LTE = "<=";
const NEQ = "<>";
const LIKE = "like";
}
75 changes: 75 additions & 0 deletions src/ApiFilter/Filter/Pattern.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

namespace FattureInCloud\ApiFilter\Filter;

class Pattern implements Condition
{
private $field;
private $op;
private $value;

/**
* @param $field
* @param $op
* @param $value
*/
public function __construct($field, $op, $value)
{
$this->field = $field;
$this->op = $op;
$this->value = $value;
}

/**
* @return string
*/
public function getField(): string
{
return $this->field;
}

/**
* @param string $field
*/
public function setField(string $field): void
{
$this->field = $field;
}

/**
* @return string
*/
public function getOp(): string
{
return $this->op;
}

/**
* @param string $op
*/
public function setOp(string $op): void
{
$this->op = $op;
}

/**
* @return mixed
*/
public function getValue()
{
return $this->value;
}

/**
* @param mixed $value
*/
public function setValue($value): void
{
$this->value = $value;
}

public function __toString(): string
{
return $this->field . " " . $this->op . " " . $this->value;
}
}
11 changes: 11 additions & 0 deletions src/ApiFilter/Filter/PatternOperator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace FattureInCloud\ApiFilter\Filter;

abstract class PatternOperator
{
const LIKE = "like";
const CONTAINS = "contains";
const STARTS_WITH = "starts with";
const ENDS_WITH = "ends with";
}
52 changes: 40 additions & 12 deletions src/ApiFilter/FilterFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Antlr\Antlr4\Runtime\Error\BailErrorStrategy;
use Antlr\Antlr4\Runtime\InputStream;
use Antlr\Antlr4\Runtime\Tree\AbstractParseTreeVisitor;
use FattureInCloud\ApiFilter\Filter\PatternOperator;
use FattureInCloud\ApiFilter\Filter\Comparison;
use FattureInCloud\ApiFilter\Filter\Condition;
use FattureInCloud\ApiFilter\Filter\Conjunction;
Expand All @@ -14,7 +15,8 @@
use FattureInCloud\ApiFilter\Filter\Expression;
use FattureInCloud\ApiFilter\Filter\FilledField;
use FattureInCloud\ApiFilter\Filter\Filter;
use FattureInCloud\ApiFilter\Filter\Operator;
use FattureInCloud\ApiFilter\Filter\ComparisonOperator;
use FattureInCloud\ApiFilter\Filter\Pattern;
use FattureInCloud\ApiFilter\Parser\ApiFilterLexer;
use FattureInCloud\ApiFilter\Parser\ApiFilterParser;
use FattureInCloud\ApiFilter\Parser\ApiFilterVisitor;
Expand All @@ -27,7 +29,7 @@
use FattureInCloud\ApiFilter\Parser\Context\ConjunctionExpContext;
use FattureInCloud\ApiFilter\Parser\Context\DisjunctionExpContext;
use FattureInCloud\ApiFilter\Parser\Context\ValueContext;
use FattureInCloud\ApiFilter\Parser\Context\OpContext;
use FattureInCloud\ApiFilter\Parser\Context\ComparisonopContext;

final class FilterFactory extends AbstractParseTreeVisitor implements ApiFilterVisitor
{
Expand All @@ -54,6 +56,11 @@ public function visitConditionExp(ConditionExpContext $context): Condition
return $this->visit($context->condition());
}

public function visitPatternExp(Context\PatternExpContext $context)
{
return $this->visit($context->pattern());
}

public function visitParenthesisExp(ParenthesisExpContext $context): Expression
{
return $this->visit($context->expression());
Expand Down Expand Up @@ -81,7 +88,7 @@ public function visitComparisonCondition(Context\ComparisonConditionContext $con
public function visitComparison(Context\ComparisonContext $context): Comparison
{
$field = $context->FIELD()->getText();
$op = $this->visit($context->op());
$op = $this->visit($context->comparisonop());
$value = $this->visit($context->value());
return new Comparison($field, $op, $value);
}
Expand Down Expand Up @@ -111,23 +118,21 @@ public function visitDecimal(DecimalContext $context)
return floatval($context->getText());
}

public function visitOp(OpContext $context)
public function visitComparisonop(ComparisonopContext $context)
{
$operator = null;
if ($context->EQ()) {
$operator = Operator::EQ;
$operator = ComparisonOperator::EQ;
} elseif ($context->GT()) {
$operator = Operator::GT;
$operator = ComparisonOperator::GT;
} elseif ($context->GTE()) {
$operator = Operator::GTE;
$operator = ComparisonOperator::GTE;
} elseif ($context->LT()) {
$operator = Operator::LT;
$operator = ComparisonOperator::LT;
} elseif ($context->LTE()) {
$operator = Operator::LTE;
$operator = ComparisonOperator::LTE;
} elseif ($context->NEQ()) {
$operator = Operator::NEQ;
} elseif ($context->LIKE()) {
$operator = Operator::LIKE;
$operator = ComparisonOperator::NEQ;
}
return $operator;
}
Expand All @@ -153,4 +158,27 @@ public function visitFilledfield(Context\FilledfieldContext $context): FilledFie
$field = $context->FIELD()->getText();
return new FilledField($field);
}

public function visitPattern(Context\PatternContext $context)
{
$field = $context->FIELD()->getText();
$op = $this->visit($context->patternop());
$value = substr($context->STRING()->getText(), 1, -1);
return new Pattern($field, $op, $value);
}

public function visitPatternop(Context\PatternopContext $context)
{
$op = null;
if ($context->LIKE()) {
$op = PatternOperator::LIKE;
} elseif ($context->CONTAINS()) {
$op = PatternOperator::CONTAINS;
} elseif ($context->STARTSWITH()) {
$op = PatternOperator::STARTS_WITH;
} elseif ($context->ENDSWITH()) {
$op = PatternOperator::ENDS_WITH;
}
return $op;
}
}
24 changes: 19 additions & 5 deletions src/ApiFilter/Parser/ApiFilter.interp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ null
null
null
null
null
null
null
null
null
null
'('
')'
'.'
null
'.'
null
null

Expand All @@ -30,17 +36,23 @@ LT
LTE
NEQ
LIKE
CONTAINS
STARTSWITH
ENDSWITH
STARTS
ENDS
WITH
BOOL
STRING
AND
OR
NOT
IS
NULL
NOT
OPEN_PAR
CLOSE_PAR
DOT
INT
DOT
FIELD
WS

Expand All @@ -51,11 +63,13 @@ condition
comparison
emptyfield
filledfield
op
comparisonop
value
pattern
patternop
integer
decimal


atn:
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 22, 80, 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, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 32, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 40, 10, 3, 12, 3, 14, 3, 43, 11, 3, 3, 4, 3, 4, 3, 4, 5, 4, 48, 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, 62, 10, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 5, 9, 72, 10, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 2, 3, 4, 12, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 2, 4, 4, 2, 3, 3, 15, 15, 3, 2, 3, 9, 2, 78, 2, 22, 3, 2, 2, 2, 4, 31, 3, 2, 2, 2, 6, 47, 3, 2, 2, 2, 8, 49, 3, 2, 2, 2, 10, 53, 3, 2, 2, 2, 12, 57, 3, 2, 2, 2, 14, 65, 3, 2, 2, 2, 16, 71, 3, 2, 2, 2, 18, 73, 3, 2, 2, 2, 20, 75, 3, 2, 2, 2, 22, 23, 5, 4, 3, 2, 23, 24, 7, 2, 2, 3, 24, 3, 3, 2, 2, 2, 25, 26, 8, 3, 1, 2, 26, 32, 5, 6, 4, 2, 27, 28, 7, 17, 2, 2, 28, 29, 5, 4, 3, 2, 29, 30, 7, 18, 2, 2, 30, 32, 3, 2, 2, 2, 31, 25, 3, 2, 2, 2, 31, 27, 3, 2, 2, 2, 32, 41, 3, 2, 2, 2, 33, 34, 12, 4, 2, 2, 34, 35, 7, 12, 2, 2, 35, 40, 5, 4, 3, 5, 36, 37, 12, 3, 2, 2, 37, 38, 7, 13, 2, 2, 38, 40, 5, 4, 3, 4, 39, 33, 3, 2, 2, 2, 39, 36, 3, 2, 2, 2, 40, 43, 3, 2, 2, 2, 41, 39, 3, 2, 2, 2, 41, 42, 3, 2, 2, 2, 42, 5, 3, 2, 2, 2, 43, 41, 3, 2, 2, 2, 44, 48, 5, 8, 5, 2, 45, 48, 5, 10, 6, 2, 46, 48, 5, 12, 7, 2, 47, 44, 3, 2, 2, 2, 47, 45, 3, 2, 2, 2, 47, 46, 3, 2, 2, 2, 48, 7, 3, 2, 2, 2, 49, 50, 7, 21, 2, 2, 50, 51, 5, 14, 8, 2, 51, 52, 5, 16, 9, 2, 52, 9, 3, 2, 2, 2, 53, 54, 7, 21, 2, 2, 54, 55, 9, 2, 2, 2, 55, 56, 7, 16, 2, 2, 56, 11, 3, 2, 2, 2, 57, 61, 7, 21, 2, 2, 58, 62, 7, 8, 2, 2, 59, 60, 7, 15, 2, 2, 60, 62, 7, 14, 2, 2, 61, 58, 3, 2, 2, 2, 61, 59, 3, 2, 2, 2, 62, 63, 3, 2, 2, 2, 63, 64, 7, 16, 2, 2, 64, 13, 3, 2, 2, 2, 65, 66, 9, 3, 2, 2, 66, 15, 3, 2, 2, 2, 67, 72, 7, 10, 2, 2, 68, 72, 7, 11, 2, 2, 69, 72, 5, 18, 10, 2, 70, 72, 5, 20, 11, 2, 71, 67, 3, 2, 2, 2, 71, 68, 3, 2, 2, 2, 71, 69, 3, 2, 2, 2, 71, 70, 3, 2, 2, 2, 72, 17, 3, 2, 2, 2, 73, 74, 7, 20, 2, 2, 74, 19, 3, 2, 2, 2, 75, 76, 7, 20, 2, 2, 76, 77, 7, 19, 2, 2, 77, 78, 7, 20, 2, 2, 78, 21, 3, 2, 2, 2, 8, 31, 39, 41, 47, 61, 71]
[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]
Loading

0 comments on commit 30794dd

Please sign in to comment.