Skip to content

Commit a3fa723

Browse files
author
Carl Schwan
committed
perf(cards): fetch all cards at once
Instead of one by one Signed-off-by: Carl Schwan <[email protected]>
1 parent 0ed8b21 commit a3fa723

File tree

5 files changed

+58
-21
lines changed

5 files changed

+58
-21
lines changed

lib/Db/CardMapper.php

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,11 @@ public function find($id, bool $enhance = true): Card {
131131
return $card;
132132
}
133133

134-
public function findAll($stackId, $limit = null, $offset = null, $since = -1) {
134+
/**
135+
* @return Card[]
136+
* @throws \OCP\DB\Exception
137+
*/
138+
public function findAll($stackId, ?int $limit = null, ?int $offset = null, int $since = -1) {
135139
$qb = $this->db->getQueryBuilder();
136140
$qb->select('*')
137141
->from('deck_cards')
@@ -146,6 +150,32 @@ public function findAll($stackId, $limit = null, $offset = null, $since = -1) {
146150
return $this->findEntities($qb);
147151
}
148152

153+
/**
154+
* @param int[] $stackIds
155+
* @return array<int, null|Card[]>
156+
* @throws \OCP\DB\Exception
157+
*/
158+
public function findAllForStacks(array $stackIds, ?int $limit = null, ?int $offset = null, int $since = -1): array {
159+
$qb = $this->db->getQueryBuilder();
160+
$qb->select('*')
161+
->from('deck_cards')
162+
->where($qb->expr()->in('stack_id', $qb->createNamedParameter($stackIds, IQueryBuilder::PARAM_INT_ARRAY)))
163+
->andWhere($qb->expr()->eq('archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
164+
->andWhere($qb->expr()->eq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
165+
->andWhere($qb->expr()->gt('last_modified', $qb->createNamedParameter($since, IQueryBuilder::PARAM_INT)))
166+
->setMaxResults($limit)
167+
->setFirstResult($offset)
168+
->orderBy('order')
169+
->addOrderBy('id');
170+
171+
$rawCards = $this->findEntities($qb);
172+
$cards = array_fill_keys($stackIds, null);
173+
foreach ($rawCards as $card) {
174+
$cards[$card->getStackId()][] = $card;
175+
}
176+
return $cards;
177+
}
178+
149179
public function queryCardsByBoard(int $boardId): IQueryBuilder {
150180
$qb = $this->db->getQueryBuilder();
151181
$qb->select('c.*')

lib/Db/Stack.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* @method int getDeletedAt()
1616
* @method int getLastModified()
1717
* @method int getOrder()
18+
* @method Card[] getCards()
1819
*/
1920
class Stack extends RelationalEntity {
2021
protected $title;

lib/Db/StackMapper.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,10 @@ public function findStackFromCardId($cardId): ?Stack {
7777

7878
/**
7979
* @param numeric $boardId
80-
* @param int|null $limit
81-
* @param int|null $offset
8280
* @return Stack[]
8381
* @throws \OCP\DB\Exception
8482
*/
85-
public function findAll($boardId, $limit = null, $offset = null): array {
83+
public function findAll($boardId, ?int $limit = null, ?int $offset = null): array {
8684
$qb = $this->db->getQueryBuilder();
8785
$qb->select('*')
8886
->from($this->getTableName())

lib/Service/StackService.php

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,22 @@ public function __construct(
7575
$this->stackServiceValidator = $stackServiceValidator;
7676
}
7777

78-
private function enrichStackWithCards($stack, $since = -1) {
79-
$cards = $this->cardMapper->findAll($stack->getId(), null, null, $since);
78+
/** @param Stack[] $stacks */
79+
private function enrichStacksWithCards(array $stacks, $since = -1): void {
80+
$cardsByStackId = $this->cardMapper->findAllForStacks(array_map(fn (Stack $stack) => $stack->getId(), $stacks), null, null, $since);
8081

81-
if (\count($cards) === 0) {
82-
return;
83-
}
82+
foreach ($cardsByStackId as $stackId => $cards) {
83+
if (!$cards) {
84+
continue;
85+
}
8486

85-
$stack->setCards($this->cardService->enrichCards($cards));
86-
}
8787

88-
private function enrichStacksWithCards($stacks, $since = -1) {
89-
foreach ($stacks as $stack) {
90-
$this->enrichStackWithCards($stack, $since);
88+
foreach ($stacks as $stack) {
89+
if ($stack->getId() === $stackId) {
90+
$stack->setCards($this->cardService->enrichCards($cards));
91+
break;
92+
}
93+
}
9194
}
9295
}
9396

@@ -124,9 +127,9 @@ function (Card $card): CardDetails {
124127
}
125128

126129
/**
127-
* @param $boardId
130+
* @param mixed $boardId
128131
*
129-
* @return array
132+
* @return Stack[]
130133
* @throws \OCA\Deck\NoPermissionException
131134
* @throws BadRequestException
132135
*/
@@ -247,7 +250,7 @@ public function delete($id) {
247250
);
248251
$this->changeHelper->boardChanged($stack->getBoardId());
249252
$this->eventDispatcher->dispatchTyped(new BoardUpdatedEvent($stack->getBoardId()));
250-
$this->enrichStackWithCards($stack);
253+
$this->enrichStacksWithCards([$stack]);
251254

252255
return $stack;
253256
}

tests/unit/Service/StackServiceTest.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,17 @@ function ($cards) {
129129
}
130130
)
131131
);
132-
$this->cardMapper->expects($this->any())->method('findAll')->willReturn($this->getCards(222));
133-
132+
$this->cardMapper->expects($this->any())->method('findAllForStacks')->willReturnCallback(function (array $stackIds) {
133+
$r = [];
134+
foreach ($stackIds as $stackId) {
135+
$r[$stackId] = $this->getCards(222);
136+
}
137+
return $r;
138+
});
134139

135140
$actual = $this->stackService->findAll(123);
136141
for ($stackId = 0; $stackId < 3; $stackId++) {
137-
for ($cardId = 0;$cardId < 10;$cardId++) {
142+
for ($cardId = 0; $cardId < 10; $cardId++) {
138143
$this->assertEquals($actual[0]->getCards()[$cardId]->getId(), $cardId);
139144
$this->assertEquals($actual[0]->getCards()[$cardId]->getStackId(), 222);
140145
$this->assertEquals($actual[0]->getCards()[$cardId]->getLabels(), $this->getLabels()[$cardId]);
@@ -211,7 +216,7 @@ public function testDelete() {
211216
$stackToBeDeleted->setBoardId(1);
212217
$this->stackMapper->expects($this->once())->method('find')->willReturn($stackToBeDeleted);
213218
$this->stackMapper->expects($this->once())->method('update')->willReturn($stackToBeDeleted);
214-
$this->cardMapper->expects($this->once())->method('findAll')->willReturn([]);
219+
$this->cardMapper->expects($this->once())->method('findAllForStacks')->willReturn([]);
215220
$this->stackService->delete(123);
216221
$this->assertTrue($stackToBeDeleted->getDeletedAt() <= time(), 'deletedAt is in the past');
217222
$this->assertTrue($stackToBeDeleted->getDeletedAt() > 0, 'deletedAt is set');

0 commit comments

Comments
 (0)