-
Notifications
You must be signed in to change notification settings - Fork 436
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Notable points: * Added support for `OR` queries. * Added support for nested `AND` and `OR` queries. * New Filter class under `Datastore/Query` namespace. * `Query::filter()` method now allows two different types of invocations.
- Loading branch information
Showing
9 changed files
with
680 additions
and
152 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
<?php | ||
/** | ||
* Copyright 2023 Google Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
namespace Google\Cloud\Datastore\Query; | ||
|
||
use Google\Cloud\Datastore\Query\Query; | ||
|
||
/** | ||
* Represents an interface to create composite and property filters for | ||
* Google\Cloud\Datastore\Query\Query via static methods. | ||
* | ||
* Each method returns an array representation of respective filter which is | ||
* consumed by other filters or Query object. | ||
* | ||
* Example: | ||
* ``` | ||
* $filter = Filter::where('CompanyName', '=', 'Google'); | ||
* $query = $datastore->query(); | ||
* $query->kind('Companies'); | ||
* $query->filter($filter); | ||
* $results = $datastore->runQuery($query); | ||
* $finalResult = []; | ||
* foreach ($results as $result) { | ||
* $finalResult[] = $result['companyName']; | ||
* } | ||
* ``` | ||
* | ||
* Composite filters can be created by using other composite/property | ||
* filters. | ||
* ``` | ||
* // Or filter | ||
* $filterType = 'or'; | ||
* $filterOr = Filter::or([$filter, ...$filters]); | ||
* $query = $datastore->query(); | ||
* $query->kind('Companies'); | ||
* $query->filter($filter); | ||
* $results = $datastore->runQuery($query); | ||
* $finalResult = []; | ||
* foreach ($results as $result) { | ||
* $finalResult[] = $result['companyName']; | ||
* } | ||
* ``` | ||
* | ||
* Similaryly, `AND` filter can be created using `Filter::and` method. | ||
*/ | ||
class Filter | ||
{ | ||
/** | ||
* Creates a property filter in array format. | ||
* | ||
* @param string $property Property name | ||
* @param string $operator Operator, one of ('=', '<', '<=', '>', '>=', | ||
* '!=', 'IN', 'NOT IN') | ||
* @param mixed $value Value for operation on property | ||
* @return array Returns array representation of a property filter. | ||
*/ | ||
public static function where($property, $operator, $value) | ||
{ | ||
return self::propertyFilter($property, $operator, $value); | ||
} | ||
|
||
/** | ||
* Creates an AND composite filter in array format. | ||
* | ||
* @param array $filters An array of filters(array representations) to AND | ||
* upon. | ||
* @return array Returns array representation of AND composite filter. | ||
*/ | ||
public static function and(array $filters) | ||
{ | ||
return self::compositeFilter('AND', $filters); | ||
} | ||
|
||
/** | ||
* Creates a OR composite filter in array format. | ||
* | ||
* @param array $filters An array of filters(array representations) to OR | ||
* upon. | ||
* @return array Returns array representation of OR composite filter. | ||
*/ | ||
public static function or(array $filters) | ||
{ | ||
return self::compositeFilter('OR', $filters); | ||
} | ||
|
||
private static function propertyFilter($property, $operator, $value) | ||
{ | ||
$filter = [ | ||
'propertyFilter' => [ | ||
'property' => $property, | ||
'value' => $value, | ||
'op' => $operator | ||
] | ||
]; | ||
return $filter; | ||
} | ||
|
||
/** | ||
* @param string $type Type of Composite Filter, i.e. `AND` / `OR`. | ||
* There values are checked in `Query::filter()` method. | ||
* @param array $filters Filter array to operator on. | ||
*/ | ||
private static function compositeFilter($type, $filters) | ||
{ | ||
$filter = [ | ||
'compositeFilter' => [ | ||
'op' => $type, | ||
'filters' => $filters | ||
] | ||
]; | ||
return $filter; | ||
} | ||
} |
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,114 @@ | ||
<?php | ||
|
||
namespace Google\Cloud\Datastore\Tests\Snippet; | ||
|
||
use Google\Cloud\Core\Testing\DatastoreOperationRefreshTrait; | ||
use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; | ||
use Google\Cloud\Core\Testing\TestHelpers; | ||
use Google\Cloud\Datastore\Connection\ConnectionInterface; | ||
use Google\Cloud\Datastore\DatastoreClient; | ||
use Google\Cloud\Datastore\EntityMapper; | ||
use Google\Cloud\Datastore\Operation; | ||
use Google\Cloud\Datastore\Query\Filter; | ||
use Google\Cloud\Datastore\Query\Query; | ||
use Google\Cloud\Datastore\Query\QueryInterface; | ||
use Prophecy\Argument; | ||
use Prophecy\PhpUnit\ProphecyTrait; | ||
|
||
class FilterTest extends SnippetTestCase | ||
{ | ||
use DatastoreOperationRefreshTrait; | ||
use ProphecyTrait; | ||
|
||
private const PROJECT = 'alpha-project'; | ||
private $connection; | ||
private $datastore; | ||
private $operation; | ||
private $query; | ||
private $filter; | ||
|
||
public function setUp(): void | ||
{ | ||
$entityMapper = new EntityMapper(self::PROJECT, false, false); | ||
|
||
$this->connection = $this->prophesize(ConnectionInterface::class); | ||
|
||
$this->datastore = TestHelpers::stub( | ||
DatastoreClient::class, | ||
[], | ||
['operation'] | ||
); | ||
|
||
$this->query = TestHelpers::stub(Query::class, [$entityMapper]); | ||
|
||
$this->filter = Filter::where('CompanyName', '=', 'Google'); | ||
} | ||
|
||
public function testFilter() | ||
{ | ||
$this->createConnectionProphecy(); | ||
|
||
$snippet = $this->snippetFromClass(Filter::class, 0); | ||
$snippet->addLocal('datastore', $this->datastore); | ||
$snippet->addLocal('query', $this->query); | ||
$snippet->addLocal('filter', $this->filter); | ||
$snippet->addUse(Filter::class); | ||
|
||
$res = $snippet->invoke('finalResult'); | ||
$this->assertEquals(['Google'], $res->returnVal()); | ||
} | ||
|
||
/** | ||
* @dataProvider getCompositeFilterTypes | ||
*/ | ||
public function testOrFilter($compositeFilterType) | ||
{ | ||
$this->createConnectionProphecy(); | ||
|
||
$snippet = $this->snippetFromClass(Filter::class, 1); | ||
$snippet->addLocal('filterType', $compositeFilterType); | ||
$snippet->addLocal('datastore', $this->datastore); | ||
$snippet->addLocal('query', $this->query); | ||
$snippet->addLocal('filter', $this->filter); | ||
$snippet->addLocal('filters', []); | ||
$snippet->addUse(Filter::class); | ||
|
||
$res = $snippet->invoke('finalResult'); | ||
$this->assertEquals(['Google'], $res->returnVal()); | ||
} | ||
|
||
public function getCompositeFilterTypes() | ||
{ | ||
return [ | ||
['or'], | ||
['and'] | ||
]; | ||
} | ||
|
||
private function createConnectionProphecy() | ||
{ | ||
$this->connection->runQuery(Argument::any()) | ||
->shouldBeCalled() | ||
->willReturn([ | ||
'batch' => [ | ||
'entityResults' => [ | ||
[ | ||
'entity' => [ | ||
'key' => ['path' => []], | ||
'properties' => [ | ||
'companyName' => [ | ||
'stringValue' => 'Google' | ||
] | ||
] | ||
] | ||
] | ||
], | ||
'moreResults' => 'no' | ||
] | ||
]); | ||
|
||
$this->refreshOperation($this->datastore, $this->connection->reveal(), [ | ||
'projectId' => self::PROJECT | ||
]); | ||
} | ||
} |
Oops, something went wrong.