TimeHandler::getInsertValues()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
cc 2
eloc 14
nc 2
nop 1
1
<?php
2
3
namespace Wikibase\QueryEngine\SQLStore\DVHandler;
4
5
use Ask\Language\Description\ValueDescription;
6
use DataValues\DataValue;
7
use DataValues\TimeValue;
8
use DataValues\TimeValueCalculator;
9
use Doctrine\DBAL\Query\QueryBuilder;
10
use Doctrine\DBAL\Schema\Table;
11
use Doctrine\DBAL\Types\Type;
12
use InvalidArgumentException;
13
use Wikibase\QueryEngine\QueryNotSupportedException;
14
use Wikibase\QueryEngine\SQLStore\DataValueHandler;
15
16
/**
17
 * @since 0.1
18
 *
19
 * @licence GNU GPL v2+
20
 * @author Adam Shorland < [email protected] >
21
 * @author Thiemo Kreuz
22
 */
23
class TimeHandler extends DataValueHandler {
24
25
	/**
26
	 * @see DataValueHandler::getBaseTableName
27
	 *
28
	 * @return string
29
	 */
30
	protected function getBaseTableName() {
31
		return 'time';
32
	}
33
34
	/**
35
	 * @see DataValueHandler::completeTable
36
	 */
37
	protected function completeTable( Table $table ) {
38
		// TODO: Do we need to store the precision, before, after, timezone and calendar model?
39
		$table->addColumn( 'value_timestamp',     Type::BIGINT );
40
		$table->addColumn( 'value_min_timestamp', Type::BIGINT );
41
		$table->addColumn( 'value_max_timestamp', Type::BIGINT );
42
		$table->addColumn( 'hash',                Type::STRING, array( 'length' => 32 ) );
43
44
		$table->addIndex( array( 'value_timestamp' ) );
45
		$table->addIndex( array( 'value_min_timestamp' ) );
46
		$table->addIndex( array( 'value_max_timestamp' ) );
47
	}
48
49
	/**
50
	 * @see DataValueHandler::getSortFieldNames
51
	 *
52
	 * @return string[]
53
	 */
54
	public function getSortFieldNames() {
55
		return array( 'value_timestamp' );
56
	}
57
58
	/**
59
	 * @see DataValueHandler::getInsertValues
60
	 *
61
	 * @param DataValue $value
62
	 *
63
	 * @throws InvalidArgumentException
64
	 * @return array
65
	 */
66
	public function getInsertValues( DataValue $value ) {
67
		if ( !( $value instanceof TimeValue ) ) {
68
			throw new InvalidArgumentException( 'Value is not a TimeValue.' );
69
		}
70
71
		$calculator = new TimeValueCalculator();
72
		$timestamp = $calculator->getTimestamp( $value );
73
		$precisionInSeconds = $calculator->getSecondsForPrecision( $value->getPrecision() );
74
75
		$before = abs( $value->getBefore() );
76
		// The range from before to after must be at least one unit long
77
		$after = max( 1, abs( $value->getAfter() ) );
78
79
		$values = array(
80
			'value_timestamp' => $timestamp,
81
			'value_min_timestamp' => $timestamp - $before * $precisionInSeconds,
82
			'value_max_timestamp' => $timestamp + $after * $precisionInSeconds,
83
84
			'hash' => $this->getEqualityFieldValue( $value ),
85
		);
86
87
		return $values;
88
	}
89
90
	/**
91
	 * @see DataValueHandler::addMatchConditions
92
	 *
93
	 * @param QueryBuilder $builder
94
	 * @param ValueDescription $description
95
	 *
96
	 * @throws InvalidArgumentException
97
	 * @throws QueryNotSupportedException
98
	 */
99
	public function addMatchConditions( QueryBuilder $builder, ValueDescription $description ) {
100
		$value = $description->getValue();
101
102
		if ( !( $value instanceof TimeValue ) ) {
103
			throw new InvalidArgumentException( 'Value is not a TimeValue.' );
104
		}
105
106
		if ( $description->getComparator() === ValueDescription::COMP_EQUAL ) {
107
			$this->addInRangeConditions( $builder, $value );
108
		} else {
109
			parent::addMatchConditions( $builder, $description);
110
		}
111
	}
112
113
	/**
114
	 * @param QueryBuilder $builder
115
	 * @param TimeValue $value
116
	 */
117
	private function addInRangeConditions( QueryBuilder $builder, TimeValue $value ) {
118
		$calculator = new TimeValueCalculator();
119
		$timestamp = $calculator->getTimestamp( $value );
120
		$precisionInSeconds = $calculator->getSecondsForPrecision( $value->getPrecision() );
121
122
		$before = abs( $value->getBefore() );
123
		// The range from before to after must be at least one unit long
124
		$after = max( 1, abs( $value->getAfter() ) );
125
126
		// When searching for 1900 (precision year) we do not want to find 1901-01-01T00:00:00.
127
		$builder->andWhere( 'value_timestamp >= :min_timestamp' );
128
		$builder->andWhere( 'value_timestamp < :max_timestamp' );
129
130
		$builder->setParameter( ':min_timestamp', $timestamp - $before * $precisionInSeconds );
131
		$builder->setParameter( ':max_timestamp', $timestamp + $after * $precisionInSeconds );
132
	}
133
134
}
135