Convert dates to date ranges on timestamp keys

This commit is contained in:
Mathieu Darse
2015-11-13 19:28:59 +01:00
parent 0f0c007e19
commit 6913d67e9a
3 changed files with 71 additions and 12 deletions

View File

@@ -20,22 +20,22 @@ class RangeExpression extends Node
public static function lessThan(Key $key, $bound) public static function lessThan(Key $key, $bound)
{ {
return new self($key, $bound, false); return new self($key, null, false, $bound, false);
} }
public static function lessThanOrEqual(Key $key, $bound) public static function lessThanOrEqual(Key $key, $bound)
{ {
return new self($key, $bound, true); return new self($key, null, false, $bound, true);
} }
public static function greaterThan(Key $key, $bound) public static function greaterThan(Key $key, $bound)
{ {
return new self($key, null, false, $bound, false); return new self($key, $bound, false);
} }
public static function greaterThanOrEqual(Key $key, $bound) public static function greaterThanOrEqual(Key $key, $bound)
{ {
return new self($key, null, false, $bound, true); return new self($key, $bound, true);
} }
public function __construct(Key $key, $lb, $li = false, $hb = null, $hi = false) public function __construct(Key $key, $lb, $li = false, $hb = null, $hi = false)
@@ -57,17 +57,17 @@ class RangeExpression extends Node
if ($this->lower_bound !== null) { if ($this->lower_bound !== null) {
$this->assertValueCompatible($this->lower_bound, $context); $this->assertValueCompatible($this->lower_bound, $context);
if ($this->lower_inclusive) { if ($this->lower_inclusive) {
$params['lte'] = $this->lower_bound; $params['gte'] = $this->lower_bound;
} else { } else {
$params['lt'] = $this->lower_bound; $params['gt'] = $this->lower_bound;
} }
} }
if ($this->higher_bound !== null) { if ($this->higher_bound !== null) {
$this->assertValueCompatible($this->higher_bound, $context); $this->assertValueCompatible($this->higher_bound, $context);
if ($this->higher_inclusive) { if ($this->higher_inclusive) {
$params['gte'] = $this->higher_bound; $params['lte'] = $this->higher_bound;
} else { } else {
$params['gt'] = $this->higher_bound; $params['lt'] = $this->higher_bound;
} }
} }
@@ -98,16 +98,16 @@ class RangeExpression extends Node
$string = ''; $string = '';
if ($this->lower_bound !== null) { if ($this->lower_bound !== null) {
if ($this->lower_inclusive) { if ($this->lower_inclusive) {
$string .= sprintf(' lte="%s"', $this->lower_bound); $string .= sprintf(' gte="%s"', $this->lower_bound);
} else { } else {
$string .= sprintf(' lt="%s"', $this->lower_bound); $string .= sprintf(' gt="%s"', $this->lower_bound);
} }
} }
if ($this->higher_bound !== null) { if ($this->higher_bound !== null) {
if ($this->higher_inclusive) { if ($this->higher_inclusive) {
$string .= sprintf(' gte="%s"', $this->higher_bound); $string .= sprintf(' lte="%s"', $this->higher_bound);
} else { } else {
$string .= sprintf(' gt="%s"', $this->higher_bound); $string .= sprintf(' lt="%s"', $this->higher_bound);
} }
} }

View File

@@ -2,6 +2,7 @@
namespace Alchemy\Phrasea\SearchEngine\Elastic\Search; namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
use Alchemy\Phrasea\SearchEngine\Elastic\Mapping;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Field; use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Field;
class QueryHelper class QueryHelper
@@ -107,4 +108,42 @@ class QueryHelper
return $query; return $query;
} }
} }
public static function getRangeFromDateString($string)
{
$formats = ['Y/m/d', 'Y/m', 'Y'];
$deltas = ['+1 day', '+1 month', '+1 year'];
$to = null;
while ($format = array_pop($formats)) {
$delta = array_pop($deltas);
$from = date_create_from_format($format, $string);
if ($from !== false) {
// Rewind to start of range
$month = 1;
$day = 1;
switch ($format) {
case 'Y/m/d':
$day = (int) $from->format('d');
case 'Y/m':
$month = (int) $from->format('m');
case 'Y':
$year = (int) $from->format('Y');
}
date_date_set($from, $year, $month, $day);
date_time_set($from, 0, 0, 0);
// Create end of the the range
$to = date_modify(clone $from, $delta);
break;
}
}
if (!$from || !$to) {
throw new \InvalidArgumentException(sprintf('Invalid date "%s".', $string));
}
return [
'from' => $from->format(Mapping::DATE_FORMAT_CAPTION_PHP),
'to' => $to->format(Mapping::DATE_FORMAT_CAPTION_PHP)
];
}
} }

View File

@@ -4,6 +4,7 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
use Alchemy\Phrasea\SearchEngine\Elastic\AST; use Alchemy\Phrasea\SearchEngine\Elastic\AST;
use Alchemy\Phrasea\SearchEngine\Elastic\Exception\Exception; use Alchemy\Phrasea\SearchEngine\Elastic\Exception\Exception;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryHelper;
use Hoa\Compiler\Llk\TreeNode; use Hoa\Compiler\Llk\TreeNode;
use Hoa\Visitor\Element; use Hoa\Visitor\Element;
use Hoa\Visitor\Visit; use Hoa\Visitor\Visit;
@@ -176,10 +177,29 @@ class QueryVisitor implements Visit
private function visitEqualNode(TreeNode $node) private function visitEqualNode(TreeNode $node)
{ {
return $this->handleBinaryExpression($node, function($left, $right) { return $this->handleBinaryExpression($node, function($left, $right) {
if ($this->isDateKey($left)) {
try {
// Try to create a range for incomplete dates
$range = QueryHelper::getRangeFromDateString($right);
return new AST\KeyValue\RangeExpression(
$left,
$range['from'], true,
$range['to'], false
);
} catch (\InvalidArgumentException $e) {
// Fall back to equal expression
}
}
return new AST\KeyValue\EqualExpression($left, $right); return new AST\KeyValue\EqualExpression($left, $right);
}); });
} }
private function isDateKey(AST\KeyValue\Key $key)
{
return $key instanceof AST\KeyValue\TimestampKey;
}
private function visitTerm(Element $element) private function visitTerm(Element $element)
{ {
$words = array(); $words = array();