|
| 1 | +// Author: Kang Lin <kl222@126.com> |
| 2 | + |
| 3 | +#include <QSqlQuery> |
| 4 | +#include <QSqlError> |
| 5 | +#include <QDateTime> |
| 6 | +#include <QLoggingCategory> |
| 7 | +#include "DatabaseUrl.h" |
| 8 | + |
| 9 | +static Q_LOGGING_CATEGORY(log, "DB.Url") |
| 10 | +CDatabaseUrl::CDatabaseUrl(QObject *parent) |
| 11 | + : CDatabase{parent} |
| 12 | +{} |
| 13 | + |
| 14 | + |
| 15 | +bool CDatabaseUrl::OnInitializeDatabase() |
| 16 | +{ |
| 17 | + QSqlQuery query(GetDatabase()); |
| 18 | + |
| 19 | + // 创建历史记录表 |
| 20 | + bool success = query.exec( |
| 21 | + "CREATE TABLE IF NOT EXISTS url (" |
| 22 | + " id INTEGER PRIMARY KEY AUTOINCREMENT," |
| 23 | + " url TEXT UNIQUE NOT NULL," |
| 24 | + " title TEXT," |
| 25 | + " icon INTEGER DEFAULT 0," |
| 26 | + " visit_time DATETIME DEFAULT CURRENT_TIMESTAMP" |
| 27 | + ")" |
| 28 | + ); |
| 29 | + |
| 30 | + if (!success) { |
| 31 | + qCritical(log) << "Failed to create url table:" << query.lastError().text(); |
| 32 | + return false; |
| 33 | + } |
| 34 | + |
| 35 | + // 创建索引 |
| 36 | + query.exec("CREATE INDEX IF NOT EXISTS idx_url_url ON url(url)"); |
| 37 | + |
| 38 | + m_iconDB.SetDatabase(GetDatabase()); |
| 39 | + success = m_iconDB.OnInitializeDatabase(); |
| 40 | + return success; |
| 41 | +} |
| 42 | + |
| 43 | +int CDatabaseUrl::AddUrl(const QString &url, const QString &title, const QIcon &icon) |
| 44 | +{ |
| 45 | + int nId = 0; |
| 46 | + if (url.isEmpty()) return 0; |
| 47 | + |
| 48 | + QSqlQuery query(GetDatabase()); |
| 49 | + |
| 50 | + // 检查URL是否已存在 |
| 51 | + query.prepare("SELECT id, title, icon FROM url WHERE url = :url"); |
| 52 | + query.bindValue(":url", url); |
| 53 | + |
| 54 | + if (query.exec() && query.next()) { |
| 55 | + // 更新现有记录 |
| 56 | + nId = query.value(0).toInt(); |
| 57 | + QString szTitle = query.value(1).toString(); |
| 58 | + if(!title.isEmpty()) |
| 59 | + szTitle = title; |
| 60 | + int iconID = query.value(2).toInt(); |
| 61 | + if(!icon.isNull()) |
| 62 | + iconID = m_iconDB.GetIcon(icon); |
| 63 | + |
| 64 | + query.prepare( |
| 65 | + "UPDATE url SET " |
| 66 | + "title = :title, " |
| 67 | + "icon = :icon " |
| 68 | + "visit_time = :visit_time" |
| 69 | + "WHERE id = :id" |
| 70 | + ); |
| 71 | + query.bindValue(":title", szTitle); |
| 72 | + query.bindValue(":icon", iconID); |
| 73 | + query.bindValue(":visit_time", QDateTime::currentDateTime()); |
| 74 | + query.bindValue(":id", nId); |
| 75 | + } else { |
| 76 | + // 插入新记录 |
| 77 | + query.prepare( |
| 78 | + "INSERT INTO url (url, title, icon) " |
| 79 | + "VALUES (:url, :title, :icon)" |
| 80 | + ); |
| 81 | + query.bindValue(":url", url); |
| 82 | + QString szTitle = title; |
| 83 | + if(szTitle.isEmpty()) |
| 84 | + szTitle = url; |
| 85 | + query.bindValue(":title", szTitle); |
| 86 | + query.bindValue(":icon", m_iconDB.GetIcon(icon)); |
| 87 | + } |
| 88 | + |
| 89 | + bool success = query.exec(); |
| 90 | + if (!success) { |
| 91 | + nId = 0; |
| 92 | + qCritical(log) << "Failed to add url:" << url << query.lastError().text(); |
| 93 | + } else { |
| 94 | + if(0 == nId) |
| 95 | + nId = query.lastInsertId().toInt(); |
| 96 | + } |
| 97 | + |
| 98 | + return nId; |
| 99 | +} |
| 100 | + |
| 101 | +bool CDatabaseUrl::DeleteUrl(const QString &url) |
| 102 | +{ |
| 103 | + if (url.isEmpty()) return false; |
| 104 | + |
| 105 | + QSqlQuery query(GetDatabase()); |
| 106 | + |
| 107 | + query.prepare("DELETE from url WHERE url = :url"); |
| 108 | + query.bindValue(":url", url); |
| 109 | + |
| 110 | + bool success = query.exec(); |
| 111 | + if (!success) { |
| 112 | + qCritical(log) << "Failed to delete url:" << url << query.lastError().text(); |
| 113 | + } |
| 114 | + |
| 115 | + return success; |
| 116 | +} |
| 117 | + |
| 118 | +bool CDatabaseUrl::DeleteUrl(int id) |
| 119 | +{ |
| 120 | + if (0 >= id) return false; |
| 121 | + |
| 122 | + QSqlQuery query(GetDatabase()); |
| 123 | + |
| 124 | + query.prepare("DELETE from url WHERE id = :id"); |
| 125 | + query.bindValue(":id", id); |
| 126 | + |
| 127 | + bool success = query.exec(); |
| 128 | + if (!success) { |
| 129 | + qCritical(log) << "Failed to delete url:" << id << query.lastError().text(); |
| 130 | + } |
| 131 | + |
| 132 | + return success; |
| 133 | +} |
| 134 | + |
| 135 | +bool CDatabaseUrl::UpdateUrl(const QString &url, const QString &title, const QIcon &icon) |
| 136 | +{ |
| 137 | + if (url.isEmpty()) return false; |
| 138 | + if(title.isEmpty() && icon.isNull()) return false; |
| 139 | + |
| 140 | + QSqlQuery query(GetDatabase()); |
| 141 | + |
| 142 | + QString szSql; |
| 143 | + szSql += "visit_time=\"" + QDateTime::currentDateTime().toString(Qt::ISODate) + "\" "; |
| 144 | + if(!title.isEmpty()) |
| 145 | + szSql += ", title=\"" + title + "\" "; |
| 146 | + if(!icon.isNull()) { |
| 147 | + szSql += ", icon=" + QString::number(m_iconDB.GetIcon(icon)) + " "; |
| 148 | + } |
| 149 | + |
| 150 | + szSql = "UPDATE url SET " + szSql; |
| 151 | + szSql += "WHERE url=\"" + url + "\""; |
| 152 | + |
| 153 | + bool success = query.exec(szSql); |
| 154 | + if (!success) { |
| 155 | + qCritical(log) << "Failed to update url:" << szSql << query.lastError().text(); |
| 156 | + } |
| 157 | + |
| 158 | + return success; |
| 159 | +} |
| 160 | + |
| 161 | +bool CDatabaseUrl::UpdateUrl(int id, const QString &title, const QIcon &icon) |
| 162 | +{ |
| 163 | + if (0 >= id) return false; |
| 164 | + |
| 165 | + if(title.isEmpty() && icon.isNull()) return false; |
| 166 | + QString szSql; |
| 167 | + szSql += "visit_time=\"" + QDateTime::currentDateTime().toString(Qt::ISODate) + "\" "; |
| 168 | + if(!title.isEmpty()) |
| 169 | + szSql += ", title=\"" + title + "\" "; |
| 170 | + if(!icon.isNull()) { |
| 171 | + szSql += ", icon=" + QString::number(m_iconDB.GetIcon(icon)) + " "; |
| 172 | + } |
| 173 | + |
| 174 | + QSqlQuery query(GetDatabase()); |
| 175 | + query.prepare("SELECT title, icon FROM url WHERE id = :id"); |
| 176 | + query.bindValue(":id", id); |
| 177 | + |
| 178 | + if (query.exec() && query.next()) { |
| 179 | + if(szSql.isEmpty()) |
| 180 | + return false; |
| 181 | + |
| 182 | + szSql = "UPDATE url SET " + szSql; |
| 183 | + szSql += "WHERE id = " + QString::number(id); |
| 184 | + } else { |
| 185 | + qCritical(log) << "Failed to update url, url is not exist:" << id; |
| 186 | + return false; |
| 187 | + } |
| 188 | + |
| 189 | + bool success = query.exec(); |
| 190 | + if (!success) { |
| 191 | + qCritical(log) << "Failed to update url:" << szSql << query.lastError().text(); |
| 192 | + } |
| 193 | + |
| 194 | + return success; |
| 195 | +} |
| 196 | + |
| 197 | +CDatabaseUrl::UrlItem CDatabaseUrl::GetItem(int id) |
| 198 | +{ |
| 199 | + UrlItem item; |
| 200 | + if (0 >= id) return item; |
| 201 | + |
| 202 | + QSqlQuery query(GetDatabase()); |
| 203 | + |
| 204 | + query.prepare("SELECT url, title, icon, visit_time FROM url " |
| 205 | + "WHERE id = :id"); |
| 206 | + query.bindValue(":id", id); |
| 207 | + |
| 208 | + if (query.exec() && query.next()) { |
| 209 | + item.id = id; |
| 210 | + item.szUrl = query.value(0).toString(); |
| 211 | + item.szTitle = query.value(1).toString(); |
| 212 | + item.iconId = query.value(2).toInt(); |
| 213 | + item.icon = m_iconDB.GetIcon(item.iconId); |
| 214 | + item.visit_time = query.value(3).toDateTime(); |
| 215 | + } |
| 216 | + return item; |
| 217 | +} |
| 218 | + |
| 219 | +CDatabaseUrl::UrlItem CDatabaseUrl::GetItem(const QString& url) |
| 220 | +{ |
| 221 | + UrlItem item; |
| 222 | + if (url.isEmpty()) return item; |
| 223 | + |
| 224 | + QSqlQuery query(GetDatabase()); |
| 225 | + |
| 226 | + query.prepare("SELECT id, title, icon, visit_time FROM url " |
| 227 | + "WHERE url = :url"); |
| 228 | + query.bindValue(":url", url); |
| 229 | + |
| 230 | + if (query.exec() && query.next()) { |
| 231 | + item.szUrl = url; |
| 232 | + item.id = query.value(0).toInt(); |
| 233 | + item.szTitle = query.value(1).toString(); |
| 234 | + item.iconId = query.value(2).toInt(); |
| 235 | + item.icon = m_iconDB.GetIcon(item.iconId); |
| 236 | + item.visit_time = query.value(3).toDateTime(); |
| 237 | + } |
| 238 | + return item; |
| 239 | +} |
| 240 | + |
| 241 | +int CDatabaseUrl::GetId(const QString& url) |
| 242 | +{ |
| 243 | + if (url.isEmpty()) return 0; |
| 244 | + |
| 245 | + QSqlQuery query(GetDatabase()); |
| 246 | + |
| 247 | + query.prepare("SELECT id, title, icon FROM url " |
| 248 | + "WHERE url = :url"); |
| 249 | + query.bindValue(":url", url); |
| 250 | + |
| 251 | + if (query.exec() && query.next()) { |
| 252 | + return query.value(0).toInt(); |
| 253 | + } |
| 254 | + return 0; |
| 255 | +} |
| 256 | + |
| 257 | +QList<int> CDatabaseUrl::GetDomain(const QString &szDomain) |
| 258 | +{ |
| 259 | + QList<int> ret; |
| 260 | + QSqlQuery query(GetDatabase()); |
| 261 | + query.prepare("SELECT id FROM url WHERE url LIKE :url"); |
| 262 | + query.bindValue(":url", QString("%%://%%%1%%").arg(szDomain)); |
| 263 | + |
| 264 | + bool bRet = query.exec(); |
| 265 | + if (bRet) { |
| 266 | + while(query.next()) { |
| 267 | + ret << query.value(0).toInt(); |
| 268 | + } |
| 269 | + } else { |
| 270 | + qCritical(log) << "Failed to get domain:" << query.lastError().text(); |
| 271 | + } |
| 272 | + |
| 273 | + return ret; |
| 274 | +} |
| 275 | + |
| 276 | +QList<CDatabaseUrl::UrlItem> CDatabaseUrl::Search(const QString &keyword) |
| 277 | +{ |
| 278 | + QList<UrlItem> items; |
| 279 | + |
| 280 | + QSqlQuery query(GetDatabase()); |
| 281 | + QString searchPattern = "%" + keyword + "%"; |
| 282 | + query.prepare( |
| 283 | + "SELECT id, url, title, visit_time " |
| 284 | + "FROM url " |
| 285 | + "WHERE url LIKE :pattern OR title LIKE :pattern " |
| 286 | + "ORDER BY visit_time DESC" |
| 287 | + ); |
| 288 | + query.bindValue(":pattern", searchPattern); |
| 289 | + |
| 290 | + if (query.exec()) { |
| 291 | + while (query.next()) { |
| 292 | + UrlItem item; |
| 293 | + item.id = query.value(0).toInt(); |
| 294 | + item.szUrl = query.value(1).toString(); |
| 295 | + item.szTitle = query.value(2).toString(); |
| 296 | + item.visit_time = query.value(3).toDateTime(); |
| 297 | + items.append(item); |
| 298 | + } |
| 299 | + } |
| 300 | + |
| 301 | + return items; |
| 302 | +} |
0 commit comments