Completed
Push — master ( db1fd4...78a9b5 )
by
unknown
02:05 queued 10s
created

deleteForPropertyWhereConstraintIdIsStatementId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace WikibaseQuality\ConstraintReport;
4
5
use InvalidArgumentException;
6
use MediaWiki\Logger\LoggerFactory;
7
use MediaWiki\MediaWikiServices;
8
use Wikimedia\Rdbms\DBUnexpectedError;
9
use Wikimedia\Rdbms\IResultWrapper;
10
use Wikimedia\Rdbms\LikeMatch;
11
use Wikibase\DataModel\Entity\PropertyId;
12
13
/**
14
 * @author BP2014N1
15
 * @license GPL-2.0-or-later
16
 */
17
class ConstraintRepository implements ConstraintLookup {
18
19
	/**
20
	 * @param PropertyId $propertyId
21
	 *
22
	 * @return Constraint[]
23
	 */
24
	public function queryConstraintsForProperty( PropertyId $propertyId ) {
25
		$db = wfGetDB( DB_REPLICA );
26
27
		$results = $db->select(
28
			'wbqc_constraints',
29
			'*',
30
			[ 'pid' => $propertyId->getNumericId() ]
31
		);
32
33
		return $this->convertToConstraints( $results );
34
	}
35
36
	private function encodeConstraintParameters( array $constraintParameters ) {
37
		$json = json_encode( $constraintParameters, JSON_FORCE_OBJECT );
38
39
		if ( strlen( $json ) > 50000 ) {
40
			$json = json_encode( [ '@error' => [ 'toolong' => true ] ] );
41
		}
42
43
		return $json;
44
	}
45
46
	/**
47
	 * @param Constraint[] $constraints
48
	 *
49
	 * @throws DBUnexpectedError
50
	 * @return bool
51
	 */
52
	public function insertBatch( array $constraints ) {
53
		$accumulator = array_map(
54
			function ( Constraint $constraint ) {
55
				return [
56
					'constraint_guid' => $constraint->getConstraintId(),
57
					'pid' => $constraint->getPropertyId()->getNumericId(),
58
					'constraint_type_qid' => $constraint->getConstraintTypeItemId(),
59
					'constraint_parameters' => $this->encodeConstraintParameters( $constraint->getConstraintParameters() )
60
				];
61
			},
62
			$constraints
63
		);
64
65
		$db = wfGetDB( DB_MASTER );
66
		return $db->insert( 'wbqc_constraints', $accumulator );
67
	}
68
69
	/**
70
	 * @param LikeMatch $any should be IDatabase::anyChar()
71
	 *
72
	 * @return string[]
73
	 */
74
	private function uuidPattern( LikeMatch $any ) {
75
		return array_merge(
76
			array_fill( 0, 8, $any ), [ '-' ],
77
			array_fill( 0, 4, $any ), [ '-' ],
78
			array_fill( 0, 4, $any ), [ '-' ],
79
			array_fill( 0, 4, $any ), [ '-' ],
80
			array_fill( 0, 12, $any )
81
		);
82
	}
83
84
	/**
85
	 * Delete all constraints for the property ID where the constraint ID is a statement ID
86
	 * (an entity ID, a '$' separator, and a UUID).
87
	 *
88
	 * @param PropertyId $propertyId
89
	 *
90
	 * @throws DBUnexpectedError
91
	 */
92
	public function deleteForPropertyWhereConstraintIdIsStatementId( PropertyId $propertyId ) {
93
		$db = wfGetDB( DB_MASTER );
94
		$db->delete(
95
			'wbqc_constraints',
96
			[
97
				'pid' => $propertyId->getNumericId(),
98
				// AND constraint_guid LIKE %$________-____-____-____-____________
99
				'constraint_guid ' . $db->buildLike( array_merge( [ $db->anyString(), '$' ], $this->uuidPattern( $db->anyChar() ) ) )
100
			]
101
		);
102
	}
103
104
	/**
105
	 * @param int $batchSize
106
	 *
107
	 * @throws InvalidArgumentException
108
	 * @throws DBUnexpectedError
109
	 */
110
	public function deleteAll( $batchSize = 1000 ) {
111
		if ( !is_int( $batchSize ) ) {
112
			throw new InvalidArgumentException();
113
		}
114
		$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
115
		$db = $lbFactory->getMainLB()->getConnection( DB_MASTER );
116
		if ( $db->getType() === 'sqlite' ) {
117
			$db->delete( 'wbqc_constraints', '*' );
118
		} else {
119
			do {
120
				$db->commit( __METHOD__, 'flush' );
121
				$lbFactory->waitForReplication();
122
				$table = $db->tableName( 'wbqc_constraints' );
123
				$db->query( sprintf( 'DELETE FROM %s LIMIT %d', $table, $batchSize ) );
124
			} while ( $db->affectedRows() > 0 );
125
		}
126
	}
127
128
	/**
129
	 * @param IResultWrapper $results
130
	 *
131
	 * @return Constraint[]
132
	 */
133
	private function convertToConstraints( IResultWrapper $results ) {
134
		$constraints = [];
135
		foreach ( $results as $result ) {
136
			$constraintTypeItemId = $result->constraint_type_qid;
137
			$constraintParameters = json_decode( $result->constraint_parameters, true );
138
139
			if ( $constraintParameters === null ) {
140
				// T171295
141
				LoggerFactory::getInstance( 'WikibaseQualityConstraints' )
142
					->warning( 'Constraint {constraintId} has invalid constraint parameters.', [
143
						'method' => __METHOD__,
144
						'constraintId' => $result->constraint_guid,
145
						'constraintParameters' => $result->constraint_parameters,
146
					] );
147
				$constraintParameters = [ '@error' => [ /* unknown */ ] ];
148
			}
149
150
			$constraints[] = new Constraint(
151
				$result->constraint_guid,
152
				PropertyId::newFromNumber( $result->pid ),
153
				$constraintTypeItemId,
154
				$constraintParameters
155
			);
156
		}
157
		return $constraints;
158
	}
159
160
}
161