Line data Source code
1 : #include "LoadNewsOperation.h"
2 : #include "../models/NewsList.h"
3 : #include "../utilities/ErrorHandling.h"
4 : #include "../utilities/FangLogging.h"
5 :
6 8 : LoadNewsOperation::LoadNewsOperation(OperationManager *parent, FeedItem* feedItem, LoadMode mode, int loadLimit) :
7 : DBOperation(parent),
8 8 : feedItem(feedItem),
9 8 : listAppend(),
10 8 : listPrepend(),
11 8 : mode(mode),
12 8 : loadLimit(loadLimit)
13 : {
14 8 : }
15 :
16 8 : LoadNewsOperation::~LoadNewsOperation()
17 : {
18 :
19 8 : }
20 :
21 0 : QString LoadNewsOperation::modeToString(LoadMode mode)
22 : {
23 0 : switch(mode) {
24 0 : case Initial:
25 0 : return "initial";
26 0 : case Prepend:
27 0 : return "prepend";
28 0 : case Append:
29 0 : return "append";
30 0 : default:
31 0 : FANG_UNREACHABLE("Invalid LoadMode enum value");
32 : return "[ERROR]";
33 : }
34 : }
35 :
36 0 : LoadNewsOperation::LoadMode LoadNewsOperation::stringToMode(QString modeString)
37 : {
38 0 : if (modeString == "initial") {
39 0 : return LoadMode::Initial;
40 0 : } else if (modeString == "prepend") {
41 0 : return LoadMode::Prepend;
42 0 : } else if (modeString == "append") {
43 0 : return LoadMode::Append;
44 : } else {
45 0 : qCWarning(logOperation) << "Invalid string load mode: " << modeString;
46 0 : FANG_UNREACHABLE("Invalid LoadMode string");
47 : return LoadMode::Error;
48 : }
49 : }
50 :
51 0 : void LoadNewsOperation::queryToNewsList(QSqlQuery& query, QList<NewsItem*>* list)
52 : {
53 0 : while (query.next()) {
54 : // Load from DB query result.
55 : NewsItem* newsItem = new NewsItem(
56 : feedItem,
57 0 : query.value("id").toULongLong(),
58 0 : query.value("feed_id").toULongLong(),
59 0 : query.value("title").toString(),
60 0 : query.value("author").toString(),
61 0 : query.value("summary").toString(),
62 0 : query.value("content").toString(),
63 0 : QDateTime::fromMSecsSinceEpoch(query.value("timestamp").toLongLong()),
64 0 : query.value("url").toString(),
65 0 : (bool) query.value("pinned").toInt(),
66 0 : query.value("media_image_url").toString()
67 0 : );
68 :
69 : // Add to our list.
70 0 : list->append(newsItem);
71 : }
72 0 : }
73 :
74 0 : qint64 LoadNewsOperation::getBookmarkID()
75 : {
76 0 : QSqlQuery query(db());
77 0 : query.prepare("SELECT bookmark_id FROM FeedItemTable WHERE id = :id");
78 0 : query.bindValue(":id", feedItem->getDbID());
79 :
80 0 : if (!query.exec() || !query.next()) {
81 0 : qCDebug(logOperation) << "Could not update bookmark for feed id: " << feedItem->getDbID();
82 0 : qCDebug(logOperation) << query.lastError();
83 :
84 0 : return -1;
85 : }
86 :
87 0 : return query.value("bookmark_id").toULongLong();
88 0 : }
89 :
90 0 : qint64 LoadNewsOperation::getFirstNewsID()
91 : {
92 : const QString queryString = "SELECT id FROM NewsItemTable WHERE feed_id = :feed_id "
93 0 : "ORDER BY timestamp ASC, id ASC LIMIT 1";
94 :
95 0 : QSqlQuery query(db());
96 0 : query.prepare(queryString);
97 :
98 0 : query.bindValue(":feed_id", feedItem->getDbID());
99 :
100 0 : if (!query.exec() || !query.next()) {
101 : // No news yet!
102 0 : return -1;
103 : }
104 :
105 0 : return query.value("id").toULongLong();
106 0 : }
107 :
108 0 : bool LoadNewsOperation::doAppend(qint64 startId)
109 : {
110 0 : qCDebug(logOperation) << "LoadNewsOperation::doAppend " << startId;
111 : // Extract the query into our news list.
112 0 : return executeLoadQuery(startId, true);
113 : }
114 :
115 0 : bool LoadNewsOperation::doPrepend(qint64 startId)
116 : {
117 0 : qCDebug(logOperation) << "LoadNewsOperation::doPrepend " << startId;
118 : // Extract the query into our news list.
119 0 : return executeLoadQuery(startId, false);
120 : }
121 :
122 0 : bool LoadNewsOperation::executeLoadQuery(qint64 startId, bool append)
123 : {
124 0 : if (append) {
125 0 : listAppend.clear();
126 : } else {
127 0 : listPrepend.clear();
128 : }
129 :
130 0 : QString direction = append ? ">=" : "<";
131 0 : QString sortOrder = append ? "ASC" : "DESC";
132 : QString queryString = "SELECT * FROM NewsItemTable WHERE feed_id = :feed_id AND id "
133 0 : + direction + " :start_id ORDER BY timestamp " + sortOrder + ", id " + sortOrder
134 0 : + " LIMIT :load_limit";
135 :
136 0 : qCDebug(logOperation) << "executeLoadQuery: Query string: " << queryString;
137 0 : QSqlQuery query(db());
138 0 : query.prepare(queryString);
139 :
140 0 : query.bindValue(":feed_id", feedItem->getDbID());
141 0 : query.bindValue(":start_id", startId);
142 0 : query.bindValue(":load_limit", loadLimit);
143 :
144 0 : if (!query.exec()) {
145 0 : qCDebug(logOperation) << "Could not load news for feed id: " << feedItem->getDbID();
146 0 : qCDebug(logOperation) << query.lastError();
147 :
148 0 : return false;
149 : }
150 :
151 : // Extract the query into our news list.
152 0 : queryToNewsList(query, append ? &listAppend : &listPrepend);
153 :
154 0 : return true;
155 0 : }
156 :
157 0 : qint64 LoadNewsOperation::getStartIDForAppend()
158 : {
159 0 : qint64 startId = -1;
160 0 : if (feedItem->getNewsList() != nullptr && feedItem->getNewsList()->size() > 0) {
161 0 : startId = feedItem->getNewsList()->last()->getDbID() + 1; // Advance to next item
162 : }
163 :
164 0 : return startId;
165 : }
166 :
167 0 : qint64 LoadNewsOperation::getStartIDForPrepend()
168 : {
169 0 : qint64 startId = -1;
170 0 : if (feedItem->getNewsList() != nullptr && feedItem->getNewsList()->size() > 0) {
171 0 : startId = feedItem->getNewsList()->first()->getDbID();
172 : }
173 :
174 0 : return startId;
175 : }
176 :
177 0 : void LoadNewsOperation::execute()
178 : {
179 0 : if (feedItem->isSpecialFeed()) {
180 : // Wrong type of load operation for special feed.
181 0 : qCCritical(logOperation) << "LoadNewsOperation: Cannot use base LoadNewsOperation for special feeds";
182 0 : return;
183 : }
184 :
185 : // DB query/ies.
186 0 : bool dbResult = true;
187 0 : qint64 bookmarkID = getBookmarkID(); // Default: unbookmarked = -1
188 0 : qint64 firstNewsID = getFirstNewsID();
189 0 : switch (mode) {
190 0 : case Initial:
191 : {
192 : // For an initial load, make sure the feed isn't populated yet.
193 0 : FANG_CHECK(feedItem->getNewsList() == nullptr || feedItem->getNewsList()->isEmpty(),
194 : "LoadNewsOperation: Initial load on already-populated feed");
195 :
196 0 : qint64 startId = bookmarkID;
197 0 : if (startId > 0) {
198 : // We has a bookmark, yo!
199 : // Try to load previous items.
200 0 : dbResult &= doPrepend(startId);
201 :
202 0 : qCDebug(logOperation) << "Start id: " << startId;
203 : }
204 :
205 : // Load next items, if available.
206 0 : dbResult &= doAppend(startId);
207 :
208 0 : break;
209 : }
210 :
211 0 : case Append:
212 : {
213 0 : dbResult &= doAppend(getStartIDForAppend());
214 :
215 0 : break;
216 : }
217 :
218 0 : case Prepend:
219 : {
220 0 : dbResult &= doPrepend(getStartIDForPrepend());
221 :
222 0 : break;
223 : }
224 :
225 0 : default:
226 0 : FANG_UNREACHABLE("LoadNewsOperation::executeSynchronous: Invalid LoadMode");
227 : break;
228 : }
229 :
230 : // Check if we done goofed.
231 0 : if (!dbResult) {
232 0 : reportError("Got no DB result.");
233 :
234 0 : return;
235 : }
236 :
237 : // Append/prepend items from our lists.
238 0 : if (!listAppend.isEmpty()) {
239 0 : for (NewsItem* newsItem: listAppend) {
240 0 : feedItem->getNewsList()->append(newsItem);
241 : }
242 : }
243 :
244 0 : if (!listPrepend.isEmpty()) {
245 0 : for (NewsItem* newsItem: listPrepend) {
246 0 : feedItem->getNewsList()->prepend(newsItem);
247 : }
248 : }
249 :
250 : // Set our bookmark.
251 0 : if (bookmarkID >= 0) {
252 0 : feedItem->setBookmark(bookmarkID);
253 : }
254 :
255 : // Set the first known ID.
256 0 : feedItem->setFirstNewsID(firstNewsID);
257 : }
|