* @brief Stores the live project JSON snapshot in project_metadata. */
| 443 | * @brief Stores the live project JSON snapshot in project_metadata. |
| 444 | */ |
| 445 | void Sessions::DatabaseWorker::storeProjectMetadata(const QString& projectJson, |
| 446 | const QString& projectTitle, |
| 447 | quint64 token) |
| 448 | { |
| 449 | if (!m_db.isOpen()) { |
| 450 | Q_EMIT mutationFinished(token, false, tr("Database not open")); |
| 451 | return; |
| 452 | } |
| 453 | |
| 454 | if (!m_db.transaction()) { |
| 455 | Q_EMIT mutationFinished(token, false, m_db.lastError().text()); |
| 456 | return; |
| 457 | } |
| 458 | |
| 459 | const auto now = QDateTime::currentDateTime().toString(Qt::ISODate); |
| 460 | |
| 461 | QSqlQuery q(m_db); |
| 462 | bool ok = true; |
| 463 | |
| 464 | q.prepare("INSERT OR REPLACE INTO project_metadata (key, value) VALUES ('project_json', ?)"); |
| 465 | q.bindValue(0, projectJson); |
| 466 | ok = ok && q.exec(); |
| 467 | |
| 468 | q.prepare("INSERT OR REPLACE INTO project_metadata (key, value) VALUES ('project_title', ?)"); |
| 469 | q.bindValue(0, projectTitle); |
| 470 | ok = ok && q.exec(); |
| 471 | |
| 472 | q.prepare("INSERT OR REPLACE INTO project_metadata (key, value) VALUES ('last_modified_at', ?)"); |
| 473 | q.bindValue(0, now); |
| 474 | ok = ok && q.exec(); |
| 475 | |
| 476 | q.prepare("INSERT INTO project_metadata (key, value) VALUES ('created_at', ?) " |
| 477 | "ON CONFLICT(key) DO NOTHING"); |
| 478 | q.bindValue(0, now); |
| 479 | ok = ok && q.exec(); |
| 480 | |
| 481 | if (!ok) { |
| 482 | m_db.rollback(); |
| 483 | Q_EMIT mutationFinished(token, false, q.lastError().text()); |
| 484 | return; |
| 485 | } |
| 486 | |
| 487 | if (!m_db.commit()) { |
| 488 | m_db.rollback(); |
| 489 | Q_EMIT mutationFinished(token, false, m_db.lastError().text()); |
| 490 | return; |
| 491 | } |
| 492 | |
| 493 | Q_EMIT mutationFinished(token, true, QString()); |
| 494 | } |
| 495 | |
| 496 | /** |
| 497 | * @brief Reads the global project JSON snapshot back to the manager. |