From 6d7eaf0c724b976325f4c46b2ff4c452c09a24ea Mon Sep 17 00:00:00 2001 From: Nikita Kostovsky Date: Wed, 13 Aug 2025 19:24:57 +0200 Subject: refactor --- src/atomchannel.cpp | 214 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 190 insertions(+), 24 deletions(-) (limited to 'src/atomchannel.cpp') diff --git a/src/atomchannel.cpp b/src/atomchannel.cpp index d3f3c3f..0f3bca2 100644 --- a/src/atomchannel.cpp +++ b/src/atomchannel.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "constants.h" @@ -185,21 +186,21 @@ QList AtomChannel::syncDbItems() return result; } -QDebug operator<<(QDebug debug, const AtomChannel &channel) +QDebug operator<<(QDebug debug, const AtomChannel &feed) { QDebugStateSaver saver{debug}; debug.nospace() << typeid(AtomChannel).name() << " {" << Qt::endl; - PRINT_ATOM_FIELD(channel, title); - PRINT_ATOM_FIELD(channel, link); - PRINT_ATOM_FIELD(channel, description); - PRINT_ATOM_FIELD(channel, lastBuildDate); - PRINT_ATOM_FIELD(channel, language); - debug << "\timage:\n" << channel.image << Qt::endl; - debug << "\titems count:" << channel.items.size() << Qt::endl; + PRINT_ATOM_FIELD(feed, title); + PRINT_ATOM_FIELD(feed, link); + PRINT_ATOM_FIELD(feed, description); + PRINT_ATOM_FIELD(feed, lastBuildDate); + PRINT_ATOM_FIELD(feed, language); + debug << "\timage:\n" << feed.image << Qt::endl; + debug << "\titems count:" << feed.items.size() << Qt::endl; - for (const auto &item : channel.items) + for (const auto &item : feed.items) debug << item << Qt::endl; debug.nospace() << "}"; @@ -207,17 +208,18 @@ QDebug operator<<(QDebug debug, const AtomChannel &channel) return debug; } -QDebug operator<<(QDebug debug, const Channel &channel) +QDebug operator<<(QDebug debug, const Feed &feed) { QDebugStateSaver saver{debug}; - const auto &mo = Channel::staticMetaObject; + // const auto &mo = Channel::staticMetaObject; + const auto &mo = *feed.metaObject(); debug.nospace() << mo.className() << " {" << Qt::endl; - for (int i = 0; i < mo.propertyCount(); ++i) { + for (int i = mo.propertyOffset(); i < mo.propertyCount(); ++i) { auto prop = mo.property(i); - debug.nospace() << "\t" << prop.name() << ": " << prop.readOnGadget(&channel) << Qt::endl; + debug.nospace() << "\t" << prop.name() << ": " << prop.readOnGadget(&feed) << Qt::endl; } debug.nospace() << "}"; @@ -229,11 +231,12 @@ QDebug operator<<(QDebug debug, const Item &item) { QDebugStateSaver saver{debug}; - const auto &mo = Item::staticMetaObject; + // const auto &mo = Item::staticMetaObject; + const auto &mo = *item.metaObject(); debug.nospace() << mo.className() << " {" << Qt::endl; - for (int i = 0; i < mo.propertyCount(); ++i) { + for (int i = mo.propertyOffset(); i < mo.propertyCount(); ++i) { auto prop = mo.property(i); debug.nospace() << "\t" << prop.name() << ": " << prop.readOnGadget(&item) << Qt::endl; } @@ -243,10 +246,10 @@ QDebug operator<<(QDebug debug, const Item &item) return debug; } -Channel::Channel(const QDomNode &node) +Feed::Feed(const QDomNode &node) : DbItem{node} { - init(staticMetaObject, node); + init(node); // use 'atom:link href="LINK"' if any const QString atomLinkTag = QStringLiteral("atom:link"); @@ -258,22 +261,27 @@ Channel::Channel(const QDomNode &node) .attribute(hrefTag, get_link().toString())); } -bool Channel::isValid() const +bool Feed::isValid() const { - staticMetaObject; return !m_title.isEmpty() && m_link.isValid(); } +const QStringList &Feed::uniqueFields() const +{ + // TODO: validate once that this class has corresponding fields + return m_uniqueFields; +} + DbItem::DbItem(const QDomNode &node) { - init(staticMetaObject, node); + init(node); } -void DbItem::init(const QMetaObject &mo, const QDomNode &node) +void DbItem::init(const QDomNode &node) { // for (int i = mo.propertyOffset(); i < mo.propertyCount(); ++i) { - for (int i = staticMetaObject.propertyOffset(); i < staticMetaObject.propertyCount(); ++i) { - const auto prop = staticMetaObject.property(i); + for (int i = metaObject()->propertyOffset(); i < metaObject()->propertyCount(); ++i) { + const auto prop = metaObject()->property(i); const auto propName = prop.name(); const auto propElement = node.toElement().elementsByTagName(propName).at(0); const auto propText = propElement.toElement().text(); @@ -306,13 +314,171 @@ void DbItem::init(const QMetaObject &mo, const QDomNode &node) } } +QStringList DbItem::propertyNames() const +{ + // TODO: init once to static var + const auto propOffset = QObject::staticMetaObject.propertyCount(); + const auto propCount = metaObject()->propertyCount(); + + QStringList result; + result.reserve(propOffset - propCount); + + for (int i = propOffset; i < propCount; ++i) { + result << metaObject()->property(i).name(); + } + + return result; +} + +QList DbItem::properties() const +{ + // TODO: init once to static var + const auto propOffset = QObject::staticMetaObject.propertyCount(); + const auto propCount = metaObject()->propertyCount(); + + QList result; + result.reserve(propOffset - propCount); + + for (int i = propOffset; i < propCount; ++i) { + result << metaObject()->property(i); + } + + return result; +} + +DbItem::DbId DbItem::syncWithDb() +{ + // const auto propOffset = QObject::staticMetaObject.propertyCount(); + // const auto propCount = metaObject()->propertyCount(); + // const auto propNames = propertyNames(); + + // "Item" -> "items" + QString tableName{metaObject()->className()}; + tableName[0] = tableName.at(0).toLower(); + tableName.append('s'); + + qDebug() << Q_FUNC_INFO << "table name:" << tableName; + + // exists in db, update data + if (m_id.has_value()) { + // TODO: what to do if item was removed from db? + return m_id; + } + // select id from db or insert + else { + QSqlQuery q; + + // TODO: validate once statically + if (uniqueFields().isEmpty()) { + qFatal() << metaObject()->className() << "has no unique fields, cannot select"; + + return {}; + } + + // TODO: init once + QStringList whereConditions; + + // for (const auto &name : propertyNames()) { + for (const auto &name : uniqueFields()) { + whereConditions << name + QStringLiteral("=:") + name; + } + + const QString where{QStringLiteral(" where (") + + whereConditions.join(QStringLiteral(" and ")) + ')'}; + // const QString queryTemplate{QStringLiteral("select * from ") + tableName + ' ' + where}; + qDebug() << "where:" << where; + const QString queryTemplate{QStringLiteral("select * from ") + tableName + where}; + qDebug().noquote() << "template:" << queryTemplate; + + const bool prepared = q.prepare(queryTemplate); + + if (!prepared) { + qCritical() << tableName + ": cannot prepare select query:" << q.lastError().text(); + qCritical().noquote() << "template: " << queryTemplate; + + return {}; + } + + for (const auto &prop : properties()) { + // FIXME: create uniqueProperties + if (!uniqueFields().contains(prop.name())) + continue; + q.addBindValue(prop.read(this).toString()); + // q.addBindValue("'asdfsdf'"); + } + + if (!q.exec()) { + qCritical() << "cannot select" << tableName << "from db:" << q.lastError().text(); + qCritical().noquote() << "template: " << queryTemplate; + + return {}; + } + + if (!q.next()) { + qCritical() << "no results for" << tableName; + // TODO: inset this shit. always inset it + return {}; + } + + const auto rec = q.record(); + + if (rec.isEmpty()) { + qCritical() << "got empty record for" << tableName; + return {}; + } + + // qDebug() << "rec:" << rec; + + bool dbNeedsUpdate{false}; + + for (const auto &prop : properties()) { + const auto val = rec.value(prop.name()); + + if (val.isNull() || !val.isValid()) { + qCritical() << "got invalid value for table" << tableName << "fieldl" + << prop.name(); + return {}; + } + + // if (prop.read(this) != val) { + // // TODO: don't use this shit with tmp vars, call update here and break + // dbNeedsUpdate = true; + // break; + // } + + prop.write(this, val); + } + + if (dbNeedsUpdate) { + } + + qDebug() << "finished reading from" << tableName; + } + + // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + // FIXME: implement + return {}; +} + Item::Item(const QDomNode &node) : DbItem{node} { - init(staticMetaObject, node); + init(node); if (m_content.isEmpty()) { const QString contentEncodedTag = QStringLiteral("content:encoded"); set_content(node.toElement().elementsByTagName(contentEncodedTag).at(0).toElement().text()); } } + +bool Item::isValid() const +{ + // TODO: check if isNull is needed + return !m_pubDate.isNull() && m_pubDate.isValid() && !m_title.isEmpty() && !m_link.isEmpty() + && !m_description.isEmpty(); +} + +const QStringList &Item::uniqueFields() const +{ + return m_uniqueFields; +} -- cgit v1.2.3-70-g09d2