mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-17 15:03:25 +00:00
Merge pull request #1564 from mdarse/query-on-exif
Query support for metadata tags
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\SearchEngine\AST;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\EqualExpression;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\Key;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Field as StructureField;
|
||||
|
||||
/**
|
||||
* @group unit
|
||||
* @group searchengine
|
||||
* @group ast
|
||||
*/
|
||||
class EqualExpressionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSerialization()
|
||||
{
|
||||
$this->assertTrue(method_exists(EqualExpression::class, '__toString'), 'Class does not have method __toString');
|
||||
$key = $this->prophesize(Key::class);
|
||||
$key->__toString()->willReturn('foo');
|
||||
$node = new EqualExpression($key->reveal(), 'bar');
|
||||
$this->assertEquals('(<foo> == <value:"bar">)', (string) $node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider queryProvider
|
||||
*/
|
||||
public function testQueryBuild($index_field, $value, $compatible_value, $private, $expected_json)
|
||||
{
|
||||
$query_context = $this->prophesize(QueryContext::class)->reveal();
|
||||
|
||||
$key = $this->prophesize(Key::class);
|
||||
$key->isValueCompatible($value, $query_context)->willReturn($compatible_value);
|
||||
$key->getIndexField($query_context, true)->willReturn($index_field);
|
||||
$key->__toString()->willReturn('foo');
|
||||
// TODO Test keys implementing QueryPostProcessor
|
||||
|
||||
$node = new EqualExpression($key->reveal(), 'bar');
|
||||
$query = $node->buildQuery($query_context);
|
||||
|
||||
$this->assertEquals(json_decode($expected_json, true), $query);
|
||||
}
|
||||
|
||||
public function queryProvider()
|
||||
{
|
||||
return [
|
||||
// TODO Put this case in another test case
|
||||
// ['foo.raw', 'bar', true, true, '{
|
||||
// "filtered": {
|
||||
// "filter": {
|
||||
// "terms": {
|
||||
// "base_id": ["baz","qux"] } },
|
||||
// "query": {
|
||||
// "term": {
|
||||
// "foo.raw": "bar" } } } }'],
|
||||
['foo.raw', 'bar', true, false, '{
|
||||
"term": {
|
||||
"foo.raw": "bar" } }'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Alchemy\Phrasea\SearchEngine\Elastic\Exception\QueryException
|
||||
* @expectedExceptionMessageRegExp #"foo"#u
|
||||
*/
|
||||
public function testQueryBuildWithIncompatibleValue()
|
||||
{
|
||||
$query_context = $this->prophesize(QueryContext::class)->reveal();
|
||||
$key = $this->prophesize(Key::class);
|
||||
$key->isValueCompatible('bar', $query_context)->willReturn(false);
|
||||
$key->getIndexField($query_context, true)->willReturn('foo.raw');
|
||||
$key->__toString()->willReturn('foo');
|
||||
|
||||
$node = new EqualExpression($key->reveal(), 'bar');
|
||||
$node->buildQuery($query_context);
|
||||
}
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\SearchEngine\AST;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\Field as ASTField;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\FieldEqualsExpression;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Field as StructureField;
|
||||
|
||||
/**
|
||||
* @group unit
|
||||
* @group searchengine
|
||||
* @group ast
|
||||
*/
|
||||
class FieldEqualsExpressionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSerialization()
|
||||
{
|
||||
$this->assertTrue(method_exists(FieldEqualsExpression::class, '__toString'), 'Class does not have method __toString');
|
||||
$field = $this->prophesize(ASTField::class);
|
||||
$field->__toString()->willReturn('foo');
|
||||
$node = new FieldEqualsExpression($field->reveal(), 'bar');
|
||||
$this->assertEquals('(foo == <value:"bar">)', (string) $node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider queryProvider
|
||||
*/
|
||||
public function testQueryBuild($index_field, $value, $compatible_value, $private, $expected_json)
|
||||
{
|
||||
$structure_field = $this->prophesize(StructureField::class);
|
||||
$structure_field->isValueCompatible($value)->willReturn($compatible_value);
|
||||
$structure_field->getIndexField(true)->willReturn($index_field);
|
||||
$structure_field->isPrivate()->willReturn($private);
|
||||
if ($private) {
|
||||
$structure_field->getDependantCollections()->willReturn(['baz', 'qux']);
|
||||
}
|
||||
|
||||
$ast_field = $this->prophesize(ASTField::class);
|
||||
$query_context = $this->prophesize(QueryContext::class);
|
||||
$query_context->get($ast_field->reveal())->willReturn($structure_field);
|
||||
|
||||
$node = new FieldEqualsExpression($ast_field->reveal(), 'bar');
|
||||
$query = $node->buildQuery($query_context->reveal());
|
||||
|
||||
$this->assertEquals(json_decode($expected_json, true), $query);
|
||||
}
|
||||
|
||||
public function queryProvider()
|
||||
{
|
||||
return [
|
||||
['foo.raw', 'bar', true, true, '{
|
||||
"filtered": {
|
||||
"filter": {
|
||||
"terms": {
|
||||
"base_id": ["baz","qux"] } },
|
||||
"query": {
|
||||
"term": {
|
||||
"foo.raw": "bar" } } } }'],
|
||||
['foo.raw', 'bar', true, false, '{
|
||||
"term": {
|
||||
"foo.raw": "bar" } }'],
|
||||
['foo.raw', 'bar', false, true, 'null'],
|
||||
['foo.raw', 'bar', false, false, 'null'],
|
||||
];
|
||||
}
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\SearchEngine\AST;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\Key;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\Expression as KeyValueExpression;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext;
|
||||
|
||||
/**
|
||||
* @group unit
|
||||
* @group searchengine
|
||||
* @group ast
|
||||
*/
|
||||
class KeyValueExpressionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSerialization()
|
||||
{
|
||||
$this->assertTrue(method_exists(KeyValueExpression::class, '__toString'), 'Class does not have method __toString');
|
||||
$key = $this->prophesize(Key::class);
|
||||
$key->__toString()->willReturn('foo');
|
||||
$node = new KeyValueExpression($key->reveal(), 'bar');
|
||||
$this->assertEquals('<foo:bar>', (string) $node);
|
||||
}
|
||||
|
||||
public function testQueryBuild()
|
||||
{
|
||||
$query_context = $this->prophesize(QueryContext::class);
|
||||
$key = $this->prophesize(Key::class);
|
||||
$key->buildQueryForValue('bar', $query_context->reveal())->willReturn('baz');
|
||||
|
||||
$node = new KeyValueExpression($key->reveal(), 'bar');
|
||||
$query = $node->buildQuery($query_context->reveal());
|
||||
$this->assertEquals('baz', $query);
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\SearchEngine\AST;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\Key;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\MatchExpression;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\MetadataKey;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\NativeKey;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext;
|
||||
|
||||
/**
|
||||
* @group unit
|
||||
* @group searchengine
|
||||
* @group ast
|
||||
*/
|
||||
class MatchExpressionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSerialization()
|
||||
{
|
||||
$this->assertTrue(method_exists(MatchExpression::class, '__toString'), 'Class does not have method __toString');
|
||||
$key = $this->prophesize(Key::class);
|
||||
$key->__toString()->willReturn('foo');
|
||||
$node = new MatchExpression($key->reveal(), 'bar');
|
||||
$this->assertEquals('<foo:"bar">', (string) $node);
|
||||
}
|
||||
|
||||
public function testQueryBuild()
|
||||
{
|
||||
$query_context = $this->prophesize(QueryContext::class)->reveal();
|
||||
$key = $this->prophesize(Key::class);
|
||||
$key->isValueCompatible('bar', $query_context)->willReturn(true);
|
||||
$key->getIndexField($query_context)->willReturn('foo');
|
||||
$node = new MatchExpression($key->reveal(), 'bar');
|
||||
$query = $node->buildQuery($query_context);
|
||||
|
||||
$result = '{"match":{"foo": "bar"}}';
|
||||
$this->assertEquals(json_decode($result, true), $query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider keyProvider
|
||||
*/
|
||||
public function testNativeQueryBuild($key, $value, $result)
|
||||
{
|
||||
$query_context = $this->prophesize(QueryContext::class);
|
||||
$node = new MatchExpression($key, $value);
|
||||
$query = $node->buildQuery($query_context->reveal());
|
||||
$this->assertEquals(json_decode($result, true), $query);
|
||||
}
|
||||
|
||||
public function keyProvider()
|
||||
{
|
||||
return [
|
||||
[NativeKey::database(), 'foo', '{"match":{"databox_name": "foo"}}'],
|
||||
[NativeKey::collection(), 'bar', '{"match":{"collection_name": "bar"}}'],
|
||||
[NativeKey::mediaType(), 'baz', '{"match":{"type": "baz"}}'],
|
||||
[NativeKey::recordIdentifier(), 'qux', '{"match":{"record_id": "qux"}}'],
|
||||
];
|
||||
}
|
||||
}
|
@@ -21,63 +21,22 @@ class NativeKeyTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('record_identifier', (string) NativeKey::recordIdentifier());
|
||||
}
|
||||
|
||||
public function testDatabaseQuery()
|
||||
/**
|
||||
* @dataProvider keyProvider
|
||||
*/
|
||||
public function testGetIndexField($key, $field)
|
||||
{
|
||||
$query_context = $this->prophesize(QueryContext::class);
|
||||
$key = NativeKey::database();
|
||||
$query = $key->buildQueryForValue('bar', $query_context->reveal());
|
||||
|
||||
$expected = '{
|
||||
"term": {
|
||||
"databox_name": "bar"
|
||||
}
|
||||
}';
|
||||
|
||||
$this->assertEquals(json_decode($expected, true), $query);
|
||||
$this->assertEquals($key->getIndexField($query_context->reveal()), $field);
|
||||
}
|
||||
|
||||
public function testCollectionQuery()
|
||||
public function keyProvider()
|
||||
{
|
||||
$query_context = $this->prophesize(QueryContext::class);
|
||||
$key = NativeKey::collection();
|
||||
$query = $key->buildQueryForValue('bar', $query_context->reveal());
|
||||
|
||||
$expected = '{
|
||||
"term": {
|
||||
"collection_name": "bar"
|
||||
}
|
||||
}';
|
||||
|
||||
$this->assertEquals(json_decode($expected, true), $query);
|
||||
}
|
||||
|
||||
public function testMediaTypeQuery()
|
||||
{
|
||||
$query_context = $this->prophesize(QueryContext::class);
|
||||
$key = NativeKey::mediaType();
|
||||
$query = $key->buildQueryForValue('bar', $query_context->reveal());
|
||||
|
||||
$expected = '{
|
||||
"term": {
|
||||
"type": "bar"
|
||||
}
|
||||
}';
|
||||
|
||||
$this->assertEquals(json_decode($expected, true), $query);
|
||||
}
|
||||
|
||||
public function testRecordIdentifierQuery()
|
||||
{
|
||||
$query_context = $this->prophesize(QueryContext::class);
|
||||
$key = NativeKey::recordIdentifier();
|
||||
$query = $key->buildQueryForValue('bar', $query_context->reveal());
|
||||
|
||||
$expected = '{
|
||||
"term": {
|
||||
"record_id": "bar"
|
||||
}
|
||||
}';
|
||||
|
||||
$this->assertEquals(json_decode($expected, true), $query);
|
||||
return [
|
||||
[NativeKey::database(), 'databox_name'],
|
||||
[NativeKey::collection(), 'collection_name'],
|
||||
[NativeKey::mediaType(), 'type'],
|
||||
[NativeKey::recordIdentifier(), 'record_id']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\SearchEngine\AST;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\Key;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\FieldKey;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\MetadataKey;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\NativeKey;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue\RangeExpression;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Field;
|
||||
use Prophecy\Argument;
|
||||
|
||||
/**
|
||||
* @group unit
|
||||
* @group searchengine
|
||||
* @group ast
|
||||
*/
|
||||
class RangeExpressionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSerializability()
|
||||
{
|
||||
$this->assertTrue(method_exists(RangeExpression::class, '__toString'), 'Class does not have method __toString');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider serializationProvider
|
||||
*/
|
||||
public function testSerialization($expression, $serialization)
|
||||
{
|
||||
$this->assertEquals($serialization, (string) $expression);
|
||||
}
|
||||
|
||||
public function serializationProvider()
|
||||
{
|
||||
$key_prophecy = $this->prophesize(Key::class);
|
||||
$key_prophecy->__toString()->willReturn('foo');
|
||||
$key = $key_prophecy->reveal();
|
||||
return [
|
||||
[RangeExpression::lessThan($key, 42), '<range:foo lt="42">' ],
|
||||
[RangeExpression::lessThanOrEqual($key, 42), '<range:foo lte="42">'],
|
||||
[RangeExpression::greaterThan($key, 42), '<range:foo gt="42">' ],
|
||||
[RangeExpression::greaterThanOrEqual($key, 42), '<range:foo gte="42">'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider queryProvider
|
||||
*/
|
||||
public function testQueryBuild($factory, $query_context, $key, $value, $result)
|
||||
{
|
||||
$node = RangeExpression::$factory($key, $value);
|
||||
$query = $node->buildQuery($query_context);
|
||||
$this->assertEquals(json_decode($result, true), $query);
|
||||
}
|
||||
|
||||
public function queryProvider()
|
||||
{
|
||||
$query_context = $this->prophesize(QueryContext::class)->reveal();
|
||||
$key_prophecy = $this->prophesize(Key::class);
|
||||
$key_prophecy->getIndexField($query_context)->willReturn('foo');
|
||||
$key_prophecy->isValueCompatible('bar', $query_context)->willReturn(true);
|
||||
$key = $key_prophecy->reveal();
|
||||
return [
|
||||
['lessThan', $query_context, $key, 'bar', '{"range":{"foo": {"lt":"bar"}}}'],
|
||||
['lessThanOrEqual', $query_context, $key, 'bar', '{"range":{"foo": {"lte":"bar"}}}'],
|
||||
['greaterThan', $query_context, $key, 'bar', '{"range":{"foo": {"gt":"bar"}}}'],
|
||||
['greaterThanOrEqual', $query_context, $key, 'bar', '{"range":{"foo": {"gte":"bar"}}}'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testQueryBuildWithFieldKey()
|
||||
{
|
||||
$query_context = $this->prophesize(QueryContext::class)->reveal();
|
||||
$key = $this->prophesize(FieldKey::class);
|
||||
$key->getIndexField($query_context)->willReturn('baz');
|
||||
$key->isValueCompatible('bar', $query_context)->willReturn(true);
|
||||
$key->postProcessQuery(Argument::any(), $query_context)->willReturnArgument(0);
|
||||
|
||||
$node = RangeExpression::lessThan($key->reveal(), 'bar');
|
||||
$query = $node->buildQuery($query_context);
|
||||
|
||||
$expected = '{
|
||||
"range": {
|
||||
"baz": {
|
||||
"lt": "bar"
|
||||
}
|
||||
}
|
||||
}';
|
||||
|
||||
$this->assertEquals(json_decode($expected, true), $query);
|
||||
}
|
||||
}
|
@@ -24,6 +24,7 @@ class RawNodeTest extends \PHPUnit_Framework_TestCase
|
||||
public function testQueryBuildOnSingleField()
|
||||
{
|
||||
$field = $this->prophesize(Field::class);
|
||||
$field->getType()->willReturn(Mapping::TYPE_STRING);
|
||||
$field->getIndexField(true)->willReturn('foo.raw');
|
||||
|
||||
$query_context = $this->prophesize(QueryContext::class);
|
||||
@@ -45,8 +46,10 @@ class RawNodeTest extends \PHPUnit_Framework_TestCase
|
||||
public function testQueryBuildOnMultipleFields()
|
||||
{
|
||||
$field_a = $this->prophesize(Field::class);
|
||||
$field_a->getType()->willReturn(Mapping::TYPE_STRING);
|
||||
$field_a->getIndexField(true)->willReturn('foo.raw');
|
||||
$field_b = $this->prophesize(Field::class);
|
||||
$field_b->getType()->willReturn(Mapping::TYPE_STRING);
|
||||
$field_b->getIndexField(true)->willReturn('bar.raw');
|
||||
|
||||
$query_context = $this->prophesize(QueryContext::class);
|
||||
|
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\SearchEngine\Structure;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Mapping;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\ValueChecker;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Typed;
|
||||
|
||||
/**
|
||||
* @group unit
|
||||
* @group structure
|
||||
*/
|
||||
class ValueCheckerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider escapeRawProvider
|
||||
*/
|
||||
public function testValueCompatibility($subject, $value, $compatible)
|
||||
{
|
||||
$this->assertEquals($compatible, ValueChecker::isValueCompatible($subject, $value));
|
||||
}
|
||||
|
||||
public function escapeRawProvider()
|
||||
{
|
||||
$values = [
|
||||
[Mapping::TYPE_FLOAT , 42 , true ],
|
||||
[Mapping::TYPE_FLOAT , '42' , true ],
|
||||
[Mapping::TYPE_FLOAT , '42foo' , false],
|
||||
[Mapping::TYPE_FLOAT , 'foo' , false],
|
||||
[Mapping::TYPE_DOUBLE , 42 , true ],
|
||||
[Mapping::TYPE_DOUBLE , '42' , true ],
|
||||
[Mapping::TYPE_DOUBLE , '42foo' , false],
|
||||
[Mapping::TYPE_DOUBLE , 'foo' , false],
|
||||
[Mapping::TYPE_INTEGER, 42 , true ],
|
||||
[Mapping::TYPE_INTEGER, '42' , true ],
|
||||
[Mapping::TYPE_INTEGER, '42foo' , false],
|
||||
[Mapping::TYPE_INTEGER, 'foo' , false],
|
||||
[Mapping::TYPE_LONG , 42 , true ],
|
||||
[Mapping::TYPE_LONG , '42' , true ],
|
||||
[Mapping::TYPE_LONG , '42foo' , false],
|
||||
[Mapping::TYPE_LONG , 'foo' , false],
|
||||
[Mapping::TYPE_SHORT , 42 , true ],
|
||||
[Mapping::TYPE_SHORT , '42' , true ],
|
||||
[Mapping::TYPE_SHORT , '42foo' , false],
|
||||
[Mapping::TYPE_SHORT , 'foo' , false],
|
||||
[Mapping::TYPE_BYTE , 42 , true ],
|
||||
[Mapping::TYPE_BYTE , '42' , true ],
|
||||
[Mapping::TYPE_BYTE , '42foo' , false],
|
||||
[Mapping::TYPE_BYTE , 'foo' , false],
|
||||
|
||||
[Mapping::TYPE_STRING , 'foo' , true ],
|
||||
[Mapping::TYPE_STRING , '42' , true ],
|
||||
[Mapping::TYPE_STRING , 42 , true ],
|
||||
|
||||
[Mapping::TYPE_BOOLEAN, true , true ],
|
||||
[Mapping::TYPE_BOOLEAN, false , true ],
|
||||
[Mapping::TYPE_BOOLEAN, 'yes' , true ],
|
||||
[Mapping::TYPE_BOOLEAN, 'no' , true ],
|
||||
[Mapping::TYPE_BOOLEAN, 'foo' , true ],
|
||||
[Mapping::TYPE_BOOLEAN, 42 , true ],
|
||||
|
||||
[Mapping::TYPE_DATE , '2015/01/01' , true ],
|
||||
[Mapping::TYPE_DATE , '2015/01/01 00:00:00', false],
|
||||
[Mapping::TYPE_DATE , 'foo' , false],
|
||||
];
|
||||
|
||||
foreach ($values as &$value) {
|
||||
$value[0] = $this->createTypedMock($value[0]);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
private function createTypedMock($type)
|
||||
{
|
||||
$typed = $this->prophesize(Typed::class);
|
||||
$typed->getType()->willReturn($type)->shouldBeCalled();
|
||||
return $typed->reveal();
|
||||
}
|
||||
}
|
@@ -49,21 +49,21 @@ foo EXCEPT (bar OR baz)|(<text:"foo"> EXCEPT (<text:"bar"> OR <text:"baz">))
|
||||
foo EXCEPT (bar EXCEPT baz)|(<text:"foo"> EXCEPT (<text:"bar"> EXCEPT <text:"baz">))
|
||||
|
||||
# Comparison operators
|
||||
foo < 42|<range:foo lt="42">
|
||||
foo ≤ 42|<range:foo lte="42">
|
||||
foo > 42|<range:foo gt="42">
|
||||
foo ≥ 42|<range:foo gte="42">
|
||||
foo < 2015/01/01|<range:foo lt="2015/01/01">
|
||||
foo ≤ 2015/01/01|<range:foo lte="2015/01/01">
|
||||
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 lt="2015/01/01">
|
||||
foo ≤ "2015/01/01"|<range:foo lte="2015/01/01">
|
||||
foo > "2015/01/01"|<range:foo gt="2015/01/01">
|
||||
foo ≥ "2015/01/01"|<range:foo gte="2015/01/01">
|
||||
foo = 42|(<field:foo> == <value:"42">)
|
||||
foo = bar|(<field:foo> == <value:"bar">)
|
||||
foo = "bar"|(<field:foo> == <value:"bar">)
|
||||
foo < 42|<range:field.foo lt="42">
|
||||
foo ≤ 42|<range:field.foo lte="42">
|
||||
foo > 42|<range:field.foo gt="42">
|
||||
foo ≥ 42|<range:field.foo gte="42">
|
||||
foo < 2015/01/01|<range:field.foo lt="2015/01/01">
|
||||
foo ≤ 2015/01/01|<range:field.foo lte="2015/01/01">
|
||||
foo > 2015/01/01|<range:field.foo gt="2015/01/01">
|
||||
foo ≥ 2015/01/01|<range:field.foo gte="2015/01/01">
|
||||
foo < "2015/01/01"|<range:field.foo lt="2015/01/01">
|
||||
foo ≤ "2015/01/01"|<range:field.foo lte="2015/01/01">
|
||||
foo > "2015/01/01"|<range:field.foo gt="2015/01/01">
|
||||
foo ≥ "2015/01/01"|<range:field.foo gte="2015/01/01">
|
||||
foo = 42|(<field.foo> == <value:"42">)
|
||||
foo = bar|(<field.foo> == <value:"bar">)
|
||||
foo = "bar"|(<field.foo> == <value:"bar">)
|
||||
|
||||
# Field narrowing
|
||||
foo:bar|(<field:foo> MATCHES <text:"bar">)
|
||||
@@ -79,19 +79,19 @@ field.type:foo|(<field:type> MATCHES <text:"foo">)
|
||||
field.id:foo|(<field:id> MATCHES <text:"foo">)
|
||||
|
||||
# Matchers
|
||||
collection:foo|<collection:foo>
|
||||
collection:foo AND bar|(<collection:foo> AND <text:"bar">)
|
||||
collection:foo bar|(<collection:foo> AND <text:"bar">)
|
||||
database:foo|<database:foo>
|
||||
database:foo AND bar|(<database:foo> AND <text:"bar">)
|
||||
database:foo bar|(<database:foo> AND <text:"bar">)
|
||||
type:foo|<media_type:foo>
|
||||
type:foo AND bar|(<media_type:foo> AND <text:"bar">)
|
||||
type:foo bar|(<media_type:foo> AND <text:"bar">)
|
||||
id:90|<record_identifier:90>
|
||||
id:90 AND foo|(<record_identifier:90> AND <text:"foo">)
|
||||
id:90 foo|(<record_identifier:90> AND <text:"foo">)
|
||||
recordid:90|<record_identifier:90>
|
||||
collection:foo|<collection:"foo">
|
||||
collection:foo AND bar|(<collection:"foo"> AND <text:"bar">)
|
||||
collection:foo bar|(<collection:"foo"> AND <text:"bar">)
|
||||
database:foo|<database:"foo">
|
||||
database:foo AND bar|(<database:"foo"> AND <text:"bar">)
|
||||
database:foo bar|(<database:"foo"> AND <text:"bar">)
|
||||
type:foo|<media_type:"foo">
|
||||
type:foo AND bar|(<media_type:"foo"> AND <text:"bar">)
|
||||
type:foo bar|(<media_type:"foo"> AND <text:"bar">)
|
||||
id:90|<record_identifier:"90">
|
||||
id:90 AND foo|(<record_identifier:"90"> AND <text:"foo">)
|
||||
id:90 foo|(<record_identifier:"90"> AND <text:"foo">)
|
||||
recordid:90|<record_identifier:"90">
|
||||
|
||||
# Flag matcher
|
||||
flag.foo:true|<flag:foo set>
|
||||
@@ -102,6 +102,20 @@ flag.true:true|<flag:true set>
|
||||
flag.foo bar:true|(<text:"flag.foo"> AND (<field:bar> MATCHES <text:"true">))
|
||||
true|<text:"true">
|
||||
|
||||
# Metadata (EXIF or anything else) matcher
|
||||
meta.MimeType:image/jpeg|<metadata.MimeType:"image/jpeg">
|
||||
exif.MimeType:image/jpeg|<metadata.MimeType:"image/jpeg">
|
||||
meta.Duration < 300|<range:metadata.Duration lt="300">
|
||||
meta.Duration ≤ 300|<range:metadata.Duration lte="300">
|
||||
meta.Duration > 300|<range:metadata.Duration gt="300">
|
||||
meta.Duration ≥ 300|<range:metadata.Duration gte="300">
|
||||
meta.Duration = 300|(<metadata.Duration> == <value:"300">)
|
||||
|
||||
# Unescaped "." issue on key prefixes
|
||||
fieldOne:foo|(<field:fieldOne> MATCHES <text:"foo">)
|
||||
flagged:true|(<field:flagged> MATCHES <text:"true">)
|
||||
metadata:foo|(<field:metadata> MATCHES <text:"foo">)
|
||||
|
||||
# Matcher on unknown name --> fulltext
|
||||
foo:bar|(<field:foo> MATCHES <text:"bar">)
|
||||
foo:bar AND baz|((<field:foo> MATCHES <text:"bar">) AND <text:"baz">)
|
||||
|
Can't render this file because it contains an unexpected character in line 1 and column 11.
|
Reference in New Issue
Block a user