1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-04-01 21:24:45 +02:00

Added BaseModel to allow tracking changes

This commit is contained in:
Laurent Cozic 2017-01-02 13:17:15 +01:00
parent bc6f419d1e
commit 0a08837ef0
23 changed files with 670 additions and 252 deletions

View File

@ -46,7 +46,7 @@ Item {
} }
onCurrentItemChanged: { onCurrentItemChanged: {
currentItemId = model.idAtIndex(currentIndex); currentItemId = model.indexToId(currentIndex);
} }
id: listView id: listView

View File

@ -18,7 +18,8 @@ SOURCES += \
settings.cpp \ settings.cpp \
uuid.cpp \ uuid.cpp \
dispatcher.cpp \ dispatcher.cpp \
models/change.cpp models/change.cpp \
models/basemodel.cpp
RESOURCES += qml.qrc \ RESOURCES += qml.qrc \
database.qrc database.qrc
@ -49,7 +50,9 @@ HEADERS += \
simpletypes.h \ simpletypes.h \
uuid.h \ uuid.h \
dispatcher.h \ dispatcher.h \
models/change.h models/change.h \
models/basemodel.h \
enum.h
DISTFILES += DISTFILES +=

View File

@ -105,15 +105,15 @@ void Application::afterSessionInitialization() {
} }
void Application::view_currentFolderChanged() { void Application::view_currentFolderChanged() {
QString folderId = selectedFolderId(); // QString folderId = selectedFolderId();
noteCollection_ = NoteCollection(db_, folderId, "title ASC"); // noteCollection_ = NoteCollection(db_, folderId, "title ASC");
noteModel_.setCollection(noteCollection_); // noteModel_.setCollection(noteCollection_);
} }
void Application::view_currentNoteChanged() { void Application::view_currentNoteChanged() {
QString noteId = selectedNoteId(); // QString noteId = selectedNoteId();
Note note = noteCollection_.byId(noteId); // Note note = noteCollection_.byId(noteId);
selectedQmlNote_.setNote(note); // selectedQmlNote_.setNote(note);
} }
void Application::view_addNoteButtonClicked() { void Application::view_addNoteButtonClicked() {

View File

@ -2,23 +2,6 @@
using namespace jop; using namespace jop;
Database::Database(const QString &path) {
// version_ = -1;
// // QFile::remove(path);
// db_ = QSqlDatabase::addDatabase("QSQLITE");
// db_.setDatabaseName(path);
// if (!db_.open()) {
// qDebug() << "Error: connection with database fail";
// } else {
// qDebug() << "Database: connection ok";
// }
// upgrade();
}
Database::Database() {} Database::Database() {}
void Database::initialize(const QString &path) { void Database::initialize(const QString &path) {
@ -26,6 +9,8 @@ void Database::initialize(const QString &path) {
// QFile::remove(path); // QFile::remove(path);
//qDebug() << Select << Text;
db_ = QSqlDatabase::addDatabase("QSQLITE"); db_ = QSqlDatabase::addDatabase("QSQLITE");
db_.setDatabaseName(path); db_.setDatabaseName(path);
@ -41,6 +26,7 @@ void Database::initialize(const QString &path) {
QSqlQuery Database::query(const QString &sql) const { QSqlQuery Database::query(const QString &sql) const {
QSqlQuery output(db_); QSqlQuery output(db_);
output.prepare(sql); output.prepare(sql);
log(sql);
return output; return output;
} }
@ -101,6 +87,8 @@ QSqlQuery Database::buildSqlQuery(Database::QueryType type, const QString &table
} }
} }
log(sql, query);
// qDebug() <<"SQL:"<<sql; // qDebug() <<"SQL:"<<sql;
// QMapIterator<QString, QVariant> i(query.boundValues()); // QMapIterator<QString, QVariant> i(query.boundValues());
@ -112,6 +100,16 @@ QSqlQuery Database::buildSqlQuery(Database::QueryType type, const QString &table
return query; return query;
} }
QSqlQuery Database::buildSqlQuery(Database::QueryType type, const QString &tableName, const QMap<QString, QVariant> &values, const QString &whereCondition) {
QStringList fields;
VariantVector fieldValues;
for (QMap<QString, QVariant>::const_iterator it = values.begin(); it != values.end(); ++it) {
fields.push_back(it.key());
fieldValues.push_back(it.value());
}
return buildSqlQuery(type, tableName, fields, fieldValues, whereCondition);
}
bool Database::errorCheck(const QSqlQuery& query) { bool Database::errorCheck(const QSqlQuery& query) {
if (query.lastError().isValid()) { if (query.lastError().isValid()) {
qCritical().noquote() << "SQL query error: " << query.lastError().text().trimmed() << ". Query was: " << query.lastQuery(); qCritical().noquote() << "SQL query error: " << query.lastError().text().trimmed() << ". Query was: " << query.lastQuery();
@ -125,10 +123,15 @@ bool Database::errorCheck(const QSqlQuery& query) {
return true; return true;
} }
//Change Database::newChange() const { void Database::log(const QString &sql, const QSqlQuery &query) const {
// return Change(*this); qDebug() <<"SQL:"<<sql;
//}
QMapIterator<QString, QVariant> i(query.boundValues());
while (i.hasNext()) {
i.next();
qDebug() << i.key() << ":" << i.value().toString();
}
}
int Database::version() const { int Database::version() const {
if (version_ >= 0) return version_; if (version_ >= 0) return version_;

View File

@ -2,6 +2,7 @@
#define DATABASE_H #define DATABASE_H
#include <stable.h> #include <stable.h>
#include "enum.h"
#include "simpletypes.h" #include "simpletypes.h"
namespace jop { namespace jop {
@ -12,18 +13,18 @@ public:
enum QueryType { Select, Insert, Update, Delete }; enum QueryType { Select, Insert, Update, Delete };
Database(const QString& path);
Database(); Database();
void initialize(const QString& path); void initialize(const QString& path);
QSqlQuery query(const QString& sql) const; QSqlQuery query(const QString& sql) const;
QSqlDatabase& database(); QSqlDatabase& database();
QSqlQuery buildSqlQuery(Database::QueryType type, const QString& tableName, const QStringList& fields, const VariantVector& values, const QString& whereCondition = ""); QSqlQuery buildSqlQuery(Database::QueryType type, const QString& tableName, const QStringList& fields, const VariantVector& values, const QString& whereCondition = "");
QSqlQuery buildSqlQuery(Database::QueryType type, const QString& tableName, const QMap<QString, QVariant>& values, const QString& whereCondition = "");
bool errorCheck(const QSqlQuery& query); bool errorCheck(const QSqlQuery& query);
//Change newChange() const;
private: private:
void log(const QString& sql, const QSqlQuery& query = QSqlQuery()) const;
QSqlDatabase db_; QSqlDatabase db_;
void upgrade(); void upgrade();
int version() const; int version() const;

View File

@ -0,0 +1,6 @@
#include "enum.h"
enum::enum()
{
}

14
QtClient/JoplinQtClient/enum.h Executable file
View File

@ -0,0 +1,14 @@
#ifndef ENUM_H
#define ENUM_H
#include <stable.h>
namespace jop {
enum ColType { UndefinedType, TextColType, IntColType };
enum Table { UndefinedTable, FoldersTable, NotesTable };
}
#endif // ENUM_H

View File

@ -0,0 +1,283 @@
#include "basemodel.h"
#include "database.h"
#include "uuid.h"
using namespace jop;
QMap<int, QVector<BaseModel::Field>> BaseModel::tableFields_;
QHash<QString, QVariant> BaseModel::cache_;
BaseModel::BaseModel() {
}
QStringList BaseModel::changedFields() const {
QStringList output;
for (QHash<QString, bool>::const_iterator it = changedFields_.begin(); it != changedFields_.end(); ++it) {
output.push_back(it.key());
}
return output;
}
int BaseModel::count(Table table) {
QString t = BaseModel::tableName(table);
QString k = QString("%1:count").arg(t);
QVariant r = BaseModel::cacheGet(k);
if (r.isValid()) return r.toInt();
QSqlQuery q = jop::db().query("SELECT count(*) as row_count FROM " + t);
q.exec();
q.next();
int output = q.value(0).toInt();
BaseModel::cacheSet(k, QVariant(output));
return output;
}
bool BaseModel::save() {
bool isNew = this->isNew();
if (!changedFields_.size() && !isNew) return true;
QStringList fields = changedFields();
QMap<QString, QVariant> values;
foreach (QString field, fields) {
values[field] = value(field).toQVariant();
}
if (isNew && primaryKeyIsUuid()) {
values[primaryKey()] = uuid::createUuid();
}
changedFields_.clear();
const QString& tableName = BaseModel::tableName(table());
if (isNew) {
cacheDelete(QString("%1:count").arg(tableName));
}
if (isNew) {
QSqlQuery q = jop::db().buildSqlQuery(Database::Insert, tableName, values);
q.exec();
return jop::db().errorCheck(q);
} else {
QSqlQuery q = jop::db().buildSqlQuery(Database::Update, tableName, values, QString("%1 = '%2'").arg(primaryKey()).arg(value("id").toString()));
q.exec();
return jop::db().errorCheck(q);
}
return false; // Unreachable
}
bool BaseModel::dispose() {
const QString& tableName = BaseModel::tableName(table());
QSqlQuery q(jop::db().database());
q.prepare("DELETE FROM " + tableName + " WHERE " + primaryKey() + " = :id");
q.bindValue(":id", id().toString());
q.exec();
cacheDelete(QString("%1:count").arg(tableName));
return jop::db().errorCheck(q);
}
Table BaseModel::table() const {
qCritical() << "BaseModel::table() must be overriden";
return jop::UndefinedTable;
}
QString BaseModel::primaryKey() const {
return "id";
}
bool BaseModel::primaryKeyIsUuid() const {
return false;
}
bool BaseModel::isNew() const {
return !valueIsSet(primaryKey());
}
BaseModel::Field createField(const QString& name, QMetaType::Type type) {
BaseModel::Field c;
c.name = name;
c.type = type;
return c;
}
QVector<BaseModel::Field> BaseModel::tableFields(jop::Table table) {
if (BaseModel::tableFields_.contains(table)) return BaseModel::tableFields_[table];
QVector<BaseModel::Field> output;
if (table == jop::FoldersTable) {
output.push_back(createField("id", QMetaType::QString ));
output.push_back(createField("title", QMetaType::QString ));
output.push_back(createField("created_time", QMetaType::Int ));
output.push_back(createField("updated_time", QMetaType::Int ));
}
BaseModel::tableFields_[table] = output;
return output;
}
QStringList BaseModel::tableFieldNames(Table table) {
QVector<BaseModel::Field> fields = BaseModel::tableFields(table);
QStringList output;
foreach (BaseModel::Field field, fields) {
output.push_back(field.name);
}
return output;
}
bool BaseModel::isValidFieldName(Table table, const QString &name) {
QVector<BaseModel::Field> fields = BaseModel::tableFields(table);
foreach (BaseModel::Field col, fields) {
if (col.name == name) return true;
}
return false;
}
void BaseModel::loadSqlQuery(const QSqlQuery &query) {
values_.clear();
QSqlRecord record = query.record();
QVector<BaseModel::Field> fields = BaseModel::tableFields(table());
foreach (BaseModel::Field field, fields) {
int idx = record.indexOf(field.name);
if (idx < 0) {
qCritical() << "Cannot find field" << field.name;
continue;
}
if (field.type == QMetaType::QString) {
values_.insert(field.name, Value(query.value(idx).toString()));
} else if (field.type == QMetaType::Int) {
values_.insert(field.name, Value(query.value(idx).toInt()));
} else {
qCritical() << "Unsupported value type" << field.name;
}
}
changedFields_.clear();
}
QHash<QString, BaseModel::Value> BaseModel::values() const {
return values_;
}
BaseModel::Value BaseModel::value(const QString &name) const {
if (!valueIsSet(name)) {
qCritical() << "Value does not exist" << name;
return Value();
}
return values_[name];
}
bool BaseModel::valueIsSet(const QString &name) const {
return values_.contains(name);
}
void BaseModel::setValue(const QString &name, const BaseModel::Value &value) {
if (!values_.contains(name)) {
values_.insert(name, value);
changedFields_.insert(name, true);
} else {
Value& v = values_[name];
if (v.isEqual(value)) return;
values_.insert(name, value);
changedFields_.insert(name, true);
}
}
void BaseModel::setValue(const QString &name, int value) {
setValue(name, Value(value));
}
BaseModel::Value BaseModel::id() const {
if (!valueIsSet(primaryKey())) return QVariant();
return value(primaryKey());
}
QString BaseModel::tableName(Table t) {
if (t == jop::FoldersTable) return "folders";
if (t == jop::NotesTable) return "notes";
return "UNDEFINED";
}
QVariant BaseModel::cacheGet(const QString &key) {
if (!BaseModel::cache_.contains(key)) return QVariant();
return cache_[key];
}
void BaseModel::cacheSet(const QString &key, const QVariant &value) {
BaseModel::cache_[key] = value;
}
void BaseModel::cacheDelete(const QString &key) {
BaseModel::cache_.remove(key);
}
void BaseModel::setValue(const QString &name, const QString &value) {
setValue(name, Value(value));
}
void BaseModel::setValue(const QString& name, const QVariant& value) {
setValue(name, Value(value));
}
BaseModel::Value::Value() {}
BaseModel::Value::Value(const QString &v) {
type_ = QMetaType::QString;
stringValue_ = v;
}
BaseModel::Value::Value(int v) {
type_ = QMetaType::Int;
intValue_ = v;
}
BaseModel::Value::Value(const QVariant &v) {
type_ = (QMetaType::Type)v.type();
if (type_ == QMetaType::QString) {
stringValue_ = v.toString();
} else if (type_ == QMetaType::Int) {
intValue_ = v.toInt();
} else {
// Creates an invalid Value
}
}
int BaseModel::Value::toInt() const {
return intValue_;
}
QString BaseModel::Value::toString() const {
return stringValue_;
}
QVariant BaseModel::Value::toQVariant() const {
QMetaType::Type t = type();
if (t == QMetaType::QString) return QVariant(toString());
if (t == QMetaType::Int) return QVariant(toInt());
return QVariant();
}
QMetaType::Type BaseModel::Value::type() const {
return type_;
}
bool BaseModel::Value::isValid() const {
return type_ > 0;
}
bool BaseModel::Value::isEqual(const BaseModel::Value &v) const {
QMetaType::Type type = v.type();
if (this->type() != type) return false;
if (type == QMetaType::QString) return toString() == v.toString();
if (type == QMetaType::Int) return toInt() == v.toInt();
qCritical() << "Unreachable";
return false;
}

View File

@ -0,0 +1,88 @@
#ifndef BASEMODEL_H
#define BASEMODEL_H
#include <stable.h>
#include "database.h"
#include "enum.h"
namespace jop {
class BaseModel {
public:
struct Field {
QString name;
QMetaType::Type type;
};
class Value {
public:
Value();
Value(const QString& v);
Value(int v);
Value(const QVariant& v);
int toInt() const;
QString toString() const;
QVariant toQVariant() const;
QMetaType::Type type() const;
bool isValid() const;
bool isEqual(const Value& v) const;
private:
QMetaType::Type type_;
QString stringValue_;
int intValue_;
};
BaseModel();
QStringList changedFields() const;
static int count(jop::Table table);
bool save();
bool dispose();
virtual Table table() const;
virtual QString primaryKey() const;
virtual bool primaryKeyIsUuid() const;
bool isNew() const;
static QVector<BaseModel::Field> tableFields(Table table);
static QStringList tableFieldNames(Table table);
static bool isValidFieldName(Table table, const QString& name);
void loadSqlQuery(const QSqlQuery& query);
QHash<QString, Value> values() const;
Value value(const QString& name) const;
bool valueIsSet(const QString& name) const;
void setValue(const QString& name, const Value& value);
void setValue(const QString& name, const QVariant& value);
void setValue(const QString& name, const QString& value);
void setValue(const QString& name, int value);
Value id() const;
static QString tableName(Table t);
protected:
QHash<QString, bool> changedFields_;
Table table_;
QHash<QString, Value> values_;
static QVariant cacheGet(const QString& key);
static void cacheSet(const QString& key, const QVariant& value);
static void cacheDelete(const QString& key);
static QMap<int, QVector<BaseModel::Field>> tableFields_;
static QHash<QString, QVariant> cache_;
};
}
#endif // BASEMODEL_H

View File

@ -5,64 +5,79 @@
using namespace jop; using namespace jop;
Folder::Folder() { Folder::Folder() : Item() {
} }
bool Folder::isNew() const { //bool Folder::isNew() const {
return id().isEmpty(); // return id().isEmpty();
} //}
bool Folder::save() { //bool Folder::save() {
bool isNew = this->isNew(); // bool isNew = this->isNew();
QStringList fields; // QStringList fields;
VariantVector values; // VariantVector values;
if (isNew) { // if (isNew) {
setId(uuid::createUuid()); // setId(uuid::createUuid());
fields << "id"; // fields << "id";
values << id(); // values << id();
} // }
fields << "title" << "synced"; // fields << "title" << "synced";
values << title() << QVariant(0); // values << title() << QVariant(0);
if (isNew) { // if (isNew) {
QSqlQuery q = jop::db().buildSqlQuery(Database::Insert, "folders", fields, values); // QSqlQuery q = jop::db().buildSqlQuery(Database::Insert, "folders", fields, values);
q.exec(); // q.exec();
return jop::db().errorCheck(q); // return jop::db().errorCheck(q);
} else { // } else {
QSqlQuery q = jop::db().buildSqlQuery(Database::Update, "folders", fields, values, "id = \"" + id() + "\""); // QSqlQuery q = jop::db().buildSqlQuery(Database::Update, "folders", fields, values, "id = \"" + id() + "\"");
q.exec(); // q.exec();
return jop::db().errorCheck(q); // return jop::db().errorCheck(q);
} // }
} //}
bool Folder::dispose() { //bool Folder::dispose() {
QSqlQuery q(jop::db().database()); // return false;
q.prepare("DELETE FROM folders WHERE id = :id"); //// QSqlQuery q(jop::db().database());
q.bindValue(":id", id()); //// q.prepare("DELETE FROM folders WHERE id = :id");
q.exec(); //// q.bindValue(":id", id());
return jop::db().errorCheck(q); //// q.exec();
} //// return jop::db().errorCheck(q);
//}
int Folder::count() { int Folder::count() {
QSqlQuery q = jop::db().query("SELECT count(*) as row_count FROM folders"); return BaseModel::count(jop::FoldersTable);
q.exec();
q.next();
return q.value(0).toInt();
} }
QVector<Folder> Folder::all(const QString &orderBy) { QVector<Folder> Folder::all(const QString &orderBy) {
QSqlQuery q = jop::db().query("SELECT " + Folder::dbFields().join(",") + " FROM folders ORDER BY " + orderBy); //QSqlQuery q = jop::db().query("SELECT " + Folder::dbFields().join(",") + " FROM folders ORDER BY " + orderBy);
QSqlQuery q = jop::db().query("SELECT " + BaseModel::tableFieldNames(jop::FoldersTable).join(",") + " FROM folders ORDER BY " + orderBy);
q.exec(); q.exec();
QVector<Folder> output; QVector<Folder> output;
while (q.next()) { while (q.next()) {
Folder folder; Folder folder;
folder.fromSqlQuery(q); folder.loadSqlQuery(q);
output.push_back(folder); output.push_back(folder);
// Folder folder;
// folder.fromSqlQuery(q);
// output.push_back(folder);
// Folder f2;
// f2.loadSqlQuery(q);
// qDebug() << "xxx" << f2.value("title").toString();
} }
return output; return output;
} }
Table Folder::table() const {
return jop::FoldersTable;
}
bool Folder::primaryKeyIsUuid() const {
return true;
}

View File

@ -11,13 +11,13 @@ class Folder : public Item {
public: public:
Folder(); Folder();
bool isNew() const;
bool save();
bool dispose();
static int count(); static int count();
static QVector<Folder> all(const QString& orderBy); static QVector<Folder> all(const QString& orderBy);
Table table() const;
bool primaryKeyIsUuid() const;
private: private:
}; };

View File

@ -7,7 +7,7 @@ FolderModel::FolderModel(Database &database) : QAbstractListModel(), db_(databas
virtualItemShown_ = false; virtualItemShown_ = false;
} }
int FolderModel::rowCount(const QModelIndex & parent) const { int FolderModel::rowCount(const QModelIndex & parent) const { Q_UNUSED(parent);
return Folder::count() + (virtualItemShown_ ? 1 : 0); return Folder::count() + (virtualItemShown_ ? 1 : 0);
} }
@ -18,17 +18,17 @@ QVariant FolderModel::data(const QModelIndex & index, int role) const {
Folder folder; Folder folder;
if (virtualItemShown_ && index.row() == rowCount() - 1) { if (virtualItemShown_ && index.row() == rowCount() - 1) {
folder.setTitle("Untitled"); folder.setValue("title", BaseModel::Value(QString("Untitled")));
} else { } else {
folder = atIndex(index.row()); folder = atIndex(index.row());
} }
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
return QVariant(folder.title()); return folder.value("title").toQVariant();
} }
if (role == IdRole) { if (role == IdRole) {
return QVariant(folder.id()); return folder.id().toQVariant();
} }
return QVariant(); return QVariant();
@ -38,7 +38,7 @@ bool FolderModel::setData(const QModelIndex &index, const QVariant &value, int r
Folder folder = atIndex(index.row()); Folder folder = atIndex(index.row());
if (role == Qt::EditRole) { if (role == Qt::EditRole) {
folder.setTitle(value.toString()); folder.setValue("title", value);
if (!folder.save()) return false; if (!folder.save()) return false;
cache_.clear(); cache_.clear();
@ -90,7 +90,7 @@ void FolderModel::hideVirtualItem() {
endRemoveRows(); endRemoveRows();
} }
QString FolderModel::idAtIndex(int index) const { QString FolderModel::indexToId(int index) const {
return data(this->index(index), IdRole).toString(); return data(this->index(index), IdRole).toString();
} }
@ -98,7 +98,7 @@ int FolderModel::idToIndex(const QString &id) const {
int count = this->rowCount(); int count = this->rowCount();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
Folder folder = atIndex(i); Folder folder = atIndex(i);
if (folder.id() == id) return i; if (folder.value("id").toString() == id) return i;
} }
return -1; return -1;
} }
@ -125,12 +125,12 @@ QHash<int, QByteArray> FolderModel::roleNames() const {
void FolderModel::addData(const QString &title) { void FolderModel::addData(const QString &title) {
Folder folder; Folder folder;
folder.setTitle(title); folder.setValue("title", title);
if (!folder.save()) return; if (!folder.save()) return;
cache_.clear(); cache_.clear();
lastInsertId_ = folder.id(); lastInsertId_ = folder.id().toString();
QVector<int> roles; QVector<int> roles;
roles << Qt::DisplayRole; roles << Qt::DisplayRole;

View File

@ -50,14 +50,10 @@ public slots:
void showVirtualItem(); void showVirtualItem();
bool virtualItemShown() const; bool virtualItemShown() const;
void hideVirtualItem(); void hideVirtualItem();
QString idAtIndex(int index) const; QString indexToId(int index) const;
int idToIndex(const QString& id) const; int idToIndex(const QString& id) const;
QString lastInsertId() const; QString lastInsertId() const;
signals:
void dataChanging();
}; };
} }

View File

@ -3,56 +3,62 @@
using namespace jop; using namespace jop;
Item::Item() { Item::Item() {}
synced_ = false;
}
QString Item::id() const { //Item::Item() {
return id_; // synced_ = false;
} //}
QString Item::title() const { ////QString Item::id() const {
return title_; //// return id_;
} ////}
int Item::createdTime() const { //QString Item::title() const {
return createdTime_; // return title_;
} //}
int Item::updatedTime() const { //int Item::createdTime() const {
return updatedTime_; // return createdTime_;
} //}
bool Item::synced() const { //int Item::updatedTime() const {
return synced_; // return updatedTime_;
} //}
void Item::setId(const QString& v) { //bool Item::synced() const {
id_ = v; // return synced_;
} //}
void Item::setTitle(const QString &v) { //void Item::setId(const QString& v) {
title_ = v; //// if (id_ == v) return;
} // id_ = v;
//// changedFields_.push_back("id");
//}
void Item::setCreatedTime(int v) { //void Item::setTitle(const QString &v) {
createdTime_ = v; //// if (title_ == v) return;
} // title_ = v;
//// changedFields_.push_back("title");
//}
void Item::setSynced(bool v) { //void Item::setCreatedTime(int v) {
synced_ = v; // createdTime_ = v;
} //}
QStringList Item::dbFields() { //void Item::setSynced(bool v) {
QStringList output; // synced_ = v;
output << "id" << "title" << "created_time" << "updated_time" << "synced"; //}
return output;
}
void Item::fromSqlQuery(const QSqlQuery &q) { //QStringList Item::dbFields() {
id_ = q.value(0).toString(); // QStringList output;
title_ = q.value(1).toString(); // output << "id" << "title" << "created_time" << "updated_time" << "synced";
createdTime_ = q.value(2).toInt(); // return output;
updatedTime_ = q.value(3).toInt(); //}
synced_ = q.value(4).toBool();
} //void Item::fromSqlQuery(const QSqlQuery &q) {
// id_ = q.value(0).toString();
// title_ = q.value(1).toString();
// createdTime_ = q.value(2).toInt();
// updatedTime_ = q.value(3).toInt();
// synced_ = q.value(4).toBool();
//}

View File

@ -3,35 +3,36 @@
#include <stable.h> #include <stable.h>
#include "models/basemodel.h"
namespace jop { namespace jop {
class Item { class Item : public BaseModel {
public: public:
Item(); Item();
QString id() const; // QString title() const;
QString title() const; // int createdTime() const;
int createdTime() const; // int updatedTime() const;
int updatedTime() const; // bool synced() const;
bool synced() const; // static QStringList dbFields();
static QStringList dbFields();
void setId(const QString &v); // void setId(const QString &v);
void setTitle(const QString& v); // void setTitle(const QString& v);
void setCreatedTime(int v); // void setCreatedTime(int v);
void setSynced(bool v); // void setSynced(bool v);
void fromSqlQuery(const QSqlQuery& query); // void fromSqlQuery(const QSqlQuery& query);
private: private:
QString id_; // QString id_;
QString title_; // QString title_;
time_t createdTime_; // time_t createdTime_;
time_t updatedTime_; // time_t updatedTime_;
bool synced_; // bool synced_;
}; };

View File

@ -7,22 +7,22 @@ Note::Note()
} }
QString Note::body() const { //QString Note::body() const {
return body_; // return body_;
} //}
void Note::setBody(const QString &v) { //void Note::setBody(const QString &v) {
body_ = v; // body_ = v;
} //}
QStringList Note::dbFields() { //QStringList Note::dbFields() {
QStringList output = Item::dbFields(); // QStringList output = Item::dbFields();
output << "body"; // output << "body";
return output; // return output;
} //}
void Note::fromSqlQuery(const QSqlQuery &q) { //void Note::fromSqlQuery(const QSqlQuery &q) {
Item::fromSqlQuery(q); // Item::fromSqlQuery(q);
int idx = Item::dbFields().size(); // int idx = Item::dbFields().size();
body_ = q.value(idx).toString(); // body_ = q.value(idx).toString();
} //}

View File

@ -11,14 +11,14 @@ class Note : public Item {
public: public:
Note(); Note();
QString body() const; // QString body() const;
void setBody(const QString& v); // void setBody(const QString& v);
static QStringList dbFields(); // static QStringList dbFields();
void fromSqlQuery(const QSqlQuery &q); // void fromSqlQuery(const QSqlQuery &q);
private: //private:
QString body_; // QString body_;
}; };

View File

@ -11,36 +11,37 @@ NoteCollection::NoteCollection(Database& db, const QString& parentId, const QStr
} }
Note NoteCollection::at(int index) const { Note NoteCollection::at(int index) const {
if (parentId_ == "") return Note(); return Note();
// if (parentId_ == "") return Note();
if (cache_.isset(index)) return cache_.get(index); // if (cache_.isset(index)) return cache_.get(index);
std::vector<int> indexes = cache_.availableBufferAround(index, 32); // std::vector<int> indexes = cache_.availableBufferAround(index, 32);
if (!indexes.size()) { // if (!indexes.size()) {
qWarning() << "Couldn't acquire buffer"; // "Cannot happen" // qWarning() << "Couldn't acquire buffer"; // "Cannot happen"
return Note(); // return Note();
} // }
int from = indexes[0]; // int from = indexes[0];
int to = indexes[indexes.size() - 1]; // int to = indexes[indexes.size() - 1];
QSqlQuery q = db_.query("SELECT id, title, body FROM notes WHERE parent_id = :parent_id ORDER BY " + orderBy_ + " LIMIT " + QString::number(to - from + 1) + " OFFSET " + QString::number(from)); // QSqlQuery q = db_.query("SELECT id, title, body FROM notes WHERE parent_id = :parent_id ORDER BY " + orderBy_ + " LIMIT " + QString::number(to - from + 1) + " OFFSET " + QString::number(from));
q.bindValue(":parent_id", parentId_); // q.bindValue(":parent_id", parentId_);
q.exec(); // q.exec();
int noteIndex = from; // int noteIndex = from;
while (q.next()) { // while (q.next()) {
Note note; // Note note;
note.setId(q.value(0).toString()); // note.setId(q.value(0).toString());
note.setTitle(q.value(1).toString()); // note.setTitle(q.value(1).toString());
note.setBody(q.value(2).toString()); // note.setBody(q.value(2).toString());
cache_.set(noteIndex, note); // cache_.set(noteIndex, note);
noteIndex++; // noteIndex++;
} // }
return cache_.get(index); // return cache_.get(index);
} }
// TODO: cache result // TODO: cache result
@ -55,25 +56,26 @@ int NoteCollection::count() const {
} }
Note NoteCollection::byId(const QString& id) const { Note NoteCollection::byId(const QString& id) const {
std::vector<int> indexes = cache_.indexes(); return Note();
for (size_t i = 0; i < indexes.size(); i++) { // std::vector<int> indexes = cache_.indexes();
Note note = cache_.get(indexes[i]); // for (size_t i = 0; i < indexes.size(); i++) {
if (note.id() == id) return note; // Note note = cache_.get(indexes[i]);
} // if (note.id() == id) return note;
// }
QSqlQuery q = db_.query("SELECT id, title, body FROM notes WHERE id = :id"); // QSqlQuery q = db_.query("SELECT id, title, body FROM notes WHERE id = :id");
q.bindValue(":id", id); // q.bindValue(":id", id);
q.exec(); // q.exec();
q.next(); // q.next();
if (!q.isValid()) { // if (!q.isValid()) {
qWarning() << "Invalid note ID:" << id; // qWarning() << "Invalid note ID:" << id;
return Note(); // return Note();
} // }
// TODO: refactor creation of note from SQL query object // // TODO: refactor creation of note from SQL query object
Note note; // Note note;
note.setId(q.value(0).toString()); // note.setId(q.value(0).toString());
note.setTitle(q.value(1).toString()); // note.setTitle(q.value(1).toString());
note.setBody(q.value(2).toString()); // note.setBody(q.value(2).toString());
return note; // return note;
} }

