summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fetchtopicsaction.cpp105
-rw-r--r--fetchtopicsaction.h1
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;