玉兔远程控制 0.1.0-bate8
载入中...
搜索中...
未找到
DatabaseTree.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QSqlDatabase>
4#include <QSqlQuery>
5#include <QSqlError>
6#include <QJsonArray>
7#include <QJsonObject>
8#include <QLoggingCategory>
9
10#include "DatabaseTree.h"
11
12static Q_LOGGING_CATEGORY(log, "DB.Tree")
13TreeItem::TreeItem(TYPE type) {
14 m_Data.m_Type = type;
15 m_Data.m_id = 0;
16 m_Data.m_nKey = 0;
17 m_Data.m_ParentId = 0;
18 m_Data.m_SortOrder = 0;
19}
20
21TreeItem::TreeItem(const TreeItem &item)
22{
23 m_Data = item.m_Data;
24}
25
26TreeItem& TreeItem::operator =(const TreeItem& item)
27{
28 m_Data = item.m_Data;
29 return *this;
30}
31
32bool TreeItem::IsNode() const
33{
34 return Node == GetType();
35}
36
37bool TreeItem::IsLeaf() const
38{
39 return Leaf == GetType();
40}
41
42TreeItem::TYPE TreeItem::GetType() const
43{
44 return m_Data.m_Type;
45}
46
47void TreeItem::SetType(TYPE type)
48{
49 m_Data.m_Type = type;
50}
51
52int TreeItem::GetId() const
53{
54 return m_Data.m_id;
55}
56
57void TreeItem::SetId(int newId)
58{
59 m_Data.m_id = newId;
60}
61
62QString TreeItem::GetName() const
63{
64 return m_Data.m_szName;
65}
66
67void TreeItem::SetName(const QString &newName)
68{
69 m_Data.m_szName = newName;
70}
71
72int TreeItem::GetParentId() const
73{
74 return m_Data.m_ParentId;
75}
76
77void TreeItem::SetParentId(int newParentId)
78{
79 m_Data.m_ParentId = newParentId;
80}
81
82int TreeItem::GetSortOrder() const
83{
84 return m_Data.m_SortOrder;
85}
86
87void TreeItem::SetSortOrder(int newSortOrder)
88{
89 m_Data.m_SortOrder = newSortOrder;
90}
91
92int TreeItem::GetKey() const
93{
94 return m_Data.m_nKey;
95}
96
97void TreeItem::SetKey(int newNKey)
98{
99 m_Data.m_nKey = newNKey;
100}
101
102QDateTime TreeItem::GetCreateTime() const
103{
104 return m_Data.m_CreateTime;
105}
106
107void TreeItem::SetCreateTime(const QDateTime &newCreateTime)
108{
109 m_Data.m_CreateTime = newCreateTime;
110}
111
112QDateTime TreeItem::GetModifyTime() const
113{
114 return m_Data.m_ModifyTime;
115}
116
117void TreeItem::SetModifyTime(const QDateTime &newModifyTime)
118{
119 m_Data.m_ModifyTime = newModifyTime;
120}
121
122QDateTime TreeItem::GetLastVisitTime() const
123{
124 return m_Data.m_LastVisitTime;
125}
126
127void TreeItem::SetLastVisitTime(const QDateTime &newLastVisitTime)
128{
129 m_Data.m_LastVisitTime = newLastVisitTime;
130}
131
132CDatabaseNode::CDatabaseNode(const QString &szPrefix, QObject *parent)
133 : CDatabase(parent)
134{
135 m_szTableName = "folders";
136 if(!szPrefix.isEmpty())
137 m_szTableName = szPrefix + "_" + m_szTableName;
138 m_szConnectName = "connect_" + m_szTableName;
139}
140
141bool CDatabaseNode::OnInitializeSqliteDatabase()
142{
143 QSqlQuery query(GetDatabase());
144
145 // 启用外键约束
146 query.exec("PRAGMA foreign_keys = ON");
147 QString szSql =
148 "CREATE TABLE IF NOT EXISTS "
149 + m_szTableName +
150 " ("
151 " id INTEGER PRIMARY KEY AUTOINCREMENT,"
152 " name TEXT NOT NULL,"
153 " parent_id INTEGER DEFAULT 0,"
154 " sort_order INTEGER DEFAULT 0,"
155 " created_time DATETIME DEFAULT CURRENT_TIMESTAMP"
156 ")";
157 // 创建文件夹表
158 bool bRet = query.exec(szSql);
159 if (!bRet) {
160 SetError("Failed to create folders sqlite table: "
161 + query.lastError().text()
162 + "; Sql: " + szSql);
163 qCritical(log) << GetError();
164 return false;
165 }
166
167 // 创建索引
168 szSql = "CREATE INDEX IF NOT EXISTS idx_" + m_szTableName + "_parent ON " + m_szTableName + "(parent_id)";
169 bRet = query.exec(szSql);
170 if(!bRet)
171 qDebug(log) << "Failed to create index idx_" + m_szTableName + "_parent:" << query.lastError().text()
172 << "; Sql: " + szSql;
173
174 return true;
175}
176
177bool CDatabaseNode::OnInitializeMySqlDatabase()
178{
179 QSqlQuery query(GetDatabase());
180
181 // 启用外键约束
182 query.exec("PRAGMA foreign_keys = ON");
183
184 // 创建文件夹表
185 QString szSql =
186 "CREATE TABLE IF NOT EXISTS "
187 + m_szTableName +
188 " ("
189 " id INTEGER PRIMARY KEY AUTO_INCREMENT,"
190 " name TEXT NOT NULL,"
191 " parent_id INTEGER DEFAULT 0,"
192 " sort_order INTEGER DEFAULT 0,"
193 " created_time DATETIME DEFAULT CURRENT_TIMESTAMP,"
194 " INDEX idx_parent (parent_id),"
195 " INDEX idx_parent_sort (parent_id, sort_order)"
196 ")";
197 bool bRet = query.exec(szSql);
198 if (!bRet) {
199 qCritical(log) << "Failed to create folders mysql table:"
200 << m_szTableName << query.lastError().text()
201 << "Sql:" << szSql;
202 return false;
203 }
204
205 return true;
206}
207
208int CDatabaseNode::AddNode(const QString &name, int parentId)
209{
210 bool bRet = false;
211 QSqlQuery query(GetDatabase());
212
213 // Check if it already exists
214 query.prepare("SELECT id FROM `" + m_szTableName + "` "
215 " WHERE `parent_id` = :parent_id "
216 " AND `name`=:name"
217 );
218 query.bindValue(":parent_id", parentId);
219 query.bindValue(":name", name);
220 bRet = query.exec();
221 if(!bRet) {
222 SetError("Failed to add folders: " + query.lastError().text()
223 + "; Sql: " + query.executedQuery());
224 qCritical(log) << GetError();
225 return 0;
226 }
227 if(query.next()) {
228 return query.value(0).toInt();
229 }
230
231 // 获取最大排序值
232 query.prepare("SELECT MAX(sort_order) FROM `" + m_szTableName + "` "
233 " WHERE `parent_id` = :parent_id");
234 query.bindValue(":parent_id", parentId);
235 bRet = query.exec();
236 if(!bRet) {
237 SetError("Failed to get max sort_order: " + query.lastError().text()
238 + "; Sql: " + query.executedQuery());
239 qCritical(log) << GetError();
240 return 0;
241 }
242 int maxOrder = 0;
243 if (query.next()) {
244 maxOrder = query.value(0).toInt() + 1;
245 }
246
247 query.prepare(
248 "INSERT INTO `" + m_szTableName + "` "
249 " (`name`, `parent_id`, `sort_order`) "
250 " VALUES (:name, :parent_id, :sort_order) "
251 );
252 query.bindValue(":name", name);
253 query.bindValue(":parent_id", parentId);
254 query.bindValue(":sort_order", maxOrder);
255
256 int id = 0;
257 bRet = query.exec();
258 if (bRet) {
259 id = query.lastInsertId().toInt();
260 if(id > 0) {
261 emit sigAddNode(id, parentId);
262 emit sigChanged();
263 }
264 } else {
265 SetError("Failed to add folders: " + query.lastError().text()
266 + "; Sql: " + query.executedQuery());
267 qCritical(log) << GetError();
268 }
269
270 return id;
271}
272
273bool CDatabaseNode::RenameNode(int id, const QString &newName)
274{
275 QSqlQuery query(GetDatabase());
276 query.prepare("UPDATE `" + m_szTableName + "` "
277 " SET `name` = :name WHERE `id` = :id");
278 query.bindValue(":id", id);
279 query.bindValue(":name", newName);
280 bool bRet = query.exec();
281 if (bRet)
282 emit sigChanged();
283 else {
284 SetError("Failed to rename folders: " + query.lastError().text()
285 + "; Sql: " + query.executedQuery());
286 qCritical(log) << GetError();
287 }
288 return bRet;
289}
290
291bool CDatabaseNode::DeleteNode(
292 int id, std::function<bool (int)> cbDeleteLeaf, bool checkReturn)
293{
294 bool bRet = false;
295 // 删除子目录
296 auto folders = GetSubNodes(id);
297 foreach(auto f, folders) {
298 bRet = DeleteNode(f.GetId(), cbDeleteLeaf, checkReturn);
299 if(checkReturn && !bRet)
300 return false;
301 }
302
303 // 删除其下面的所有条目
304 if(cbDeleteLeaf) {
305 bRet = cbDeleteLeaf(id);
306 if(checkReturn && !bRet) {
307 SetError("Failed to call cbDeleteLeaf");
308 qCritical(log) << GetError();
309 return false;
310 }
311 }
312
313 bRet = OnDeleteLeafs(id);
314 if(checkReturn && !bRet) {
315 SetError("Failed to call OnDeleteLeafs");
316 qCritical(log) << GetError();
317 return false;
318 }
319
320 // 删除文件夹
321 QSqlQuery query(GetDatabase());
322 query.prepare("DELETE FROM `" + m_szTableName + "` WHERE `id` = :id");
323 query.bindValue(":id", id);
324 bRet = query.exec();
325 if (bRet)
326 emit sigChanged();
327 else {
328 SetError("Failed to delete folders: " + query.lastError().text()
329 + "; Sql: " + query.executedQuery());
330 qCritical(log) << GetError();
331 }
332
333 return bRet;
334}
335
336bool CDatabaseNode::OnDeleteLeafs(int id)
337{
338 Q_UNUSED(id);
339 return true;
340}
341
342bool CDatabaseNode::MoveNode(int id, int newParentId)
343{
344 if(id == newParentId) {
345 SetError("Failed to move node. The same node: " + id);
346 qWarning(log) << GetError();
347 return false;
348 }
349 // Check the newParentId is not the child of id
350 bool bRet = InSubNode(id, newParentId);
351 if(bRet) {
352 SetError("The id is the parent of newParentId. "
353 + QString::number(id) + " is the parent of "
354 + QString::number(newParentId));
355 qWarning(log) << GetError();
356 return false;
357 }
358 QSqlQuery query(GetDatabase());
359 query.prepare("UPDATE `" + m_szTableName + "` "
360 " SET `parent_id` = :parent_id WHERE `id` = :id");
361 query.bindValue(":id", id);
362 query.bindValue(":parent_id", newParentId);
363 bRet = query.exec();
364 if (bRet)
365 emit sigChanged();
366 else {
367 SetError("Failed to move folders: " + query.lastError().text()
368 + "; Sql: " + query.executedQuery());
369 qCritical(log) << GetError();
370 }
371 return bRet;
372}
373
374TreeItem CDatabaseNode::GetNode(int id)
375{
376 TreeItem folder(TreeItem::Node);
377 if(0 >= id) return folder;
378 QSqlQuery query(GetDatabase());
379 query.prepare(
380 "SELECT `id`, `name`, `parent_id`, `sort_order`, `created_time` "
381 "FROM `" + m_szTableName + "` "
382 "WHERE `id`=:id"
383 );
384 query.bindValue(":id", id);
385 if (query.exec()) {
386 if(query.next()) {
387 folder.SetId(query.value(0).toInt());
388 folder.SetName(query.value(1).toString());
389 folder.SetParentId(query.value(2).toInt());
390 folder.SetSortOrder(query.value(3).toInt());
391 folder.SetCreateTime(query.value(4).toDateTime());
392 }
393 } else {
394 SetError("Failed to get folder: " + query.lastError().text()
395 + "; Sql: " + query.executedQuery() + QString::number(id));
396 qCritical(log) << GetError();
397 }
398 return folder;
399}
400
401QList<TreeItem> CDatabaseNode::GetAllNodes()
402{
403 QList<TreeItem> folders;
404 QSqlQuery query(GetDatabase());
405 query.prepare(
406 "SELECT `id`, `name`, `parent_id`, `sort_order`, `created_time` "
407 " FROM `" + m_szTableName + "` "
408 " ORDER BY `parent_id`, `sort_order`, `name`"
409 );
410 if (query.exec()) {
411 while (query.next()) {
412 TreeItem folder(TreeItem::Node);
413 folder.SetId(query.value(0).toInt());
414 folder.SetName(query.value(1).toString());
415 folder.SetParentId(query.value(2).toInt());
416 folder.SetSortOrder(query.value(3).toInt());
417 folder.SetCreateTime(query.value(4).toDateTime());
418 folders.append(folder);
419 }
420 } else {
421 SetError("Failed to get all folders: " + query.lastError().text()
422 + "; Sql: " + query.executedQuery());
423 qCritical(log) << GetError();
424 }
425
426 return folders;
427}
428
429QList<TreeItem> CDatabaseNode::GetSubNodes(int parentId)
430{
431 QList<TreeItem> folders;
432
433 QSqlQuery query(GetDatabase());
434 query.prepare(
435 "SELECT `id`, `name`, `parent_id`, `sort_order`, `created_time` "
436 "FROM `" + m_szTableName + "` "
437 "WHERE `parent_id` = :parent_id "
438 "ORDER BY `sort_order`, `name`"
439 );
440 query.bindValue(":parent_id", parentId);
441 if (query.exec()) {
442 while (query.next()) {
443 TreeItem folder(TreeItem::Node);
444 folder.SetId(query.value(0).toInt());
445 folder.SetName(query.value(1).toString());
446 folder.SetParentId(query.value(2).toInt());
447 folder.SetSortOrder(query.value(3).toInt());
448 folder.SetCreateTime(query.value(4).toDateTime());
449 folders.append(folder);
450 }
451 } else {
452 SetError("Failed to get sub folders: " + query.lastError().text()
453 + "; Sql: " + query.executedQuery()
454 + "; parentId: " + QString::number(parentId));
455 qCritical(log) << GetError();
456 }
457
458 return folders;
459}
460
461bool CDatabaseNode::InSubNode(int parentId, int id)
462{
463 bool bRet = false;
464 auto items = GetSubNodes(parentId);
465 foreach(auto it, items) {
466 if(it.GetId() == id)
467 return true;
468 bRet = InSubNode(it.GetId(), id);
469 if(bRet) return true;
470 }
471 return bRet;
472}
473
474int CDatabaseNode::GetCount(int parentId)
475{
476 QSqlQuery query(GetDatabase());
477 if(0 == parentId) {
478 query.prepare("SELECT COUNT(*) FROM `" + m_szTableName + "`");
479 } else {
480 query.prepare("SELECT COUNT(*) FROM `" + m_szTableName + "` WHERE `parent_id`=:id");
481 query.bindValue(":id", parentId);
482 }
483 if (query.exec()) {
484 if(query.next())
485 return query.value(0).toInt();
486 } else {
487 SetError("Failed to get count: " + query.lastError().text()
488 + "; parentId: " + QString::number(parentId));
489 qCritical(log) << GetError();
490 }
491 return 0;
492}
493
494bool CDatabaseNode::ExportToJson(QJsonObject& obj)
495{
496 QSqlQuery query(GetDatabase());
497 query.prepare(
498 "SELECT `id`, `name`, `parent_id`, `sort_order`, `created_time` "
499 "FROM `" + m_szTableName + "` "
500 );
501 bool success = query.exec();
502 if (!success) {
503 SetError("Failed to export folder to json: " + query.lastError().text()
504 + "; Sql: " + query.executedQuery());
505 qCritical(log) << GetError();
506 return false;
507 }
508 QJsonArray folder;
509 while(query.next()) {
510 QJsonObject f;
511 f.insert("id", query.value(0).toInt());
512 f.insert("name", query.value(1).toString());
513 f.insert("parent_id", query.value(2).toInt());
514 f.insert("sort_order", query.value(3).toInt());
515 f.insert("created_time", query.value(4).toDateTime().toString());
516 folder.append(f);
517 }
518 if(!folder.isEmpty())
519 obj.insert("folder", folder);
520 return true;
521}
522
523bool CDatabaseNode::ImportFromJson(const QJsonObject& obj)
524{
525 return true;
526}
527
528CDatabaseTree::CDatabaseTree(const QString &szPrefix, QObject *parent)
529 : CDatabase(parent)
530 , m_FolderDB(szPrefix)
531{
532 m_szTableName = "tree";
533 if(!szPrefix.isEmpty())
534 m_szTableName = szPrefix + "_" + m_szTableName;
535 m_szConnectName = "connect_" + m_szTableName;
536}
537
539{
540 bool bRet = false;
542
543 if(!bRet) return false;
544 bRet = m_FolderDB.SetDatabase(GetDatabase(), m_pPara);
545 if(!bRet) return false;
546 bRet = connect(&m_FolderDB, &CDatabaseNode::sigAddNode,
547 this, &CDatabaseTree::sigAddNode);
548 Q_ASSERT(bRet);
549
550 return bRet;
551}
552
553bool CDatabaseTree::OnInitializeSqliteDatabase()
554{
555 QSqlQuery query(GetDatabase());
556
557 // 启用外键约束
558 query.exec("PRAGMA foreign_keys = ON");
559
560 QString szSql =
561 "CREATE TABLE IF NOT EXISTS `" + m_szTableName + "` (" +
562 " `id` INTEGER PRIMARY KEY AUTOINCREMENT,"
563 " `parent_id` INTEGER DEFAULT 0,"
564 " `name` TEXT,"
565 " `key` INTEGER DEFAULT 0,"
566 " `created_time` DATETIME DEFAULT CURRENT_TIMESTAMP,"
567 " `modified_time` DATETIME DEFAULT CURRENT_TIMESTAMP,"
568 " `last_visit_time` DATETIME"
569 ")";
570 bool bRet = query.exec(szSql);
571 if (!bRet) {
572 SetError("Failed to create tree sqlite table: " + query.lastError().text()
573 + "; Sql: " + szSql);
574 qCritical(log) << GetError();
575 return false;
576 }
577
578 // 创建索引
579 query.exec("CREATE INDEX IF NOT EXISTS `idx_" + m_szTableName + "_key` ON " + m_szTableName + "(`key`)");
580 query.exec("CREATE INDEX IF NOT EXISTS `idx_" + m_szTableName + "_parent_id` ON " + m_szTableName + "(`parent_id`)");
581
582 return true;
583}
584
585bool CDatabaseTree::OnInitializeMySqlDatabase()
586{
587 QSqlQuery query(GetDatabase());
588
589 // 启用外键约束
590 query.exec("PRAGMA foreign_keys = ON");
591
592 QString szSql =
593 "CREATE TABLE IF NOT EXISTS `" + m_szTableName + "` (" +
594 " `id` INTEGER PRIMARY KEY AUTO_INCREMENT,"
595 " `parent_id` INTEGER DEFAULT 0,"
596 " `name` TEXT,"
597 " `key` INTEGER DEFAULT 0,"
598 " `created_time` DATETIME DEFAULT CURRENT_TIMESTAMP,"
599 " `modified_time` DATETIME DEFAULT CURRENT_TIMESTAMP,"
600 " `last_visit_time` DATETIME,"
601 " INDEX `idx_key` (`key`),"
602 " INDEX `idx_parent_id` (`parent_id`)"
603 ")";
604 bool bRet = query.exec(szSql);
605 if (!bRet) {
606 SetError("Failed to create tree mysql table: " + query.lastError().text()
607 + "; Sql: " + szSql);
608 qCritical(log) << GetError();
609 return false;
610 }
611
612 return true;
613}
614
616{
617 bool ok = false;
618 // Check if it is a leaf
619 if(item.IsNode()) {
620 qCritical(log) << "The item is not leaf";
621 return 0;
622 }
623
624 QSqlQuery query(GetDatabase());
625
626 // Check if it already exists
627 query.prepare(
628 "SELECT `id` FROM `" + m_szTableName + "` "
629 " WHERE `key`=:key AND `parent_id`=:parent_id"
630 );
631 query.bindValue(":key", item.GetKey());
632 query.bindValue(":parent_id", item.GetParentId());
633 ok = query.exec();
634 if(!ok) {
635 SetError("Failed to add tree: " + query.lastError().text()
636 + "; Sql: " + query.executedQuery());
637 qCritical(log) << GetError();
638 return 0;
639 }
640 if(query.next()) {
641 return query.value(0).toInt();
642 }
643
644 // Insert
645 query.prepare(
646 "INSERT INTO `" + m_szTableName + "` (`name`, `key`, "
647 "`created_time`, `modified_time`, `last_visit_time`, `parent_id`) "
648 "VALUES (:name, :key, "
649 ":created_time, :modified_time, :last_visit_time, :parent_id)"
650 );
651 query.bindValue(":name", item.GetName());
652 query.bindValue(":key", item.GetKey());
653 QDateTime time = QDateTime::currentDateTime();
654 query.bindValue(":created_time", time);
655 query.bindValue(":modified_time", time);
656 query.bindValue(":last_visit_time", time);
657 query.bindValue(":parent_id", item.GetParentId());
658
659 bool bRet = query.exec();
660 if (!bRet) {
661 SetError("Failed to add tree item: " + query.lastError().text()
662 + "; Sql: " + query.executedQuery());
663 qCritical(log) << GetError();
664 return 0;
665 }
666
667 int id = query.lastInsertId().toInt();
668 if(0 < id)
669 emit sigAdd(id, item.GetParentId());
670 return id;
671}
672
673bool CDatabaseTree::Update(const TreeItem &item)
674{
675 // Check if it is a leaf
676 if(item.IsNode()) {
677 qCritical(log) << "The item is not leaf";
678 return false;
679 }
680
681 QSqlQuery query(GetDatabase());
682 query.prepare(
683 "UPDATE `" + m_szTableName + "` SET "
684 "`name` = :name, "
685 "`key` = :key, "
686 "`created_time` = :created_time, "
687 "`modified_time` = :modified_time, "
688 "`last_visit_time` = :last_visit_time, "
689 "`parent_id` = :parent_id "
690 "WHERE `id` = :id"
691 );
692 query.bindValue(":name", item.GetName());
693 query.bindValue(":key", item.GetKey());
694 query.bindValue(":created_time", item.GetCreateTime());
695 query.bindValue(":modified_time", QDateTime::currentDateTime());
696 query.bindValue(":last_visit_time", item.GetLastVisitTime());
697 query.bindValue(":parent_id", item.GetParentId());
698 query.bindValue(":id", item.GetId());
699 qDebug(log) << "Sql:" << query.executedQuery();
700 qDebug(log) << "Bound value:" << query.boundValues();
701 bool bRet = query.exec();
702 if (!bRet) {
703 SetError("Failed to update tree item: " + query.lastError().text()
704 + "; Sql: " + query.executedQuery());
705 qCritical(log) << GetError();
706 }
707 return bRet;
708}
709
710bool CDatabaseTree::Delete(int id, bool delKey)
711{
712 // 如果是最后的一个,则从 key 相关表中删除 key
713 if(delKey) {
714 auto leaf = GetLeaf(id);
715 if(leaf.GetKey() > 0) {
716 auto leaves = GetLeavesByKey(leaf.GetKey());
717 if(leaves.count() == 1) {
718 bool ok = OnDeleteKey(leaf.GetKey());
719 if(!ok)
720 return ok;
721 }
722 }
723 }
724 QSqlQuery query(GetDatabase());
725 query.prepare("DELETE FROM `" + m_szTableName + "` WHERE `id` = :id");
726 query.bindValue(":id", id);
727 bool bRet = query.exec();
728 if (!bRet) {
729 SetError("Failed to delete item: " + query.lastError().text()
730 + "; Sql: " + query.executedQuery()
731 + "; table: " + m_szTableName
732 + "; id: " + QString::number(id));
733 qCritical(log) << GetError();
734 }
735 return bRet;
736}
737
738bool CDatabaseTree::Delete(QList<int> items, bool delKey)
739{
740 if(items.isEmpty()) return false;
741
742 if(delKey) {
743 foreach(auto id, items) {
744 // 如果是最后的一个,则从 key 相关表中删除 key
745 auto leaf = GetLeaf(id);
746 if(leaf.GetKey() > 0) {
747 auto leaves = GetLeavesByKey(leaf.GetKey());
748 if(leaves.count() == 1) {
749 bool ok = OnDeleteKey(leaf.GetKey());
750 if(!ok)
751 return ok;
752 }
753 }
754 }
755 }
756
757 QSqlQuery query(GetDatabase());
758 QString szSql = "DELETE FROM `" + m_szTableName + "` WHERE ";
759 int i = 0;
760 foreach(auto id, items) {
761 if(0 == i) {
762 i++;
763 szSql += " `id` = " + QString::number(id);
764 } else {
765 szSql += " OR `id` = " + QString::number(id);
766 }
767 }
768 bool success = query.exec(szSql);
769 if (!success) {
770 SetError("Failed to delete item: " + query.lastError().text()
771 + "; Sql: " + query.executedQuery());
772 qCritical(log) << GetError();
773 }
774
775 return success;
776}
777
778bool CDatabaseTree::DeleteChild(int parentId, bool delKey)
779{
780 if(delKey) {
781 auto leaves = GetLeaves(parentId);
782 foreach(auto leaf, leaves) {
783 if(!Delete(leaf.GetId(), delKey))
784 return false;
785 }
786 }
787
788 QSqlQuery query(GetDatabase());
789 query.prepare("DELETE FROM `" + m_szTableName + "` WHERE `parent_id` = :parent_id");
790 query.bindValue(":parent_id", parentId);
791 bool success = query.exec();
792 if (!success) {
793 SetError("Failed to delete child item:" + query.lastError().text()
794 + "; Sql: " + query.executedQuery());
795 qCritical(log) << GetError();
796 }
797
798 return success;
799}
800
801bool CDatabaseTree::Move(int id, int newParent)
802{
803 QSqlQuery query(GetDatabase());
804 query.prepare(
805 "UPDATE `" + m_szTableName + "` SET "
806 "`parent_id` = :parent_id WHERE `id` = :id");
807 query.bindValue(":parent_id", newParent);
808 query.bindValue(":id", id);
809 bool bRet = query.exec();
810 if (!bRet) {
811 SetError("Failed to add tree item: " + query.lastError().text()
812 + "; Sql: " + query.executedQuery());
813 qCritical(log) << GetError();
814 }
815 return bRet;
816}
817
818TreeItem CDatabaseTree::GetLeaf(int id)
819{
820 TreeItem item(TreeItem::Leaf);
821
822 QSqlQuery query(GetDatabase());
823 query.prepare(
824 "SELECT `name`, `key`, `created_time`, `modified_time`, `last_visit_time`, `parent_id` "
825 " FROM `" + m_szTableName + "` "
826 " WHERE `id` = :id");
827 query.bindValue(":id", id);
828 bool bRet = query.exec();
829 if (!bRet) {
830 QString szErr
831 = "Failed to get leaf: " + query.lastError().text()
832 + "; Sql: " + query.executedQuery()
833 + "; id: " + QString::number(id);
834 SetError(szErr);
835 qCritical(log) << GetError();
836 return item;
837 }
838
839 if(query.next()) {
840 item.SetId(id);
841 item.SetName(query.value(0).toString());
842 item.SetKey(query.value(1).toInt());
843 item.SetCreateTime(query.value(2).toDateTime());
844 item.SetModifyTime(query.value(3).toDateTime());
845 item.SetLastVisitTime(query.value(4).toDateTime());
846 item.SetParentId(query.value(5).toInt());
847 }
848
849 return item;
850}
851
852QList<TreeItem> CDatabaseTree::GetLeaves(int nodeId)
853{
854 QList<TreeItem> items;
855 QSqlQuery query(GetDatabase());
856 QString szSql;
857 szSql = "SELECT `id`, `name`, `key`, "
858 "`created_time`, `modified_time`, `last_visit_time`, `parent_id` "
859 "FROM `" + m_szTableName + "`";
860 if(0 <= nodeId)
861 szSql += " WHERE `parent_id` = :parent_id";
862 query.prepare(szSql);
863 query.bindValue(":parent_id", nodeId);
864 bool bRet = query.exec();
865 if (!bRet) {
866 SetError("Failed to get leaves: " + query.lastError().text()
867 + "; Sql: " + query.executedQuery()
868 + "; parentId: " + QString::number(nodeId));
869 qCritical(log) << GetError();
870 return items;
871 }
872 while(query.next()) {
873 TreeItem item(TreeItem::Leaf);
874 item.SetId(query.value(0).toInt());
875 item.SetName(query.value(1).toString());
876 item.SetKey(query.value(2).toInt());
877 item.SetCreateTime(query.value(3).toDateTime());
878 item.SetModifyTime(query.value(4).toDateTime());
879 item.SetLastVisitTime(query.value(5).toDateTime());
880 item.SetParentId(query.value(6).toInt());
881
882 items.append(item);
883 }
884 return items;
885}
886
887QList<TreeItem> CDatabaseTree::GetLeavesByKey(int key)
888{
889 QList<TreeItem> items;
890 QSqlQuery query(GetDatabase());
891 QString szSql;
892 szSql = "SELECT `id`, `name`, "
893 " `created_time`, `modified_time`, `last_visit_time`, `parent_id` "
894 " FROM `" + m_szTableName + "` "
895 " WHERE `key` = :key";
896 query.prepare(szSql);
897 query.bindValue(":key", key);
898 bool success = query.exec();
899 if (!success) {
900 SetError("Failed to get leaves by key: " + query.lastError().text()
901 + "; Sql: " + query.executedQuery()
902 + "; key: " + QString::number(key));
903 return items;
904 }
905 while(query.next()) {
906 TreeItem item(TreeItem::Leaf);
907 item.SetId(query.value(0).toInt());
908 item.SetName(query.value(1).toString());
909 item.SetKey(key);
910 item.SetCreateTime(query.value(2).toDateTime());
911 item.SetModifyTime(query.value(3).toDateTime());
912 item.SetLastVisitTime(query.value(4).toDateTime());
913 item.SetParentId(query.value(5).toInt());
914
915 items.append(item);
916 }
917 return items;
918}
919
920QList<TreeItem> CDatabaseTree::GetLeavesByKey(QList<int> key)
921{
922 QList<TreeItem> items;
923 if(key.isEmpty()) return items;
924
925 QSqlQuery query(GetDatabase());
926 QString szSql;
927 szSql = "SELECT `id`, `name`, `key`, "
928 " `created_time`, `modified_time`, `last_visit_time`, `parent_id` "
929 " FROM `" + m_szTableName + "` "
930 " WHERE ";
931 int i = 0;
932 foreach(auto KeyId, key) {
933 if(0 == i++) {
934 szSql += " `key` = " + QString::number(KeyId);
935 continue;
936 }
937 szSql += " OR `key` = " + QString::number(KeyId);
938 }
939 bool success = query.exec(szSql);
940 if (!success) {
941 SetError("Failed to get leaves by key: " + query.lastError().text()
942 + "; Sql: " + szSql);
943 qCritical(log) << GetError();
944 return items;
945 }
946 while(query.next()) {
947 TreeItem item(TreeItem::Leaf);
948 item.SetId(query.value(0).toInt());
949 item.SetName(query.value(1).toString());
950 item.SetKey(query.value(2).toInt());
951 item.SetCreateTime(query.value(3).toDateTime());
952 item.SetModifyTime(query.value(4).toDateTime());
953 item.SetLastVisitTime(query.value(5).toDateTime());
954 item.SetParentId(query.value(6).toInt());
955
956 items.append(item);
957 }
958 return items;
959}
960
961int CDatabaseTree::GetLeafCount(int parentId)
962{
963 QSqlQuery query(GetDatabase());
964 if(0 == parentId) {
965 query.prepare("SELECT COUNT(*) FROM `" + m_szTableName + "`");
966 } else {
967 query.prepare("SELECT COUNT(*) FROM `" + m_szTableName + "` WHERE `parent_id`=:id");
968 query.bindValue(":id", parentId);
969 }
970 if (query.exec()) {
971 if(query.next())
972 return query.value(0).toInt();
973 } else {
974 SetError("Failed to get leaf count: " + query.lastError().text()
975 + "; Sql: " + query.executedQuery());
976 qCritical(log) << GetError();
977 }
978 return 0;
979}
980
981int CDatabaseTree::AddNode(const QString &name, int parentId)
982{
983 return m_FolderDB.AddNode(name, parentId);
984}
985
986bool CDatabaseTree::RenameNode(int id, const QString &newName)
987{
988 return m_FolderDB.RenameNode(id, newName);
989}
990
991bool CDatabaseTree::DeleteNode(int id, bool delKey)
992{
993 return m_FolderDB.DeleteNode(
994 id,
995 [&, delKey](int parentId)->bool {
996 return DeleteChild(parentId, delKey);
997 },
998 true);
999}
1000
1001bool CDatabaseTree::MoveNode(int id, int newParentId)
1002{
1003 return m_FolderDB.MoveNode(id, newParentId);
1004}
1005
1006TreeItem CDatabaseTree::GetNode(int id)
1007{
1008 return m_FolderDB.GetNode(id);
1009}
1010
1011QList<TreeItem> CDatabaseTree::GetAllNodes()
1012{
1013 return m_FolderDB.GetAllNodes();
1014}
1015
1016QList<TreeItem> CDatabaseTree::GetSubNodes(int parentId)
1017{
1018 return m_FolderDB.GetSubNodes(parentId);
1019}
1020
1021int CDatabaseTree::GetNodeCount(int nParentId)
1022{
1023 return m_FolderDB.GetCount(nParentId);
1024}
1025
1027{
1028 return GetNodeCount(parentId) + GetLeafCount(parentId);
1029}
1030
1032{
1033 return 0;
1034}
1035
1036bool CDatabaseTree::ExportToJson(QJsonObject& obj)
1037{
1038 bool bRet = true;
1039
1040 QSqlQuery query(GetDatabase());
1041 query.prepare(
1042 "SELECT `id`, `parent_id`, `name`, `key`, "
1043 " `created_time`, `modified_time`, `last_visit_time` "
1044 " FROM `" + m_szTableName + "`");
1045 bRet = query.exec();
1046 if (!bRet) {
1047 SetError("Failed to export tree to json: " + query.lastError().text()
1048 + "; Sql: " + query.executedQuery());
1049 qCritical(log) << GetError();
1050 return false;
1051 }
1052
1053 QJsonArray tree;
1054 while(query.next()) {
1055 QJsonObject t;
1056 t.insert("id", query.value(0).toInt());
1057 t.insert("parent_id", query.value(1).toInt());
1058 t.insert("name", query.value(2).toString());
1059 t.insert("key", query.value(3).toInt());
1060 t.insert("created_time", query.value(4).toDateTime().toString());
1061 t.insert("modified_time", query.value(5).toDateTime().toString());
1062 t.insert("last_visit_time", query.value(6).toDateTime().toString());
1063 tree.append(t);
1064 }
1065 if(!tree.isEmpty())
1066 obj.insert("tree", tree);
1067
1068 bRet = m_FolderDB.ExportToJson(obj);
1069 return bRet;
1070}
1071
1072bool CDatabaseTree::ImportFromJson(const QJsonObject& obj)
1073{
1074 bool bRet = true;
1075 bRet = m_FolderDB.ImportFromJson(obj);
1076 return bRet;
1077}
int GetCount(int parentId=0)
Get count
virtual int Add(const TreeItem &item)
Add item
QList< TreeItem > GetLeavesByKey(int key)
Get leaves
virtual bool OnDeleteKey(int key)
从 key 相关的表中删除 key
int GetCount(int parentId=0)
得到指定id节点下的所有节点和叶子数。不递归。
QList< TreeItem > GetLeaves(int nodeId)
Get the leaves under nodeId
virtual bool OnInitializeDatabase() override
Initialize database
提供打开数据库和初始化数据库等接口
Definition Database.h:21
virtual bool OnInitializeDatabase()
Initialize database
Definition Database.cpp:288
bool SetDatabase(const CDatabase *db)
Share an existing database
Definition Database.cpp:34