/** * @param string $rql * @param string $exceptionMessage * @return void * * @dataProvider dataSyntaxError() */ public function testSyntaxError($rql, $exceptionMessage) { $this->setExpectedException(SyntaxErrorException::class, $exceptionMessage); $lexer = new Lexer(); $parser = new Parser(); $parser->parse($lexer->tokenize($rql)); }
/** * @param string $rql * @param string $exceptionMessage * @return void * * @covers Parser::parse() * @dataProvider dataSyntaxError() */ public function testSyntaxError($rql, $exceptionMessage) { $this->setExpectedException('Xiag\\Rql\\Parser\\Exception\\SyntaxErrorException', $exceptionMessage); $lexer = new Lexer(); $parser = Parser::createDefault(); $parser->parse($lexer->tokenize($rql)); }
/** * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param callable|null $next * @return ResponseInterface */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null) { $id = $request->getAttribute('id'); if (is_null($id)) { $rqlQueryString = $request->getUri()->getQuery(); $tokens = $this->lexer->tokenize($rqlQueryString); /* @var $rqlQueryObject \Xiag\Rql\Parser\Query */ $rqlQueryObject = $this->parser->parse($tokens); $request = $request->withAttribute('Rql-Query-Object', $rqlQueryObject); //$response->write(var_dump($rqlQueryObject)); $attributes['order'] = $rqlQueryObject->getSort(); $attributes['limit'] = $rqlQueryObject->getLimit(); $attributes['select'] = $rqlQueryObject->getSelect(); $request = $this->setAttributes($request, $attributes); } if ($next) { return $next($request, $response); } /** if($key = 'select-param') { //'select-param': 'prop1,prop2' $fildsArray = explode(',', urldecode($value)); */ return $response; }
protected function processValue($value) { if ($value === 'true()') { $this->pushToken(Token::T_TRUE, $value); $this->moveCursor($value); } elseif ($value === 'false()') { $this->pushToken(Token::T_FALSE, $value); $this->moveCursor($value); } elseif ($value === 'null()') { $this->pushToken(Token::T_NULL, $value); $this->moveCursor($value); } elseif ($value === 'empty()') { $this->pushToken(Token::T_EMPTY, $value); $this->moveCursor($value); } elseif ($value === 'true' || $value === 'false' || $value === 'null') { $this->pushToken(Token::T_STRING, $value); $this->moveCursor($value); } else { parent::processValue($value); } }
return $this; } } class QueryBuilder extends BaseQueryBuilder { public function __construct() { parent::__construct(); $this->query = new Query(); } public function addNode(AbstractNode $node) { if ($node instanceof GroupbyNode) { return $this->query->setGroupby($node); } return parent::addNode($node); } } class Parser extends BaseParser { protected function createQueryBuilder() { return new QueryBuilder(); } } $nodeParser = (new NodeParserChain())->addNodeParser(new SelectTokenParser(['count', 'sum', 'avg', 'min', 'max']))->addNodeParser(new GroupbyTokenParser())->addNodeParser(new EqNodeParser(new FieldParser(), new ScalarParser())); // parse $lexer = new Lexer(); $parser = new Parser($nodeParser); $tokenStream = $lexer->tokenize(implode('&', ['select(type,avg(age),min(age),max(age))', 'eq(type,customer)', 'groupby(type)'])); var_dump($parser->parse($tokenStream));
/** * execute a query againts the test db * * @param string $query query to execute * @param MongoOdm $visitor visitor we are testing * * @return array */ private function runTestQuery($query, $visitor) { $lexer = new Lexer(); $parser = RqlParser::createDefault(); $rqlQuery = $parser->parse($lexer->tokenize($query)); $builder = $visitor->visit($rqlQuery); $results = []; foreach ($builder->getQuery()->execute() as $doc) { $results[] = $doc; } return $results; }
{ return $tokenStream->test(Token::T_OPERATOR, 'elemMatch'); } public function parse(TokenStream $tokenStream) { $tokenStream->expect(Token::T_OPERATOR, 'elemMatch'); $tokenStream->expect(Token::T_OPEN_PARENTHESIS); $field = $tokenStream->expect(Token::T_STRING)->getValue(); $tokenStream->expect(Token::T_COMMA); $query = $this->queryParser->parse($tokenStream); if (!$query instanceof AbstractQueryNode) { throw new SyntaxErrorException(sprintf('"elemMatch" operator expects parameter "query" to be instance of "%s", "%s" given', AbstractQueryNode::class, get_class($query))); } $tokenStream->expect(Token::T_CLOSE_PARENTHESIS); return new ElemMatchNode($field, $query); } } // create node parser $scalarParser = (new ValueParser\ScalarParser())->registerTypeCaster('string', new TypeCaster\StringTypeCaster())->registerTypeCaster('integer', new TypeCaster\IntegerTypeCaster())->registerTypeCaster('float', new TypeCaster\FloatTypeCaster())->registerTypeCaster('boolean', new TypeCaster\BooleanTypeCaster()); $arrayParser = new ValueParser\ArrayParser($scalarParser); $globParser = new ValueParser\GlobParser(); $fieldParser = new ValueParser\FieldParser(); $integerParser = new ValueParser\IntegerParser(); $queryNodeParser = new NodeParser\QueryNodeParser(); $queryNodeParser->addNodeParser(new NodeParser\Query\GroupNodeParser($queryNodeParser))->addNodeParser(new NodeParser\Query\LogicalOperator\AndNodeParser($queryNodeParser))->addNodeParser(new NodeParser\Query\LogicalOperator\OrNodeParser($queryNodeParser))->addNodeParser(new NodeParser\Query\LogicalOperator\NotNodeParser($queryNodeParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Rql\InNodeParser($fieldParser, $arrayParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Rql\OutNodeParser($fieldParser, $arrayParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Rql\EqNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Rql\NeNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Rql\LtNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Rql\GtNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Rql\LeNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Rql\GeNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Rql\LikeNodeParser($fieldParser, $globParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Fiql\InNodeParser($fieldParser, $arrayParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Fiql\OutNodeParser($fieldParser, $arrayParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Fiql\EqNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Fiql\NeNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Fiql\LtNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Fiql\GtNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Fiql\LeNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Fiql\GeNodeParser($fieldParser, $scalarParser))->addNodeParser(new NodeParser\Query\ComparisonOperator\Fiql\LikeNodeParser($fieldParser, $globParser))->addNodeParser(new BetweenTokenParser($scalarParser))->addNodeParser(new ElemMatchNodeParser($queryNodeParser)); $nodeParser = (new NodeParserChain())->addNodeParser($queryNodeParser)->addNodeParser(new NodeParser\SelectNodeParser($fieldParser))->addNodeParser(new NodeParser\SortNodeParser($fieldParser))->addNodeParser(new NodeParser\LimitNodeParser($integerParser)); // parse $lexer = new Lexer(); $parser = new Parser($nodeParser); $tokenStream = $lexer->tokenize('between(x,1,2)&elemMatch(array,(between(x,3,4)&a=b&(c!=d|e!=f)¬(le(g,h))))'); var_dump($parser->parse($tokenStream));
namespace Xiag\Rql\ParserExample07; use Xiag\Rql\Parser\Lexer; use Xiag\Rql\Parser\Parser; use Xiag\Rql\Parser\Token; use Xiag\Rql\Parser\TypeCasterInterface; use Xiag\Rql\Parser\Exception\SyntaxErrorException; use Xiag\Rql\Parser\NodeParser\Query\ComparisonOperator\Rql\EqNodeParser; use Xiag\Rql\Parser\ValueParser; require __DIR__ . '/../vendor/autoload.php'; class TimestampCaster implements TypeCasterInterface { /** * @inheritdoc */ public function typeCast(Token $token) { if (!$token->test(Token::T_INTEGER)) { throw new SyntaxErrorException('Timestamp type caster expects an integer token'); } return new \DateTime('@' . $token->getValue()); } } $scalarParser = (new ValueParser\ScalarParser())->registerTypeCaster('timestamp', new TimestampCaster()); $fieldNameParser = new ValueParser\FieldParser(); $nodeParser = new EqNodeParser($fieldNameParser, $scalarParser); // parse $lexer = new Lexer(); $parser = new Parser($nodeParser); $tokenStream = $lexer->tokenize('eq(a,timestamp:1444000000)'); var_dump($parser->parse($tokenStream));
<?php namespace Xiag\Rql\ParserExample01; use Xiag\Rql\Parser\Lexer; use Xiag\Rql\Parser\Parser; use Xiag\Rql\Parser\ExpressionParser; use Xiag\Rql\Parser\TokenParserGroup; use Xiag\Rql\Parser\TokenParser\Query\GroupTokenParser; use Xiag\Rql\Parser\TokenParser\Query\Fiql; require __DIR__ . '/../vendor/autoload.php'; $queryTokenParser = new TokenParserGroup(); $queryTokenParser->addTokenParser(new GroupTokenParser($queryTokenParser))->addTokenParser(new Fiql\ArrayOperator\InTokenParser())->addTokenParser(new Fiql\ArrayOperator\OutTokenParser())->addTokenParser(new Fiql\ScalarOperator\EqTokenParser())->addTokenParser(new Fiql\ScalarOperator\NeTokenParser())->addTokenParser(new Fiql\ScalarOperator\LtTokenParser())->addTokenParser(new Fiql\ScalarOperator\GtTokenParser())->addTokenParser(new Fiql\ScalarOperator\LeTokenParser())->addTokenParser(new Fiql\ScalarOperator\GeTokenParser()); $parser = new Parser(new ExpressionParser()); $parser->addTokenParser($queryTokenParser); $lexer = new Lexer(); // ok $tokenStream = $lexer->tokenize('((a==true|b!=str)&c>=10&d=in=(1,value,null))'); var_dump($parser->parse($tokenStream)); // error $tokenStream = $lexer->tokenize('or(eq(a,true),ne(b,str))>e(c,10)&in(d,(1,value,null))'); var_dump($parser->parse($tokenStream));
private function visitLogicalNode(Node\Query\AbstractLogicalOperatorNode $node, SqlBuilder $sqlBuilder) { if ($node->getNodeName() === 'not') { $operator = ' AND '; $sqlBuilder->addRawWhere('NOT'); } elseif ($node->getNodeName() === 'and') { $operator = ' AND '; } elseif ($node->getNodeName() === 'or') { $operator = ' OR '; } else { throw new \LogicException(sprintf('Unknown logical node "%s"', $node->getNodeName())); } $sqlBuilder->addRawWhere('('); foreach ($node->getQueries() as $index => $query) { $this->visitQueryNode($query, $sqlBuilder); if ($index !== count($node->getQueries()) - 1) { $sqlBuilder->addRawWhere($operator); } } $sqlBuilder->addRawWhere(')'); } } // parse $lexer = new Lexer(); $parser = new Parser(); $query = $parser->parse($lexer->tokenize(implode('&', ['select(a,b,c)', 'ne(a,b)', '(not(c=d)|e=f)&out(c,(1,2))', 'in(d,(true(),false(),null(),empty()))', 'ge(e,2016-06-30T12:09:44Z)', 'like(f,*sea?rch?)', 'sort(-a,+b)', 'limit(1,0)']))); // traversing $sqlBuilder = new SqlBuilder(); $nodeVisitor = new SqlNodeVisitor(); $nodeVisitor->visit($query, $sqlBuilder); var_dump($sqlBuilder->createQuery());
use Xiag\Rql\Parser\Exception\SyntaxErrorException; use Xiag\Rql\Parser\Lexer; use Xiag\Rql\Parser\Node; use Xiag\Rql\Parser\Parser; use Xiag\Rql\Parser\Token; use Xiag\Rql\Parser\SubLexerChain; use Xiag\Rql\Parser\SubLexer; use Xiag\Rql\Parser\SubLexerInterface; require __DIR__ . '/../vendor/autoload.php'; class DateSubLexer implements SubLexerInterface { /** * @inheritdoc */ public function getTokenAt($code, $cursor) { if (!preg_match('/(?<y>\\d{4})-(?<m>\\d{2})-(?<d>\\d{2})/A', $code, $matches, null, $cursor)) { return null; } if (!checkdate($matches['m'], $matches['d'], $matches['y'])) { throw new SyntaxErrorException(sprintf('Invalid date value "%s"', $matches[0])); } return new Token(Token::T_DATE, $matches[0] . 'T00:00:00+00:00', $cursor, $cursor + strlen($matches[0])); } } $subLexer = (new SubLexerChain())->addSubLexer(new SubLexer\ConstantSubLexer())->addSubLexer(new SubLexer\PunctuationSubLexer())->addSubLexer(new SubLexer\FiqlOperatorSubLexer())->addSubLexer(new SubLexer\RqlOperatorSubLexer())->addSubLexer(new SubLexer\TypeSubLexer())->addSubLexer(new SubLexer\GlobSubLexer())->addSubLexer(new SubLexer\StringSubLexer())->addSubLexer(new SubLexer\DatetimeSubLexer())->addSubLexer(new DateSubLexer())->addSubLexer(new SubLexer\NumberSubLexer())->addSubLexer(new SubLexer\SortSubLexer()); // parse $lexer = new Lexer($subLexer); $parser = new Parser(); $tokenStream = $lexer->tokenize('in(a,(2016-06-30,2016-06-30T09:12:33Z))'); var_dump($parser->parse($tokenStream));
/** * @param string $value * @return Glob */ private function getGlob($value) { $lexer = new Lexer(); $parser = new Parser(); $rql = 'like(field,' . $value . ')'; $stream = $lexer->tokenize($rql); $query = $parser->parse($stream); /** @var LikeNode $like */ $like = $query->getQuery(); $this->assertInstanceOf(LikeNode::class, $like); /** @var Glob $glob */ $glob = $like->getValue(); $this->assertInstanceOf(Glob::class, $glob); return $glob; }
use Xiag\Rql\Parser\Parser; use Xiag\Rql\Parser\Node; use Xiag\Rql\Parser\Token; use Xiag\Rql\Parser\NodeParser\Query\ComparisonOperator\Rql\InNodeParser; use Xiag\Rql\Parser\TokenStream; use Xiag\Rql\Parser\ValueParser; require __DIR__ . '/../vendor/autoload.php'; class ArrayParser extends ValueParser\ArrayParser { /** * @inheritdoc */ public function parse(TokenStream $tokenStream) { if ($tokenStream->nextIf(Token::T_TYPE, 'array')) { $tokenStream->expect(Token::T_COLON); return [$this->itemParser->parse($tokenStream)]; } else { return parent::parse($tokenStream); } } } $scalarParser = new ValueParser\ScalarParser(); $fieldNameParser = new ValueParser\FieldParser(); $arrayParser = new ArrayParser($scalarParser); $nodeParser = new InNodeParser($fieldNameParser, $arrayParser); // parse $lexer = new Lexer(); $parser = new Parser($nodeParser); $tokenStream = $lexer->tokenize(implode('&', ['in(a,(1,string,true()))', 'in(b,array:1)'])); var_dump($parser->parse($tokenStream));
/** * Workaround for https://github.com/xiag-ag/rql-parser/issues/8 * * @param string $code * * @return \Xiag\Rql\Parser\TokenStream * @author Andreas Glaser */ public function tokenize($code) { $code = str_replace('.', '%2E', $code); return parent::tokenize($code); }
if ($tokenStream->nextIf(Token::T_FALSE)) { return false; } elseif ($tokenStream->nextIf(Token::T_TRUE)) { return true; } elseif ($tokenStream->nextIf(Token::T_NULL)) { return null; } elseif ($tokenStream->nextIf(Token::T_DATE)) { return new \DateTime($token->getValue()); } elseif ($tokenStream->nextIf(Token::T_STRING)) { return $token->getValue(); } elseif ($tokenStream->nextIf(Token::T_INTEGER)) { return (int) $token->getValue(); } elseif ($tokenStream->nextIf(Token::T_FLOAT)) { return (double) $token->getValue(); } throw new SyntaxErrorException(sprintf('Invalid scalar token "%s" (%s)', $token->getValue(), $token->getName())); } } $subLexer = (new SubLexerChain())->addSubLexer(new SubLexer\PunctuationSubLexer())->addSubLexer(new SubLexer\FiqlOperatorSubLexer())->addSubLexer(new SubLexer\RqlOperatorSubLexer())->addSubLexer(new ConstantSubLexer())->addSubLexer(new StringSubLexer())->addSubLexer(new IdentifierSubLexer())->addSubLexer(new SubLexer\DatetimeSubLexer())->addSubLexer(new SubLexer\NumberSubLexer())->addSubLexer(new SubLexer\SortSubLexer()); $identifierParser = new IdentifierParser(); $scalarParser = new ScalarParser(); $arrayParser = new ValueParser\ArrayParser($scalarParser); $integerParser = new ValueParser\IntegerParser(); $queryNodeParser = new NodeParser\QueryNodeParser(); $queryNodeParser->addNodeParser(new NodeParser\Query\GroupNodeParser($queryNodeParser))->addNodeParser(new LogicalOperator\AndNodeParser($queryNodeParser))->addNodeParser(new LogicalOperator\OrNodeParser($queryNodeParser))->addNodeParser(new LogicalOperator\NotNodeParser($queryNodeParser))->addNodeParser(new ComparisonOperator\Rql\InNodeParser($identifierParser, $arrayParser))->addNodeParser(new ComparisonOperator\Rql\OutNodeParser($identifierParser, $arrayParser))->addNodeParser(new ComparisonOperator\Rql\EqNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Rql\NeNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Rql\LtNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Rql\GtNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Rql\LeNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Rql\GeNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Rql\LikeNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Fiql\InNodeParser($identifierParser, $arrayParser))->addNodeParser(new ComparisonOperator\Fiql\OutNodeParser($identifierParser, $arrayParser))->addNodeParser(new ComparisonOperator\Fiql\EqNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Fiql\NeNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Fiql\LtNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Fiql\GtNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Fiql\LeNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Fiql\GeNodeParser($identifierParser, $scalarParser))->addNodeParser(new ComparisonOperator\Fiql\LikeNodeParser($identifierParser, $scalarParser)); $nodeParser = (new NodeParserChain())->addNodeParser($queryNodeParser)->addNodeParser(new NodeParser\SelectNodeParser($identifierParser))->addNodeParser(new NodeParser\SortNodeParser($identifierParser))->addNodeParser(new NodeParser\LimitNodeParser($integerParser)); // parse $lexer = new Lexer($subLexer); $parser = new Parser($nodeParser); $tokenStream = $lexer->tokenize(implode('&', ['select(a.b,c.d)', 'ne(a.b,"quoted string !@#$%^&*()_+[]{} ;:\'\\"\\| ,<.>/? ~ + escaped \\" double quote")', '(not(c.d="d")|e=false)', 'out(f,(1,"2",null,2016-06-29T23:30:33Z,true))', 'sort(-a.b,+c.d)', 'limit(1,2)'])); var_dump($parser->parse($tokenStream));