View File

@ -13,13 +13,13 @@ int jop::NoteModel::rowCount(const QModelIndex &parent) const {
QVariant jop::NoteModel::data(const QModelIndex &index, int role) const { QVariant jop::NoteModel::data(const QModelIndex &index, int role) const {
if (index.row() < 0 || index.row() >= rowCount()) return QVariant(); if (index.row() < 0 || index.row() >= rowCount()) return QVariant();
Note note = collection_.at(index.row()); // Note note = collection_.at(index.row());
if (role == IdRole) { // if (role == IdRole) {
return QVariant(note.id()); // return QVariant(note.id());
} // }
return QVariant(note.title()); // return QVariant(note.title());
} }
void jop::NoteModel::setFolderId(const QString &v) { void jop::NoteModel::setFolderId(const QString &v) {

View File

@ -5,11 +5,11 @@ using namespace jop;
QmlNote::QmlNote() {} QmlNote::QmlNote() {}
QString QmlNote::title() const { QString QmlNote::title() const {
return note_.title(); return note_.value("title").toString();
} }
QString QmlNote::body() const { QString QmlNote::body() const {
return note_.body(); return note_.value("body").toString();
} }
void QmlNote::setNote(const Note &note) { void QmlNote::setNote(const Note &note) {

View File

@ -14,48 +14,48 @@ void Synchronizer::start() {
QSqlQuery query; QSqlQuery query;
std::vector<Folder> folders; // std::vector<Folder> folders;
query = db_.query("SELECT " + Folder::dbFields().join(',') + " FROM folders WHERE synced = 0"); // query = db_.query("SELECT " + Folder::dbFields().join(',') + " FROM folders WHERE synced = 0");
query.exec(); // query.exec();
while (query.next()) { // while (query.next()) {
Folder folder; // Folder folder;
folder.fromSqlQuery(query); // folder.fromSqlQuery(query);
folders.push_back(folder); // folders.push_back(folder);
} // }
QList<Note> notes; // QList<Note> notes;
query = db_.query("SELECT " + Note::dbFields().join(',') + " FROM notes WHERE synced = 0"); // query = db_.query("SELECT " + Note::dbFields().join(',') + " FROM notes WHERE synced = 0");
query.exec(); // query.exec();
while (query.next()) { // while (query.next()) {
Note note; // Note note;
note.fromSqlQuery(query); // note.fromSqlQuery(query);
notes << note; // notes << note;
} // }
for (size_t i = 0; i < folders.size(); i++) { // for (size_t i = 0; i < folders.size(); i++) {
Folder folder = folders[i]; // Folder folder = folders[i];
QUrlQuery data; // QUrlQuery data;
data.addQueryItem("id", folder.id()); // data.addQueryItem("id", folder.id());
data.addQueryItem("title", folder.title()); // data.addQueryItem("title", folder.title());
data.addQueryItem("created_time", QString::number(folder.createdTime())); // data.addQueryItem("created_time", QString::number(folder.createdTime()));
data.addQueryItem("updated_time", QString::number(folder.updatedTime())); // data.addQueryItem("updated_time", QString::number(folder.updatedTime()));
api_.put("folders/" + folder.id(), QUrlQuery(), data, "putFolder:" + folder.id()); // api_.put("folders/" + folder.id(), QUrlQuery(), data, "putFolder:" + folder.id());
} // }
return; // return;
for (int i = 0; i < notes.size(); i++) { // for (int i = 0; i < notes.size(); i++) {
Note note = notes[i]; // Note note = notes[i];
QUrlQuery data; // QUrlQuery data;
data.addQueryItem("id", note.id()); // data.addQueryItem("id", note.id());
data.addQueryItem("title", note.title()); // data.addQueryItem("title", note.title());
data.addQueryItem("body", note.body()); // data.addQueryItem("body", note.body());
data.addQueryItem("created_time", QString::number(note.createdTime())); // data.addQueryItem("created_time", QString::number(note.createdTime()));
data.addQueryItem("updated_time", QString::number(note.updatedTime())); // data.addQueryItem("updated_time", QString::number(note.updatedTime()));
api_.put("notes/" + note.id(), QUrlQuery(), data, "putNote:" + note.id()); // api_.put("notes/" + note.id(), QUrlQuery(), data, "putNote:" + note.id());
} // }
} }
void Synchronizer::api_requestDone(const QJsonObject& response, const QString& tag) { void Synchronizer::api_requestDone(const QJsonObject& response, const QString& tag) {

Binary file not shown.

Binary file not shown.