LCOV - code coverage report
Current view: top level - src/operations - LoadNewsOperation.cpp (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 6.7 % 135 9
Test Date: 2026-03-23 10:19:47 Functions: 14.3 % 14 2

            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              : }
        

Generated by: LCOV version 2.0-1