LCOV - code coverage report
Current view: top level - src/operations - UpdateOrdinalsOperation.cpp (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 90.8 % 76 69
Test Date: 2026-03-23 10:19:47 Functions: 100.0 % 2 2

            Line data    Source code
       1              : #include "UpdateOrdinalsOperation.h"
       2              : #include "../models/FeedItem.h"
       3              : #include "../models/FolderFeedItem.h"
       4              : #include "../models/ListModel.h"
       5              : #include "../utilities/UnreadCountReader.h"
       6              : 
       7              : #include <QList>
       8              : #include <QSet>
       9              : #include <QDebug>
      10              : 
      11           12 : UpdateOrdinalsOperation::UpdateOrdinalsOperation(OperationManager *parent, ListModel *feedList) :
      12              :     DBOperation(parent),
      13           12 :     feedList(feedList)
      14              : {
      15           12 : }
      16              : 
      17           12 : void UpdateOrdinalsOperation::execute()
      18              : {
      19           12 :     QSet<qint64> folderIDs;
      20           12 :     QList<FeedItem*> removedFromFolder;
      21           12 :     db().transaction();
      22              : 
      23              :     // Update ordinals and gather folder IDs.
      24           36 :     for (int i = 0; i < feedList->count(); i++) {
      25           24 :         FeedItem* feedItem = qobject_cast<FeedItem*>(feedList->row(i));
      26           24 :         if (feedItem->isSpecialFeed()) {
      27            1 :             continue;
      28              :         }
      29              : 
      30              :         // Track folder IDs for later cleanup.
      31           23 :         FolderFeedItem* folder = qobject_cast<FolderFeedItem*>(feedItem);
      32           23 :         if (folder) {
      33            8 :             folderIDs.insert(folder->getDbID());
      34              :         }
      35              : 
      36           23 :         QSqlQuery update(db());
      37           23 :         update.prepare("UPDATE FeedItemTable SET ordinal = :ordinal WHERE id = :feed_id");
      38           23 :         update.bindValue(":ordinal", i);
      39           23 :         update.bindValue(":feed_id", feedItem->getDbID());
      40              : 
      41           23 :         if (!update.exec()) {
      42            0 :             reportSQLError(update, "Unable to update ordinal for feed id " + QString::number(feedItem->getDbID()));
      43            0 :             db().rollback();
      44            0 :             return;
      45              :         }
      46           23 :     }
      47              : 
      48              :     // Update parent folder associations.
      49           36 :     for (int i = 0; i < feedList->count(); i++) {
      50           24 :         FeedItem* feedItem = qobject_cast<FeedItem*>(feedList->row(i));
      51           24 :         if (feedItem->isSpecialFeed()) {
      52            1 :             continue;
      53              :         }
      54              : 
      55           23 :         if (!folderIDs.contains(feedItem->getParentFolderID())) {
      56              :             // Feed's parent folder no longer exists; track for model update later.
      57           18 :             removedFromFolder << feedItem;
      58              :         }
      59              : 
      60           23 :         QSqlQuery update(db());
      61           23 :         update.prepare("UPDATE FeedItemTable SET parent_folder = :parent_folder WHERE id = :feed_id");
      62           23 :         update.bindValue(":parent_folder", feedItem->getParentFolderID());
      63           23 :         update.bindValue(":feed_id", feedItem->getDbID());
      64              : 
      65           23 :         if (!update.exec()) {
      66            0 :             reportSQLError(update, "Unable to update parent for feed id " + QString::number(feedItem->getDbID()));
      67            0 :             db().rollback();
      68            0 :             return;
      69              :         }
      70           23 :     }
      71              : 
      72              :     // Check for empty folders and remove them from model, DB, and/or both.
      73           12 :     QSet<qint64> foldersWithChildren;
      74           36 :     for (int i = 0; i < feedList->count(); i++) {
      75           24 :         FeedItem* feedItem = qobject_cast<FeedItem*>(feedList->row(i));
      76           24 :         if (feedItem->isSpecialFeed() || feedItem->isFolder()) {
      77            9 :             continue;
      78              :         }
      79              : 
      80           15 :         qint64 parentId = feedItem->getParentFolderID();
      81           15 :         if (parentId > 0) {
      82            6 :             foldersWithChildren.insert(parentId);
      83              :         }
      84              :     }
      85              : 
      86              :     // Remove empty folders from the model (work backwards to avoid altering the index).
      87           36 :     for (int i = feedList->count() - 1; i >= 0; i--) {
      88           24 :         FolderFeedItem* folder = qobject_cast<FolderFeedItem*>(feedList->row(i));
      89           24 :         if (folder && !foldersWithChildren.contains(folder->getDbID())) {
      90            4 :             feedList->removeItem(folder);
      91            4 :             folderIDs.remove(folder->getDbID());
      92              :         }
      93              :     }
      94              : 
      95              :     // Delete orphaned folders from the database.
      96           12 :     QSqlQuery selectFolders(db());
      97           12 :     selectFolders.prepare("SELECT id FROM FeedItemTable WHERE is_folder = 1");
      98           12 :     if (selectFolders.exec()) {
      99           22 :         while (selectFolders.next()) {
     100           10 :             qint64 dbFolderId = selectFolders.value(0).toLongLong();
     101           10 :             if (!folderIDs.contains(dbFolderId)) {
     102            6 :                 QSqlQuery deleteFolder(db());
     103            6 :                 deleteFolder.prepare("DELETE FROM FeedItemTable WHERE id = :folder_id");
     104            6 :                 deleteFolder.bindValue(":folder_id", dbFolderId);
     105            6 :                 if (!deleteFolder.exec()) {
     106            0 :                     reportSQLError(deleteFolder, "Unable to delete empty folder " + QString::number(dbFolderId));
     107              :                 }
     108            6 :             }
     109              :         }
     110              :     }
     111              : 
     112              :     // Complete the DB transaction.
     113           12 :     db().commit();
     114              : 
     115              :     // Now we need to refresh our model. First up: ordinals.
     116           32 :     for (int i = 0; i < feedList->count(); i++) {
     117           20 :         FeedItem* feedItem = qobject_cast<FeedItem*>(feedList->row(i));
     118           20 :         if (feedItem->isSpecialFeed()) {
     119            1 :             continue;
     120              :         }
     121              : 
     122           19 :         feedItem->setOrdinal(i);
     123              :     }
     124              : 
     125              :     // Second: parent folders (or lack thereof.)
     126           30 :     for (FeedItem* item : removedFromFolder) {
     127           18 :         item->setParentFolder(-1);
     128              :     }
     129              : 
     130              :     // Recalculate unread counts for all folders; this handles the case where a feed
     131              :     // item is moved from one folder to another and both folders need to have their
     132              :     // feed counts updated.
     133           32 :     for (int i = 0; i < feedList->count(); i++) {
     134           20 :         FolderFeedItem* folder = qobject_cast<FolderFeedItem*>(feedList->row(i));
     135           20 :         if (folder) {
     136            4 :             UnreadCountReader::update(db(), folder);
     137              :         }
     138              :     }
     139           12 : }
        

Generated by: LCOV version 2.0-1