diff options
-rw-r--r-- | fetchtopicsaction.cpp | 105 | ||||
-rw-r--r-- | fetchtopicsaction.h | 1 |
2 files changed, 97 insertions, 9 deletions
diff --git a/fetchtopicsaction.cpp b/fetchtopicsaction.cpp index 9e42723..d8ea173 100644 --- a/fetchtopicsaction.cpp +++ b/fetchtopicsaction.cpp @@ -62,12 +62,23 @@ void FetchTopicsAction::handleFinishedCall() QSqlDatabase db = _board->database(); db.transaction(); + const int total_topic_num = map["total_topic_num"].toInt(); + int expected_end = _end == FetchAllTopics ? _start + MAX_FORUM_PAGE_SIZE : _end; + QList<int> current_topics = getCurrentDbTopics(_start, expected_end); + QList<int> unchanged_topics = current_topics; + + if (_start >= total_topic_num) { + // Workaround an issue where the service always returns one post. + topics.clear(); + } + + Q_ASSERT(_start >= 0); + int position = _start; + QSqlQuery query(db); query.prepare("INSERT OR REPLACE INTO topics (forum_id, topic_id, topic_title, topic_author_id, topic_author_name, is_subscribed, is_closed, icon_url, last_reply_time, reply_number, new_post, position, last_update_time) " "VALUES (:forum_id, :topic_id, :topic_title, :topic_author_id, :topic_author_name, :is_subscribed, :is_closed, :icon_url, :last_reply_time, :reply_number, :new_post, :position, :last_update_time)"); - Q_ASSERT(_start >= 0); - int position = _start; foreach (const QVariant& topic_v, topics) { QVariantMap topic = topic_v.toMap(); @@ -80,7 +91,9 @@ void FetchTopicsAction::handleFinishedCall() int topic_id = topic["topic_id"].toInt(&ok); if (!ok) { qWarning() << "No topic_id in" << topic; - continue; + // This is now a fatal error. + db.rollback(); + goto finish; } query.bindValue(":forum_id", forum_id); @@ -102,21 +115,73 @@ void FetchTopicsAction::handleFinishedCall() if (!query.exec()) { qWarning() << "Failed to store topic info for:" << topic_id; handleDatabaseError("storing topic info", query); - continue; + db.rollback(); + goto finish; + } + + unchanged_topics.removeOne(topic_id); + } + + // "position" would now point to "_end + 1", if we had gotten as + // many topics as we requested. + + int fetched_end = position - 1; + bool eof = fetched_end < expected_end; + if (eof) { + // Service did not return as many topics as we expected, thus we + // can safely delete any topics after the current position. + query.prepare("DELETE FROM topics WHERE forum_id = :forum_id AND position >= :position"); + query.bindValue(":forum_id", _forumId); + query.bindValue(":position", position); + if (query.exec()) { + position += query.numRowsAffected(); // Advance the position counter + } else { + handleDatabaseError("deleting topics", query); + db.rollback(); + goto finish; + } + + if (!unchanged_topics.empty()) { + // The topics that were in the begin..end range but were not updated + // need to be removed. + query.prepare("DELETE FROM topics WHERE topic_id = :topic_id"); + foreach (int topic_id, unchanged_topics) { + query.bindValue(":topic_id", topic_id); + if (!query.exec()) { + handleDatabaseError("deleting topics", query); + db.rollback(); + goto finish; + } + position++; + } + } + } else if (!unchanged_topics.empty()) { + // The topics that were in the begin..end range but were not updated + // need to be renumbered. + query.prepare("UPDATE topics SET position = :position WHERE topic_id = :topic_id"); + foreach (int topic_id, unchanged_topics) { + query.bindValue(":position", position); + query.bindValue(":topic_id", topic_id); + if (!query.exec()) { + handleDatabaseError("updating topic position", query); + db.rollback(); + goto finish; + } + position++; } + + Q_ASSERT(position >= expected_end + 1); } db.commit(); - if (!topics.isEmpty()) { - Q_ASSERT(_start >= 0); - Q_ASSERT(position - 1 >= _start); + if (position > _start) { _board->notifyForumTopicsChanged(_forumId, _start, position - 1); } - if (_end == FetchAllTopics && topics.size() == MAX_FORUM_PAGE_SIZE) { + if (_end == FetchAllTopics && !eof) { // Ok, let's prepare to fetch the next block of topics because // there are probably more of them - int next_start = _start + MAX_FORUM_PAGE_SIZE; + int next_start = fetched_end + 1; _board->enqueueAction(new FetchTopicsAction(_forumId, next_start, FetchAllTopics, @@ -126,6 +191,7 @@ void FetchTopicsAction::handleFinishedCall() qWarning() << "Could not fetch topics"; // TODO emit error ... } +finish: emit finished(this); _call->deleteLater(); } @@ -135,3 +201,24 @@ QString FetchTopicsAction::decodeTopicText(const QVariant &v) QByteArray ba = v.toByteArray(); return QString::fromUtf8(ba.constData(), ba.length()); } + +QList<int> FetchTopicsAction::getCurrentDbTopics(int start, int end) +{ + QSqlQuery query(_board->database()); + query.prepare("SELECT topic_id FROM topics " + "WHERE forum_id = :forum_id AND position BETWEEN :start AND :end " + "ORDER by position ASC"); + query.bindValue(":forum_id", _forumId); + query.bindValue(":start", start); + query.bindValue(":end", end); + if (query.exec()) { + QList<int> list; + while (query.next()) { + list << query.value(0).toInt(); + } + return list; + } else { + qWarning() << "Could not get current topics list:" << query.lastError().text(); + return QList<int>(); + } +} diff --git a/fetchtopicsaction.h b/fetchtopicsaction.h index 87b756f..307e528 100644 --- a/fetchtopicsaction.h +++ b/fetchtopicsaction.h @@ -26,6 +26,7 @@ private slots: private: static QString decodeTopicText(const QVariant& v); + QList<int> getCurrentDbTopics(int start, int end); private: XmlRpcPendingCall *_call; |