* @brief Runs an array of project mutations under a single suspended-autosave window. */
| 5424 | * @brief Runs an array of project mutations under a single suspended-autosave window. |
| 5425 | */ |
| 5426 | API::CommandResponse API::Handlers::ProjectHandler::projectBatch(const QString& id, |
| 5427 | const QJsonObject& params) |
| 5428 | { |
| 5429 | QJsonArray ops; |
| 5430 | if (const auto invalid = validateBatchOps(id, params, ops); invalid) |
| 5431 | return *invalid; |
| 5432 | |
| 5433 | const bool stopOnError = params.value(QStringLiteral("stopOnError")).toBool(false); |
| 5434 | const bool isDryRun = params.value(QStringLiteral("dryRun")).toBool(false); |
| 5435 | |
| 5436 | if (isDryRun) { |
| 5437 | if (const auto invalid = ensureBatchDryRunCompatible(id, ops); invalid) |
| 5438 | return *invalid; |
| 5439 | } |
| 5440 | |
| 5441 | auto& project = DataModel::ProjectModel::instance(); |
| 5442 | if (!isDryRun) |
| 5443 | project.setAutoSaveSuspended(true); |
| 5444 | |
| 5445 | QJsonArray results; |
| 5446 | int successCount = 0; |
| 5447 | int failureCount = 0; |
| 5448 | bool aborted = false; |
| 5449 | |
| 5450 | for (int i = 0; i < ops.size(); ++i) { |
| 5451 | bool opSucceeded = false; |
| 5452 | QJsonObject entry = executeBatchOp(i, ops.at(i).toObject(), isDryRun, opSucceeded); |
| 5453 | results.append(entry); |
| 5454 | if (opSucceeded) |
| 5455 | ++successCount; |
| 5456 | else |
| 5457 | ++failureCount; |
| 5458 | |
| 5459 | if (!opSucceeded && stopOnError) { |
| 5460 | aborted = true; |
| 5461 | break; |
| 5462 | } |
| 5463 | } |
| 5464 | |
| 5465 | if (!isDryRun) { |
| 5466 | project.setAutoSaveSuspended(false); |
| 5467 | project.flushAutoSave(); |
| 5468 | } |
| 5469 | |
| 5470 | QJsonObject result; |
| 5471 | if (isDryRun) |
| 5472 | result[QStringLiteral("dryRun")] = true; |
| 5473 | |
| 5474 | result[QStringLiteral("results")] = results; |
| 5475 | result[QStringLiteral("total")] = ops.size(); |
| 5476 | result[QStringLiteral("succeeded")] = successCount; |
| 5477 | result[QStringLiteral("failed")] = failureCount; |
| 5478 | result[QStringLiteral("aborted")] = aborted; |
| 5479 | result[QStringLiteral("autoSaveMode")] = |
| 5480 | isDryRun ? QStringLiteral("none") : QStringLiteral("flushed"); |
| 5481 | if (isDryRun) |
| 5482 | result[QStringLiteral("warning")] = |
| 5483 | QStringLiteral("DRY RUN: no ops were committed. Each op's per-result still carries the " |
nothing calls this directly
no test coverage detected