mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Record changes
This commit is contained in:
parent
0a08837ef0
commit
629fe42c59
@ -6,10 +6,9 @@ Database::Database() {}
|
|||||||
|
|
||||||
void Database::initialize(const QString &path) {
|
void Database::initialize(const QString &path) {
|
||||||
version_ = -1;
|
version_ = -1;
|
||||||
|
transactionCount_ = 0;
|
||||||
|
|
||||||
// QFile::remove(path);
|
//QFile::remove(path);
|
||||||
|
|
||||||
//qDebug() << Select << Text;
|
|
||||||
|
|
||||||
db_ = QSqlDatabase::addDatabase("QSQLITE");
|
db_ = QSqlDatabase::addDatabase("QSQLITE");
|
||||||
db_.setDatabaseName(path);
|
db_.setDatabaseName(path);
|
||||||
@ -123,6 +122,28 @@ bool Database::errorCheck(const QSqlQuery& query) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Database::transaction() {
|
||||||
|
transactionCount_++;
|
||||||
|
if (transactionCount_ > 1) return true;
|
||||||
|
return db_.transaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::commit() {
|
||||||
|
transactionCount_--;
|
||||||
|
|
||||||
|
if (transactionCount_ < 0) {
|
||||||
|
transactionCount_ = 0;
|
||||||
|
qCritical() << "Attempting commit on a database that is not in transaction mode";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transactionCount_ <= 0) {
|
||||||
|
return db_.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Database::log(const QString &sql, const QSqlQuery &query) const {
|
void Database::log(const QString &sql, const QSqlQuery &query) const {
|
||||||
qDebug() <<"SQL:"<<sql;
|
qDebug() <<"SQL:"<<sql;
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@ public:
|
|||||||
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 = "");
|
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);
|
||||||
|
bool transaction();
|
||||||
|
bool commit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -30,6 +32,7 @@ private:
|
|||||||
int version() const;
|
int version() const;
|
||||||
mutable int version_;
|
mutable int version_;
|
||||||
QStringList sqlStringToLines(const QString& sql);
|
QStringList sqlStringToLines(const QString& sql);
|
||||||
|
int transactionCount_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,9 +5,7 @@
|
|||||||
|
|
||||||
namespace jop {
|
namespace jop {
|
||||||
|
|
||||||
enum ColType { UndefinedType, TextColType, IntColType };
|
enum Table { UndefinedTable, FoldersTable, NotesTable, ChangesTable };
|
||||||
|
|
||||||
enum Table { UndefinedTable, FoldersTable, NotesTable };
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "basemodel.h"
|
#include "basemodel.h"
|
||||||
|
|
||||||
|
#include "models/change.h"
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
|
|
||||||
@ -8,9 +9,7 @@ using namespace jop;
|
|||||||
QMap<int, QVector<BaseModel::Field>> BaseModel::tableFields_;
|
QMap<int, QVector<BaseModel::Field>> BaseModel::tableFields_;
|
||||||
QHash<QString, QVariant> BaseModel::cache_;
|
QHash<QString, QVariant> BaseModel::cache_;
|
||||||
|
|
||||||
BaseModel::BaseModel() {
|
BaseModel::BaseModel() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList BaseModel::changedFields() const {
|
QStringList BaseModel::changedFields() const {
|
||||||
QStringList output;
|
QStringList output;
|
||||||
@ -26,7 +25,7 @@ int BaseModel::count(Table table) {
|
|||||||
QVariant r = BaseModel::cacheGet(k);
|
QVariant r = BaseModel::cacheGet(k);
|
||||||
if (r.isValid()) return r.toInt();
|
if (r.isValid()) return r.toInt();
|
||||||
|
|
||||||
QSqlQuery q = jop::db().query("SELECT count(*) as row_count FROM " + t);
|
QSqlQuery q = jop::db().query("SELECT count(*) AS row_count FROM " + t);
|
||||||
q.exec();
|
q.exec();
|
||||||
q.next();
|
q.next();
|
||||||
int output = q.value(0).toInt();
|
int output = q.value(0).toInt();
|
||||||
@ -47,10 +46,28 @@ bool BaseModel::save() {
|
|||||||
values[field] = value(field).toQVariant();
|
values[field] = value(field).toQVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If it's a new entry and the ID is a UUID, we need to create this
|
||||||
|
// ID now. If the ID is an INT, it will be automatically set by
|
||||||
|
// SQLite.
|
||||||
if (isNew && primaryKeyIsUuid()) {
|
if (isNew && primaryKeyIsUuid()) {
|
||||||
values[primaryKey()] = uuid::createUuid();
|
values[primaryKey()] = uuid::createUuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update created_time and updated_time if needed. If updated_time
|
||||||
|
// has already been updated (maybe manually by the user), don't
|
||||||
|
// automatically update it.
|
||||||
|
if (isNew) {
|
||||||
|
if (BaseModel::hasField(table(), "created_time")) {
|
||||||
|
values["created_time"] = (int)(QDateTime::currentMSecsSinceEpoch() / 1000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!values.contains("updated_time")) {
|
||||||
|
if (BaseModel::hasField(table(), "updated_time")) {
|
||||||
|
values["updated_time"] = (int)(QDateTime::currentMSecsSinceEpoch() / 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
changedFields_.clear();
|
changedFields_.clear();
|
||||||
|
|
||||||
const QString& tableName = BaseModel::tableName(table());
|
const QString& tableName = BaseModel::tableName(table());
|
||||||
@ -59,17 +76,43 @@ bool BaseModel::save() {
|
|||||||
cacheDelete(QString("%1:count").arg(tableName));
|
cacheDelete(QString("%1:count").arg(tableName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool output = false;
|
||||||
|
|
||||||
|
jop::db().transaction();
|
||||||
|
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
QSqlQuery q = jop::db().buildSqlQuery(Database::Insert, tableName, values);
|
QSqlQuery q = jop::db().buildSqlQuery(Database::Insert, tableName, values);
|
||||||
q.exec();
|
q.exec();
|
||||||
return jop::db().errorCheck(q);
|
output = jop::db().errorCheck(q);
|
||||||
|
if (output) setValue("id", values["id"]);
|
||||||
} else {
|
} else {
|
||||||
QSqlQuery q = jop::db().buildSqlQuery(Database::Update, tableName, values, QString("%1 = '%2'").arg(primaryKey()).arg(value("id").toString()));
|
QSqlQuery q = jop::db().buildSqlQuery(Database::Update, tableName, values, QString("%1 = '%2'").arg(primaryKey()).arg(value("id").toString()));
|
||||||
q.exec();
|
q.exec();
|
||||||
return jop::db().errorCheck(q);
|
output = jop::db().errorCheck(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // Unreachable
|
if (output && trackChanges()) {
|
||||||
|
if (isNew) {
|
||||||
|
Change change;
|
||||||
|
change.setValue("item_id", id());
|
||||||
|
change.setValue("item_type", table());
|
||||||
|
change.setValue("type", Change::Create);
|
||||||
|
change.save();
|
||||||
|
} else {
|
||||||
|
for (QMap<QString, QVariant>::const_iterator it = values.begin(); it != values.end(); ++it) {
|
||||||
|
Change change;
|
||||||
|
change.setValue("item_id", id());
|
||||||
|
change.setValue("item_type", table());
|
||||||
|
change.setValue("type", Change::Update);
|
||||||
|
change.setValue("item_field", it.key());
|
||||||
|
change.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jop::db().commit();
|
||||||
|
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseModel::dispose() {
|
bool BaseModel::dispose() {
|
||||||
@ -78,8 +121,20 @@ bool BaseModel::dispose() {
|
|||||||
q.prepare("DELETE FROM " + tableName + " WHERE " + primaryKey() + " = :id");
|
q.prepare("DELETE FROM " + tableName + " WHERE " + primaryKey() + " = :id");
|
||||||
q.bindValue(":id", id().toString());
|
q.bindValue(":id", id().toString());
|
||||||
q.exec();
|
q.exec();
|
||||||
cacheDelete(QString("%1:count").arg(tableName));
|
|
||||||
return jop::db().errorCheck(q);
|
bool output = jop::db().errorCheck(q);
|
||||||
|
|
||||||
|
if (output) cacheDelete(QString("%1:count").arg(tableName));
|
||||||
|
|
||||||
|
if (output && trackChanges()) {
|
||||||
|
Change change;
|
||||||
|
change.setValue("item_id", id());
|
||||||
|
change.setValue("item_type", table());
|
||||||
|
change.setValue("type", Change::Delete);
|
||||||
|
change.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
Table BaseModel::table() const {
|
Table BaseModel::table() const {
|
||||||
@ -95,6 +150,10 @@ bool BaseModel::primaryKeyIsUuid() const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BaseModel::trackChanges() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool BaseModel::isNew() const {
|
bool BaseModel::isNew() const {
|
||||||
return !valueIsSet(primaryKey());
|
return !valueIsSet(primaryKey());
|
||||||
}
|
}
|
||||||
@ -121,6 +180,14 @@ QVector<BaseModel::Field> BaseModel::tableFields(jop::Table table) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BaseModel::hasField(jop::Table table, const QString &name) {
|
||||||
|
QVector<BaseModel::Field> fields = tableFields(table);
|
||||||
|
foreach (Field field, fields) {
|
||||||
|
if (field.name == name) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QStringList BaseModel::tableFieldNames(Table table) {
|
QStringList BaseModel::tableFieldNames(Table table) {
|
||||||
QVector<BaseModel::Field> fields = BaseModel::tableFields(table);
|
QVector<BaseModel::Field> fields = BaseModel::tableFields(table);
|
||||||
QStringList output;
|
QStringList output;
|
||||||
@ -202,6 +269,7 @@ BaseModel::Value BaseModel::id() const {
|
|||||||
QString BaseModel::tableName(Table t) {
|
QString BaseModel::tableName(Table t) {
|
||||||
if (t == jop::FoldersTable) return "folders";
|
if (t == jop::FoldersTable) return "folders";
|
||||||
if (t == jop::NotesTable) return "notes";
|
if (t == jop::NotesTable) return "notes";
|
||||||
|
if (t == jop::ChangesTable) return "changes";
|
||||||
return "UNDEFINED";
|
return "UNDEFINED";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include <stable.h>
|
#include <stable.h>
|
||||||
|
|
||||||
#include "database.h"
|
|
||||||
#include "enum.h"
|
#include "enum.h"
|
||||||
|
|
||||||
namespace jop {
|
namespace jop {
|
||||||
@ -49,10 +48,12 @@ public:
|
|||||||
virtual Table table() const;
|
virtual Table table() const;
|
||||||
virtual QString primaryKey() const;
|
virtual QString primaryKey() const;
|
||||||
virtual bool primaryKeyIsUuid() const;
|
virtual bool primaryKeyIsUuid() const;
|
||||||
|
virtual bool trackChanges() const;
|
||||||
|
|
||||||
bool isNew() const;
|
bool isNew() const;
|
||||||
|
|
||||||
static QVector<BaseModel::Field> tableFields(Table table);
|
static QVector<BaseModel::Field> tableFields(Table table);
|
||||||
|
static bool hasField(jop::Table table, const QString& name);
|
||||||
static QStringList tableFieldNames(Table table);
|
static QStringList tableFieldNames(Table table);
|
||||||
static bool isValidFieldName(Table table, const QString& name);
|
static bool isValidFieldName(Table table, const QString& name);
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
using namespace jop;
|
using namespace jop;
|
||||||
|
|
||||||
Change::Change(Database &database) : database_(database) {
|
Change::Change() {}
|
||||||
|
|
||||||
|
Table Change::table() const {
|
||||||
|
return jop::ChangesTable;
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,18 @@
|
|||||||
|
|
||||||
#include <stable.h>
|
#include <stable.h>
|
||||||
|
|
||||||
#include "database.h"
|
#include "models/basemodel.h"
|
||||||
|
|
||||||
namespace jop {
|
namespace jop {
|
||||||
|
|
||||||
class Change {
|
class Change : public BaseModel {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Change(Database& database);
|
enum Type { Undefined, Create, Update, Delete };
|
||||||
|
|
||||||
private:
|
Change();
|
||||||
|
Table table() const;
|
||||||
Database& database_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,53 +5,25 @@
|
|||||||
|
|
||||||
using namespace jop;
|
using namespace jop;
|
||||||
|
|
||||||
Folder::Folder() : Item() {
|
Folder::Folder() : Item() {}
|
||||||
|
|
||||||
|
Table Folder::table() const {
|
||||||
|
return jop::FoldersTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
//bool Folder::isNew() const {
|
bool Folder::primaryKeyIsUuid() const {
|
||||||
// return id().isEmpty();
|
return true;
|
||||||
//}
|
}
|
||||||
|
|
||||||
//bool Folder::save() {
|
bool Folder::trackChanges() const {
|
||||||
// bool isNew = this->isNew();
|
return true;
|
||||||
|
}
|
||||||
// QStringList fields;
|
|
||||||
// VariantVector values;
|
|
||||||
// if (isNew) {
|
|
||||||
// setId(uuid::createUuid());
|
|
||||||
// fields << "id";
|
|
||||||
// values << id();
|
|
||||||
// }
|
|
||||||
// fields << "title" << "synced";
|
|
||||||
// values << title() << QVariant(0);
|
|
||||||
|
|
||||||
// if (isNew) {
|
|
||||||
// QSqlQuery q = jop::db().buildSqlQuery(Database::Insert, "folders", fields, values);
|
|
||||||
// q.exec();
|
|
||||||
// return jop::db().errorCheck(q);
|
|
||||||
// } else {
|
|
||||||
// QSqlQuery q = jop::db().buildSqlQuery(Database::Update, "folders", fields, values, "id = \"" + id() + "\"");
|
|
||||||
// q.exec();
|
|
||||||
// return jop::db().errorCheck(q);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//bool Folder::dispose() {
|
|
||||||
// return false;
|
|
||||||
//// QSqlQuery q(jop::db().database());
|
|
||||||
//// q.prepare("DELETE FROM folders WHERE id = :id");
|
|
||||||
//// q.bindValue(":id", id());
|
|
||||||
//// q.exec();
|
|
||||||
//// return jop::db().errorCheck(q);
|
|
||||||
//}
|
|
||||||
|
|
||||||
int Folder::count() {
|
int Folder::count() {
|
||||||
return BaseModel::count(jop::FoldersTable);
|
return BaseModel::count(jop::FoldersTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 " + BaseModel::tableFieldNames(jop::FoldersTable).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();
|
||||||
|
|
||||||
@ -61,23 +33,7 @@ QVector<Folder> Folder::all(const QString &orderBy) {
|
|||||||
Folder folder;
|
Folder folder;
|
||||||
folder.loadSqlQuery(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;
|
|
||||||
}
|
|
||||||
|
@ -17,6 +17,7 @@ public:
|
|||||||
|
|
||||||
Table table() const;
|
Table table() const;
|
||||||
bool primaryKeyIsUuid() const;
|
bool primaryKeyIsUuid() const;
|
||||||
|
bool trackChanges() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -66,9 +66,10 @@ CREATE TABLE version (
|
|||||||
|
|
||||||
CREATE TABLE changes (
|
CREATE TABLE changes (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
|
`type` INT,
|
||||||
item_id TEXT,
|
item_id TEXT,
|
||||||
item_type INT,
|
item_type INT,
|
||||||
item_property TEXT
|
item_field TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
--CREATE TABLE mimetypes (
|
--CREATE TABLE mimetypes (
|
||||||
|
Loading…
Reference in New Issue
Block a user