From 6b8e1618ea695adb64777e9f1cda096b130285b0 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Tue, 25 Jun 2019 14:15:23 -0100 Subject: [PATCH] Cleaner stream Signed-off-by: Maxence Lange --- lib/Db/CoreRequestBuilder.php | 50 ++++++++++++++++++++++++++------- lib/Db/StreamRequest.php | 7 +++-- lib/Db/StreamRequestBuilder.php | 41 +++++++++++++++++++-------- 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php index fc9a835f..9dcf8eb2 100644 --- a/lib/Db/CoreRequestBuilder.php +++ b/lib/Db/CoreRequestBuilder.php @@ -475,7 +475,7 @@ class CoreRequestBuilder { protected function limitToDBField( IQueryBuilder &$qb, string $field, string $value, bool $cs = true, string $alias = '' ) { - $expr = $this->exprLimitToDBField($qb, $field, $value, $cs, $alias); + $expr = $this->exprLimitToDBField($qb, $field, $value, true, $cs, $alias); $qb->andWhere($expr); } @@ -484,13 +484,15 @@ class CoreRequestBuilder { * @param IQueryBuilder $qb * @param string $field * @param string $value + * @param bool $eq * @param bool $cs * @param string $alias * * @return string */ protected function exprLimitToDBField( - IQueryBuilder &$qb, string $field, string $value, bool $cs = true, string $alias = '' + IQueryBuilder &$qb, string $field, string $value, bool $eq = true, bool $cs = true, + string $alias = '' ): string { $expr = $qb->expr(); @@ -500,12 +502,20 @@ class CoreRequestBuilder { } $field = $pf . $field; + if ($eq) { + $comp = 'eq'; + } else { + $comp = 'neq'; + } + if ($cs) { - return $expr->eq($field, $qb->createNamedParameter($value)); + return $expr->$comp($field, $qb->createNamedParameter($value)); } else { $func = $qb->func(); - return $expr->eq($func->lower($field), $func->lower($qb->createNamedParameter($value))); + return $expr->$comp( + $func->lower($field), $func->lower($qb->createNamedParameter($value)) + ); } } @@ -653,9 +663,12 @@ class CoreRequestBuilder { /** * @param IQueryBuilder $qb * @param string $fieldActorId + * @param Person $author * @param string $alias */ - protected function leftJoinCacheActors(IQueryBuilder &$qb, string $fieldActorId, string $alias = '') { + protected function leftJoinCacheActors( + IQueryBuilder &$qb, string $fieldActorId, Person $author = null, string $alias = '' + ) { if ($qb->getType() !== QueryBuilder::SELECT) { return; } @@ -681,11 +694,28 @@ class CoreRequestBuilder { ->selectAlias('ca.public_key', 'cacheactor_public_key') ->selectAlias('ca.source', 'cacheactor_source') ->selectAlias('ca.creation', 'cacheactor_creation') - ->selectAlias('ca.local', 'cacheactor_local') - ->leftJoin( - $this->defaultSelectAlias, CoreRequestBuilder::TABLE_CACHE_ACTORS, 'ca', - $expr->eq($func->lower($pf . '.' . $fieldActorId), $func->lower('ca.id')) - ); + ->selectAlias('ca.local', 'cacheactor_local'); + + $orX = $expr->orX(); + $orX->add($expr->eq($func->lower($pf . '.' . $fieldActorId), $func->lower('ca.id'))); + if ($author !== null) { + $andX = $expr->andX(); + $andX->add( + $this->exprLimitToDBField($qb, 'attributed_to', $author->getId(), true, false, 's') + ); + $andX->add( + $expr->eq( + $func->lower($this->defaultSelectAlias . '.attributed_to'), + $func->lower('ca.id') + ) + ); + $orX->add($andX); + } + + $qb->leftJoin( + $this->defaultSelectAlias, CoreRequestBuilder::TABLE_CACHE_ACTORS, 'ca', $orX + ); + } diff --git a/lib/Db/StreamRequest.php b/lib/Db/StreamRequest.php index db16ad95..1e482739 100644 --- a/lib/Db/StreamRequest.php +++ b/lib/Db/StreamRequest.php @@ -278,10 +278,11 @@ class StreamRequest extends StreamRequestBuilder { public function getTimelineHome(Person $actor, int $since = 0, int $limit = 5): array { $qb = $this->getStreamSelectSql(); - $this->joinFollowing($qb, $actor); + $this->leftJoinFollowing($qb, $actor); + $this->limitToFollowing($qb, $actor); $this->limitPaginate($qb, $since, $limit); - $this->leftJoinCacheActors($qb, 'object_id', 'f'); + $this->leftJoinCacheActors($qb, 'object_id', $actor, 'f'); $this->leftJoinStreamAction($qb); $this->filterDuplicate($qb); @@ -646,7 +647,7 @@ class StreamRequest extends StreamRequestBuilder { $pf = $this->defaultSelectAlias . '.'; $on = $expr->andX(); - $on->add($this->exprLimitToDBField($qb, 'actor_id', $actor->getId(), false, 'fs')); + $on->add($this->exprLimitToDBField($qb, 'actor_id', $actor->getId(), true, false, 'fs')); $on->add($expr->eq($func->lower($pf . 'attributed_to'), $func->lower('fs.object_id'))); $on->add($this->exprLimitToDBFieldInt($qb, 'accepted', 1, 'fs')); diff --git a/lib/Db/StreamRequestBuilder.php b/lib/Db/StreamRequestBuilder.php index 3198887b..003660d5 100644 --- a/lib/Db/StreamRequestBuilder.php +++ b/lib/Db/StreamRequestBuilder.php @@ -99,8 +99,7 @@ class StreamRequestBuilder extends CoreRequestBuilder { 's.object_id', 's.attributed_to', 's.in_reply_to', 's.source', 's.local', 's.instances', 's.creation', 's.hidden_on_timeline' ) - ->from(self::TABLE_STREAMS, 's') - ->groupBy('s.id'); + ->from(self::TABLE_STREAMS, 's'); $this->defaultSelectAlias = 's'; @@ -143,7 +142,7 @@ class StreamRequestBuilder extends CoreRequestBuilder { protected function limitToViewer(IQueryBuilder $qb) { $actor = $this->viewer; - $on = $this->exprJoinFollowing($qb, $actor, false); + $on = $this->exprJoinFollowing($qb, $actor); $on->add($this->exprLimitToRecipient($qb, ACore::CONTEXT_PUBLIC, false)); $on->add($this->exprLimitToRecipient($qb, $actor->getId(), true)); $qb->join($this->defaultSelectAlias, CoreRequestBuilder::TABLE_FOLLOWS, 'f', $on); @@ -180,7 +179,9 @@ class StreamRequestBuilder extends CoreRequestBuilder { $func->lower('attributed_to') ) ); - $follower->add($this->exprLimitToDBField($qb, 'actor_id', $actor->getId(), false, 'f')); + $follower->add( + $this->exprLimitToDBField($qb, 'actor_id', $actor->getId(), true, false, 'f') + ); $filter->add($follower); $qb->andwhere($filter); @@ -191,33 +192,47 @@ class StreamRequestBuilder extends CoreRequestBuilder { * @param IQueryBuilder $qb * @param Person $actor */ - protected function joinFollowing(IQueryBuilder $qb, Person $actor) { + protected function leftJoinFollowing(IQueryBuilder $qb, Person $actor) { if ($qb->getType() !== QueryBuilder::SELECT) { return; } $on = $this->exprJoinFollowing($qb, $actor); $qb->selectAlias('f.object_id', 'following_actor_id'); - $qb->join($this->defaultSelectAlias, CoreRequestBuilder::TABLE_FOLLOWS, 'f', $on); + $qb->leftJoin($this->defaultSelectAlias, CoreRequestBuilder::TABLE_FOLLOWS, 'f', $on); + } + + + /** + * @param IQueryBuilder $qb + * @param Person $actor + */ + protected function limitToFollowing(IQueryBuilder $qb, Person $actor) { + $expr = $qb->expr(); + $andX = $expr->andX(); + $andX->add($this->exprLimitToDBField($qb, 'attributed_to', $actor->getId(), true, false)); + $andX->add($this->exprLimitToDBField($qb, 'cc', '[]', false)); + + $orX = $expr->orX(); + $orX->add($andX); + $orX->add($expr->isNotNull('f.object_id')); + + $qb->andWhere($orX); } /** * @param IQueryBuilder $qb * @param Person $actor - * @param bool $followers * * @return ICompositeExpression */ - protected function exprJoinFollowing(IQueryBuilder $qb, Person $actor, bool $followers = true) { + protected function exprJoinFollowing(IQueryBuilder $qb, Person $actor) { $expr = $qb->expr(); $func = $qb->func(); $pf = $this->defaultSelectAlias . '.'; $on = $expr->orX(); - if ($followers) { - $on->add($this->exprLimitToRecipient($qb, $actor->getFollowers(), false)); - } // list of possible recipient as a follower (to, to_array, cc, ...) $recipientFields = $expr->orX(); @@ -229,7 +244,9 @@ class StreamRequestBuilder extends CoreRequestBuilder { // all possible follow, but linked by followers (actor_id) and accepted follow $crossFollows = $expr->andX(); $crossFollows->add($recipientFields); - $crossFollows->add($this->exprLimitToDBField($qb, 'actor_id', $actor->getId(), false, 'f')); + $crossFollows->add( + $this->exprLimitToDBField($qb, 'actor_id', $actor->getId(), true, false, 'f') + ); $crossFollows->add($this->exprLimitToDBFieldInt($qb, 'accepted', 1, 'f')); $on->add($crossFollows);