Skip to content

Commit 6e75286

Browse files
Add error handling callbacks for batch document operations
1 parent eb2f759 commit 6e75286

4 files changed

Lines changed: 131 additions & 32 deletions

File tree

src/Database/Database.php

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5755,6 +5755,7 @@ private function deleteCascade(Document $collection, Document $relatedCollection
57555755
* @param array<Query> $queries
57565756
* @param int $batchSize
57575757
* @param callable|null $onNext
5758+
* @param callable|null $onError
57585759
* @return int
57595760
* @throws AuthorizationException
57605761
* @throws DatabaseException
@@ -5766,6 +5767,7 @@ public function deleteDocuments(
57665767
array $queries = [],
57675768
int $batchSize = self::DELETE_BATCH_SIZE,
57685769
?callable $onNext = null,
5770+
?callable $onError = null,
57695771
): int {
57705772
if ($this->adapter->getSharedTables() && empty($this->adapter->getTenant())) {
57715773
throw new DatabaseException('Missing tenant. Tenant must be set when table sharing is enabled.');
@@ -5846,32 +5848,33 @@ public function deleteDocuments(
58465848

58475849
$sequences = [];
58485850
$permissionIds = [];
5849-
foreach ($batch as $document) {
5850-
$sequences[] = $document->getSequence();
5851-
if (!empty($document->getPermissions())) {
5852-
$permissionIds[] = $document->getId();
5853-
}
58545851

5855-
if ($this->resolveRelationships) {
5856-
$document = $this->silent(fn () => $this->deleteDocumentRelationships(
5857-
$collection,
5858-
$document
5859-
));
5860-
}
5852+
$this->withTransaction(function () use ($collection, $sequences, $permissionIds, $batch) {
5853+
foreach ($batch as $document) {
5854+
$sequences[] = $document->getSequence();
5855+
if (!empty($document->getPermissions())) {
5856+
$permissionIds[] = $document->getId();
5857+
}
58615858

5862-
// Check if document was updated after the request timestamp
5863-
try {
5864-
$oldUpdatedAt = new \DateTime($document->getUpdatedAt());
5865-
} catch (Exception $e) {
5866-
throw new DatabaseException($e->getMessage(), $e->getCode(), $e);
5867-
}
5859+
if ($this->resolveRelationships) {
5860+
$document = $this->silent(fn () => $this->deleteDocumentRelationships(
5861+
$collection,
5862+
$document
5863+
));
5864+
}
58685865

5869-
if (!\is_null($this->timestamp) && $oldUpdatedAt > $this->timestamp) {
5870-
throw new ConflictException('Document was updated after the request timestamp');
5866+
// Check if document was updated after the request timestamp
5867+
try {
5868+
$oldUpdatedAt = new \DateTime($document->getUpdatedAt());
5869+
} catch (Exception $e) {
5870+
throw new DatabaseException($e->getMessage(), $e->getCode(), $e);
5871+
}
5872+
5873+
if (!\is_null($this->timestamp) && $oldUpdatedAt > $this->timestamp) {
5874+
throw new ConflictException('Document was updated after the request timestamp');
5875+
}
58715876
}
5872-
}
58735877

5874-
$this->withTransaction(function () use ($collection, $sequences, $permissionIds) {
58755878
$this->adapter->deleteDocuments(
58765879
$collection->getId(),
58775880
$sequences,
@@ -5887,8 +5890,11 @@ public function deleteDocuments(
58875890
} else {
58885891
$this->purgeCachedDocument($collection->getId(), $document->getId());
58895892
}
5890-
5891-
$onNext && $onNext($document);
5893+
try {
5894+
$onNext && $onNext($document);
5895+
} catch (Exception $e) {
5896+
$onError && $onError($e);
5897+
}
58925898
$modified++;
58935899
}
58945900

src/Database/Mirror.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,7 @@ public function deleteDocuments(
827827
array $queries = [],
828828
int $batchSize = self::DELETE_BATCH_SIZE,
829829
?callable $onNext = null,
830+
?callable $onError = null,
830831
): int {
831832
$modified = 0;
832833

@@ -838,6 +839,7 @@ function ($doc) use (&$modified, $onNext) {
838839
$onNext && $onNext($doc);
839840
$modified++;
840841
},
842+
$onError
841843
);
842844

843845
if (

tests/e2e/Adapter/Scopes/DocumentTests.php

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3963,13 +3963,33 @@ public function testDeleteBulkDocuments(): void
39633963
Query::orderAsc(),
39643964
Query::limit(2),
39653965
],
3966-
batchSize: 1
3966+
batchSize: 1,
3967+
onNext: function () {
3968+
throw new Exception("Error thrown to test update doesn't stopped and error is caught");
3969+
},
3970+
onError:function ($e) {
3971+
if ($e instanceof Exception) {
3972+
$this->assertInstanceOf(Exception::class, $e);
3973+
$this->assertEquals("Error thrown to test update doesn't stopped and error is caught", $e->getMessage());
3974+
} else {
3975+
$this->fail("Caught value is not an Exception.");
3976+
}
3977+
}
39673978
);
39683979

39693980
$this->assertEquals(2, $count);
39703981

39713982
// TEST: Bulk Delete All Documents
3972-
$this->assertEquals(8, $database->deleteDocuments('bulk_delete'));
3983+
$this->assertEquals(8, $database->deleteDocuments('bulk_delete', onNext: function () {
3984+
throw new Exception("Error thrown to test update doesn't stopped and error is caught");
3985+
}, onError:function ($e) {
3986+
if ($e instanceof Exception) {
3987+
$this->assertInstanceOf(Exception::class, $e);
3988+
$this->assertEquals("Error thrown to test update doesn't stopped and error is caught", $e->getMessage());
3989+
} else {
3990+
$this->fail("Caught value is not an Exception.");
3991+
}
3992+
}));
39733993

39743994
$docs = $database->find('bulk_delete');
39753995
$this->assertCount(0, $docs);
@@ -3982,6 +4002,14 @@ public function testDeleteBulkDocuments(): void
39824002
Query::greaterThanEqual('integer', 5)
39834003
], onNext: function ($doc) use (&$results) {
39844004
$results[] = $doc;
4005+
throw new Exception("Error thrown to test update doesn't stopped and error is caught");
4006+
}, onError:function ($e) {
4007+
if ($e instanceof Exception) {
4008+
$this->assertInstanceOf(Exception::class, $e);
4009+
$this->assertEquals("Error thrown to test update doesn't stopped and error is caught", $e->getMessage());
4010+
} else {
4011+
$this->fail("Caught value is not an Exception.");
4012+
}
39854013
});
39864014

39874015
$this->assertEquals(5, $count);
@@ -3998,7 +4026,16 @@ public function testDeleteBulkDocuments(): void
39984026

39994027
try {
40004028
$this->getDatabase()->withRequestTimestamp($oneHourAgo, function () {
4001-
return $this->getDatabase()->deleteDocuments('bulk_delete');
4029+
return $this->getDatabase()->deleteDocuments('bulk_delete', onNext: function () {
4030+
throw new Exception("Error thrown to test update doesn't stopped and error is caught");
4031+
}, onError:function ($e) {
4032+
if ($e instanceof Exception) {
4033+
$this->assertInstanceOf(Exception::class, $e);
4034+
$this->assertEquals("Error thrown to test update doesn't stopped and error is caught", $e->getMessage());
4035+
} else {
4036+
$this->fail("Caught value is not an Exception.");
4037+
}
4038+
});
40024039
});
40034040
$this->fail('Failed to throw exception');
40044041
} catch (ConflictException $e) {
@@ -4042,7 +4079,16 @@ public function testDeleteBulkDocuments(): void
40424079
Permission::delete(Role::any())
40434080
], false);
40444081

4045-
$database->deleteDocuments('bulk_delete');
4082+
$database->deleteDocuments('bulk_delete', onNext: function () {
4083+
throw new Exception("Error thrown to test update doesn't stopped and error is caught");
4084+
}, onError:function ($e) {
4085+
if ($e instanceof Exception) {
4086+
$this->assertInstanceOf(Exception::class, $e);
4087+
$this->assertEquals("Error thrown to test update doesn't stopped and error is caught", $e->getMessage());
4088+
} else {
4089+
$this->fail("Caught value is not an Exception.");
4090+
}
4091+
});
40464092

40474093
$this->assertEquals(0, \count($this->getDatabase()->find('bulk_delete')));
40484094

@@ -4087,10 +4133,28 @@ public function testDeleteBulkDocumentsQueries(): void
40874133
// Test limit
40884134
$this->propagateBulkDocuments('bulk_delete_queries');
40894135

4090-
$this->assertEquals(5, $database->deleteDocuments('bulk_delete_queries', [Query::limit(5)]));
4136+
$this->assertEquals(5, $database->deleteDocuments('bulk_delete_queries', [Query::limit(5)], onNext: function () {
4137+
throw new Exception("Error thrown to test update doesn't stopped and error is caught");
4138+
}, onError:function ($e) {
4139+
if ($e instanceof Exception) {
4140+
$this->assertInstanceOf(Exception::class, $e);
4141+
$this->assertEquals("Error thrown to test update doesn't stopped and error is caught", $e->getMessage());
4142+
} else {
4143+
$this->fail("Caught value is not an Exception.");
4144+
}
4145+
}));
40914146
$this->assertEquals(5, \count($database->find('bulk_delete_queries')));
40924147

4093-
$this->assertEquals(5, $database->deleteDocuments('bulk_delete_queries', [Query::limit(5)]));
4148+
$this->assertEquals(5, $database->deleteDocuments('bulk_delete_queries', [Query::limit(5)], onNext: function () {
4149+
throw new Exception("Error thrown to test update doesn't stopped and error is caught");
4150+
}, onError:function ($e) {
4151+
if ($e instanceof Exception) {
4152+
$this->assertInstanceOf(Exception::class, $e);
4153+
$this->assertEquals("Error thrown to test update doesn't stopped and error is caught", $e->getMessage());
4154+
} else {
4155+
$this->fail("Caught value is not an Exception.");
4156+
}
4157+
}));
40944158
$this->assertEquals(0, \count($database->find('bulk_delete_queries')));
40954159

40964160
// Test Limit more than batchSize

tests/e2e/Adapter/Scopes/Relationships/ManyToManyTests.php

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,18 +1581,45 @@ public function testDeleteBulkDocumentsManyToManyRelationship(): void
15811581

15821582
// Delete person
15831583
try {
1584-
$this->getDatabase()->deleteDocuments('bulk_delete_person_m2m');
1584+
$this->getDatabase()->deleteDocuments('bulk_delete_person_m2m', onNext: function () {
1585+
throw new Exception("Error thrown to test update doesn't stopped and error is caught");
1586+
}, onError:function ($e) {
1587+
if ($e instanceof Exception) {
1588+
$this->assertInstanceOf(Exception::class, $e);
1589+
$this->assertEquals("Error thrown to test update doesn't stopped and error is caught", $e->getMessage());
1590+
} else {
1591+
$this->fail("Caught value is not an Exception.");
1592+
}
1593+
});
15851594
$this->fail('Failed to throw exception');
15861595
} catch (RestrictedException $e) {
15871596
$this->assertEquals('Cannot delete document because it has at least one related document.', $e->getMessage());
15881597
}
15891598

15901599
// Restrict Cleanup
15911600
$this->getDatabase()->deleteRelationship('bulk_delete_person_m2m', 'bulk_delete_library_m2m');
1592-
$this->getDatabase()->deleteDocuments('bulk_delete_library_m2m');
1601+
$this->getDatabase()->deleteDocuments('bulk_delete_library_m2m', onNext: function () {
1602+
throw new Exception("Error thrown to test update doesn't stopped and error is caught");
1603+
}, onError:function ($e) {
1604+
if ($e instanceof Exception) {
1605+
$this->assertInstanceOf(Exception::class, $e);
1606+
$this->assertEquals("Error thrown to test update doesn't stopped and error is caught", $e->getMessage());
1607+
} else {
1608+
$this->fail("Caught value is not an Exception.");
1609+
}
1610+
});
15931611
$this->assertCount(0, $this->getDatabase()->find('bulk_delete_library_m2m'));
15941612

1595-
$this->getDatabase()->deleteDocuments('bulk_delete_person_m2m');
1613+
$this->getDatabase()->deleteDocuments('bulk_delete_person_m2m', onNext: function () {
1614+
throw new Exception("Error thrown to test update doesn't stopped and error is caught");
1615+
}, onError:function ($e) {
1616+
if ($e instanceof Exception) {
1617+
$this->assertInstanceOf(Exception::class, $e);
1618+
$this->assertEquals("Error thrown to test update doesn't stopped and error is caught", $e->getMessage());
1619+
} else {
1620+
$this->fail("Caught value is not an Exception.");
1621+
}
1622+
});
15961623
$this->assertCount(0, $this->getDatabase()->find('bulk_delete_person_m2m'));
15971624
}
15981625
}

0 commit comments

Comments
 (0)