perf: Enrich calls in combined sql queries

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl
2023-02-15 09:36:51 +01:00
parent 23813b7a03
commit 7bfbbee6e8
4 changed files with 72 additions and 64 deletions

View File

@@ -28,11 +28,13 @@ namespace OCA\Deck\Service;
use OCA\Deck\Activity\ActivityManager; use OCA\Deck\Activity\ActivityManager;
use OCA\Deck\Activity\ChangeSet; use OCA\Deck\Activity\ChangeSet;
use OCA\Deck\Db\Assignment;
use OCA\Deck\Db\AssignmentMapper; use OCA\Deck\Db\AssignmentMapper;
use OCA\Deck\Db\Card; use OCA\Deck\Db\Card;
use OCA\Deck\Db\CardMapper; use OCA\Deck\Db\CardMapper;
use OCA\Deck\Db\Acl; use OCA\Deck\Db\Acl;
use OCA\Deck\Db\ChangeHelper; use OCA\Deck\Db\ChangeHelper;
use OCA\Deck\Db\Label;
use OCA\Deck\Db\StackMapper; use OCA\Deck\Db\StackMapper;
use OCA\Deck\Event\CardCreatedEvent; use OCA\Deck\Event\CardCreatedEvent;
use OCA\Deck\Event\CardDeletedEvent; use OCA\Deck\Event\CardDeletedEvent;
@@ -114,32 +116,52 @@ class CardService {
$this->cardServiceValidator = $cardServiceValidator; $this->cardServiceValidator = $cardServiceValidator;
} }
public function enrich($card) { public function enrichCards($cards) {
$cardId = $card->getId();
$this->cardMapper->mapOwner($card);
$card->setAssignedUsers($this->assignedUsersMapper->findAll($cardId));
$card->setLabels($this->labelMapper->findAssignedLabelsForCard($cardId));
$card->setAttachmentCount($this->attachmentService->count($cardId));
$user = $this->userManager->get($this->currentUser); $user = $this->userManager->get($this->currentUser);
$lastRead = $this->commentsManager->getReadMark('deckCard', (string)$card->getId(), $user);
$countUnreadComments = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId(), $lastRead);
$countComments = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId());
$card->setCommentsUnread($countUnreadComments);
$card->setCommentsCount($countComments);
$stack = $this->stackMapper->find($card->getStackId()); $cardIds = array_map(function (Card $card) {
$board = $this->boardService->find($stack->getBoardId()); // Everything done in here might be heavy as it is executed for every card
$card->setRelatedStack($stack); $cardId = $card->getId();
$card->setRelatedBoard($board); $this->cardMapper->mapOwner($card);
$card->setAttachmentCount($this->attachmentService->count($cardId));
// TODO We should find a better way just to get the comment count so we can save 1-3 queries per card here
$countComments = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId());
$lastRead = $countComments > 0 ? $this->commentsManager->getReadMark('deckCard', (string)$card->getId(), $user) : null;
$countUnreadComments = $lastRead ? $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId(), $lastRead) : 0;
$card->setCommentsUnread($countUnreadComments);
$card->setCommentsCount($countComments);
$stack = $this->stackMapper->find($card->getStackId());
$board = $this->boardService->find($stack->getBoardId(), false);
$card->setRelatedStack($stack);
$card->setRelatedBoard($board);
return $card->getId();
}, $cards);
$assignedLabels = $this->labelMapper->findAssignedLabelsForCards($cardIds);
$assignedUsers = $this->assignedUsersMapper->findIn($cardIds);
foreach ($cards as $card) {
$cardLabels = array_filter($assignedLabels, function (Label $label) use ($card) {
return $label->getCardId() === $card->getId();
});
$cardAssignedUsers = array_filter($assignedUsers, function (Assignment $label) use ($card) {
return $label->getCardId() === $card->getId();
});
$card->setLabels($cardLabels);
$card->setAssignedUsers($cardAssignedUsers);
}
return $cards;
} }
public function fetchDeleted($boardId) { public function fetchDeleted($boardId) {
$this->cardServiceValidator->check(compact('boardId')); $this->cardServiceValidator->check(compact('boardId'));
$this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ); $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ);
$cards = $this->cardMapper->findDeleted($boardId); $cards = $this->cardMapper->findDeleted($boardId);
foreach ($cards as $card) { $this->enrichCards($cards);
$this->enrich($card);
}
return $cards; return $cards;
} }
@@ -162,7 +184,7 @@ class CardService {
} }
$card->setAssignedUsers($assignedUsers); $card->setAssignedUsers($assignedUsers);
$card->setAttachments($attachments); $card->setAttachments($attachments);
$this->enrich($card); $this->enrichCards([$card]);
return $card; return $card;
} }
@@ -174,9 +196,7 @@ class CardService {
return []; return [];
} }
$cards = $this->cardMapper->findCalendarEntries($boardId); $cards = $this->cardMapper->findCalendarEntries($boardId);
foreach ($cards as $card) { $this->enrichCards($cards);
$this->enrich($card);
}
return $cards; return $cards;
} }

