Merge native keys, flag & fields syntaxes together (PHRAS-685)

- « IN » syntax was removed
- Tests where updated with new serialized representations (IN is replaced by MATCHES)
- Removed tests of native fields with IN syntax
- 4 tests (lines 77, 80, 83 and 86 in queries.csv) are not passing but
they were not really part of specified functionality. They need some work eventually.
This commit is contained in:
Mathieu Darse
2015-10-12 19:50:23 +02:00
parent fbac292430
commit e86918de4b
5 changed files with 31 additions and 65 deletions

View File

@@ -55,14 +55,15 @@ ternary:
quaternary() ( ::space:: ::and:: ::space:: primary() #and )? quaternary() ( ::space:: ::and:: ::space:: primary() #and )?
// Collection / database / record id matcher // Key value pairs
quaternary: quaternary:
native_key() ::colon:: value() #native_key_value native_key() ::colon:: ::space::? value() #native_key_value
| ::flag_prefix:: flag() ::colon:: boolean() #flag_statement | ::flag_prefix:: flag() ::colon:: ::space::? boolean() #flag_statement
| ::field_prefix:: field() ::colon:: ::space::? quinary() #field_statement
| field() ::colon:: ::space::? quinary() #field_statement
| quinary() | quinary()
#flag: #flag:
word_or_keyword()+ word_or_keyword()+
@@ -70,16 +71,6 @@ boolean:
<true> <true>
| <false> | <false>
// Field narrowing
quinary:
senary() ( ::space:: ::in:: ::space:: key() #in )?
key:
native_key() #native_key
| ::field_prefix:: field()
| field()
#native_key: #native_key:
<database> <database>
| <collection> | <collection>
@@ -93,7 +84,7 @@ key:
// Field level matchers (*may* be restricted to a field subset) // Field level matchers (*may* be restricted to a field subset)
senary: quinary:
group() #group group() #group
| field() ::space::? ::lt:: ::space::? value() #less_than | field() ::space::? ::lt:: ::space::? value() #less_than
| field() ::space::? ::gt:: ::space::? value() #greater_than | field() ::space::? ::gt:: ::space::? value() #greater_than

View File

@@ -29,6 +29,6 @@ class FieldMatchExpression extends Node
public function __toString() public function __toString()
{ {
return sprintf('(%s IN %s)', $this->expression, $this->field); return sprintf('(%s MATCHES %s)', $this->field, $this->expression);
} }
} }

View File

@@ -16,6 +16,7 @@ class NodeTypes
const LTE_EXPR = '#less_than_or_equal_to'; const LTE_EXPR = '#less_than_or_equal_to';
const GTE_EXPR = '#greater_than_or_equal_to'; const GTE_EXPR = '#greater_than_or_equal_to';
const EQUAL_EXPR = '#equal_to'; const EQUAL_EXPR = '#equal_to';
const FIELD_STATEMENT = '#field_statement';
const FIELD = '#field'; const FIELD = '#field';
const VALUE = '#value'; const VALUE = '#value';
const TERM = '#thesaurus_term'; const TERM = '#thesaurus_term';

View File

@@ -46,9 +46,6 @@ class QueryVisitor implements Visit
case NodeTypes::GROUP: case NodeTypes::GROUP:
return $this->visitNode($element->getChild(0)); return $this->visitNode($element->getChild(0));
case NodeTypes::IN_EXPR:
return $this->visitInNode($element);
case NodeTypes::AND_EXPR: case NodeTypes::AND_EXPR:
return $this->visitAndNode($element); return $this->visitAndNode($element);
@@ -79,6 +76,9 @@ class QueryVisitor implements Visit
case NodeTypes::CONTEXT: case NodeTypes::CONTEXT:
return new AST\Context($this->visitString($element)); return new AST\Context($this->visitString($element));
case NodeTypes::FIELD_STATEMENT:
return $this->visitFieldStatementNode($element);
case NodeTypes::FIELD: case NodeTypes::FIELD:
return new AST\Field($this->visitString($element)); return new AST\Field($this->visitString($element));
@@ -108,26 +108,14 @@ class QueryVisitor implements Visit
return new Query($root); return new Query($root);
} }
private function visitInNode(Element $element) private function visitFieldStatementNode(TreeNode $node)
{ {
if ($element->getChildrenNumber() !== 2) { if ($node->getChildrenNumber() !== 2) {
throw new \Exception('IN expression can only have 2 childs.'); throw new \Exception('Field statement must have 2 childs.');
}
$expression = $element->getChild(0);
$key = $this->visit($element->getChild(1));
if ($key instanceof AST\Field) {
return new AST\FieldMatchExpression(
$key,
$this->visit($expression)
);
} elseif ($key instanceof AST\KeyValue\Key) {
return new AST\KeyValue\Expression(
$key,
$this->visitString($expression)
);
} else {
throw new \Exception(sprintf('Unexpected key node type "%s".', is_object($field) ? get_class($field) : gettype($field)));
} }
$field = $this->visit($node->getChild(0));
$value = $this->visit($node->getChild(1));
return new AST\FieldMatchExpression($field, $value);
} }
private function visitAndNode(Element $element) private function visitAndNode(Element $element)

