Migrate to IReadableDatabase::newSelectQueryBuilder
Also use expression builder to avoid raw sql Bug: T312330 Bug: T350954 Change-Id: Iaa1b114954da723bef14d1a59953aeffb85f4a8c
这个提交包含在:
父节点
2b1aa56370
当前提交
d91fa9a1ba
|
@ -20,6 +20,7 @@ use OOUI\ButtonWidget;
|
|||
use OOUI\IconWidget;
|
||||
use PageImages\PageImages;
|
||||
use Wikimedia\Rdbms\IConnectionProvider;
|
||||
use Wikimedia\Rdbms\SelectQueryBuilder;
|
||||
|
||||
/**
|
||||
* This is the "Impact" module. It shows the page views information
|
||||
|
@ -585,35 +586,34 @@ class Impact extends BaseModule {
|
|||
$actorMigration = ActorMigration::newMigration();
|
||||
$dbr = $this->connectionProvider->getReplicaDatabase();
|
||||
$actorQuery = $actorMigration->getWhere( $dbr, 'rev_user', $this->getContext()->getUser() );
|
||||
$subquery = $dbr->buildSelectSubquery(
|
||||
array_merge( [ 'revision' ], $actorQuery[ 'tables' ], [ 'page' ] ),
|
||||
[ 'rev_page', 'page_title', 'page_namespace', 'rev_timestamp' ],
|
||||
[
|
||||
$subquery = $dbr->newSelectQueryBuilder()
|
||||
->select( [ 'rev_page', 'page_title', 'page_namespace', 'rev_timestamp' ] )
|
||||
->from( 'revision' )
|
||||
->tables( $actorQuery[ 'tables' ] )
|
||||
->joinConds( $actorQuery[ 'joins' ] )
|
||||
->join( 'page', null, 'rev_page = page_id' )
|
||||
->where( [
|
||||
$actorQuery[ 'conds' ],
|
||||
'rev_deleted' => 0,
|
||||
'page_namespace' => 0,
|
||||
],
|
||||
__METHOD__,
|
||||
[ 'ORDER BY' => 'rev_timestamp DESC', 'limit' => 1000 ],
|
||||
[ 'page' => [ 'JOIN', [ 'rev_page = page_id' ] ] ] + $actorQuery[ 'joins' ]
|
||||
);
|
||||
$result = $dbr->select(
|
||||
[ 'latest_edits' => $subquery ],
|
||||
[
|
||||
] )
|
||||
->orderBy( 'rev_timestamp', SelectQueryBuilder::SORT_DESC )
|
||||
->limit( 1000 )
|
||||
->caller( __METHOD__ );
|
||||
$result = $dbr->newSelectQueryBuilder()
|
||||
->select( [
|
||||
'rev_page',
|
||||
'page_title',
|
||||
'page_namespace',
|
||||
'max_ts' => 'MAX(rev_timestamp)',
|
||||
'min_ts' => 'MIN(rev_timestamp)',
|
||||
],
|
||||
[],
|
||||
__METHOD__,
|
||||
[
|
||||
'GROUP BY' => 'rev_page',
|
||||
'ORDER BY' => 'max_ts DESC',
|
||||
'LIMIT' => 10,
|
||||
]
|
||||
);
|
||||
] )
|
||||
->from( $subquery, 'latest_edits' )
|
||||
->groupBy( 'rev_page' )
|
||||
->orderBy( 'max_ts', SelectQueryBuilder::SORT_DESC )
|
||||
->limit( 10 )
|
||||
->caller( __METHOD__ )
|
||||
->fetchResultSet();
|
||||
$contribs = [];
|
||||
foreach ( $result as $row ) {
|
||||
$contribs[] = [
|
||||
|
|
|
@ -548,12 +548,12 @@ class UncachedMenteeOverviewDataProvider implements MenteeOverviewDataProvider {
|
|||
*/
|
||||
private function getRegistrationTimestampForUsers( array $userIds ): array {
|
||||
$startTime = microtime( true );
|
||||
$rows = $this->getReadConnection()->select(
|
||||
'user',
|
||||
[ 'user_id', 'user_registration' ],
|
||||
[ 'user_id' => $userIds ],
|
||||
__METHOD__
|
||||
);
|
||||
$rows = $this->getReadConnection()->newSelectQueryBuilder()
|
||||
->select( [ 'user_id', 'user_registration' ] )
|
||||
->from( 'user' )
|
||||
->where( [ 'user_id' => $userIds ] )
|
||||
->caller( __METHOD__ )
|
||||
->fetchResultSet();
|
||||
$res = [];
|
||||
foreach ( $rows as $row ) {
|
||||
$res[$row->user_id] = $row->user_registration;
|
||||
|
|
|
@ -245,10 +245,8 @@ class MentorStatusManager {
|
|||
->from( 'user_properties' )
|
||||
->where( [
|
||||
'up_property' => self::MENTOR_AWAY_TIMESTAMP_PREF,
|
||||
'up_value IS NOT NULL',
|
||||
'up_value > ' . $db->addQuotes(
|
||||
$db->timestamp()
|
||||
)
|
||||
$db->expr( 'up_value', '!=', null ),
|
||||
$db->expr( 'up_value', '>', $db->timestamp() )
|
||||
] )
|
||||
->recency( $flags )
|
||||
->caller( __METHOD__ )
|
||||
|
|
|
@ -15,7 +15,6 @@ use MediaWiki\SpecialPage\Hook\ChangesListSpecialPageStructuredFiltersHook;
|
|||
use MediaWiki\User\UserIdentity;
|
||||
use RecentChange;
|
||||
use Wikimedia\Rdbms\IDatabase;
|
||||
use Wikimedia\Rdbms\SelectQueryBuilder;
|
||||
|
||||
/**
|
||||
* RecentChanges filters for mentors. Separate from MentorHooks because MentorManager
|
||||
|
@ -105,7 +104,7 @@ class MentorFilterHooks implements ChangesListSpecialPageStructuredFiltersHook {
|
|||
// there is a risk of key conflict. Convert into non-associate instead.
|
||||
// Only apply when $targetIds has at least one ID
|
||||
if ( $targetActorIds !== [] ) {
|
||||
$conds[] = $dbr->makeList( [ 'rc_actor' => $targetActorIds ], IDatabase::LIST_AND );
|
||||
$conds['rc_actor'] = $targetActorIds;
|
||||
} else {
|
||||
$conds[] = '0=1';
|
||||
}
|
||||
|
@ -198,11 +197,13 @@ class MentorFilterHooks implements ChangesListSpecialPageStructuredFiltersHook {
|
|||
|
||||
// No need to worry about properly acquiring actor IDs - if it shows up in
|
||||
// recent changes, it already has an actor ID
|
||||
$queryBuilder = new SelectQueryBuilder( $db );
|
||||
$queryBuilder->table( 'actor' );
|
||||
$queryBuilder->field( 'actor_id' );
|
||||
$queryBuilder->where( [ 'actor_user' => $userIds ] );
|
||||
return array_map( 'intval', $queryBuilder->fetchFieldValues() );
|
||||
$res = $db->newSelectQueryBuilder()
|
||||
->select( 'actor_id' )
|
||||
->from( 'actor' )
|
||||
->where( [ 'actor_user' => $userIds ] )
|
||||
->caller( __METHOD__ )
|
||||
->fetchFieldValues();
|
||||
return array_map( 'intval', $res );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ use RuntimeException;
|
|||
use stdClass;
|
||||
use Wikimedia\Rdbms\IDatabase;
|
||||
use Wikimedia\Rdbms\ILoadBalancer;
|
||||
use Wikimedia\Rdbms\OrExpressionGroup;
|
||||
use Wikimedia\Rdbms\SelectQueryBuilder;
|
||||
|
||||
/**
|
||||
|
@ -134,10 +135,11 @@ class LinkRecommendationStore {
|
|||
* @return LinkRecommendation[]
|
||||
*/
|
||||
public function getAllRecommendations( int $limit, int &$fromPageId ): array {
|
||||
$res = $this->getDB( DB_REPLICA )->newSelectQueryBuilder()
|
||||
$dbr = $this->getDB( DB_REPLICA );
|
||||
$res = $dbr->newSelectQueryBuilder()
|
||||
->select( [ 'gelr_revision', 'gelr_page', 'gelr_data' ] )
|
||||
->from( 'growthexperiments_link_recommendations' )
|
||||
->where( [ 'gelr_page >= ' . $fromPageId ] )
|
||||
->where( $dbr->expr( 'gelr_page', '>=', $fromPageId ) )
|
||||
->orderBy( 'gelr_page ASC' )
|
||||
->limit( $limit )
|
||||
->caller( __METHOD__ )->fetchResultSet();
|
||||
|
@ -161,25 +163,23 @@ class LinkRecommendationStore {
|
|||
->fetchPageRecords();
|
||||
|
||||
$conds = [];
|
||||
$dbr = $this->loadBalancer->getConnection( DB_REPLICA );
|
||||
/** @var PageRecord $pageRecord */
|
||||
foreach ( $pageRecords as $pageRecord ) {
|
||||
// Making it obvious there's no SQL injection risk is nice, but Phan disagrees.
|
||||
// @phan-suppress-next-line PhanRedundantConditionInLoop
|
||||
$pageId = (int)$pageRecord->getId();
|
||||
$revId = (int)$pageRecord->getLatest();
|
||||
$pageId = $pageRecord->getId();
|
||||
$revId = $pageRecord->getLatest();
|
||||
if ( !$pageId || !$revId ) {
|
||||
continue;
|
||||
}
|
||||
// $revId can be outdated due to replag; we don't want to delete the record then.
|
||||
$conds[] = "gelr_page = $pageId AND gelr_revision >= $revId";
|
||||
$conds[] = $dbr->expr( 'gelr_page', '=', $pageId )->and( 'gelr_revision', '>=', $revId );
|
||||
}
|
||||
$dbr = $this->loadBalancer->getConnection( DB_REPLICA );
|
||||
return array_map( 'intval', $dbr->selectFieldValues(
|
||||
'growthexperiments_link_recommendations',
|
||||
'gelr_page',
|
||||
$dbr->makeList( $conds, IDatabase::LIST_OR ),
|
||||
__METHOD__
|
||||
) );
|
||||
return array_map( 'intval', $dbr->newSelectQueryBuilder()
|
||||
->select( 'gelr_page' )
|
||||
->from( 'growthexperiments_link_recommendations' )
|
||||
->where( new OrExpressionGroup( ...$conds ) )
|
||||
->caller( __METHOD__ )
|
||||
->fetchFieldValues() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -189,11 +189,11 @@ class LinkRecommendationStore {
|
|||
* @return int[]
|
||||
*/
|
||||
public function listPageIds( int $limit, int $from = null ): array {
|
||||
return array_map( 'intval', $this->loadBalancer->getConnection( DB_REPLICA )
|
||||
->newSelectQueryBuilder()
|
||||
$dbr = $this->loadBalancer->getConnection( DB_REPLICA );
|
||||
return array_map( 'intval', $dbr->newSelectQueryBuilder()
|
||||
->select( 'gelr_page' )
|
||||
->from( 'growthexperiments_link_recommendations' )
|
||||
->where( $from ? [ "gelr_page > $from" ] : [] )
|
||||
->where( $from ? $dbr->expr( 'gelr_page', '>', $from ) : [] )
|
||||
->groupBy( 'gelr_page' )
|
||||
->orderBy( 'gelr_page ASC' )
|
||||
->limit( $limit )
|
||||
|
|
|
@ -56,15 +56,15 @@ class ProtectionFilter extends AbstractTaskSetFilter implements TaskSetFilter {
|
|||
// In the longer run, adding batch querying to RestrictionStore itself would be nice.
|
||||
$results = [];
|
||||
if ( $validTasks ) {
|
||||
$results = $this->connectionProvider->getReplicaDatabase()->select(
|
||||
'page_restrictions',
|
||||
[ 'pr_page' ],
|
||||
[
|
||||
$results = $this->connectionProvider->getReplicaDatabase()->newSelectQueryBuilder()
|
||||
->select( [ 'pr_page' ] )
|
||||
->from( 'page_restrictions' )
|
||||
->where( [
|
||||
'pr_page' => array_keys( $validTasks ),
|
||||
'pr_type' => 'edit'
|
||||
],
|
||||
__METHOD__
|
||||
);
|
||||
] )
|
||||
->caller( __METHOD__ )
|
||||
->fetchResultSet();
|
||||
}
|
||||
|
||||
foreach ( $results as $item ) {
|
||||
|
|
|
@ -45,9 +45,9 @@ class NewcomersByMentorMetric implements IMetric {
|
|||
->where( [
|
||||
'log_type' => 'newusers',
|
||||
'log_action' => 'create',
|
||||
'log_timestamp > ' . $this->dbr->timestamp(
|
||||
$this->dbr->expr( 'log_timestamp', '>', $this->dbr->timestamp(
|
||||
(int)wfTimestamp() - ExpirationAwareness::TTL_MONTH
|
||||
)
|
||||
) )
|
||||
] )
|
||||
->caller( __METHOD__ )
|
||||
->fetchField();
|
||||
|
|
|
@ -42,14 +42,13 @@ class UserDatabaseHelper {
|
|||
public function findFirstUserIdForRegistrationTimestamp( $registrationTimestamp ): ?int {
|
||||
$dbr = $this->connectionProvider->getReplicaDatabase();
|
||||
$registrationTimestamp = $dbr->timestamp( $registrationTimestamp );
|
||||
$queryBuilder = new SelectQueryBuilder( $dbr );
|
||||
$queryBuilder->table( 'user' );
|
||||
$queryBuilder->field( 'user_id' );
|
||||
$queryBuilder->where( "user_registration >= " . $dbr->addQuotes( $registrationTimestamp ) );
|
||||
$queryBuilder->orderBy( 'user_id', SelectQueryBuilder::SORT_ASC );
|
||||
$queryBuilder->limit( 1 );
|
||||
$queryBuilder->caller( __METHOD__ );
|
||||
$userId = $queryBuilder->fetchField();
|
||||
$userId = $dbr->newSelectQueryBuilder()
|
||||
->field( 'user_id' )
|
||||
->from( 'user' )
|
||||
->where( $dbr->expr( 'user_registration', '>=', $registrationTimestamp ) )
|
||||
->orderBy( 'user_id', SelectQueryBuilder::SORT_ASC )
|
||||
->caller( __METHOD__ )
|
||||
->fetchField();
|
||||
return $userId === false ? null : (int)$userId;
|
||||
}
|
||||
|
||||
|
@ -62,19 +61,20 @@ class UserDatabaseHelper {
|
|||
*/
|
||||
public function hasMainspaceEdits( UserIdentity $userIdentity, int $limit = 1000 ): ?bool {
|
||||
$user = $this->userFactory->newFromUserIdentity( $userIdentity );
|
||||
$queryBuilder = new SelectQueryBuilder( $this->connectionProvider->getReplicaDatabase() );
|
||||
$queryBuilder->table( 'revision' );
|
||||
$queryBuilder->join( 'page', null, 'page_id = rev_page' );
|
||||
$queryBuilder->field( 'page_namespace' );
|
||||
$queryBuilder->where( [
|
||||
'rev_actor' => $user->getActorId()
|
||||
] );
|
||||
// Look at the user's oldest edits - arbitrary choice, other than we want the method to be
|
||||
// deterministic. Can be done efficiently via the rev_actor_timestamp index.
|
||||
$queryBuilder->orderBy( 'rev_timestamp', SelectQueryBuilder::SORT_ASC );
|
||||
$queryBuilder->limit( $limit );
|
||||
$queryBuilder->caller( __METHOD__ );
|
||||
$result = array_map( 'intval', $queryBuilder->fetchFieldValues() );
|
||||
$res = $this->connectionProvider->getReplicaDatabase()->newSelectQueryBuilder()
|
||||
->select( 'page_namespace' )
|
||||
->from( 'revision' )
|
||||
->join( 'page', null, 'page_id = rev_page' )
|
||||
->where( [
|
||||
'rev_actor' => $user->getActorId()
|
||||
] )
|
||||
// Look at the user's oldest edits - arbitrary choice, other than we want the method to be
|
||||
// deterministic. Can be done efficiently via the rev_actor_timestamp index.
|
||||
->orderBy( 'rev_timestamp', SelectQueryBuilder::SORT_ASC )
|
||||
->limit( $limit )
|
||||
->caller( __METHOD__ )
|
||||
->fetchFieldValues();
|
||||
$result = array_map( 'intval', $res );
|
||||
if ( in_array( NS_MAIN, $result ) ) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ use Psr\Log\LoggerInterface;
|
|||
use Psr\Log\NullLogger;
|
||||
use StatusValue;
|
||||
use Wikimedia\Rdbms\IConnectionProvider;
|
||||
use Wikimedia\Rdbms\SelectQueryBuilder;
|
||||
|
||||
class ComputedUserImpactLookup implements UserImpactLookup {
|
||||
|
||||
|
@ -213,8 +212,8 @@ class ComputedUserImpactLookup implements UserImpactLookup {
|
|||
private function getEditData( User $user, int $flags ): EditData {
|
||||
$db = DBAccessObjectUtils::getDBFromRecency( $this->connectionProvider, $flags );
|
||||
|
||||
$queryBuilder = new SelectQueryBuilder( $db );
|
||||
$queryBuilder->table( 'revision' )
|
||||
$queryBuilder = $db->newSelectQueryBuilder()
|
||||
->table( 'revision' )
|
||||
->join( 'page', null, 'rev_page = page_id' );
|
||||
|
||||
$taskChangeTagNames = $this->taskTypeHandlerRegistry->getUniqueChangeTags();
|
||||
|
|
|
@ -6,7 +6,6 @@ use IDBAccessObject;
|
|||
use MediaWiki\User\UserIdentity;
|
||||
use Wikimedia\AtEase\AtEase;
|
||||
use Wikimedia\Rdbms\ILoadBalancer;
|
||||
use Wikimedia\Rdbms\SelectQueryBuilder;
|
||||
|
||||
class DatabaseUserImpactStore implements UserImpactStore {
|
||||
|
||||
|
@ -43,10 +42,11 @@ class DatabaseUserImpactStore implements UserImpactStore {
|
|||
}
|
||||
|
||||
$userImpacts = array_fill_keys( $userIds, null );
|
||||
$queryBuilder = new SelectQueryBuilder( $this->loadBalancer->getConnection( DB_REPLICA ) );
|
||||
$queryBuilder->table( self::TABLE_NAME );
|
||||
$queryBuilder->fields( [ 'geui_user_id', 'geui_data' ] );
|
||||
$queryBuilder->where( [ 'geui_user_id' => $userIds ] );
|
||||
$queryBuilder = $this->loadBalancer->getConnection( DB_REPLICA )->newSelectQueryBuilder()
|
||||
->select( [ 'geui_user_id', 'geui_data' ] )
|
||||
->from( self::TABLE_NAME )
|
||||
->where( [ 'geui_user_id' => $userIds ] )
|
||||
->caller( __METHOD__ );
|
||||
foreach ( $queryBuilder->fetchResultSet() as $row ) {
|
||||
AtEase::suppressWarnings();
|
||||
$userImpactArray = gzinflate( $row->geui_data );
|
||||
|
|
|
@ -88,8 +88,7 @@ class ExportWelcomeSurveyMailingListData extends Maintenance {
|
|||
return;
|
||||
}
|
||||
|
||||
$queryBuilderTemplate = new SelectQueryBuilder( $dbr );
|
||||
$queryBuilderTemplate
|
||||
$queryBuilderTemplate = $dbr->newSelectQueryBuilder()
|
||||
->table( 'user' )
|
||||
->join( 'user_properties', 'survey_prop', [
|
||||
'user_id = survey_prop.up_user',
|
||||
|
@ -113,7 +112,7 @@ class ExportWelcomeSurveyMailingListData extends Maintenance {
|
|||
->limit( $this->getBatchSize() )
|
||||
->caller( __METHOD__ );
|
||||
if ( $toId ) {
|
||||
$queryBuilderTemplate->where( 'user_id <= ' . $dbr->addQuotes( $toId ) );
|
||||
$queryBuilderTemplate->where( $dbr->expr( 'user_id', '<=', $toId ) );
|
||||
}
|
||||
|
||||
$userOptionsLookup = $services->getUserOptionsLookup();
|
||||
|
@ -125,7 +124,7 @@ class ExportWelcomeSurveyMailingListData extends Maintenance {
|
|||
$group = $this->getOption( 'group' );
|
||||
do {
|
||||
$queryBuilder = clone $queryBuilderTemplate;
|
||||
$queryBuilder->andWhere( 'user_id > ' . $dbr->addQuotes( $fromId ?? 0 ) );
|
||||
$queryBuilder->andWhere( $dbr->expr( 'user_id', '>', $fromId ?? 0 ) );
|
||||
$result = $queryBuilder->fetchResultSet();
|
||||
foreach ( $result as $row ) {
|
||||
$fromId = $row->user_id;
|
||||
|
@ -172,14 +171,13 @@ class ExportWelcomeSurveyMailingListData extends Maintenance {
|
|||
* @return int|null
|
||||
*/
|
||||
private function getLastUserIdBeforeRegistrationDate( IDatabase $dbr, string $registrationDate ): ?int {
|
||||
$queryBuilder = new SelectQueryBuilder( $dbr );
|
||||
$queryBuilder
|
||||
->fields( [ 'user_id' => 'max(user_id)' ] )
|
||||
->table( 'user' )
|
||||
$res = $dbr->newSelectQueryBuilder()
|
||||
->select( [ 'user_id' => 'max(user_id)' ] )
|
||||
->from( 'user' )
|
||||
// Old user records have no registration date. We won't use 'from' dates old enough
|
||||
// to encounter those so we can ignore them here.
|
||||
->where( 'user_registration <= ' . $dbr->timestamp( $registrationDate ) );
|
||||
$res = $queryBuilder->fetchField();
|
||||
->where( $dbr->expr( 'user_registration', '<=', $registrationDate ) )
|
||||
->fetchField();
|
||||
return is_numeric( $res ) ? intval( $res ) : null;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,12 +37,13 @@ class DeleteExpiredUserImpactData extends Maintenance {
|
|||
$expiry = $this->getOption( 'expiry', '30days' );
|
||||
$expiryTimestamp = $this->getTimestampFromRelativeDate( $expiry );
|
||||
|
||||
$queryBuilder = new SelectQueryBuilder( $dbw );
|
||||
$queryBuilder->table( DatabaseUserImpactStore::TABLE_NAME );
|
||||
$queryBuilder->field( 'geui_user_id' );
|
||||
$queryBuilder->where( 'geui_timestamp < ' . $expiryTimestamp );
|
||||
$queryBuilder->orderBy( 'geui_timestamp', SelectQueryBuilder::SORT_ASC );
|
||||
$queryBuilder->limit( $this->getBatchSize() );
|
||||
$queryBuilder = $dbw->newSelectQueryBuilder()
|
||||
->select( 'geui_user_id' )
|
||||
->from( DatabaseUserImpactStore::TABLE_NAME )
|
||||
->where( $dbw->expr( 'geui_timestamp', '<', $dbw->timestamp( $expiryTimestamp ) ) )
|
||||
->orderBy( 'geui_timestamp', SelectQueryBuilder::SORT_ASC )
|
||||
->limit( $this->getBatchSize() )
|
||||
->caller( __METHOD__ );
|
||||
|
||||
$deletedCount = 0;
|
||||
$idsToDelete = $queryBuilder->fetchFieldValues();
|
||||
|
|
|
@ -62,7 +62,7 @@ class DeleteOldSurveys extends Maintenance {
|
|||
->join( 'user', null, [ 'user_id = up_user' ] )
|
||||
->where( [
|
||||
'up_property' => WelcomeSurvey::SURVEY_PROP,
|
||||
'user_id > ' . $dbr->addQuotes( $fromUserId )
|
||||
$dbr->expr( 'user_id', '>', $fromUserId )
|
||||
] )
|
||||
->orderBy( 'user_id ASC' )
|
||||
->limit( $this->mBatchSize )
|
||||
|
|
|
@ -79,7 +79,7 @@ class ReassignMentees extends Maintenance {
|
|||
->from( 'growthexperiments_mentor_mentee' )
|
||||
->where( [
|
||||
'gemm_mentor_role' => MentorStore::ROLE_PRIMARY,
|
||||
'gemm_mentor_id NOT IN (' . $this->growthDbr->makeList( $officialMentorIds ) . ')'
|
||||
$this->growthDbr->expr( 'gemm_mentor_id', '!=', $officialMentorIds ),
|
||||
] )
|
||||
->fetchFieldValues();
|
||||
|
||||
|
|
|
@ -156,13 +156,14 @@ class RefreshUserImpactData extends Maintenance {
|
|||
$queryBuilder->limit( $this->getBatchSize() );
|
||||
$queryBuilder->orderByUserId( SelectQueryBuilder::SORT_ASC );
|
||||
$lastUserId = (int)$this->getOption( 'fromUser', 0 );
|
||||
$dbr = $this->getDB( DB_REPLICA );
|
||||
do {
|
||||
$this->output( "processing {$this->getBatchSize()} users starting with $lastUserId\n" );
|
||||
$batchQueryBuilder = clone $queryBuilder;
|
||||
$batchQueryBuilder->where( 'actor_user > ' . $lastUserId );
|
||||
$batchQueryBuilder->where( $dbr->expr( 'actor_user', '>', $lastUserId ) );
|
||||
$userIds = $batchQueryBuilder->fetchFieldValues();
|
||||
if ( $userIds ) {
|
||||
$users = $this->actorStore->newSelectQueryBuilder( $this->getDB( DB_REPLICA ) )
|
||||
$users = $this->actorStore->newSelectQueryBuilder( $dbr )
|
||||
->whereUserIds( $userIds )
|
||||
->fetchUserIdentities();
|
||||
} else {
|
||||
|
@ -203,7 +204,7 @@ class RefreshUserImpactData extends Maintenance {
|
|||
if ( $editedWithin ) {
|
||||
$timestamp = $dbr->timestamp( $this->getTimestampFromRelativeDate( $editedWithin ) );
|
||||
$queryBuilder->join( 'revision', null, [ 'rev_actor = actor_id' ] );
|
||||
$queryBuilder->where( "rev_timestamp >= $timestamp" );
|
||||
$queryBuilder->where( $dbr->expr( 'rev_timestamp', '>=', $timestamp ) );
|
||||
$queryBuilder->groupBy( [ 'actor_user' ] );
|
||||
}
|
||||
if ( $registeredWithin ) {
|
||||
|
@ -211,14 +212,14 @@ class RefreshUserImpactData extends Maintenance {
|
|||
$this->getTimestampFromRelativeDate( $registeredWithin )
|
||||
);
|
||||
if ( $firstUserId ) {
|
||||
$queryBuilder->where( "actor_user >= $firstUserId" );
|
||||
$queryBuilder->where( $dbr->expr( 'actor_user', '>=', $firstUserId ) );
|
||||
} else {
|
||||
$queryBuilder->where( '0 = 1' );
|
||||
}
|
||||
}
|
||||
if ( $hasEditsAtLeast ) {
|
||||
$queryBuilder->join( 'user', null, [ 'user_id = actor_user' ] );
|
||||
$queryBuilder->where( 'user_editcount >= ' . (int)$hasEditsAtLeast );
|
||||
$queryBuilder->where( $dbr->expr( 'user_editcount', '>=', (int)$hasEditsAtLeast ) );
|
||||
}
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ use WANObjectCache;
|
|||
use Wikimedia\Rdbms\FakeResultWrapper;
|
||||
use Wikimedia\Rdbms\IConnectionProvider;
|
||||
use Wikimedia\Rdbms\IReadableDatabase;
|
||||
use Wikimedia\Rdbms\SelectQueryBuilder;
|
||||
use Wikimedia\TestingAccessWrapper;
|
||||
|
||||
/**
|
||||
|
@ -120,10 +121,11 @@ class SuggestedEditsTest extends MediaWikiUnitTestCase {
|
|||
);
|
||||
$titleFactoryMock = $this->createMock( TitleFactory::class );
|
||||
$linkBatchFactoryMock = $this->createMock( LinkBatchFactory::class );
|
||||
$queryBuilder = $this->createMock( SelectQueryBuilder::class );
|
||||
$queryBuilder->method( $this->logicalOr( 'select', 'from', 'where', 'caller' ) )->willReturnSelf();
|
||||
$queryBuilder->method( 'fetchResultSet' )->willReturn( new FakeResultWrapper( [] ) );
|
||||
$databaseMock = $this->createMock( IReadableDatabase::class );
|
||||
$databaseMock->expects( $this->once() )
|
||||
->method( 'select' )
|
||||
->willReturn( new FakeResultWrapper( [] ) );
|
||||
$databaseMock->method( 'newSelectQueryBuilder' )->willReturn( $queryBuilder );
|
||||
$connProvider = $this->createMock( IConnectionProvider::class );
|
||||
$connProvider->method( 'getReplicaDatabase' )->willReturn( $databaseMock );
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ use stdClass;
|
|||
use Wikimedia\Rdbms\FakeResultWrapper;
|
||||
use Wikimedia\Rdbms\IConnectionProvider;
|
||||
use Wikimedia\Rdbms\IReadableDatabase;
|
||||
use Wikimedia\Rdbms\SelectQueryBuilder;
|
||||
|
||||
/**
|
||||
* @covers \GrowthExperiments\NewcomerTasks\ProtectionFilter
|
||||
|
@ -105,7 +106,7 @@ class ProtectionFilterTest extends MediaWikiUnitTestCase {
|
|||
$dbr = $this->createMock( IReadableDatabase::class );
|
||||
$dbr->expects( $this->exactly( 4 ) )
|
||||
->method( 'select' )
|
||||
->with( 'page_restrictions' )
|
||||
->with( [ 'page_restrictions' ] )
|
||||
->willReturnCallback(
|
||||
static function ( $table, $vars, $conds ) use ( $map ) {
|
||||
$data = [];
|
||||
|
@ -122,6 +123,10 @@ class ProtectionFilterTest extends MediaWikiUnitTestCase {
|
|||
}
|
||||
return new FakeResultWrapper( $data );
|
||||
} );
|
||||
$dbr->method( 'newSelectQueryBuilder' )
|
||||
->willReturnCallback( static function () use ( $dbr ) {
|
||||
return new SelectQueryBuilder( $dbr );
|
||||
} );
|
||||
$connProvider = $this->createMock( IConnectionProvider::class );
|
||||
$connProvider->method( 'getReplicaDatabase' )->willReturn( $dbr );
|
||||
return $connProvider;
|
||||
|
|
正在加载...
在新工单中引用