diff --git a/grammar/query.pp b/grammar/query.pp index cfd5b0f242..a71d8d3a98 100644 --- a/grammar/query.pp +++ b/grammar/query.pp @@ -27,9 +27,9 @@ %token except [Ee][Xx][Cc][Ee][Pp][Tt]|[Ss][Aa][Uu][Ff] // Rest +%token database database %token collection collection -%token recordid recordid -%token base base +%token id id|recordid %token word [^\s()\[\]:<>≤≥=]+ // relative order of precedence is NOT > XOR > AND > OR @@ -50,12 +50,12 @@ ternary: quaternary() ( ::space:: ::and:: ::space:: primary() #and )? -// Collection / recordid / base matcher +// Collection / database / record id matcher quaternary: - ::collection:: ::colon:: string() #collection - | ::recordid:: ::colon:: string() #recordid - | ::base:: ::colon:: string() #base + ::database:: ::colon:: string() #database + | ::collection:: ::colon:: string() #collection + | ::id:: ::colon:: string() #id | quinary() @@ -134,9 +134,9 @@ keyword: | | | + | | - | - | + | symbol: diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/BaseExpression.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/DatabaseExpression.php similarity index 59% rename from lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/BaseExpression.php rename to lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/DatabaseExpression.php index b26e6ff513..811b638349 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/BaseExpression.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/DatabaseExpression.php @@ -4,19 +4,19 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\AST; use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext; -class BaseExpression extends Node +class DatabaseExpression extends Node { - private $baseName; + private $database; - public function __construct($baseName) + public function __construct($database) { - $this->baseName = $baseName; + $this->database = $database; } public function buildQuery(QueryContext $context) { $query = array(); - $query['term']['databox_name'] = $this->baseName; + $query['term']['databox_name'] = $this->database; return $query; } @@ -28,6 +28,6 @@ class BaseExpression extends Node public function __toString() { - return sprintf('', $this->baseName); + return sprintf('', $this->database); } } diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/RecordidExpression.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/RecordIdentifierExpression.php similarity index 57% rename from lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/RecordidExpression.php rename to lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/RecordIdentifierExpression.php index 285290d46d..18da6a00d4 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/RecordidExpression.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/AST/RecordIdentifierExpression.php @@ -4,19 +4,19 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\AST; use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext; -class RecordidExpression extends Node +class RecordIdentifierExpression extends Node { - private $recordid; + private $record_id; - public function __construct($recordid) + public function __construct($record_id) { - $this->recordid = $recordid; + $this->record_id = $record_id; } public function buildQuery(QueryContext $context) { $query = array(); - $query['term']['record_id'] = $this->recordid; + $query['term']['record_id'] = $this->record_id; return $query; } @@ -28,6 +28,6 @@ class RecordidExpression extends Node public function __toString() { - return sprintf('', $this->recordid); + return sprintf('', $this->record_id); } } diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php index d7f3a8fb7a..684d957fad 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php @@ -71,16 +71,12 @@ class FacetsResponse implements JsonSerializable { switch($name) { case 'Collection': - $r = sprintf('collection:%s', $this->escaper->escapeWord($value)); - break; - case "Base": - $r = sprintf('base:%s', $this->escaper->escapeWord($value)); - break; + return sprintf('collection:%s', $this->escaper->escapeWord($value)); + case 'Base': + return sprintf('database:%s', $this->escaper->escapeWord($value)); default: - $r = sprintf('r"%s" IN %s', $this->escaper->escapeRaw($value), $name); - break; + return sprintf('r"%s" IN %s', $this->escaper->escapeRaw($value), $name); } - return $r; } private function throwAggregationResponseError() diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/NodeTypes.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/NodeTypes.php index febcfcbd2b..71ee841ebd 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/NodeTypes.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/NodeTypes.php @@ -22,8 +22,8 @@ class NodeTypes const TEXT = '#text'; const CONTEXT = '#context'; const COLLECTION = '#collection'; - const RECORDID = '#recordid'; - const BASE = '#base'; + const DATABASE = '#database'; + const IDENTIFIER = '#id'; // Token types for leaf nodes const TOKEN_WORD = 'word'; const TOKEN_QUOTED_STRING = 'quoted'; diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/QueryVisitor.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/QueryVisitor.php index 8baf4ea391..38861bd1ad 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/QueryVisitor.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/QueryVisitor.php @@ -82,14 +82,14 @@ class QueryVisitor implements Visit case NodeTypes::FIELD: return new AST\Field($this->visitString($element)); + case NodeTypes::DATABASE: + return $this->visitDatabaseNode($element); + case NodeTypes::COLLECTION: return $this->visitCollectionNode($element); - case NodeTypes::RECORDID: - return $this->visitRecordidNode($element); - - case NodeTypes::BASE: - return $this->visitBaseNode($element); + case NodeTypes::IDENTIFIER: + return $this->visitIdentifierNode($element); default: throw new \Exception(sprintf('Unknown node type "%s".', $element->getId())); @@ -259,6 +259,16 @@ class QueryVisitor implements Visit return implode($tokens); } + private function visitDatabaseNode(Element $element) + { + if ($element->getChildrenNumber() !== 1) { + throw new \Exception('Base filter can only have a single child.'); + } + $baseName = $element->getChild(0)->getValue()['value']; + + return new AST\DatabaseExpression($baseName); + } + private function visitCollectionNode(Element $element) { if ($element->getChildrenNumber() !== 1) { @@ -269,23 +279,13 @@ class QueryVisitor implements Visit return new AST\CollectionExpression($collectionName); } - private function visitRecordidNode(Element $element) + private function visitIdentifierNode(Element $element) { if ($element->getChildrenNumber() !== 1) { - throw new \Exception('Recordid filter can only have a single child.'); + throw new \Exception('Identifier filter can only have a single child.'); } - $recordid = $element->getChild(0)->getValue()['value']; + $identifier = $element->getChild(0)->getValue()['value']; - return new AST\RecordidExpression($recordid); - } - - private function visitBaseNode(Element $element) - { - if ($element->getChildrenNumber() !== 1) { - throw new \Exception('Base filter can only have a single child.'); - } - $baseName = $element->getChild(0)->getValue()['value']; - - return new AST\BaseExpression($baseName); + return new AST\RecordIdentifierExpression($identifier); } } diff --git a/tests/Alchemy/Tests/Phrasea/SearchEngine/resources/queries.csv b/tests/Alchemy/Tests/Phrasea/SearchEngine/resources/queries.csv index 7ef4b9a0b1..24e80869d4 100644 --- a/tests/Alchemy/Tests/Phrasea/SearchEngine/resources/queries.csv +++ b/tests/Alchemy/Tests/Phrasea/SearchEngine/resources/queries.csv @@ -70,8 +70,13 @@ fooINbar| collection:foo| collection:foo AND bar|( AND ) collection:foo bar| -recordid:90| -base:foo| +database:foo| +database:foo AND bar|( AND ) +database:foo bar| +id:90| +id:90 AND foo|( AND ) +id:90 foo| +recordid:90| # Matcher on unknown name --> fulltext foo:bar|