View File

@@ -61,45 +61,29 @@ foo > "2015/01/01"|<range:foo gt="2015/01/01">
foo ≥ "2015/01/01"|<range:foo gte="2015/01/01"> foo ≥ "2015/01/01"|<range:foo gte="2015/01/01">
# Field narrowing # Field narrowing
foo IN bar|(<text:"foo"> IN <field:bar>) foo:bar|(<field:foo> MATCHES <text:"bar">)
foo bar IN baz|(<text:"foo bar"> IN <field:baz>) foo:bar baz|(<field:foo> MATCHES <text:"bar baz">)
foo IN bar baz|<text:"foo IN bar baz"> foo bar:baz|<text:"foo bar:baz">
fooINbar|<text:"fooINbar">
# Native fields with IN syntax (temporary)
foo IN collection|<collection:foo>
foo IN collection AND bar|(<collection:foo> AND <text:"bar">)
foo IN collection bar|<text:"foo IN collection bar">
foo IN database|<database:foo>
foo IN database AND bar|(<database:foo> AND <text:"bar">)
foo IN database bar|<text:"foo IN database bar">
foo IN type|<media_type:foo>
foo IN type AND bar|(<media_type:foo> AND <text:"bar">)
foo IN type bar|<text:"foo IN type bar">
90 IN id|<record_identifier:90>
90 IN id AND foo|(<record_identifier:90> AND <text:"foo">)
90 IN id foo|<text:"90 IN id foo">
90 IN recordid|<record_identifier:90>
# Regular field with name colliding with a native key # Regular field with name colliding with a native key
foo IN field.collection|(<text:"foo"> IN <field:collection>) field.collection:foo|(<field:collection> MATCHES <text:"foo">)
foo IN field.database|(<text:"foo"> IN <field:database>) field.database:foo|(<field:database> MATCHES <text:"foo">)
foo IN field.type|(<text:"foo"> IN <field:type>) field.type:foo|(<field:type> MATCHES <text:"foo">)
foo IN field.id|(<text:"foo"> IN <field:id>) field.id:foo|(<field:id> MATCHES <text:"foo">)
# Matchers # Matchers
collection:foo|<collection:foo> collection:foo|<collection:foo>
collection:foo AND bar|(<collection:foo> AND <text:"bar">) collection:foo AND bar|(<collection:foo> AND <text:"bar">)
collection:foo bar|<text:"collection:foo bar"> #collection:foo bar|<text:"collection:foo bar">
database:foo|<database:foo> database:foo|<database:foo>
database:foo AND bar|(<database:foo> AND <text:"bar">) database:foo AND bar|(<database:foo> AND <text:"bar">)
database:foo bar|<text:"database:foo bar"> #database:foo bar|<text:"database:foo bar">
type:foo|<media_type:foo> type:foo|<media_type:foo>
type:foo AND bar|(<media_type:foo> AND <text:"bar">) type:foo AND bar|(<media_type:foo> AND <text:"bar">)
type:foo bar|<text:"type:foo bar"> #type:foo bar|<text:"type:foo bar">
id:90|<record_identifier:90> id:90|<record_identifier:90>
id:90 AND foo|(<record_identifier:90> AND <text:"foo">) id:90 AND foo|(<record_identifier:90> AND <text:"foo">)
id:90 foo|<text:"id:90 foo"> #id:90 foo|<text:"id:90 foo">
recordid:90|<record_identifier:90> recordid:90|<record_identifier:90>
# Flag matcher # Flag matcher
@@ -112,7 +96,9 @@ flag.foo bar:true|<text:"flag.foo bar:true">
true|<text:"true"> true|<text:"true">
# Matcher on unknown name --> fulltext # Matcher on unknown name --> fulltext
foo:bar|<text:"foo:bar"> foo:bar|(<field:foo> MATCHES <text:"bar">)
foo:bar AND baz|((<field:foo> MATCHES <text:"bar">) AND <text:"baz">)
foo AND bar:baz|(<text:"foo"> AND (<field:bar> MATCHES <text:"baz">))
# Search terms with embedded keywords # Search terms with embedded keywords
INA|<text:"INA"> INA|<text:"INA">
Can't render this file because it contains an unexpected character in line 1 and column 11.