/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * 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 3, or (at your option) * any later version. * * 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 #include #include #include #include #include #include "dbManager.h" /*! * \brief DBManager::DBManager * \param parent */ DBManager::DBManager(QObject *parent) : QObject(parent) { qRegisterMetaType >("QList"); } /*! * \brief DBManager::open * \param path * \param doCreate */ void DBManager::open(const QString &path, bool doCreate) { QSqlDatabase m_db; m_db = QSqlDatabase::addDatabase("QSQLITE","note"); m_db.setDatabaseName(path); if(!m_db.open()){ qDebug() << "Error: connection with database fail"; }else{ qDebug() << "Database: connection ok"; } if(doCreate) createTables(); } /*! * \brief DBManager::createTables */ void DBManager::createTables() { QSqlQuery query(QSqlDatabase::database("note")); QString active = "CREATE TABLE active_notes (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "creation_date INTEGER NOT NULL DEFAULT (0)," "modification_date INTEGER NOT NULL DEFAULT (0)," "deletion_date INTEGER NOT NULL DEFAULT (0)," "content TEXT, " "full_title TEXT," "note_color INTEGER DEFAULT (0)," "md_content TEXT);"; query.exec(active); //CREATE UNIQUE INDEX 用于在表中创建唯一索引,这意味着两个行不能拥有相同的索引值 // ASC: 升序 DESC: 降序 //CREATE UNIQUE INDEX active_index on active_notes (id ASC); QString active_index = "CREATE UNIQUE INDEX active_index on active_notes (id ASC);"; query.exec(active_index); QString deleted = "CREATE TABLE deleted_notes (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," "creation_date INTEGER NOT NULL DEFAULT (0)," "modification_date INTEGER NOT NULL DEFAULT (0)," "deletion_date INTEGER NOT NULL DEFAULT (0)," "content TEXT," "full_title TEXT," "note_color INTEGER DEFAULT (0)," "md_content TEXT);"; query.exec(deleted); } /*! * \brief DBManager::getLastRowID * \return */ int DBManager::getLastRowID() { QSqlQuery query(QSqlDatabase::database("note")); //sqlite_sequence表也是SQLite的系统表,数据库被创建时,sqlite_sequence表会被自动创建 //该表包括两列。第一列为name,用来存储表的名称。第二列为seq,用来保存表对应的RowID的最大值 //当对应的表增加记录,该表会自动更新。当表删除,该表对应的记录也会自动删除。如果该值超过最大值,会引起SQL_FULL错误。 query.exec("SELECT seq from SQLITE_SEQUENCE WHERE name='active_notes';"); query.next(); return query.value(0).toInt(); } /*! * \brief DBManager::forceLastRowIndexValue * \param indexValue * \return */ bool DBManager::forceLastRowIndexValue(const int indexValue) { QSqlQuery query(QSqlDatabase::database("note")); QString queryStr = QStringLiteral("UPDATE SQLITE_SEQUENCE " "SET seq=%1 " "WHERE name='active_notes';").arg(indexValue); query.exec(queryStr); //Returns the number of rows affected by the result's SQL statement return query.numRowsAffected() == 1; } /*! * \brief DBManager::getNote * \param id * \return */ NoteData* DBManager::getNote(QString id) { QSqlQuery query(QSqlDatabase::database("note")); int parsedId = id.split('_')[1].toInt(); QString queryStr = QStringLiteral("SELECT * FROM active_notes WHERE id = %1 LIMIT 1").arg(parsedId); query.exec(queryStr); //检索结果中的第一条记录(如果有),并将查询放在检索到的记录上 if (query.first()) { NoteData* note = new NoteData(this->parent() == Q_NULLPTR ? Q_NULLPTR : this); int id = query.value(0).toInt(); qint64 epochDateTimeCreation = query.value(1).toLongLong(); QDateTime dateTimeCreation = QDateTime::fromMSecsSinceEpoch(epochDateTimeCreation); qint64 epochDateTimeModification= query.value(2).toLongLong(); QDateTime dateTimeModification = QDateTime::fromMSecsSinceEpoch(epochDateTimeModification); QString content = query.value(4).toString(); QString fullTitle = query.value(5).toString(); int notecolor = query.value(6).toInt(); QString mdContent = query.value(7).toString(); note->setId(id); note->setCreationDateTime(dateTimeCreation); note->setLastModificationDateTime(dateTimeModification); note->setContent(content); note->setFullTitle(fullTitle); note->setNoteColor(notecolor); note->setMdContent(mdContent); return note; } return Q_NULLPTR; } /*! * \brief DBManager::isNoteExist * \param note * \return */ bool DBManager::isNoteExist(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); int id = note->id(); QString queryStr = QStringLiteral("SELECT EXISTS(SELECT 1 FROM active_notes WHERE id = %1 LIMIT 1 )") .arg(id); query.exec(queryStr); query.next(); return query.value(0).toInt() == 1; } /*! * \brief DBManager::getAllNotes * \return */ QList DBManager::getAllNotes() { QList noteList; QSqlQuery query(QSqlDatabase::database("note")); query.prepare("SELECT * FROM active_notes"); bool status = query.exec(); if(status){ while(query.next()){ NoteData* note = new NoteData(this); int id = query.value(0).toInt(); //Qt::UTC 1 世界标准时间,代替格林威治标准时间 //Qt::LocalTime 0 与语言环境相关的时间(时区和夏时制) qint64 epochDateTimeCreation = query.value(1).toLongLong(); //协调世界时间(Qt::UTC),并转换为Qt::LocalTime //返回一个时间日期是毫秒级的datetime QDateTime dateTimeCreation = QDateTime::fromMSecsSinceEpoch(epochDateTimeCreation); qint64 epochDateTimeModification= query.value(2).toLongLong(); QDateTime dateTimeModification = QDateTime::fromMSecsSinceEpoch(epochDateTimeModification); QString content = query.value(4).toString(); QString fullTitle = query.value(5).toString(); int notecolor = query.value(6).toInt(); QString mdContent = query.value(7).toString(); note->setId(id); note->setCreationDateTime(dateTimeCreation); note->setLastModificationDateTime(dateTimeModification); note->setContent(content); note->setFullTitle(fullTitle); note->setNoteColor(notecolor); note->setMdContent(mdContent); noteList.push_back(note); } } return noteList; } /*! * \brief DBManager::addNote * \param note * \return */ bool DBManager::addNote(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); QString emptyStr; qint64 epochTimeDateCreated = note->creationDateTime() .toMSecsSinceEpoch(); QString content = note->content() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString fullTitle = note->fullTitle() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString mdContent = note->mdContent() .replace("'","''") .replace(QChar('\x0'), emptyStr); int notecolor = note->notecolor(); qint64 epochTimeDateLastModified = note->lastModificationdateTime().isNull() ? epochTimeDateCreated : note->lastModificationdateTime().toMSecsSinceEpoch(); QString queryStr = QString("INSERT INTO active_notes " "(creation_date, modification_date, deletion_date, content, full_title, note_color, md_content) " "VALUES (%1, %2, -1, '%3', '%4', '%5', '%6');") .arg(epochTimeDateCreated) .arg(epochTimeDateLastModified) .arg(content) .arg(fullTitle) .arg(notecolor) .arg(mdContent); query.exec(queryStr); //Returns the number of rows affected by the result's SQL statement return (query.numRowsAffected() == 1); } /*! * \brief DBManager::removeNote * \param note * \return */ bool DBManager::removeNote(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); QString emptyStr; int id = note->id(); QString queryStr = QStringLiteral("DELETE FROM active_notes " "WHERE id=%1").arg(id); query.exec(queryStr); bool removed = (query.numRowsAffected() == 1); qint64 epochTimeDateCreated = note->creationDateTime().toMSecsSinceEpoch(); qint64 epochTimeDateModified = note->lastModificationdateTime().toMSecsSinceEpoch(); qint64 epochTimeDateDeleted = note->deletionDateTime().toMSecsSinceEpoch(); QString content = note->content() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString fullTitle = note->fullTitle() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString mdContent = note->mdContent() .replace("'","''") .replace(QChar('\x0'), emptyStr); int notecolor = note->notecolor(); queryStr = QString("INSERT INTO deleted_notes " "VALUES (%1, %2, %3, %4, '%5', '%6', '%7', '%8');") .arg(id) .arg(epochTimeDateCreated) .arg(epochTimeDateModified) .arg(epochTimeDateDeleted) .arg(content) .arg(fullTitle) .arg(notecolor) .arg(mdContent); query.exec(queryStr); bool addedToTrashDB = (query.numRowsAffected() == 1); return (removed && addedToTrashDB); } /*! * \brief DBManager::permanantlyRemoveAllNotes * \return */ bool DBManager::permanantlyRemoveAllNotes() { QSqlQuery query(QSqlDatabase::database("note")); return query.exec(QString("DELETE FROM active_notes")); } /*! * \brief DBManager::updateNote * \param note * \return */ bool DBManager::updateNote(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); QString emptyStr; int id = note->id(); qDebug() << "updateNote note id = " <notecolor(); qint64 epochTimeDateModified = note->lastModificationdateTime().toMSecsSinceEpoch(); QString content = note->content().replace(QChar('\x0'), emptyStr); QString fullTitle = note->fullTitle().replace(QChar('\x0'), emptyStr); QString mdContent = note->mdContent().replace(QChar('\x0'), emptyStr); query.prepare(QStringLiteral("UPDATE active_notes SET md_content = :mdContent, note_color = :color," "modification_date = :date, content = :content, full_title = :title WHERE id = :id")); query.bindValue(QStringLiteral(":mdContent"), mdContent); query.bindValue(QStringLiteral(":color"), notecolor); query.bindValue(QStringLiteral(":date"), epochTimeDateModified); query.bindValue(QStringLiteral(":content"), content); query.bindValue(QStringLiteral(":title"), fullTitle); query.bindValue(QStringLiteral(":id"), id); if (!query.exec()) { qWarning () << __func__ << ": " << query.lastError(); } return (query.numRowsAffected() == 1); } /*! * \brief DBManager::migrateNote * \param note * \return */ bool DBManager::migrateNote(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); QString emptyStr; int id = note->id(); int notecolor = note->notecolor(); qint64 epochTimeDateCreated = note->creationDateTime().toMSecsSinceEpoch(); qint64 epochTimeDateModified = note->lastModificationdateTime().toMSecsSinceEpoch(); QString content = note->content() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString fullTitle = note->fullTitle() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString mdContent = note->mdContent() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString queryStr = QString("INSERT INTO active_notes " "VALUES (%1, %2, %3, -1, '%4', '%5', '%6', '%7');") .arg(id) .arg(epochTimeDateCreated) .arg(epochTimeDateModified) .arg(content) .arg(fullTitle) .arg(notecolor) .arg(mdContent); query.exec(queryStr); return (query.numRowsAffected() == 1); } /*! * \brief DBManager::migrateTrash * \param note * \return */ bool DBManager::migrateTrash(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); QString emptyStr; int id = note->id(); int notecolor = note->notecolor(); qint64 epochTimeDateCreated = note->creationDateTime().toMSecsSinceEpoch(); qint64 epochTimeDateModified = note->lastModificationdateTime().toMSecsSinceEpoch(); qint64 epochTimeDateDeleted = note->deletionDateTime().toMSecsSinceEpoch(); QString content = note->content() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString fullTitle = note->fullTitle() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString mdContent = note->mdContent() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString queryStr = QString("INSERT INTO deleted_notes " "VALUES (%1, %2, %3, %4, '%5', '%6', '%7', '%8');") .arg(id) .arg(epochTimeDateCreated) .arg(epochTimeDateModified) .arg(epochTimeDateDeleted) .arg(content) .arg(fullTitle) .arg(notecolor) .arg(mdContent); query.exec(queryStr); return (query.numRowsAffected() == 1); } /*! * \brief DBManager::onNotesListRequested */ void DBManager::onNotesListRequested() { int noteCounter; QList noteList; noteCounter = getLastRowID(); noteList = getAllNotes(); emit notesReceived(noteList, noteCounter); } /*! * \brief DBManager::onOpenDBManagerRequested * \param path * \param doCreate */ void DBManager::onOpenDBManagerRequested(QString path, bool doCreate) { open(path, doCreate); } /*! * \brief DBManager::onCreateUpdateRequested * \param note */ void DBManager::onCreateUpdateRequested(NoteData* note) { bool exists = isNoteExist(note); if(exists){ qDebug() << "DBManager::updateNote"; updateNote(note); } else{ qDebug() << "DBManager::addNote"; addNote(note); } } /*! * \brief DBManager::onDeleteNoteRequested * \param note */ void DBManager::onDeleteNoteRequested(NoteData* note) { qDebug() << "receive requestDeleteNote :" << __FILE__ << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; removeNote(note); } /*! * \brief DBManager::onImportNotesRequested * \param noteList */ void DBManager::onImportNotesRequested(QList noteList) { QSqlDatabase::database().transaction(); for(NoteData* note : noteList) addNote(note); QSqlDatabase::database().commit(); } /*! * \brief DBManager::onRestoreNotesRequested * \param noteList */ void DBManager::onRestoreNotesRequested(QList noteList) { this->permanantlyRemoveAllNotes(); this->onImportNotesRequested(noteList); } /*! * \brief DBManager::onExportNotesRequested * \param fileName */ void DBManager::onExportNotesRequested(QString fileName) { QList noteList; QFile file(fileName); file.open(QIODevice::WriteOnly); QDataStream out(&file); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) out.setVersion(QDataStream::Qt_5_6); #elif QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) out.setVersion(QDataStream::Qt_5_4); #elif QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) out.setVersion(QDataStream::Qt_5_2); #endif noteList = getAllNotes(); out << noteList; file.close(); qDeleteAll(noteList); noteList.clear(); } /*! * \brief DBManager::onMigrateNotesRequested * \param noteList */ void DBManager::onMigrateNotesRequested(QList noteList) { QSqlDatabase::database().transaction(); for(NoteData* note : noteList) migrateNote(note); QSqlDatabase::database().commit(); qDeleteAll(noteList); noteList.clear(); } /*! * \brief DBManager::onMigrateTrashRequested * \param noteList */ void DBManager::onMigrateTrashRequested(QList noteList) { QSqlDatabase::database().transaction(); for(NoteData* note : noteList) migrateTrash(note); QSqlDatabase::database().commit(); qDeleteAll(noteList); noteList.clear(); } /*! * \brief DBManager::onForceLastRowIndexValueRequested * \param index */ void DBManager::onForceLastRowIndexValueRequested(int index) { forceLastRowIndexValue(index); }