From 910f27016bfb4c3fddd36b06e5f48e7dd6b0ff6c Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 17 Jun 2025 22:08:08 -0400 Subject: [PATCH] Add operation to txn meta --- app/config/collections/projects.php | 10 ++++++++++ app/controllers/api/databases.php | 20 +++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/app/config/collections/projects.php b/app/config/collections/projects.php index e76a17abe5..53a665bfab 100644 --- a/app/config/collections/projects.php +++ b/app/config/collections/projects.php @@ -2527,6 +2527,16 @@ return [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('operations'), + 'type' => Database::VAR_INTEGER, + 'size' => 0, + 'signed' => false, + 'required' => true, + 'default' => 0, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('expiresAt'), 'type' => Database::VAR_DATETIME, diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index cc51fd0def..3e0ec7a88b 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -1564,6 +1564,7 @@ App::post('/v1/databases/transactions') $transaction = $dbForProject->createDocument('transactions', new Document([ '$id' => ID::unique(), 'status' => 'pending', + 'operations' => 0, 'expiresAt' => DateTime::addSeconds(new \DateTime(), $ttl), ])); @@ -1598,11 +1599,19 @@ App::post('/v1/databases/transactions/:transactionId/operations') ->inject('plan') ->action(function (string $transactionId, array $operations, Response $response, Database $dbForProject, array $plan) { $transaction = $dbForProject->getDocument('transactions', $transactionId); - - if ($transaction->isEmpty() || $transaction['status'] !== 'pending') { + if ($transaction->isEmpty() || $transaction->getAttribute('status', '') !== 'pending') { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid or non‑pending transaction'); } + $maxBatch = $plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH; + $existing = $transaction->getAttribute('operations', 0); + + if (($existing + \count($operations)) > $maxBatch) { + throw new Exception( + Exception::TRANSACTION_LIMIT_EXCEEDED, + 'Transaction already has ' . $existing . ' operations, adding ' . \count($operations) . ' would exceed the maximum of ' . $maxBatch + ); + } $databases = $collections = $staged = []; foreach ($operations as $operation) { @@ -1627,7 +1636,12 @@ App::post('/v1/databases/transactions/:transactionId/operations') ]); } - $dbForProject->createDocuments('transactionLogs', $staged); + $dbForProject->withTransaction(function () use ($dbForProject, $transactionId, $staged, $existing, $operations) { + $dbForProject->createDocuments('transactionLogs', $staged); + $dbForProject->updateDocument('transactions', $transactionId, new Document([ + 'operations' => $existing + \count($operations), + ])); + }); $response ->setStatusCode(Response::STATUS_CODE_CREATED)