From d65cd8e0715f11d128fba9a750515c93790f1602 Mon Sep 17 00:00:00 2001 From: wickedOne Date: Tue, 14 Jul 2020 11:00:51 +0200 Subject: [PATCH] implementation and documentation - added query builder implementation in query trait - added query builder implementation for adding filter queries - added some documentation for the query builder --- docs/queries/query-helper/query-builder.md | 84 ++++++++++++ src/Builder/Comparison.php | 5 + src/Builder/Select/ExpressionBuilder.php | 10 ++ .../{FilterBuilder.php => QueryBuilder.php} | 2 +- src/Builder/Select/QueryExpressionVisitor.php | 2 + src/Component/QueryTrait.php | 20 +++ src/QueryType/Select/Query/Query.php | 24 ++++ ...ryBuilderTest.php => QueryBuilderTest.php} | 122 ++++++++++-------- .../Select/Query/AbstractQueryTest.php | 56 ++++++++ tests/QueryType/Select/Query/QueryTest.php | 44 +++++++ 10 files changed, 313 insertions(+), 56 deletions(-) create mode 100644 docs/queries/query-helper/query-builder.md rename src/Builder/Select/{FilterBuilder.php => QueryBuilder.php} (98%) rename tests/Builder/Select/{SelectQueryBuilderTest.php => QueryBuilderTest.php} (71%) diff --git a/docs/queries/query-helper/query-builder.md b/docs/queries/query-helper/query-builder.md new file mode 100644 index 000000000..ef1f87300 --- /dev/null +++ b/docs/queries/query-helper/query-builder.md @@ -0,0 +1,84 @@ +Query builder +------------- + +The query builder is a simple helper class to help writing and maintaining (filter) queries using Solr's query language. +While the query will only accept a single (composite) expression, the addition of filter queries can consist of multiple expressions. + +Query example +------------- +```php +createSelect(); + +$expr = QueryBuilder::expr(); +$builder = QueryBuilder::create() + ->where($expr->andX( + $expr->eq('foo', 'bar'), + $expr->eq('baz', 'qux') + )) +; + +$query->setQueryFromQueryBuilder($builder); + +// which would be equal to +$query->setQuery('foo:"bar" AND baz:"qux"'); +``` + +Filter Query example +------------- +```php +createSelect(); + +$expr = QueryBuilder::expr(); +$builder = QueryBuilder::create() + ->where($expr->eq('foo', 'bar')), + ->andWhere($expr->neq('baz', 'qux') +); + +$query->addFilterQueriesFromQueryBuilder($builder); + +// which would be equal to +$value = 'foo:"bar"'; +$query->addFilterQuery(['key' => sha1($value), 'query' => $value]); +$value = '-baz:"qux"'; +$query->addFilterQuery(['key' => sha1($value), 'query' => $value]); +``` + +Complex filter queries +---------------------- +While the ``addFilterQueriesFromQueryBuilder`` method only provides in setting the facet query key and actual query, the ``QueryBuilder`` can be used in the construction of more complex facet queries. +If one, for example, need to add a tag to the filter query the following method could be used. +```php +createSelect(); + +$expr = QueryBuilder::expr(); +$visitor = new QueryExpressionVisitor(); + +$builder = QueryBuilder::create() + ->where($expr->eq('foo', 'bar')) +); + +$query->addFilterQuery([ + 'key' => 'my-key, + 'query' => $visitor->dispatch($builder->getExpression()[0]), + 'local_tag' => 'my-tag', +]); +``` \ No newline at end of file diff --git a/src/Builder/Comparison.php b/src/Builder/Comparison.php index da2ad93f3..4fedddb07 100644 --- a/src/Builder/Comparison.php +++ b/src/Builder/Comparison.php @@ -71,6 +71,11 @@ class Comparison implements ExpressionInterface */ public const MATCH = 'MATCH'; + /** + * Empty. + */ + public const EMPTY = 'EMPTY'; + /** * @var string */ diff --git a/src/Builder/Select/ExpressionBuilder.php b/src/Builder/Select/ExpressionBuilder.php index 11801d0eb..d2f78edd6 100644 --- a/src/Builder/Select/ExpressionBuilder.php +++ b/src/Builder/Select/ExpressionBuilder.php @@ -169,4 +169,14 @@ public function match(string $field, $value): Comparison { return new Comparison($field, Comparison::MATCH, $value); } + + /** + * @param string $field + * + * @return \Solarium\Builder\Comparison + */ + public function empty(string $field): Comparison + { + return new Comparison($field, Comparison::EMPTY, null); + } } diff --git a/src/Builder/Select/FilterBuilder.php b/src/Builder/Select/QueryBuilder.php similarity index 98% rename from src/Builder/Select/FilterBuilder.php rename to src/Builder/Select/QueryBuilder.php index a673f9c2d..c65aad3aa 100644 --- a/src/Builder/Select/FilterBuilder.php +++ b/src/Builder/Select/QueryBuilder.php @@ -11,7 +11,7 @@ * * @author wicliff */ -class FilterBuilder +class QueryBuilder { /** * @var \Solarium\Builder\ExpressionInterface[] diff --git a/src/Builder/Select/QueryExpressionVisitor.php b/src/Builder/Select/QueryExpressionVisitor.php index a37c30a77..e3904b42d 100644 --- a/src/Builder/Select/QueryExpressionVisitor.php +++ b/src/Builder/Select/QueryExpressionVisitor.php @@ -101,6 +101,8 @@ public function walkExpression(ExpressionInterface $expression) } return sprintf('%s:%s', $field, $this->valueToString($value, ',', '', false)); + case Comparison::EMPTY: + return sprintf('(*:* NOT %s:*)', $field); default: throw new RuntimeException('Unknown comparison operator: '.$expression->getOperator()); } diff --git a/src/Component/QueryTrait.php b/src/Component/QueryTrait.php index 338038f0c..32e3fbfc1 100644 --- a/src/Component/QueryTrait.php +++ b/src/Component/QueryTrait.php @@ -2,6 +2,10 @@ namespace Solarium\Component; +use Solarium\Builder\Select\QueryBuilder; +use Solarium\Builder\Select\QueryExpressionVisitor; +use Solarium\Exception\RuntimeException; + /** * Query Trait. */ @@ -27,6 +31,22 @@ public function setQuery(string $query, array $bind = null): QueryInterface return $this->setOption('query', trim($query)); } + /** + * @param \Solarium\Builder\Select\QueryBuilder $builder + * + * @return \Solarium\Component\QueryInterface + * + * @throws \Solarium\Exception\RuntimeException + */ + public function setQueryFromQueryBuilder(QueryBuilder $builder): QueryInterface + { + if (1 !== count($builder->getExpressions())) { + throw new RuntimeException('The QueryBuilder can only contain one expression when setting the query. Use ExpressionBuilder::andX or ExpressionBuilder::orX to combine expressions.'); + } + + return $this->setOption('query', (new QueryExpressionVisitor())->dispatch($builder->getExpressions()[0])); + } + /** * Get query option. * diff --git a/src/QueryType/Select/Query/Query.php b/src/QueryType/Select/Query/Query.php index b294af750..c84dca08f 100644 --- a/src/QueryType/Select/Query/Query.php +++ b/src/QueryType/Select/Query/Query.php @@ -2,6 +2,8 @@ namespace Solarium\QueryType\Select\Query; +use Solarium\Builder\Select\QueryBuilder; +use Solarium\Builder\Select\QueryExpressionVisitor; use Solarium\Component\Analytics\Analytics; use Solarium\Component\ComponentAwareQueryInterface; use Solarium\Component\ComponentAwareQueryTrait; @@ -581,6 +583,28 @@ public function addFilterQueries(array $filterQueries): self return $this; } + /** + * Add multiple filter queries from the QueryBuilder. + * + * @param \Solarium\Builder\Select\QueryBuilder $builder + * + * @return $this + * + * @throws \Solarium\Exception\RuntimeException + */ + public function addFilterQueriesFromQueryBuilder(QueryBuilder $builder): self + { + $visitor = new QueryExpressionVisitor(); + + foreach ($builder->getExpressions() as $expression) { + $value = $visitor->dispatch($expression); + + $this->addFilterQuery(new FilterQuery(['key' => sha1($value), 'query' => $value])); + } + + return $this; + } + /** * Get a filterquery. * diff --git a/tests/Builder/Select/SelectQueryBuilderTest.php b/tests/Builder/Select/QueryBuilderTest.php similarity index 71% rename from tests/Builder/Select/SelectQueryBuilderTest.php rename to tests/Builder/Select/QueryBuilderTest.php index 39361373a..b9602b2e4 100644 --- a/tests/Builder/Select/SelectQueryBuilderTest.php +++ b/tests/Builder/Select/QueryBuilderTest.php @@ -5,14 +5,14 @@ namespace Solarium\Tests\Builder\Select; use PHPUnit\Framework\TestCase; -use Solarium\Exception\RuntimeException; use Solarium\Builder\AbstractExpressionVisitor; use Solarium\Builder\Comparison; use Solarium\Builder\CompositeComparison; use Solarium\Builder\ExpressionInterface; -use Solarium\Builder\Select\FilterBuilder; +use Solarium\Builder\Select\QueryBuilder; use Solarium\Builder\Select\QueryExpressionVisitor; use Solarium\Builder\Value; +use Solarium\Exception\RuntimeException; /** * Select Query Builder Test. @@ -40,13 +40,13 @@ public function setUp(): void */ public function testEquals(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->eq('foo', 'bar')); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->eq('foo', 'bar')); $this->assertSame('foo:"bar"', $this->visitor->dispatch($filter->getExpressions()[0])); - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->eq('foo', date_create('2020-01-01', new \DateTimeZone('UTC')))); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->eq('foo', date_create('2020-01-01', new \DateTimeZone('UTC')))); $this->assertSame('foo:[2020-01-01T00:00:00Z TO 2020-01-01T00:00:00Z]', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -57,8 +57,8 @@ public function testEquals(): void */ public function testNullValue(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->eq('foo', null)); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->eq('foo', null)); $this->assertSame('foo:[* TO *]', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -69,13 +69,13 @@ public function testNullValue(): void */ public function testDoesNotEqual(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->neq('foo', 'bar')); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->neq('foo', 'bar')); $this->assertSame('-foo:"bar"', $this->visitor->dispatch($filter->getExpressions()[0])); - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->neq('foo', date_create('2020-01-01', new \DateTimeZone('UTC')))); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->neq('foo', date_create('2020-01-01', new \DateTimeZone('UTC')))); $this->assertSame('-foo:[2020-01-01T00:00:00Z TO 2020-01-01T00:00:00Z]', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -86,8 +86,8 @@ public function testDoesNotEqual(): void */ public function testGreaterThan(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->gt('foo', 2)); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->gt('foo', 2)); $this->assertSame('foo:{2 TO *]', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -98,8 +98,8 @@ public function testGreaterThan(): void */ public function testGreaterThanEqual(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->gte('foo', 2)); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->gte('foo', 2)); $this->assertSame('foo:[2 TO *]', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -110,8 +110,8 @@ public function testGreaterThanEqual(): void */ public function testLowerThan(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->lt('foo', 2)); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->lt('foo', 2)); $this->assertSame('foo:[* TO 2}', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -122,8 +122,8 @@ public function testLowerThan(): void */ public function testLowerThanEqual(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->lte('foo', 2)); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->lte('foo', 2)); $this->assertSame('foo:[* TO 2]', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -134,13 +134,13 @@ public function testLowerThanEqual(): void */ public function testRange(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->range('foo', [2])); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->range('foo', [2])); $this->assertSame('foo:[2 TO *]', $this->visitor->dispatch($filter->getExpressions()[0])); - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->range('foo', [2, 5])); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->range('foo', [2, 5])); $this->assertSame('foo:[2 TO 5]', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -150,8 +150,8 @@ public function testRange(): void */ public function testRangeInvalidValue(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->range('foo', 'bar')); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->range('foo', 'bar')); $this->expectException(RuntimeException::class); @@ -164,13 +164,13 @@ public function testRangeInvalidValue(): void */ public function testIn(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->in('foo', [2, 5])); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->in('foo', [2, 5])); $this->assertSame('foo:(2 OR 5)', $this->visitor->dispatch($filter->getExpressions()[0])); - $filter = FilterBuilder::create() - ->andWhere(FilterBuilder::expr()->in('foo', 'bar')); + $filter = QueryBuilder::create() + ->andWhere(QueryBuilder::expr()->in('foo', 'bar')); $this->assertSame('foo:"bar"', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -181,13 +181,13 @@ public function testIn(): void */ public function testNotIn(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->notIn('foo', [2, 5])); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->notIn('foo', [2, 5])); $this->assertSame('-foo:(2 OR 5)', $this->visitor->dispatch($filter->getExpressions()[0])); - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->notIn('foo', 'bar')); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->notIn('foo', 'bar')); $this->assertSame('-foo:"bar"', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -198,13 +198,13 @@ public function testNotIn(): void */ public function testLike(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->like('title', ['*foo', 'bar*'])); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->like('title', ['*foo', 'bar*'])); $this->assertSame('title:(*foo OR bar*)', $this->visitor->dispatch($filter->getExpressions()[0])); - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->like('title', 'foo*')); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->like('title', 'foo*')); $this->assertSame('title:foo*', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -215,8 +215,8 @@ public function testLike(): void */ public function testRegularExpression(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->regexp('title', '[0-9]{5}')); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->regexp('title', '[0-9]{5}')); $this->assertSame('title:/[0-9]{5}/', $this->visitor->dispatch($filter->getExpressions()[0])); } @@ -227,22 +227,34 @@ public function testRegularExpression(): void */ public function testMatch(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->match('title', 'foo*')); + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->match('title', 'foo*')); $this->assertSame('title:foo*', $this->visitor->dispatch($filter->getExpressions()[0])); } + /** + * @throws \PHPUnit\Framework\ExpectationFailedException + * @throws \Solarium\Exception\RuntimeException + */ + public function testEmpty(): void + { + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->empty('title')); + + $this->assertSame('(*:* NOT title:*)', $this->visitor->dispatch($filter->getExpressions()[0])); + } + /** * @throws \PHPUnit\Framework\ExpectationFailedException * @throws \Solarium\Exception\RuntimeException */ public function testCompositeAnd(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->andX( - FilterBuilder::expr()->eq('title', 'foo'), - FilterBuilder::expr()->in('description', ['bar', 'baz']) + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->andX( + QueryBuilder::expr()->eq('title', 'foo'), + QueryBuilder::expr()->in('description', ['bar', 'baz']) )); $this->assertSame('title:"foo" AND description:("bar" OR "baz")', $this->visitor->dispatch($filter->getExpressions()[0])); @@ -254,10 +266,10 @@ public function testCompositeAnd(): void */ public function testCompositeOr(): void { - $filter = FilterBuilder::create() - ->where(FilterBuilder::expr()->orX( - FilterBuilder::expr()->eq('title', 'foo'), - FilterBuilder::expr()->in('description', ['bar', 'baz']) + $filter = QueryBuilder::create() + ->where(QueryBuilder::expr()->orX( + QueryBuilder::expr()->eq('title', 'foo'), + QueryBuilder::expr()->in('description', ['bar', 'baz']) )); $this->assertSame('title:"foo" OR description:("bar" OR "baz")', $this->visitor->dispatch($filter->getExpressions()[0])); @@ -269,13 +281,13 @@ public function testCompositeOr(): void */ public function testVisitExpressions(): void { - $expression = FilterBuilder::expr()->eq('title', 'foo'); + $expression = QueryBuilder::expr()->eq('title', 'foo'); $this->assertSame('title:"foo"', $expression->visit($this->visitor)); - $compositeExpression = FilterBuilder::expr()->andX( - FilterBuilder::expr()->eq('title', 'foo'), - FilterBuilder::expr()->in('description', ['bar', 'baz']) + $compositeExpression = QueryBuilder::expr()->andX( + QueryBuilder::expr()->eq('title', 'foo'), + QueryBuilder::expr()->in('description', ['bar', 'baz']) ); $this->assertSame('title:"foo" AND description:("bar" OR "baz")', $compositeExpression->visit($this->visitor)); @@ -320,7 +332,7 @@ public function testUnknownExpression(): void */ public function testUnknownCompositeComparison(): void { - $comparison = new CompositeComparison('TO', [FilterBuilder::expr()->eq('title', 'foo')]); + $comparison = new CompositeComparison('TO', [QueryBuilder::expr()->eq('title', 'foo')]); $this->expectException(RuntimeException::class); diff --git a/tests/QueryType/Select/Query/AbstractQueryTest.php b/tests/QueryType/Select/Query/AbstractQueryTest.php index fd153330e..0f43e245f 100644 --- a/tests/QueryType/Select/Query/AbstractQueryTest.php +++ b/tests/QueryType/Select/Query/AbstractQueryTest.php @@ -3,11 +3,14 @@ namespace Solarium\Tests\QueryType\Select\Query; use PHPUnit\Framework\TestCase; +use Solarium\Builder\Select\QueryBuilder; +use Solarium\Builder\Select\QueryExpressionVisitor; use Solarium\Component\Analytics\Analytics; use Solarium\Component\MoreLikeThis; use Solarium\Core\Client\Client; use Solarium\Exception\InvalidArgumentException; use Solarium\Exception\OutOfBoundsException; +use Solarium\Exception\RuntimeException; use Solarium\QueryType\Select\Query\FilterQuery; use Solarium\QueryType\Select\Query\Query; @@ -749,4 +752,57 @@ public function testSetAndGetSplitOnWhitespace() $this->query->setSplitOnWhitespace(false); $this->assertFalse($this->query->getSplitOnWhitespace()); } + + /** + * @throws \PHPUnit\Framework\ExpectationFailedException + * @throws \Solarium\Exception\RuntimeException + */ + public function testSetQueryFromQueryBuilder(): void + { + $visitor = new QueryExpressionVisitor(); + $builder = QueryBuilder::create() + ->where(QueryBuilder::expr()->eq('foo', 'bar')); + + $this->query->setQueryFromQueryBuilder($builder); + + self::assertSame($visitor->dispatch($builder->getExpressions()[0]), $this->query->getQuery()); + } + + /** + * @throws \PHPUnit\Framework\ExpectationFailedException + * @throws \Solarium\Exception\RuntimeException + */ + public function testSetCompositeQueryFromQueryBuilder(): void + { + $expr = QueryBuilder::expr(); + $visitor = new QueryExpressionVisitor(); + + $builder = QueryBuilder::create() + ->where($expr->andX( + $expr->eq('foo', 'bar'), + $expr->eq('baz', 'qux') + )) + ; + + $this->query->setQueryFromQueryBuilder($builder); + + self::assertSame($visitor->dispatch($builder->getExpressions()[0]), $this->query->getQuery()); + } + + /** + * @throws \Solarium\Exception\RuntimeException + */ + public function testSetQueryFromQueryBuilderException(): void + { + $this->expectException(RuntimeException::class); + + $expr = QueryBuilder::expr(); + + $builder = QueryBuilder::create() + ->where($expr->eq('foo', 'bar')) + ->andWhere($expr->eq('baz', 'qux')) + ; + + $this->query->setQueryFromQueryBuilder($builder); + } } diff --git a/tests/QueryType/Select/Query/QueryTest.php b/tests/QueryType/Select/Query/QueryTest.php index 9356ddbb2..982a60697 100644 --- a/tests/QueryType/Select/Query/QueryTest.php +++ b/tests/QueryType/Select/Query/QueryTest.php @@ -2,6 +2,8 @@ namespace Solarium\Tests\QueryType\Select\Query; +use Solarium\Builder\Select\QueryBuilder; +use Solarium\Builder\Select\QueryExpressionVisitor; use Solarium\QueryType\Select\Query\Query; class QueryTest extends AbstractQueryTest @@ -10,4 +12,46 @@ public function setUp(): void { $this->query = new Query(); } + + /** + * @throws \PHPUnit\Framework\ExpectationFailedException + * @throws \Solarium\Exception\RuntimeException + */ + public function testSetFacetQueryFromQueryBuilder(): void + { + $visitor = new QueryExpressionVisitor(); + $builder = QueryBuilder::create() + ->where(QueryBuilder::expr()->eq('foo', 'bar')); + + $this->query->addFilterQueriesFromQueryBuilder($builder); + + $value = $visitor->dispatch($builder->getExpressions()[0]); + $filterQuery = $this->query->getFilterQuery(sha1($value)); + + self::assertSame($value, $filterQuery->getQuery()); + } + + /** + * @throws \PHPUnit\Framework\Exception + * @throws \PHPUnit\Framework\ExpectationFailedException + * @throws \Solarium\Exception\RuntimeException + */ + public function testSetMultipleFilterQueriesFromQueryBuilder(): void + { + $visitor = new QueryExpressionVisitor(); + $expr = QueryBuilder::expr(); + + $builder = QueryBuilder::create() + ->where($expr->eq('foo', 'bar')) + ->andWhere($expr->eq('baz', 'qux')) + ; + + $this->query->addFilterQueriesFromQueryBuilder($builder); + + $first = $visitor->dispatch($builder->getExpressions()[0]); + $second = $visitor->dispatch($builder->getExpressions()[1]); + + self::assertArrayHasKey(sha1($first), $this->query->getFilterQueries()); + self::assertArrayHasKey(sha1($second), $this->query->getFilterQueries()); + } }