View File

@@ -35,8 +35,10 @@ use OCP\Comments\ICommentsManager;
use OCA\Deck\Db\BoardMapper; use OCA\Deck\Db\BoardMapper;
use OCA\Deck\Db\LabelMapper; use OCA\Deck\Db\LabelMapper;
use OCP\IUserManager; use OCP\IUserManager;
use OCP\IUserSession;
class OverviewService { class OverviewService {
private CardService $cardService;
private BoardMapper $boardMapper; private BoardMapper $boardMapper;
private LabelMapper $labelMapper; private LabelMapper $labelMapper;
private CardMapper $cardMapper; private CardMapper $cardMapper;
@@ -46,6 +48,7 @@ class OverviewService {
private AttachmentService $attachmentService; private AttachmentService $attachmentService;
public function __construct( public function __construct(
CardService $cardService,
BoardMapper $boardMapper, BoardMapper $boardMapper,
LabelMapper $labelMapper, LabelMapper $labelMapper,
CardMapper $cardMapper, CardMapper $cardMapper,
@@ -54,6 +57,7 @@ class OverviewService {
ICommentsManager $commentsManager, ICommentsManager $commentsManager,
AttachmentService $attachmentService AttachmentService $attachmentService
) { ) {
$this->cardService = $cardService;
$this->boardMapper = $boardMapper; $this->boardMapper = $boardMapper;
$this->labelMapper = $labelMapper; $this->labelMapper = $labelMapper;
$this->cardMapper = $cardMapper; $this->cardMapper = $cardMapper;
@@ -63,32 +67,15 @@ class OverviewService {
$this->attachmentService = $attachmentService; $this->attachmentService = $attachmentService;
} }
public function enrich(Card $card, string $userId): void {
$cardId = $card->getId();
$this->cardMapper->mapOwner($card);
$card->setAssignedUsers($this->assignedUsersMapper->findAll($cardId));
$card->setLabels($this->labelMapper->findAssignedLabelsForCard($cardId));
$card->setAttachmentCount($this->attachmentService->count($cardId));
$user = $this->userManager->get($userId);
if ($user !== null) {
$lastRead = $this->commentsManager->getReadMark('deckCard', (string)$card->getId(), $user);
$count = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId(), $lastRead);
$card->setCommentsUnread($count);
}
}
public function findAllWithDue(string $userId): array { public function findAllWithDue(string $userId): array {
$userBoards = $this->boardMapper->findAllForUser($userId); $userBoards = $this->boardMapper->findAllForUser($userId);
$allDueCards = []; $allDueCards = [];
foreach ($userBoards as $userBoard) { foreach ($userBoards as $userBoard) {
$allDueCards[] = array_map(function ($card) use ($userBoard, $userId) { $allDueCards[] = array_map(function ($card) use ($userBoard, $userId) {
$this->enrich($card, $userId);
return (new CardDetails($card, $userBoard))->jsonSerialize(); return (new CardDetails($card, $userBoard))->jsonSerialize();
}, $this->cardMapper->findAllWithDue($userBoard->getId())); }, $this->cardMapper->findAllWithDue($userBoard->getId()));
} }
return array_merge(...$allDueCards); return $this->cardService->enrichCards(array_merge(...$allDueCards));
} }
public function findUpcomingCards(string $userId): array { public function findUpcomingCards(string $userId): array {
@@ -103,26 +90,29 @@ class OverviewService {
$cards = $this->cardMapper->findToMeOrNotAssignedCards($userBoard->getId(), $userId); $cards = $this->cardMapper->findToMeOrNotAssignedCards($userBoard->getId(), $userId);
} }
foreach ($cards as $card) { $foundCards[] = $cards;
$this->enrich($card, $userId); }
$diffDays = $card->getDaysUntilDue();
$key = 'later'; $foundCards = array_merge(...$foundCards);
if ($diffDays === null) { $this->cardService->enrichCards($foundCards);
$key = 'nodue'; foreach ($foundCards as $card) {
} elseif ($diffDays < 0) { $diffDays = $card->getDaysUntilDue();
$key = 'overdue';
} elseif ($diffDays === 0) {
$key = 'today';
} elseif ($diffDays === 1) {
$key = 'tomorrow';
} elseif ($diffDays <= 7) {
$key = 'nextSevenDays';
}
$card = (new CardDetails($card, $userBoard)); $key = 'later';
$overview[$key][] = $card->jsonSerialize(); if ($diffDays === null) {
$key = 'nodue';
} elseif ($diffDays < 0) {
$key = 'overdue';
} elseif ($diffDays === 0) {
$key = 'today';
} elseif ($diffDays === 1) {
$key = 'tomorrow';
} elseif ($diffDays <= 7) {
$key = 'nextSevenDays';
} }
$card = (new CardDetails($card, $userBoard));
$overview[$key][] = $card->jsonSerialize();
} }
return $overview; return $overview;
} }

View File

@@ -83,10 +83,7 @@ class SearchService {
$matchedCards = $this->cardMapper->search($boardIds, $this->filterStringParser->parse($term), $limit, $cursor); $matchedCards = $this->cardMapper->search($boardIds, $this->filterStringParser->parse($term), $limit, $cursor);
$self = $this; $self = $this;
return array_map(function (Card $card) use ($self) { return $this->cardService->enrichCards($matchedCards);
$self->cardService->enrich($card);
return $card;
}, $matchedCards);
} }
public function searchBoards(string $term, ?int $limit, ?int $cursor): array { public function searchBoards(string $term, ?int $limit, ?int $cursor): array {
@@ -117,7 +114,8 @@ class SearchService {
$comment = $this->commentsManager->get($cardRow['comment_id']); $comment = $this->commentsManager->get($cardRow['comment_id']);
unset($cardRow['comment_id']); unset($cardRow['comment_id']);
$card = Card::fromRow($cardRow); $card = Card::fromRow($cardRow);
$self->cardService->enrich($card); // TODO: Only perform one enrich call here
$self->cardService->enrichCards([$card]);
$user = $this->userManager->get($comment->getActorId()); $user = $this->userManager->get($comment->getActorId());
$displayName = $user ? $user->getDisplayName() : ''; $displayName = $user ? $user->getDisplayName() : '';
return new CommentSearchResultEntry($comment->getId(), $comment->getMessage(), $displayName, $card, $this->urlGenerator, $this->l10n); return new CommentSearchResultEntry($comment->getId(), $comment->getMessage(), $displayName, $card, $this->urlGenerator, $this->l10n);

View File

@@ -94,9 +94,9 @@ class StackService {
return; return;
} }
$this->cardService->enrichCards($cards);
$cards = array_map( $cards = array_map(
function (Card $card): CardDetails { function (Card $card): CardDetails {
$this->cardService->enrich($card);
return new CardDetails($card); return new CardDetails($card);
}, },
$cards $cards