Left join the last comment instead of doing O(n) queries

Signed-off-by: Joas Schilling <coding@schilljs.com>
This commit is contained in:
Joas Schilling 2018-07-18 16:25:24 +02:00
Родитель 27cd7954ae
Коммит f37e260ac5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 7076EA9751AACDDA
7 изменённых файлов: 154 добавлений и 17 удалений

Просмотреть файл

@ -17,7 +17,7 @@ And in the works for the [coming versions](https://github.com/nextcloud/spreed/m
]]></description>
<version>3.99.5</version>
<version>3.99.6</version>
<licence>agpl</licence>
<author>Daniel Calviño Sánchez</author>

Просмотреть файл

@ -76,6 +76,9 @@ class ChatManager {
$this->commentsManager->save($comment);
// Update last_message
$chat->setLastMessage($comment);
$this->notifier->notifyMentionedUsers($chat, $comment);
return $comment;
}

Просмотреть файл

@ -29,6 +29,14 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
class CommentsManager extends Manager {
/**
* @param array $data
* @return IComment
*/
public function getCommentFromData(array $data): IComment {
return new Comment($this->normalizeDatabaseData($data));
}
/**
* @param string $objectType
* @param string $objectId

Просмотреть файл

@ -38,6 +38,7 @@ use OCA\Spreed\TalkSession;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\Comments\IComment;
use OCP\IL10N;
use OCP\ILogger;
use OCP\IRequest;
@ -115,7 +116,7 @@ class RoomController extends OCSController {
* @return DataResponse
*/
public function getRooms() {
$rooms = $this->manager->getRoomsForParticipant($this->userId);
$rooms = $this->manager->getRoomsForParticipant($this->userId, true);
$return = [];
foreach ($rooms as $room) {
@ -249,35 +250,35 @@ class RoomController extends OCSController {
$room->cleanGuestParticipants();
}
$lastMessageFromHistory = $this->chatManager->getHistory($room->getId(), 0, 1);
$lastMessage = [];
$lastMessage = $room->getLastMessage();
if ($lastMessage instanceof IComment) {
if (!empty($lastMessageFromHistory)) {
list($message, $messageParameters) = $this->richMessageHelper->getRichMessage($lastMessageFromHistory[0]);
list($message, $messageParameters) = $this->richMessageHelper->getRichMessage($lastMessage);
$displayName = '';
$actorId = $lastMessageFromHistory[0]->getActorId();
$actorType = $lastMessageFromHistory[0]->getActorType();
$actorId = $lastMessage->getActorId();
$actorType = $lastMessage->getActorType();
if ($actorType === 'users') {
$user = $this->userManager->get($actorId);
$displayName = $user instanceof IUser ? $user->getDisplayName() : '';
} else if ($actorType === 'guests') {
$guestNames = !empty($actorId) ? $this->guestManager->getNamesBySessionHashes([$actorId]) : [];
$displayName = isset($guestNames[$actorId]) ? $guestNames[$actorId] : '';
$displayName = $guestNames[$actorId] ?? '';
}
$lastMessage = [
'id' => $lastMessageFromHistory[0]->getId(),
'id' => $lastMessage->getId(),
'actorType' => $actorType,
'actorId' => $actorId,
'actorDisplayName' => $displayName,
'timestamp' => $lastMessageFromHistory[0]->getCreationDateTime()->getTimestamp(),
'timestamp' => $lastMessage->getCreationDateTime()->getTimestamp(),
'message' => $message,
'messageParameters' => $messageParameters,
];
} else {
$lastMessage = [];
}
$roomData = array_merge($roomData, [

Просмотреть файл

@ -22,6 +22,7 @@
namespace OCA\Spreed;
use OCA\Spreed\Chat\CommentsManager;
use OCA\Spreed\Exceptions\RoomNotFoundException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IConfig;
@ -39,6 +40,8 @@ class Manager {
private $config;
/** @var ISecureRandom */
private $secureRandom;
/** @var CommentsManager */
private $commentsManager;
/** @var EventDispatcherInterface */
private $dispatcher;
/** @var IHasher */
@ -50,13 +53,15 @@ class Manager {
* @param IDBConnection $db
* @param IConfig $config
* @param ISecureRandom $secureRandom
* @param CommentsManager $commentsManager
* @param EventDispatcherInterface $dispatcher
* @param IHasher $hasher
*/
public function __construct(IDBConnection $db, IConfig $config, ISecureRandom $secureRandom, EventDispatcherInterface $dispatcher, IHasher $hasher) {
public function __construct(IDBConnection $db, IConfig $config, ISecureRandom $secureRandom, CommentsManager $commentsManager, EventDispatcherInterface $dispatcher, IHasher $hasher) {
$this->db = $db;
$this->config = $config;
$this->secureRandom = $secureRandom;
$this->commentsManager = $commentsManager;
$this->dispatcher = $dispatcher;
$this->hasher = $hasher;
}
@ -89,7 +94,12 @@ class Manager {
$lastActivity = new \DateTime($row['last_activity']);
}
return new Room($this, $this->db, $this->secureRandom, $this->dispatcher, $this->hasher, (int) $row['id'], (int) $row['type'], $row['token'], $row['name'], $row['password'], (int) $row['active_guests'], $activeSince, $lastActivity);
$lastMessage = null;
if (!empty($row['comment_id'])) {
$lastMessage = $this->commentsManager->getCommentFromData(array_merge($row, ['id' => $row['comment_id']]));
}
return new Room($this, $this->db, $this->secureRandom, $this->dispatcher, $this->hasher, (int) $row['id'], (int) $row['type'], $row['token'], $row['name'], $row['password'], (int) $row['active_guests'], $activeSince, $lastActivity, $lastMessage);
}
/**
@ -103,11 +113,12 @@ class Manager {
/**
* @param string $participant
* @param bool $includeLastMessage
* @return Room[]
*/
public function getRoomsForParticipant($participant) {
public function getRoomsForParticipant($participant, $includeLastMessage = false) {
$query = $this->db->getQueryBuilder();
$query->select('*')
$query->select('r.*')->addSelect('p.*')
->from('talk_rooms', 'r')
->leftJoin('r', 'talk_participants', 'p', $query->expr()->andX(
$query->expr()->eq('p.user_id', $query->createNamedParameter($participant)),
@ -115,6 +126,12 @@ class Manager {
))
->where($query->expr()->isNotNull('p.user_id'));
if ($includeLastMessage) {
$query->leftJoin('r','comments', 'c', $query->expr()->eq('r.last_message', 'c.id'));
$query->selectAlias('c.id', 'comment_id');
$query->addSelect('c.actor_id', 'c.actor_type', 'c.message', 'c.creation_timestamp');
}
$result = $query->execute();
$rooms = [];
while ($row = $result->fetch()) {

Просмотреть файл

@ -0,0 +1,88 @@
<?php
/**
* @copyright Copyright (c) 2018, Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Spreed\Migration;
use Doctrine\DBAL\Types\Type;
use OCP\DB\ISchemaWrapper;
use OCP\IDBConnection;
use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;
class Version3003Date20180718133519 extends SimpleMigrationStep {
/** @var IDBConnection */
protected $connection;
public function __construct(IDBConnection $connection) {
$this->connection = $connection;
}
/**
* @param IOutput $output
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @return null|ISchemaWrapper
* @since 13.0.0
*/
public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
$table = $schema->getTable('talk_rooms');
if (!$table->hasColumn('last_message')) {
$table->addColumn('last_message', Type::BIGINT, [
'notnull' => false,
'default' => 0,
]);
}
return $schema;
}
/**
* @param IOutput $output
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @since 13.0.0
*/
public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) {
$update = $this->connection->getQueryBuilder();
$update->update('talk_rooms')
->set('last_message', $update->createParameter('message'))
->where($update->expr()->eq('id', $update->createParameter('room')));
$query = $this->connection->getQueryBuilder();
$query->selectAlias($query->createFunction('MAX(' . $query->getColumnName('id') . ')'), 'message')
->addSelect('object_id')
->from('comments')
->where($query->expr()->eq('object_type', $query->createNamedParameter('chat')))
->groupBy('object_id');
$result = $query->execute();
while ($row = $result->fetch()) {
$update->setParameter('message', $row['message'])
->setParameter('room', $row['object_id']);
$update->execute();
}
$result->closeCursor();
}
}

Просмотреть файл

@ -27,6 +27,7 @@ namespace OCA\Spreed;
use OCA\Spreed\Exceptions\InvalidPasswordException;
use OCA\Spreed\Exceptions\ParticipantNotFoundException;
use OCP\Comments\IComment;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\IUser;
@ -68,6 +69,8 @@ class Room {
private $activeSince;
/** @var \DateTime|null */
private $lastActivity;
/** @var IComment|null */
private $lastMessage;
/** @var string */
protected $currentUser;
@ -90,8 +93,9 @@ class Room {
* @param int $activeGuests
* @param \DateTime|null $activeSince
* @param \DateTime|null $lastActivity
* @param IComment|null $lastMessage
*/
public function __construct(Manager $manager, IDBConnection $db, ISecureRandom $secureRandom, EventDispatcherInterface $dispatcher, IHasher $hasher, $id, $type, $token, $name, $password, $activeGuests, \DateTime $activeSince = null, \DateTime $lastActivity = null) {
public function __construct(Manager $manager, IDBConnection $db, ISecureRandom $secureRandom, EventDispatcherInterface $dispatcher, IHasher $hasher, $id, $type, $token, $name, $password, $activeGuests, \DateTime $activeSince = null, \DateTime $lastActivity = null, IComment $lastMessage = null) {
$this->manager = $manager;
$this->db = $db;
$this->secureRandom = $secureRandom;
@ -105,6 +109,7 @@ class Room {
$this->activeGuests = $activeGuests;
$this->activeSince = $activeSince;
$this->lastActivity = $lastActivity;
$this->lastMessage = $lastMessage;
}
/**
@ -156,6 +161,13 @@ class Room {
return $this->lastActivity;
}
/**
* @return IComment|null
*/
public function getLastMessage() {
return $this->lastMessage;
}
/**
* @return bool
*/
@ -369,6 +381,14 @@ class Room {
return true;
}
public function setLastMessage(IComment $message) {
$query = $this->db->getQueryBuilder();
$query->update('talk_rooms')
->set('last_message', $query->createNamedParameter((int) $message->getId()))
->where($query->expr()->eq('id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)));
$query->execute();
}
/**
* @return bool
*/