summaryrefslogtreecommitdiff
path: root/src/atomchannel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/atomchannel.cpp')
-rw-r--r--src/atomchannel.cpp214
1 files changed, 190 insertions, 24 deletions
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 <QSqlError>
#include <QSqlQuery>
+#include <QSqlRecord>
#include <QXmlStreamReader>
#include "constants.h"
@@ -185,21 +186,21 @@ QList<int> 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<QMetaProperty> DbItem::properties() const
+{
+ // TODO: init once to static var
+ const auto propOffset = QObject::staticMetaObject.propertyCount();
+ const auto propCount = metaObject()->propertyCount();
+
+ QList<QMetaProperty> 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;
+}