Rework the database system
This commit is contained in:
parent
5168e06147
commit
a6f6969912
@ -5,6 +5,7 @@ set(alligator_SRCS
|
|||||||
fetcher.cpp
|
fetcher.cpp
|
||||||
feed.cpp
|
feed.cpp
|
||||||
entry.cpp
|
entry.cpp
|
||||||
|
database.cpp
|
||||||
resources.qrc
|
resources.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
89
src/database.cpp
Normal file
89
src/database.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2020 Tobias Fella <fella@posteo.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QSqlError>
|
||||||
|
#include <QSqlDatabase>
|
||||||
|
|
||||||
|
#include "database.h"
|
||||||
|
#include "alligator-debug.h"
|
||||||
|
|
||||||
|
#define TRUE_OR_RETURN(x) if(!x) return false;
|
||||||
|
|
||||||
|
Database::Database()
|
||||||
|
{
|
||||||
|
QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"));
|
||||||
|
QString databasePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||||
|
QDir(databasePath).mkpath(databasePath);
|
||||||
|
db.setDatabaseName(databasePath + QStringLiteral("/database.db3"));
|
||||||
|
qCDebug(ALLIGATOR) << "Opening database " << databasePath << "/database.db3";
|
||||||
|
db.open();
|
||||||
|
|
||||||
|
if(!migrate()) {
|
||||||
|
qCCritical(ALLIGATOR) << "Failed to migrate the database";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::migrate() {
|
||||||
|
qCDebug(ALLIGATOR) << "Migrating database";
|
||||||
|
if(version() < 1) TRUE_OR_RETURN(migrateTo1());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::migrateTo1() {
|
||||||
|
QSqlQuery query(QSqlDatabase::database());
|
||||||
|
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Feeds (name TEXT, url TEXT);")));
|
||||||
|
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Entries (feed TEXT, id TEXT, title TEXT, content TEXT);")));
|
||||||
|
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Authors (id TEXT, name TEXT, uri TEXT, email TEXT);")));
|
||||||
|
TRUE_OR_RETURN(execute(QStringLiteral("PRAGMA user_version = 1;")));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::execute(QString query) {
|
||||||
|
QSqlQuery q;
|
||||||
|
q.prepare(query);
|
||||||
|
return execute(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::execute(QSqlQuery &query) {
|
||||||
|
if(!query.exec()) {
|
||||||
|
qCWarning(ALLIGATOR) << "Failed to execute SQL Query";
|
||||||
|
qCWarning(ALLIGATOR) << query.lastQuery();
|
||||||
|
qCWarning(ALLIGATOR) << query.lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Database::version() {
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare(QStringLiteral("PRAGMA user_version;"));
|
||||||
|
execute(query);
|
||||||
|
if(query.next()) {
|
||||||
|
bool ok;
|
||||||
|
int value = query.value(0).toInt(&ok);
|
||||||
|
qCDebug(ALLIGATOR) << "Database version " << value;
|
||||||
|
if(ok) return value;
|
||||||
|
} else {
|
||||||
|
qCCritical(ALLIGATOR) << "Failed to check database version";
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
42
src/database.h
Normal file
42
src/database.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2020 Tobias Fella <fella@posteo.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QSqlQuery>
|
||||||
|
|
||||||
|
class Database
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Database &instance()
|
||||||
|
{
|
||||||
|
static Database _instance;
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
bool execute(QSqlQuery &query);
|
||||||
|
bool execute(QString query);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Database();
|
||||||
|
int version();
|
||||||
|
|
||||||
|
bool migrate();
|
||||||
|
bool migrateTo1();
|
||||||
|
};
|
@ -18,12 +18,11 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QSqlDatabase>
|
|
||||||
#include <QSqlQuery>
|
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
#include "entryListModel.h"
|
#include "entryListModel.h"
|
||||||
#include "fetcher.h"
|
#include "fetcher.h"
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
EntryListModel::EntryListModel(QObject *parent)
|
EntryListModel::EntryListModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
@ -70,10 +69,10 @@ void EntryListModel::fetch()
|
|||||||
{
|
{
|
||||||
connect(&Fetcher::instance(), &Fetcher::finished, this, [this]() {
|
connect(&Fetcher::instance(), &Fetcher::finished, this, [this]() {
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
QSqlQuery query(QSqlDatabase::database());
|
QSqlQuery query;
|
||||||
query.prepare(QStringLiteral("SELECT id, title, content FROM Entries WHERE feed=:feed;"));
|
query.prepare(QStringLiteral("SELECT id, title, content FROM Entries WHERE feed=:feed;"));
|
||||||
query.bindValue(QStringLiteral(":feed"), m_feed);
|
query.bindValue(QStringLiteral(":feed"), m_feed);
|
||||||
query.exec();
|
Database::instance().execute(query);
|
||||||
while (query.next()) {
|
while (query.next()) {
|
||||||
m_entries.append(Entry(query.value(1).toString(), query.value(2).toString(), false, false));
|
m_entries.append(Entry(query.value(1).toString(), query.value(2).toString(), false, false));
|
||||||
}
|
}
|
||||||
|
@ -18,21 +18,22 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QSqlDatabase>
|
|
||||||
#include <QSqlQuery>
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QSqlError>
|
|
||||||
|
|
||||||
#include <Syndication/Syndication>
|
#include <Syndication/Syndication>
|
||||||
|
|
||||||
#include "feedListModel.h"
|
#include "feedListModel.h"
|
||||||
#include "fetcher.h"
|
#include "fetcher.h"
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
|
#include "alligator-debug.h"
|
||||||
|
|
||||||
FeedListModel::FeedListModel(QObject *parent)
|
FeedListModel::FeedListModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
QSqlQuery query(QSqlDatabase::database());
|
QSqlQuery query;
|
||||||
query.exec(QStringLiteral("SELECT name, url FROM Feeds"));
|
query.prepare(QStringLiteral("SELECT name, url FROM Feeds"));
|
||||||
|
Database::instance().execute(query);
|
||||||
beginInsertRows(QModelIndex(), 0, query.size());
|
beginInsertRows(QModelIndex(), 0, query.size());
|
||||||
while (query.next()) {
|
while (query.next()) {
|
||||||
feeds += Feed(query.value(1).toString(), query.value(0).toString());
|
feeds += Feed(query.value(1).toString(), query.value(0).toString());
|
||||||
@ -63,11 +64,17 @@ int FeedListModel::rowCount(const QModelIndex &index) const
|
|||||||
|
|
||||||
void FeedListModel::addFeed(QString url)
|
void FeedListModel::addFeed(QString url)
|
||||||
{
|
{
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare(QStringLiteral("SELECT COUNT (url) FROM Feeds WHERE url=:url;"));
|
||||||
|
query.bindValue(QStringLiteral(":url"), url);
|
||||||
|
Database::instance().execute(query);
|
||||||
|
query.next();
|
||||||
|
if(query.value(0).toInt() != 0) return;
|
||||||
connect(&Fetcher::instance(), &Fetcher::finished, this, [this, url]() {
|
connect(&Fetcher::instance(), &Fetcher::finished, this, [this, url]() {
|
||||||
QSqlQuery query(QSqlDatabase::database());
|
QSqlQuery query;
|
||||||
query.prepare(QStringLiteral("SELECT name FROM Feeds WHERE url=:url;"));
|
query.prepare(QStringLiteral("SELECT name FROM Feeds WHERE url=:url;"));
|
||||||
query.bindValue(QStringLiteral(":url"), url);
|
query.bindValue(QStringLiteral(":url"), url);
|
||||||
query.exec();
|
Database::instance().execute(query);
|
||||||
query.next();
|
query.next();
|
||||||
for(int i = 0; i < feeds.length(); i++) {
|
for(int i = 0; i < feeds.length(); i++) {
|
||||||
if(feeds[i].url() == url) {
|
if(feeds[i].url() == url) {
|
||||||
@ -82,21 +89,21 @@ void FeedListModel::addFeed(QString url)
|
|||||||
beginInsertRows(QModelIndex(), feeds.size(), feeds.size());
|
beginInsertRows(QModelIndex(), feeds.size(), feeds.size());
|
||||||
feeds.append(Feed(url));
|
feeds.append(Feed(url));
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
QSqlQuery query(QSqlDatabase::database());
|
|
||||||
query.prepare(QStringLiteral("INSERT INTO Feeds VALUES (:url, :name);"));
|
query.prepare(QStringLiteral("INSERT INTO Feeds VALUES (:url, :name);"));
|
||||||
query.bindValue(QStringLiteral(":url"), url);
|
query.bindValue(QStringLiteral(":url"), url);
|
||||||
query.bindValue(QStringLiteral(":name"), url);
|
query.bindValue(QStringLiteral(":name"), url);
|
||||||
query.exec();
|
Database::instance().execute(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedListModel::remove_feed(int index)
|
void FeedListModel::remove_feed(int index)
|
||||||
{
|
{
|
||||||
Feed toRemove = feeds[index];
|
Feed toRemove = feeds[index];
|
||||||
QSqlQuery query(QSqlDatabase::database());
|
QSqlQuery query;
|
||||||
query.prepare(QStringLiteral("DELETE FROM Feeds WHERE name=:name AND url=url;"));
|
query.prepare(QStringLiteral("DELETE FROM Feeds WHERE name=:name AND url=url;"));
|
||||||
query.bindValue(QStringLiteral(":url"), toRemove.url());
|
query.bindValue(QStringLiteral(":url"), toRemove.url());
|
||||||
query.bindValue(QStringLiteral(":name"), toRemove.name());
|
query.bindValue(QStringLiteral(":name"), toRemove.name());
|
||||||
query.exec();
|
Database::instance().execute(query);
|
||||||
beginRemoveRows(QModelIndex(), index, index);
|
beginRemoveRows(QModelIndex(), index, index);
|
||||||
feeds.remove(index);
|
feeds.remove(index);
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
|
@ -20,13 +20,13 @@
|
|||||||
|
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QSqlDatabase>
|
|
||||||
#include <QSqlQuery>
|
|
||||||
|
|
||||||
#include <Syndication/Syndication>
|
#include <Syndication/Syndication>
|
||||||
|
|
||||||
#include "fetcher.h"
|
#include "fetcher.h"
|
||||||
|
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
Fetcher::Fetcher() {
|
Fetcher::Fetcher() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,6 @@ void Fetcher::fetch(QUrl url)
|
|||||||
QSqlQuery query(db);
|
QSqlQuery query(db);
|
||||||
|
|
||||||
for (const auto &entry : feed->items()) {
|
for (const auto &entry : feed->items()) {
|
||||||
query = QSqlQuery(db);
|
|
||||||
query.prepare(QStringLiteral("INSERT INTO Entries VALUES (:feed, :id, :title, :content);"));
|
query.prepare(QStringLiteral("INSERT INTO Entries VALUES (:feed, :id, :title, :content);"));
|
||||||
query.bindValue(QStringLiteral(":feed"), url.toString());
|
query.bindValue(QStringLiteral(":feed"), url.toString());
|
||||||
query.bindValue(QStringLiteral(":id"), entry->id());
|
query.bindValue(QStringLiteral(":id"), entry->id());
|
||||||
@ -56,7 +55,7 @@ void Fetcher::fetch(QUrl url)
|
|||||||
query.bindValue(QStringLiteral(":content"), entry->content());
|
query.bindValue(QStringLiteral(":content"), entry->content());
|
||||||
else
|
else
|
||||||
query.bindValue(QStringLiteral(":content"), entry->description());
|
query.bindValue(QStringLiteral(":content"), entry->description());
|
||||||
query.exec();
|
Database::instance().execute(query);
|
||||||
for (const auto &author : entry->authors()) {
|
for (const auto &author : entry->authors()) {
|
||||||
query = QSqlQuery(db);
|
query = QSqlQuery(db);
|
||||||
query.prepare(QStringLiteral("INSERT INTO Authors VALUES(:id, :name, :uri, :email);"));
|
query.prepare(QStringLiteral("INSERT INTO Authors VALUES(:id, :name, :uri, :email);"));
|
||||||
@ -64,12 +63,12 @@ void Fetcher::fetch(QUrl url)
|
|||||||
query.bindValue(QStringLiteral(":name"), author->name());
|
query.bindValue(QStringLiteral(":name"), author->name());
|
||||||
query.bindValue(QStringLiteral(":uri"), author->uri());
|
query.bindValue(QStringLiteral(":uri"), author->uri());
|
||||||
query.bindValue(QStringLiteral(":email"), author->email());
|
query.bindValue(QStringLiteral(":email"), author->email());
|
||||||
query.exec();
|
Database::instance().execute(query);
|
||||||
}
|
}
|
||||||
query.prepare(QStringLiteral("UPDATE Feeds SET name=:name WHERE url=:url;"));
|
query.prepare(QStringLiteral("UPDATE Feeds SET name=:name WHERE url=:url;"));
|
||||||
query.bindValue(QStringLiteral(":name"), feed->title());
|
query.bindValue(QStringLiteral(":name"), feed->title());
|
||||||
query.bindValue(QStringLiteral(":url"), url.toString());
|
query.bindValue(QStringLiteral(":url"), url.toString());
|
||||||
query.exec();
|
Database::instance().execute(query);
|
||||||
}
|
}
|
||||||
delete reply;
|
delete reply;
|
||||||
emit finished();
|
emit finished();
|
||||||
|
17
src/main.cpp
17
src/main.cpp
@ -21,14 +21,10 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQuickView>
|
#include <QQuickView>
|
||||||
#include <QSqlDatabase>
|
|
||||||
#include <QSqlQuery>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QStandardPaths>
|
|
||||||
#include <QDir>
|
|
||||||
|
|
||||||
#include "entryListModel.h"
|
#include "entryListModel.h"
|
||||||
#include "feedListModel.h"
|
#include "feedListModel.h"
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
#include "alligator-debug.h"
|
#include "alligator-debug.h"
|
||||||
|
|
||||||
@ -48,16 +44,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
|||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
|
|
||||||
QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"));
|
Database::instance();
|
||||||
QString databasePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
|
||||||
QDir(databasePath).mkpath(databasePath);
|
|
||||||
db.setDatabaseName(databasePath + "/database.db3");
|
|
||||||
db.open();
|
|
||||||
|
|
||||||
QSqlQuery query(db);
|
|
||||||
query.exec(QStringLiteral("CREATE TABLE IF NOT EXISTS Feeds (name TEXT, url TEXT);"));
|
|
||||||
query.exec(QStringLiteral("CREATE TABLE IF NOT EXISTS Entries (feed TEXT, id TEXT UNIQUE, title TEXT, content TEXT);"));
|
|
||||||
query.exec(QStringLiteral("CREATE TABLE IF NOT EXISTS Authors (id TEXT, name TEXT, uri TEXT, email TEXT);"));
|
|
||||||
|
|
||||||
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
|
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user