* @brief Creates the SQLite database file and writes the schema and session. */
| 212 | * @brief Creates the SQLite database file and writes the schema and session. |
| 213 | */ |
| 214 | void Sessions::ExportWorker::createDatabase(const DataModel::Frame& frame) |
| 215 | { |
| 216 | Q_ASSERT(!m_dbOpen); |
| 217 | |
| 218 | const auto dbPath = Sessions::DatabaseManager::canonicalDbPath(frame.title); |
| 219 | const auto dirPath = QFileInfo(dbPath).absolutePath(); |
| 220 | QDir dir(dirPath); |
| 221 | if (!dir.exists() && !dir.mkpath(".")) { |
| 222 | qWarning() << "[SQLite] Failed to create directory:" << dirPath; |
| 223 | return; |
| 224 | } |
| 225 | |
| 226 | const auto dt = QDateTime::currentDateTime(); |
| 227 | const QString connName = QStringLiteral("ss_sqlite_%1").arg(dt.toMSecsSinceEpoch()); |
| 228 | m_db.emplace(QSqlDatabase::addDatabase("QSQLITE", connName)); |
| 229 | m_db->setDatabaseName(dbPath); |
| 230 | if (!m_db->open()) { |
| 231 | qWarning() << "[SQLite] Cannot open database:" << m_db->lastError().text(); |
| 232 | m_db.reset(); |
| 233 | QSqlDatabase::removeDatabase(connName); |
| 234 | return; |
| 235 | } |
| 236 | |
| 237 | QSqlQuery pragma(*m_db); |
| 238 | pragma.exec("PRAGMA journal_mode=WAL"); |
| 239 | pragma.exec("PRAGMA synchronous=NORMAL"); |
| 240 | pragma.exec("PRAGMA busy_timeout=5000"); |
| 241 | |
| 242 | createSchema(pragma); |
| 243 | |
| 244 | insertSession(frame, dt); |
| 245 | if (m_sessionId < 0) [[unlikely]] { |
| 246 | qWarning() << "[SQLite] Aborting database open -- session row was not inserted"; |
| 247 | m_db->close(); |
| 248 | m_db.reset(); |
| 249 | QSqlDatabase::removeDatabase(connName); |
| 250 | return; |
| 251 | } |
| 252 | |
| 253 | writeColumnDefs(frame); |
| 254 | |
| 255 | storeProjectMetadata(frame); |
| 256 | |
| 257 | prepareHotpathQueries(); |
| 258 | |
| 259 | m_dbOpen = true; |
| 260 | Q_EMIT resourceOpenChanged(); |
| 261 | } |
| 262 | |
| 263 | /** |
| 264 | * @brief Delegates to DatabaseManager::createSchema for a single source of truth. |