From 66890a7dda00a233ab8d1864e92c967d36dc0917 Mon Sep 17 00:00:00 2001 From: Wade Womersley <155439365+wadedvsa@users.noreply.github.com> Date: Tue, 26 Mar 2024 10:19:48 +0000 Subject: [PATCH] feat: Transport manager deleted/merged search filters (dvsa/olcs-backend#124) * feat: Transport manager deleted/merged search filters * fix: ByConversation wrong field count * fix: Query tests --- .../Messaging/Message/ByConversation.php | 2 +- .../Db/src/Controller/SearchController.php | 2 +- .../Db/src/Service/Search/QueryTemplate.php | 76 +++++++++++-------- .../Olcs/Db/src/Service/Search/Search.php | 24 +++--- .../src/Service/Search/QueryTemplateTest.php | 67 +++++++++++----- 5 files changed, 105 insertions(+), 66 deletions(-) diff --git a/app/api/module/Api/src/Domain/QueryHandler/Messaging/Message/ByConversation.php b/app/api/module/Api/src/Domain/QueryHandler/Messaging/Message/ByConversation.php index 36ec0e223c..19d7276228 100644 --- a/app/api/module/Api/src/Domain/QueryHandler/Messaging/Message/ByConversation.php +++ b/app/api/module/Api/src/Domain/QueryHandler/Messaging/Message/ByConversation.php @@ -49,7 +49,7 @@ public function handleQuery(QueryInterface $query) $messages = $messageRepository->fetchPaginatedList($messagesQuery, Query::HYDRATE_ARRAY, $query); $messages = $messages->getArrayCopy(); - if ($query->getIncludeReadRoles() && count($query->getIncludeReadRoles()) > 0) { + if ($query->getIncludeReadRoles() && count($query->getReadRoles()) > 0) { $messages = $this->filterReadHistory($messages, $query->getReadRoles()); } diff --git a/app/api/module/Olcs/Db/src/Controller/SearchController.php b/app/api/module/Olcs/Db/src/Controller/SearchController.php index b97bf6a8a7..90c8d787d3 100644 --- a/app/api/module/Olcs/Db/src/Controller/SearchController.php +++ b/app/api/module/Olcs/Db/src/Controller/SearchController.php @@ -35,7 +35,7 @@ public function getList() $indices = explode('|', $params['index']); if (isset($params['filters']) && !empty($params['filters']) && is_array($params['filters'])) { - $this->elasticSearchService->setFilters($params['filters']); + $this->elasticSearchService->setFilters($params['filters'], $params['filterTypes'] ?? []); } if (!empty($params['dateRanges']) && is_array($params['dateRanges'])) { try { diff --git a/app/api/module/Olcs/Db/src/Service/Search/QueryTemplate.php b/app/api/module/Olcs/Db/src/Service/Search/QueryTemplate.php index 941f327478..fd33c42aa8 100644 --- a/app/api/module/Olcs/Db/src/Service/Search/QueryTemplate.php +++ b/app/api/module/Olcs/Db/src/Service/Search/QueryTemplate.php @@ -2,7 +2,9 @@ namespace Olcs\Db\Service\Search; +use DomainException; use Elastica\Query; +use RuntimeException; /** * Class QueryTemplate @@ -11,26 +13,24 @@ */ class QueryTemplate extends Query { - /** - * QueryTemplate constructor. - * - * @param string $filename Filename - * @param string $searchTerm Search term - * @param array $filters Filters - * @param array $dateRanges Date ranges - * - * @return void - */ - public function __construct($filename, $searchTerm, $filters = [], $dateRanges = []) - { + public const FILTER_TYPE_DYNAMIC = 'DYNAMIC'; + public const FILTER_TYPE_BOOLEAN = 'BOOLEAN'; + + public function __construct( + string $filename, + string $searchTerm, + array $filters = [], + array $filterTypes = [], + $dateRanges = [] + ) { if (!file_exists($filename)) { - throw new \RuntimeException("Query template file '" . $filename . "' is missing"); + throw new RuntimeException("Query template file '" . $filename . "' is missing"); } $searchTermReplace = json_encode($searchTerm); if ($searchTermReplace === false) { - throw new \RuntimeException( + throw new RuntimeException( "Search term '" . $searchTerm . "' gives invalid json. Error: " . json_last_error_msg() ); } @@ -45,38 +45,54 @@ public function __construct($filename, $searchTerm, $filters = [], $dateRanges = $this->_params = json_decode($template, true); if (empty($this->_params)) { - throw new \RuntimeException( + throw new RuntimeException( "Empty params for query template file '" . $filename . "' and search term '" . $searchTerm . "'" ); } // apply filters - $this->applyFilters($filters); + $this->applyFilters($filters, $filterTypes); // apply date ranges $this->applyDateRanges($dateRanges); } - /** - * Apply filters - * - * @param array $filters Filters - * - * @return $this - */ - private function applyFilters($filters) + private function applyFilters(array $filters, array $filterTypes): self { if (empty($filters)) { return $this; } foreach ($filters as $field => $value) { - if (!empty($field) && !empty($value)) { - $this->_params['query']['bool']['filter'][] = [ - 'term' => [ - $field => $value - ] - ]; + if (empty($field) || $value === '') { + continue; + } + + switch ($filterTypes[$field]) { + case self::FILTER_TYPE_DYNAMIC: + $this->_params['query']['bool']['filter'][] = [ + 'term' => [ + $field => $value, + ], + ]; + break; + case self::FILTER_TYPE_BOOLEAN: + if ((int)$value === 1) { + $this->_params['query']['bool']['must']['bool']['must'][] = [ + 'exists' => [ + 'field' => $field, + ], + ]; + } else { + $this->_params['query']['bool']['must_not'][] = [ + 'exists' => [ + 'field' => $field, + ], + ]; + } + break; + default: + throw new DomainException('Invalid filter type: ' . $filterTypes[$field]); } } diff --git a/app/api/module/Olcs/Db/src/Service/Search/Search.php b/app/api/module/Olcs/Db/src/Service/Search/Search.php index a3795f90d7..9577001efd 100644 --- a/app/api/module/Olcs/Db/src/Service/Search/Search.php +++ b/app/api/module/Olcs/Db/src/Service/Search/Search.php @@ -39,10 +39,9 @@ class Search implements AuthAwareInterface */ protected $sysParamRepo; - /** - * @var array - */ - protected $filters = []; + protected array $filters = []; + + protected array $filterTypes = []; /** * @var array @@ -143,7 +142,7 @@ public function search($query, $indexes = [], $page = 1, $limit = 10) if ($queryTemplate === false) { throw new \RuntimeException('Cannot generate an elasticsearch query, is the template missing'); } - $elasticaQuery = new QueryTemplate($queryTemplate, $query, $this->getFilters(), $this->getDateRanges()); + $elasticaQuery = new QueryTemplate($queryTemplate, $query, $this->getFilters(), $this->getFilterTypes(), $this->getDateRanges()); if (!empty($this->getSort()) && !empty($this->getOrder())) { $elasticaQuery->setSort([$this->getSort() => strtolower($this->getOrder())]); @@ -274,19 +273,18 @@ public function getFilters() return $this->filters; } - /** - * Sets the filters. - * - * @param array $filters Filters - * - * @return $this - */ - public function setFilters(array $filters) + public function getFilterTypes(): array + { + return $this->filterTypes; + } + + public function setFilters(array $filters, array $filterTypes = []): self { $f = new CamelCaseToUnderscore(); foreach ($filters as $filterName => $value) { $this->filters[strtolower($f->filter($filterName))] = $value; + $this->filterTypes[strtolower($f->filter($filterName))] = $filterTypes[$filterName] ?? QueryTemplate::FILTER_TYPE_DYNAMIC; } return $this; diff --git a/app/api/test/module/Olcs/Db/src/Service/Search/QueryTemplateTest.php b/app/api/test/module/Olcs/Db/src/Service/Search/QueryTemplateTest.php index c2cc1aac5e..3b161209f5 100644 --- a/app/api/test/module/Olcs/Db/src/Service/Search/QueryTemplateTest.php +++ b/app/api/test/module/Olcs/Db/src/Service/Search/QueryTemplateTest.php @@ -21,9 +21,9 @@ public function testQueryTemplateMissing() /** * @dataProvider queryTemplateDataProvider */ - public function testQueryTemplate($query, $filters, $dates, $expected) + public function testQueryTemplate($query, $filters, $filterTypes, $dates, $expected) { - $sut = new QueryTemplate(__DIR__ . '/mock-query-template.json', $query, $filters, $dates); + $sut = new QueryTemplate(__DIR__ . '/mock-query-template.json', $query, $filters, $filterTypes, $dates); $this->assertEquals($expected, $sut->getParam('query')); } @@ -33,7 +33,8 @@ public function queryTemplateDataProvider() // simple query [ 'SMITH', - null, + [], + [], null, [ 'bool' => [ @@ -54,7 +55,8 @@ public function queryTemplateDataProvider() // query with special chars [ 'SM"\das\'[]{}ITH', - null, + [], + [], null, [ 'bool' => [ @@ -75,7 +77,8 @@ public function queryTemplateDataProvider() // query empty [ '', - null, + [], + [], null, [ 'bool' => [ @@ -96,7 +99,8 @@ public function queryTemplateDataProvider() // query single " (double quote) [ '"', - null, + [], + [], null, [ 'bool' => [ @@ -117,7 +121,8 @@ public function queryTemplateDataProvider() // query double " (double quote) [ '""', - null, + [], + [], null, [ 'bool' => [ @@ -138,7 +143,8 @@ public function queryTemplateDataProvider() // query ending with " (double quote) [ '"SMITH"', - null, + [], + [], null, [ 'bool' => [ @@ -159,7 +165,8 @@ public function queryTemplateDataProvider() // query json [ '{"key":"value"}', - null, + [], + [], null, [ 'bool' => [ @@ -181,9 +188,12 @@ public function queryTemplateDataProvider() [ 'SMITH', [ - 'field_1' => 'value1' + 'field_1' => 'value1', ], - null, + [ + 'field_1' => 'DYNAMIC', + ], + [], [ 'bool' => [ 'must' => [ @@ -213,9 +223,14 @@ public function queryTemplateDataProvider() [ 'field_1' => 'value1', 'field_2' => 'value2', - 'field_3' => 'value3', + 'field_3' => '0', ], - null, + [ + 'field_1' => 'DYNAMIC', + 'field_2' => 'DYNAMIC', + 'field_3' => 'BOOLEAN', + ], + [], [ 'bool' => [ 'must' => [ @@ -240,19 +255,22 @@ public function queryTemplateDataProvider() 'field_2' => 'value2' ] ], - [ - 'term' => [ - 'field_3' => 'value3' + ], + 'must_not' => [ + 0 => [ + 'exists' => [ + 'field' => 'field_3', ] - ] - ] + ], + ], ] ] ], // query with from_and_to date range [ 'SMITH', - null, + [], + [], [ 'field_1_from_and_to' => '2010-09-30' ], @@ -282,7 +300,8 @@ public function queryTemplateDataProvider() // query with from only date range [ 'SMITH', - null, + [], + [], [ 'field_1_from' => '2010-09-30' ], @@ -312,7 +331,8 @@ public function queryTemplateDataProvider() // query with from and to date range [ 'SMITH', - null, + [], + [], [ 'field_1_from' => '2010-09-30', 'field_1_to' => '2010-10-30' @@ -348,6 +368,11 @@ public function queryTemplateDataProvider() 'field_2' => 'value2', 'field_3' => 'value3', ], + [ + 'field_1' => 'DYNAMIC', + 'field_2' => 'DYNAMIC', + 'field_3' => 'DYNAMIC', + ], [ 'field_1_from_and_to' => '2010-09-30', 'field_2_from' => '2010-09-30',