From 797e9a4b2d4cb5ec2d64ef0ef6d523b427d4e4be Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 19 May 2025 12:37:45 +0300 Subject: [PATCH 01/23] poc cursor --- phpunit.xml | 2 +- src/Database/Database.php | 49 ++++++++---- src/Database/Query.php | 26 +++++-- tests/e2e/Adapter/Base.php | 2 +- tests/e2e/Adapter/Scopes/DocumentTests.php | 86 +++++++++++----------- tests/e2e/Adapter/Scopes/GeneralTests.php | 2 +- 6 files changed, 99 insertions(+), 68 deletions(-) diff --git a/phpunit.xml b/phpunit.xml index 8ba994793..7469c5341 100755 --- a/phpunit.xml +++ b/phpunit.xml @@ -7,7 +7,7 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" - stopOnFailure="false"> + stopOnFailure="true"> ./tests/unit diff --git a/src/Database/Database.php b/src/Database/Database.php index 0c7dfbb41..65f7eec34 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -4358,9 +4358,9 @@ public function updateDocuments( $limit = $grouped['limit']; $cursor = $grouped['cursor']; - if (!empty($cursor) && $cursor->getCollection() !== $collection->getId()) { - throw new DatabaseException("cursor Document must be from the same Collection."); - } +// if (!empty($cursor) && $cursor->getCollection() !== $collection->getId()) { +// throw new DatabaseException("cursor Document must be from the same Collection."); +// } unset($updates['$id']); unset($updates['$createdAt']); @@ -4403,7 +4403,7 @@ public function updateDocuments( ]; if (!empty($last)) { - $new[] = Query::cursorAfter($last); + $new[] = Query::cursorAfter($last->getId()); } $batch = $this->silent(fn () => $this->find( @@ -5756,12 +5756,13 @@ public function deleteDocuments( $limit = $grouped['limit']; $cursor = $grouped['cursor']; - if (!empty($cursor) && $cursor->getCollection() !== $collection->getId()) { - throw new DatabaseException("Cursor document must be from the same Collection."); - } +// if (!empty($cursor) && $cursor->getCollection() !== $collection->getId()) { +// throw new DatabaseException("Cursor document must be from the same Collection."); +// } $originalLimit = $limit; - $last = $cursor; + //$last = $cursor; + $last = new Document(); $modified = 0; while (true) { @@ -5775,8 +5776,8 @@ public function deleteDocuments( Query::limit($batchSize) ]; - if (!empty($last)) { - $new[] = Query::cursorAfter($last); + if (!empty($cursor)) { + $new[] = Query::cursorAfter($cursor, cursor: $last); } /** @@ -5847,6 +5848,8 @@ public function deleteDocuments( } $last = \end($batch); + + $cursor = $last->getId(); } $this->trigger(self::EVENT_DOCUMENTS_DELETE, new Document([ @@ -5960,14 +5963,28 @@ public function find(string $collection, array $queries = [], string $forPermiss $offset = $grouped['offset']; $orderAttributes = $grouped['orderAttributes']; $orderTypes = $grouped['orderTypes']; - $cursor = $grouped['cursor']; + $cursorId = $grouped['cursor']; + /** + * @var Document $cursorHardcoded + */ + $cursorHardcoded = $grouped['cursorHardcoded']; + $cursor = []; $cursorDirection = $grouped['cursorDirection']; - if (!empty($cursor) && $cursor->getCollection() !== $collection->getId()) { - throw new DatabaseException("cursor Document must be from the same Collection."); - } + if (!empty($cursorId)) { + var_dump($cursorHardcoded); + if($cursorHardcoded->isEmpty()){ + $cursor = $this->getDocument($collection->getId(), $cursorId); + }else { + $cursor = $cursorHardcoded; + } - $cursor = empty($cursor) ? [] : $this->encode($collection, $cursor)->getArrayCopy(); + if ($cursor->isEmpty()){ + throw new DatabaseException("Cursor not found"); + } + + $cursor = $this->encode($collection, $cursor)->getArrayCopy(); + } /** @var array $queries */ $queries = \array_merge( @@ -6105,7 +6122,7 @@ public function foreach(string $collection, callable $callback, array $queries = array_unshift($newQueries, Query::offset(0)); } - array_unshift($newQueries, Query::cursorAfter($latestDocument)); + array_unshift($newQueries, Query::cursorAfter($latestDocument->getId())); } if (!$limitExists) { $newQueries[] = Query::limit($limit); diff --git a/src/Database/Query.php b/src/Database/Query.php index 745227401..bca54745d 100644 --- a/src/Database/Query.php +++ b/src/Database/Query.php @@ -73,6 +73,7 @@ class Query protected string $method = ''; protected string $attribute = ''; protected bool $onArray = false; + protected Document $cursor; /** * @var array @@ -86,7 +87,7 @@ class Query * @param string $attribute * @param array $values */ - public function __construct(string $method, string $attribute = '', array $values = []) + public function __construct(string $method, string $attribute = '', array $values = [], Document $cursor = new Document) { if ($attribute === '' && \in_array($method, [Query::TYPE_ORDER_ASC, Query::TYPE_ORDER_DESC])) { $attribute = '$internalId'; @@ -95,6 +96,7 @@ public function __construct(string $method, string $attribute = '', array $value $this->method = $method; $this->attribute = $attribute; $this->values = $values; + $this->cursor = $cursor; } public function __clone(): void @@ -512,21 +514,21 @@ public static function offset(int $value): self /** * Helper method to create Query with cursorAfter method * - * @param Document $value + * @param string $value * @return Query */ - public static function cursorAfter(Document $value): self + public static function cursorAfter(string $value, Document $cursor = new Document): self { - return new self(self::TYPE_CURSOR_AFTER, values: [$value]); + return new self(self::TYPE_CURSOR_AFTER, values: [$value], cursor: $cursor); } /** * Helper method to create Query with cursorBefore method * - * @param Document $value + * @param string $value * @return Query */ - public static function cursorBefore(Document $value): self + public static function cursorBefore(string $value): self { return new self(self::TYPE_CURSOR_BEFORE, values: [$value]); } @@ -625,6 +627,7 @@ public static function groupByType(array $queries): array $orderAttributes = []; $orderTypes = []; $cursor = null; + $cursorHardcoded = new Document(); $cursorDirection = null; foreach ($queries as $query) { @@ -673,6 +676,8 @@ public static function groupByType(array $queries): array $cursor = $values[0] ?? $limit; $cursorDirection = $method === Query::TYPE_CURSOR_AFTER ? Database::CURSOR_AFTER : Database::CURSOR_BEFORE; + $cursorHardcoded = $query->getCursor(); + break; case Query::TYPE_SELECT: @@ -693,6 +698,7 @@ public static function groupByType(array $queries): array 'orderAttributes' => $orderAttributes, 'orderTypes' => $orderTypes, 'cursor' => $cursor, + 'cursorHardcoded' => $cursorHardcoded, 'cursorDirection' => $cursorDirection, ]; } @@ -727,4 +733,12 @@ public function setOnArray(bool $bool): void { $this->onArray = $bool; } + + /** + * @return Document + */ + public function getCursor(): Document + { + return $this->cursor; + } } diff --git a/tests/e2e/Adapter/Base.php b/tests/e2e/Adapter/Base.php index a57fe2748..06445a09e 100644 --- a/tests/e2e/Adapter/Base.php +++ b/tests/e2e/Adapter/Base.php @@ -17,7 +17,7 @@ abstract class Base extends TestCase { - use CollectionTests; + //use CollectionTests; use DocumentTests; use AttributeTests; use IndexTests; diff --git a/tests/e2e/Adapter/Scopes/DocumentTests.php b/tests/e2e/Adapter/Scopes/DocumentTests.php index 35ab3d191..426a6b7ed 100644 --- a/tests/e2e/Adapter/Scopes/DocumentTests.php +++ b/tests/e2e/Adapter/Scopes/DocumentTests.php @@ -1550,7 +1550,7 @@ public function testFindOrderByCursorAfter(): void $documents = static::getDatabase()->find('movies', [ Query::limit(2), Query::offset(0), - Query::cursorAfter($movies[1]) + Query::cursorAfter($movies[1]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[2]['name'], $documents[0]['name']); @@ -1559,7 +1559,7 @@ public function testFindOrderByCursorAfter(): void $documents = static::getDatabase()->find('movies', [ Query::limit(2), Query::offset(0), - Query::cursorAfter($movies[3]) + Query::cursorAfter($movies[3]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[4]['name'], $documents[0]['name']); @@ -1568,7 +1568,7 @@ public function testFindOrderByCursorAfter(): void $documents = static::getDatabase()->find('movies', [ Query::limit(2), Query::offset(0), - Query::cursorAfter($movies[4]) + Query::cursorAfter($movies[4]->getId()) ]); $this->assertEquals(1, count($documents)); $this->assertEquals($movies[5]['name'], $documents[0]['name']); @@ -1576,7 +1576,7 @@ public function testFindOrderByCursorAfter(): void $documents = static::getDatabase()->find('movies', [ Query::limit(2), Query::offset(0), - Query::cursorAfter($movies[5]) + Query::cursorAfter($movies[5]->getId()) ]); $this->assertEmpty(count($documents)); } @@ -1595,7 +1595,7 @@ public function testFindOrderByCursorBefore(): void $documents = static::getDatabase()->find('movies', [ Query::limit(2), Query::offset(0), - Query::cursorBefore($movies[5]) + Query::cursorBefore($movies[5]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[3]['name'], $documents[0]['name']); @@ -1604,7 +1604,7 @@ public function testFindOrderByCursorBefore(): void $documents = static::getDatabase()->find('movies', [ Query::limit(2), Query::offset(0), - Query::cursorBefore($movies[3]) + Query::cursorBefore($movies[3]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[1]['name'], $documents[0]['name']); @@ -1613,7 +1613,7 @@ public function testFindOrderByCursorBefore(): void $documents = static::getDatabase()->find('movies', [ Query::limit(2), Query::offset(0), - Query::cursorBefore($movies[2]) + Query::cursorBefore($movies[2]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[0]['name'], $documents[0]['name']); @@ -1622,7 +1622,7 @@ public function testFindOrderByCursorBefore(): void $documents = static::getDatabase()->find('movies', [ Query::limit(2), Query::offset(0), - Query::cursorBefore($movies[1]) + Query::cursorBefore($movies[1]->getId()) ]); $this->assertEquals(1, count($documents)); $this->assertEquals($movies[0]['name'], $documents[0]['name']); @@ -1630,7 +1630,7 @@ public function testFindOrderByCursorBefore(): void $documents = static::getDatabase()->find('movies', [ Query::limit(2), Query::offset(0), - Query::cursorBefore($movies[0]) + Query::cursorBefore($movies[0]->getId()) ]); $this->assertEmpty(count($documents)); } @@ -1649,7 +1649,7 @@ public function testFindOrderByAfterNaturalOrder(): void Query::limit(2), Query::offset(0), Query::orderDesc(''), - Query::cursorAfter($movies[1]) + Query::cursorAfter($movies[1]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[2]['name'], $documents[0]['name']); @@ -1659,7 +1659,7 @@ public function testFindOrderByAfterNaturalOrder(): void Query::limit(2), Query::offset(0), Query::orderDesc(''), - Query::cursorAfter($movies[3]) + Query::cursorAfter($movies[3]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[4]['name'], $documents[0]['name']); @@ -1669,7 +1669,7 @@ public function testFindOrderByAfterNaturalOrder(): void Query::limit(2), Query::offset(0), Query::orderDesc(''), - Query::cursorAfter($movies[4]) + Query::cursorAfter($movies[4]->getId()) ]); $this->assertEquals(1, count($documents)); $this->assertEquals($movies[5]['name'], $documents[0]['name']); @@ -1678,7 +1678,7 @@ public function testFindOrderByAfterNaturalOrder(): void Query::limit(2), Query::offset(0), Query::orderDesc(''), - Query::cursorAfter($movies[5]) + Query::cursorAfter($movies[5]->getId()) ]); $this->assertEmpty(count($documents)); } @@ -1697,7 +1697,7 @@ public function testFindOrderByBeforeNaturalOrder(): void Query::limit(2), Query::offset(0), Query::orderDesc(''), - Query::cursorBefore($movies[5]) + Query::cursorBefore($movies[5]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[3]['name'], $documents[0]['name']); @@ -1707,7 +1707,7 @@ public function testFindOrderByBeforeNaturalOrder(): void Query::limit(2), Query::offset(0), Query::orderDesc(''), - Query::cursorBefore($movies[3]) + Query::cursorBefore($movies[3]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[1]['name'], $documents[0]['name']); @@ -1717,7 +1717,7 @@ public function testFindOrderByBeforeNaturalOrder(): void Query::limit(2), Query::offset(0), Query::orderDesc(''), - Query::cursorBefore($movies[2]) + Query::cursorBefore($movies[2]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[0]['name'], $documents[0]['name']); @@ -1727,7 +1727,7 @@ public function testFindOrderByBeforeNaturalOrder(): void Query::limit(2), Query::offset(0), Query::orderDesc(''), - Query::cursorBefore($movies[1]) + Query::cursorBefore($movies[1]->getId()) ]); $this->assertEquals(1, count($documents)); $this->assertEquals($movies[0]['name'], $documents[0]['name']); @@ -1736,7 +1736,7 @@ public function testFindOrderByBeforeNaturalOrder(): void Query::limit(2), Query::offset(0), Query::orderDesc(''), - Query::cursorBefore($movies[0]) + Query::cursorBefore($movies[0]->getId()) ]); $this->assertEmpty(count($documents)); } @@ -1756,7 +1756,7 @@ public function testFindOrderBySingleAttributeAfter(): void Query::limit(2), Query::offset(0), Query::orderDesc('year'), - Query::cursorAfter($movies[1]) + Query::cursorAfter($movies[1]->getId()) ]); $this->assertEquals(2, count($documents)); @@ -1767,7 +1767,7 @@ public function testFindOrderBySingleAttributeAfter(): void Query::limit(2), Query::offset(0), Query::orderDesc('year'), - Query::cursorAfter($movies[3]) + Query::cursorAfter($movies[3]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[4]['name'], $documents[0]['name']); @@ -1777,7 +1777,7 @@ public function testFindOrderBySingleAttributeAfter(): void Query::limit(2), Query::offset(0), Query::orderDesc('year'), - Query::cursorAfter($movies[4]) + Query::cursorAfter($movies[4]->getId()) ]); $this->assertEquals(1, count($documents)); $this->assertEquals($movies[5]['name'], $documents[0]['name']); @@ -1786,7 +1786,7 @@ public function testFindOrderBySingleAttributeAfter(): void Query::limit(2), Query::offset(0), Query::orderDesc('year'), - Query::cursorAfter($movies[5]) + Query::cursorAfter($movies[5]->getId()) ]); $this->assertEmpty(count($documents)); } @@ -1807,7 +1807,7 @@ public function testFindOrderBySingleAttributeBefore(): void Query::limit(2), Query::offset(0), Query::orderDesc('year'), - Query::cursorBefore($movies[5]) + Query::cursorBefore($movies[5]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[3]['name'], $documents[0]['name']); @@ -1817,7 +1817,7 @@ public function testFindOrderBySingleAttributeBefore(): void Query::limit(2), Query::offset(0), Query::orderDesc('year'), - Query::cursorBefore($movies[3]) + Query::cursorBefore($movies[3]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[1]['name'], $documents[0]['name']); @@ -1827,7 +1827,7 @@ public function testFindOrderBySingleAttributeBefore(): void Query::limit(2), Query::offset(0), Query::orderDesc('year'), - Query::cursorBefore($movies[2]) + Query::cursorBefore($movies[2]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[0]['name'], $documents[0]['name']); @@ -1837,7 +1837,7 @@ public function testFindOrderBySingleAttributeBefore(): void Query::limit(2), Query::offset(0), Query::orderDesc('year'), - Query::cursorBefore($movies[1]) + Query::cursorBefore($movies[1]->getId()) ]); $this->assertEquals(1, count($documents)); $this->assertEquals($movies[0]['name'], $documents[0]['name']); @@ -1846,7 +1846,7 @@ public function testFindOrderBySingleAttributeBefore(): void Query::limit(2), Query::offset(0), Query::orderDesc('year'), - Query::cursorBefore($movies[0]) + Query::cursorBefore($movies[0]->getId()) ]); $this->assertEmpty(count($documents)); } @@ -1868,7 +1868,7 @@ public function testFindOrderByMultipleAttributeAfter(): void Query::offset(0), Query::orderDesc('price'), Query::orderAsc('year'), - Query::cursorAfter($movies[1]) + Query::cursorAfter($movies[1]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[2]['name'], $documents[0]['name']); @@ -1879,7 +1879,7 @@ public function testFindOrderByMultipleAttributeAfter(): void Query::offset(0), Query::orderDesc('price'), Query::orderAsc('year'), - Query::cursorAfter($movies[3]) + Query::cursorAfter($movies[3]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[4]['name'], $documents[0]['name']); @@ -1890,7 +1890,7 @@ public function testFindOrderByMultipleAttributeAfter(): void Query::offset(0), Query::orderDesc('price'), Query::orderAsc('year'), - Query::cursorAfter($movies[4]) + Query::cursorAfter($movies[4]->getId()) ]); $this->assertEquals(1, count($documents)); $this->assertEquals($movies[5]['name'], $documents[0]['name']); @@ -1900,7 +1900,7 @@ public function testFindOrderByMultipleAttributeAfter(): void Query::offset(0), Query::orderDesc('price'), Query::orderAsc('year'), - Query::cursorAfter($movies[5]) + Query::cursorAfter($movies[5]->getId()) ]); $this->assertEmpty(count($documents)); } @@ -1922,7 +1922,7 @@ public function testFindOrderByMultipleAttributeBefore(): void Query::offset(0), Query::orderDesc('price'), Query::orderAsc('year'), - Query::cursorBefore($movies[5]) + Query::cursorBefore($movies[5]->getId()) ]); $this->assertEquals(2, count($documents)); @@ -1934,7 +1934,7 @@ public function testFindOrderByMultipleAttributeBefore(): void Query::offset(0), Query::orderDesc('price'), Query::orderAsc('year'), - Query::cursorBefore($movies[4]) + Query::cursorBefore($movies[4]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[2]['name'], $documents[0]['name']); @@ -1945,7 +1945,7 @@ public function testFindOrderByMultipleAttributeBefore(): void Query::offset(0), Query::orderDesc('price'), Query::orderAsc('year'), - Query::cursorBefore($movies[2]) + Query::cursorBefore($movies[2]->getId()) ]); $this->assertEquals(2, count($documents)); $this->assertEquals($movies[0]['name'], $documents[0]['name']); @@ -1956,7 +1956,7 @@ public function testFindOrderByMultipleAttributeBefore(): void Query::offset(0), Query::orderDesc('price'), Query::orderAsc('year'), - Query::cursorBefore($movies[1]) + Query::cursorBefore($movies[1]->getId()) ]); $this->assertEquals(1, count($documents)); $this->assertEquals($movies[0]['name'], $documents[0]['name']); @@ -1966,7 +1966,7 @@ public function testFindOrderByMultipleAttributeBefore(): void Query::offset(0), Query::orderDesc('price'), Query::orderAsc('year'), - Query::cursorBefore($movies[0]) + Query::cursorBefore($movies[0]->getId()) ]); $this->assertEmpty(count($documents)); } @@ -1984,7 +1984,7 @@ public function testFindOrderByAndCursor(): void Query::limit(1), Query::offset(0), Query::orderDesc('price'), - Query::cursorAfter($documentsTest[0]) + Query::cursorAfter($documentsTest[0]->getId()) ]); $this->assertEquals($documentsTest[1]['$id'], $documents[0]['$id']); @@ -2003,7 +2003,7 @@ public function testFindOrderByIdAndCursor(): void Query::limit(1), Query::offset(0), Query::orderDesc('$id'), - Query::cursorAfter($documentsTest[0]) + Query::cursorAfter($documentsTest[0]->getId()) ]); $this->assertEquals($documentsTest[1]['$id'], $documents[0]['$id']); @@ -2024,7 +2024,7 @@ public function testFindOrderByCreateDateAndCursor(): void Query::limit(1), Query::offset(0), Query::orderDesc('$createdAt'), - Query::cursorAfter($documentsTest[0]) + Query::cursorAfter($documentsTest[0]->getId()) ]); $this->assertEquals($documentsTest[1]['$id'], $documents[0]['$id']); @@ -2044,7 +2044,7 @@ public function testFindOrderByUpdateDateAndCursor(): void Query::limit(1), Query::offset(0), Query::orderDesc('$updatedAt'), - Query::cursorAfter($documentsTest[0]) + Query::cursorAfter($documentsTest[0]->getId()) ]); $this->assertEquals($documentsTest[1]['$id'], $documents[0]['$id']); @@ -2535,7 +2535,7 @@ public function testForeach(): void $first = $documents[0]; $documents = []; - static::getDatabase()->foreach('movies', queries: [Query::limit(2), Query::cursorAfter($first)], callback: function ($document) use (&$documents) { + static::getDatabase()->foreach('movies', queries: [Query::limit(2), Query::cursorAfter($first->getId())], callback: function ($document) use (&$documents) { $documents[] = $document; }); $this->assertEquals(5, count($documents)); @@ -2554,7 +2554,7 @@ public function testForeach(): void * Test, cursor before throws error */ try { - static::getDatabase()->foreach('movies', queries: [Query::cursorBefore($documents[0]), Query::offset(2)], callback: function ($document) use (&$documents) { + static::getDatabase()->foreach('movies', queries: [Query::cursorBefore($documents[0]->getId()), Query::offset(2)], callback: function ($document) use (&$documents) { $documents[] = $document; }); @@ -3467,7 +3467,7 @@ public function testDeleteBulkDocuments(): void collection: 'bulk_delete', queries: [ Query::select([...$selects, '$createdAt']), - Query::cursorAfter($docs[6]), + Query::cursorAfter($docs[6]->getId()), Query::greaterThan('$createdAt', '2000-01-01'), Query::orderAsc('$createdAt'), Query::orderAsc(), diff --git a/tests/e2e/Adapter/Scopes/GeneralTests.php b/tests/e2e/Adapter/Scopes/GeneralTests.php index c6ae1d4f3..ef6b7ddcf 100644 --- a/tests/e2e/Adapter/Scopes/GeneralTests.php +++ b/tests/e2e/Adapter/Scopes/GeneralTests.php @@ -274,7 +274,7 @@ public function testFindOrderByAfterException(): void static::getDatabase()->find('movies', [ Query::limit(2), Query::offset(0), - Query::cursorAfter($document) + Query::cursorAfter($document->getId()) ]); } From 96329d3ba7c46c629ad14ba93c65ba307153e7bb Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 19 May 2025 16:14:37 +0300 Subject: [PATCH 02/23] Remove comment --- src/Database/Database.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 65f7eec34..286251a71 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5756,10 +5756,6 @@ public function deleteDocuments( $limit = $grouped['limit']; $cursor = $grouped['cursor']; -// if (!empty($cursor) && $cursor->getCollection() !== $collection->getId()) { -// throw new DatabaseException("Cursor document must be from the same Collection."); -// } - $originalLimit = $limit; //$last = $cursor; $last = new Document(); @@ -5972,7 +5968,6 @@ public function find(string $collection, array $queries = [], string $forPermiss $cursorDirection = $grouped['cursorDirection']; if (!empty($cursorId)) { - var_dump($cursorHardcoded); if($cursorHardcoded->isEmpty()){ $cursor = $this->getDocument($collection->getId(), $cursorId); }else { From 486988dfd9ce589392370885d0202aef3e3779be Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 19 May 2025 18:51:39 +0300 Subject: [PATCH 03/23] use withCursor --- src/Database/Database.php | 51 +++++++++++++++++++++++++-------------- src/Database/Query.php | 26 +++++--------------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 286251a71..c59d51bb6 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -334,6 +334,8 @@ class Database protected ?\DateTime $timestamp = null; + protected ?Document $cursor = null; + protected bool $resolveRelationships = true; protected bool $checkRelationshipsExist = true; @@ -614,6 +616,26 @@ public function withRequestTimestamp(?\DateTime $requestTimestamp, callable $cal return $result; } + /** + * Executes $callback with $timestamp set to $requestTimestamp + * + * @template T + * @param callable(): T $callback + * @return T + */ + public function withCursor(Document $document, callable $callback): mixed + { + $previous = $this->cursor; + $this->cursor = $document; + + try { + $result = $callback(); + } finally { + $this->cursor = $previous; + } + return $result; + } + /** * Set Namespace. * @@ -4358,10 +4380,6 @@ public function updateDocuments( $limit = $grouped['limit']; $cursor = $grouped['cursor']; -// if (!empty($cursor) && $cursor->getCollection() !== $collection->getId()) { -// throw new DatabaseException("cursor Document must be from the same Collection."); -// } - unset($updates['$id']); unset($updates['$createdAt']); unset($updates['$tenant']); @@ -5757,7 +5775,6 @@ public function deleteDocuments( $cursor = $grouped['cursor']; $originalLimit = $limit; - //$last = $cursor; $last = new Document(); $modified = 0; @@ -5773,17 +5790,19 @@ public function deleteDocuments( ]; if (!empty($cursor)) { - $new[] = Query::cursorAfter($cursor, cursor: $last); + $new[] = Query::cursorAfter($cursor); } /** * @var array $batch */ - $batch = $this->silent(fn () => $this->find( - $collection->getId(), - array_merge($new, $queries), - forPermission: Database::PERMISSION_DELETE - )); + + $batch = $this->silent(fn () => + $this->withCursor($last, fn () => $this->find( + $collection->getId(), + array_merge($new, $queries), + forPermission: Database::PERMISSION_DELETE + ))); if (empty($batch)) { break; @@ -5960,18 +5979,14 @@ public function find(string $collection, array $queries = [], string $forPermiss $orderAttributes = $grouped['orderAttributes']; $orderTypes = $grouped['orderTypes']; $cursorId = $grouped['cursor']; - /** - * @var Document $cursorHardcoded - */ - $cursorHardcoded = $grouped['cursorHardcoded']; $cursor = []; $cursorDirection = $grouped['cursorDirection']; if (!empty($cursorId)) { - if($cursorHardcoded->isEmpty()){ + if (!is_null($this->cursor) && !$this->cursor->isEmpty()){ + $cursor = $this->cursor; + } else { $cursor = $this->getDocument($collection->getId(), $cursorId); - }else { - $cursor = $cursorHardcoded; } if ($cursor->isEmpty()){ diff --git a/src/Database/Query.php b/src/Database/Query.php index bca54745d..745227401 100644 --- a/src/Database/Query.php +++ b/src/Database/Query.php @@ -73,7 +73,6 @@ class Query protected string $method = ''; protected string $attribute = ''; protected bool $onArray = false; - protected Document $cursor; /** * @var array @@ -87,7 +86,7 @@ class Query * @param string $attribute * @param array $values */ - public function __construct(string $method, string $attribute = '', array $values = [], Document $cursor = new Document) + public function __construct(string $method, string $attribute = '', array $values = []) { if ($attribute === '' && \in_array($method, [Query::TYPE_ORDER_ASC, Query::TYPE_ORDER_DESC])) { $attribute = '$internalId'; @@ -96,7 +95,6 @@ public function __construct(string $method, string $attribute = '', array $value $this->method = $method; $this->attribute = $attribute; $this->values = $values; - $this->cursor = $cursor; } public function __clone(): void @@ -514,21 +512,21 @@ public static function offset(int $value): self /** * Helper method to create Query with cursorAfter method * - * @param string $value + * @param Document $value * @return Query */ - public static function cursorAfter(string $value, Document $cursor = new Document): self + public static function cursorAfter(Document $value): self { - return new self(self::TYPE_CURSOR_AFTER, values: [$value], cursor: $cursor); + return new self(self::TYPE_CURSOR_AFTER, values: [$value]); } /** * Helper method to create Query with cursorBefore method * - * @param string $value + * @param Document $value * @return Query */ - public static function cursorBefore(string $value): self + public static function cursorBefore(Document $value): self { return new self(self::TYPE_CURSOR_BEFORE, values: [$value]); } @@ -627,7 +625,6 @@ public static function groupByType(array $queries): array $orderAttributes = []; $orderTypes = []; $cursor = null; - $cursorHardcoded = new Document(); $cursorDirection = null; foreach ($queries as $query) { @@ -676,8 +673,6 @@ public static function groupByType(array $queries): array $cursor = $values[0] ?? $limit; $cursorDirection = $method === Query::TYPE_CURSOR_AFTER ? Database::CURSOR_AFTER : Database::CURSOR_BEFORE; - $cursorHardcoded = $query->getCursor(); - break; case Query::TYPE_SELECT: @@ -698,7 +693,6 @@ public static function groupByType(array $queries): array 'orderAttributes' => $orderAttributes, 'orderTypes' => $orderTypes, 'cursor' => $cursor, - 'cursorHardcoded' => $cursorHardcoded, 'cursorDirection' => $cursorDirection, ]; } @@ -733,12 +727,4 @@ public function setOnArray(bool $bool): void { $this->onArray = $bool; } - - /** - * @return Document - */ - public function getCursor(): Document - { - return $this->cursor; - } } From 14eff2a2d7450521a97faaa4a3d5603af4e3d4ef Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 19 May 2025 18:54:14 +0300 Subject: [PATCH 04/23] change Document to string --- src/Database/Query.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Database/Query.php b/src/Database/Query.php index 745227401..bf1c3d607 100644 --- a/src/Database/Query.php +++ b/src/Database/Query.php @@ -512,10 +512,10 @@ public static function offset(int $value): self /** * Helper method to create Query with cursorAfter method * - * @param Document $value + * @param string $value * @return Query */ - public static function cursorAfter(Document $value): self + public static function cursorAfter(string $value): self { return new self(self::TYPE_CURSOR_AFTER, values: [$value]); } @@ -523,10 +523,10 @@ public static function cursorAfter(Document $value): self /** * Helper method to create Query with cursorBefore method * - * @param Document $value + * @param string $value * @return Query */ - public static function cursorBefore(Document $value): self + public static function cursorBefore(string $value): self { return new self(self::TYPE_CURSOR_BEFORE, values: [$value]); } From e949b9918c8870eef3a2bb95c4b3c707cbf4927f Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 19 May 2025 18:57:17 +0300 Subject: [PATCH 05/23] Base test --- tests/e2e/Adapter/Base.php | 2 +- tests/unit/QueryTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/Adapter/Base.php b/tests/e2e/Adapter/Base.php index 06445a09e..a57fe2748 100644 --- a/tests/e2e/Adapter/Base.php +++ b/tests/e2e/Adapter/Base.php @@ -17,7 +17,7 @@ abstract class Base extends TestCase { - //use CollectionTests; + use CollectionTests; use DocumentTests; use AttributeTests; use IndexTests; diff --git a/tests/unit/QueryTest.php b/tests/unit/QueryTest.php index d9ad6cd93..8b0ec2633 100644 --- a/tests/unit/QueryTest.php +++ b/tests/unit/QueryTest.php @@ -68,7 +68,7 @@ public function testCreate(): void $this->assertEquals([10], $query->getValues()); $cursor = new Document(); - $query = Query::cursorAfter($cursor); + $query = Query::cursorAfter($cursor->getId()); $this->assertEquals(Query::TYPE_CURSOR_AFTER, $query->getMethod()); $this->assertEquals('', $query->getAttribute()); From aec4252e61686ec7ca6ce82736ceffe8fc2a1a0c Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 19 May 2025 18:59:18 +0300 Subject: [PATCH 06/23] Base test --- tests/unit/Validator/QueriesTest.php | 2 +- tests/unit/Validator/QueryTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/Validator/QueriesTest.php b/tests/unit/Validator/QueriesTest.php index 86158014a..cb85cd808 100644 --- a/tests/unit/Validator/QueriesTest.php +++ b/tests/unit/Validator/QueriesTest.php @@ -70,7 +70,7 @@ public function testValid(): void ] ); - $this->assertEquals(true, $validator->isValid([Query::cursorAfter(new Document(['$id' => 'asdf']))]), $validator->getDescription()); + $this->assertEquals(true, $validator->isValid([Query::cursorAfter('asdf')]), $validator->getDescription()); $this->assertEquals(true, $validator->isValid([Query::equal('name', ['value'])]), $validator->getDescription()); $this->assertEquals(true, $validator->isValid([Query::limit(10)]), $validator->getDescription()); $this->assertEquals(true, $validator->isValid([Query::offset(10)]), $validator->getDescription()); diff --git a/tests/unit/Validator/QueryTest.php b/tests/unit/Validator/QueryTest.php index 7b4125145..6d843d0b3 100644 --- a/tests/unit/Validator/QueryTest.php +++ b/tests/unit/Validator/QueryTest.php @@ -227,7 +227,7 @@ public function testQueryCursor(): void { $validator = new Documents($this->attributes, []); - $response = $validator->isValid([Query::cursorAfter(new Document(['$id' => 'asdf']))]); + $response = $validator->isValid([Query::cursorAfter('asdf')]); $this->assertEquals(true, $response); } From 225ff894dc2b8bc5f5e0e08354dcbb135b54e4d1 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 19 May 2025 19:07:58 +0300 Subject: [PATCH 07/23] lint --- src/Database/Database.php | 6 +++--- tests/unit/Validator/DocumentsQueriesTest.php | 4 ++-- tests/unit/Validator/IndexedQueriesTest.php | 2 +- tests/unit/Validator/QueryTest.php | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index c59d51bb6..d4fdbf2ff 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5802,7 +5802,7 @@ public function deleteDocuments( $collection->getId(), array_merge($new, $queries), forPermission: Database::PERMISSION_DELETE - ))); + ))); if (empty($batch)) { break; @@ -5983,13 +5983,13 @@ public function find(string $collection, array $queries = [], string $forPermiss $cursorDirection = $grouped['cursorDirection']; if (!empty($cursorId)) { - if (!is_null($this->cursor) && !$this->cursor->isEmpty()){ + if (!is_null($this->cursor) && !$this->cursor->isEmpty()) { $cursor = $this->cursor; } else { $cursor = $this->getDocument($collection->getId(), $cursorId); } - if ($cursor->isEmpty()){ + if ($cursor->isEmpty()) { throw new DatabaseException("Cursor not found"); } diff --git a/tests/unit/Validator/DocumentsQueriesTest.php b/tests/unit/Validator/DocumentsQueriesTest.php index 45ae23933..ac0b5f2f0 100644 --- a/tests/unit/Validator/DocumentsQueriesTest.php +++ b/tests/unit/Validator/DocumentsQueriesTest.php @@ -130,8 +130,8 @@ public function testValidQueries(): void Query::endsWith('title', 'Night'), Query::isNull('title'), Query::isNotNull('title'), - Query::cursorAfter(new Document(['$id' => 'a'])), - Query::cursorBefore(new Document(['$id' => 'b'])), + Query::cursorAfter('a'), + Query::cursorBefore('b'), Query::orderAsc('title'), Query::limit(10), Query::offset(10), diff --git a/tests/unit/Validator/IndexedQueriesTest.php b/tests/unit/Validator/IndexedQueriesTest.php index 69ed9aeb1..4faa265bb 100644 --- a/tests/unit/Validator/IndexedQueriesTest.php +++ b/tests/unit/Validator/IndexedQueriesTest.php @@ -87,7 +87,7 @@ public function testValid(): void ] ); - $query = Query::cursorAfter(new Document(['$id' => 'abc'])); + $query = Query::cursorAfter('abc'); $this->assertEquals(true, $validator->isValid([$query])); $query = Query::parse('{"method":"cursorAfter","attribute":"","values":["abc"]}'); $this->assertEquals(true, $validator->isValid([$query])); diff --git a/tests/unit/Validator/QueryTest.php b/tests/unit/Validator/QueryTest.php index 6d843d0b3..893ef8e27 100644 --- a/tests/unit/Validator/QueryTest.php +++ b/tests/unit/Validator/QueryTest.php @@ -119,8 +119,8 @@ public function testQuery(): void $this->assertEquals(true, $validator->isValid([Query::lessThanEqual('price', 6)])); $this->assertEquals(true, $validator->isValid([Query::contains('tags', ['action1', 'action2'])])); $this->assertEquals(true, $validator->isValid([Query::contains('tags', ['action1'])])); - $this->assertEquals(true, $validator->isValid([Query::cursorAfter(new Document(['$id' => 'docId']))])); - $this->assertEquals(true, $validator->isValid([Query::cursorBefore(new Document(['$id' => 'docId']))])); + $this->assertEquals(true, $validator->isValid([Query::cursorAfter('docId')])); + $this->assertEquals(true, $validator->isValid([Query::cursorBefore('docId')])); $this->assertEquals(true, $validator->isValid([Query::orderAsc('title')])); $this->assertEquals(true, $validator->isValid([Query::orderDesc('title')])); $this->assertEquals(true, $validator->isValid([Query::isNull('title')])); @@ -239,8 +239,8 @@ public function testQueryGetByType(): void $queries = [ Query::equal('key', ['value']), Query::select(['attr1', 'attr2']), - Query::cursorBefore(new Document([])), - Query::cursorAfter(new Document([])), + Query::cursorBefore('dsds'), + Query::cursorAfter('dsdsds'), ]; $queries = Query::getByType($queries, [Query::TYPE_CURSOR_AFTER, Query::TYPE_CURSOR_BEFORE]); From 2b680e26ced47b772dfea3244d280830389f5fc2 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 19 May 2025 19:15:01 +0300 Subject: [PATCH 08/23] cursor validation --- src/Database/Validator/Query/Cursor.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Database/Validator/Query/Cursor.php b/src/Database/Validator/Query/Cursor.php index 46020d7b4..925f3b21e 100644 --- a/src/Database/Validator/Query/Cursor.php +++ b/src/Database/Validator/Query/Cursor.php @@ -29,9 +29,9 @@ public function isValid($value): bool if ($method === Query::TYPE_CURSOR_AFTER || $method === Query::TYPE_CURSOR_BEFORE) { $cursor = $value->getValue(); - if ($cursor instanceof Document) { - $cursor = $cursor->getId(); - } +// if ($cursor instanceof Document) { +// $cursor = $cursor->getId(); +// } $validator = new UID(); if ($validator->isValid($cursor)) { From 6d483e737ac3bdc10cadc409d7f94a42869afd78 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 08:29:45 +0300 Subject: [PATCH 09/23] Use null --- src/Database/Database.php | 7 +++---- tests/e2e/Adapter/Base.php | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index d4fdbf2ff..11eb53730 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -623,7 +623,7 @@ public function withRequestTimestamp(?\DateTime $requestTimestamp, callable $cal * @param callable(): T $callback * @return T */ - public function withCursor(Document $document, callable $callback): mixed + public function withCursor(?Document $document, callable $callback): mixed { $previous = $this->cursor; $this->cursor = $document; @@ -5773,9 +5773,8 @@ public function deleteDocuments( $grouped = Query::groupByType($queries); $limit = $grouped['limit']; $cursor = $grouped['cursor']; - $originalLimit = $limit; - $last = new Document(); + $last = null; $modified = 0; while (true) { @@ -5862,7 +5861,7 @@ public function deleteDocuments( break; } - $last = \end($batch); + $last = $batch[array_key_last($batch)]; $cursor = $last->getId(); } diff --git a/tests/e2e/Adapter/Base.php b/tests/e2e/Adapter/Base.php index a57fe2748..06445a09e 100644 --- a/tests/e2e/Adapter/Base.php +++ b/tests/e2e/Adapter/Base.php @@ -17,7 +17,7 @@ abstract class Base extends TestCase { - use CollectionTests; + //use CollectionTests; use DocumentTests; use AttributeTests; use IndexTests; From 05c0ce29d42a98ba5ee90d59c454dd0d94f7388a Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 09:04:25 +0300 Subject: [PATCH 10/23] Use getDocument --- src/Database/Database.php | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 11eb53730..9cd13bc81 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5797,11 +5797,13 @@ public function deleteDocuments( */ $batch = $this->silent(fn () => - $this->withCursor($last, fn () => $this->find( - $collection->getId(), - array_merge($new, $queries), - forPermission: Database::PERMISSION_DELETE - ))); + + $this->withCursor($last, fn () => + $this->find( + $collection->getId(), + array_merge($new, $queries), + forPermission: Database::PERMISSION_DELETE + ))); if (empty($batch)) { break; @@ -5834,6 +5836,15 @@ public function deleteDocuments( } } + $last = $batch[array_key_last($batch)]; + $cursor = $last->getId(); + /** + * Independent Cursor data. + * todo: add specific selects... (order by , $id, $internalId)) + * Do we need silent here? + */ + $last = $this->silent(fn () => $this->getDocument($collection->getId(), $cursor)); + $this->withTransaction(function () use ($collection, $internalIds, $permissionIds) { $this->adapter->deleteDocuments( $collection->getId(), @@ -5860,10 +5871,6 @@ public function deleteDocuments( } elseif ($originalLimit && $modified >= $originalLimit) { break; } - - $last = $batch[array_key_last($batch)]; - - $cursor = $last->getId(); } $this->trigger(self::EVENT_DOCUMENTS_DELETE, new Document([ From cd5d5407402adf1439ff318bbad63aaefb73760c Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 09:05:13 +0300 Subject: [PATCH 11/23] comment --- src/Database/Database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 9cd13bc81..83a3ed0da 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5839,7 +5839,7 @@ public function deleteDocuments( $last = $batch[array_key_last($batch)]; $cursor = $last->getId(); /** - * Independent Cursor data. + * Independent Cursor data regardless to find selects queries * todo: add specific selects... (order by , $id, $internalId)) * Do we need silent here? */ From 31dda1ca461aee5d8d49f05a3968fd25deee459b Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 09:05:53 +0300 Subject: [PATCH 12/23] comment --- src/Database/Database.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Database/Database.php b/src/Database/Database.php index 83a3ed0da..3adf6d0d2 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5839,6 +5839,7 @@ public function deleteDocuments( $last = $batch[array_key_last($batch)]; $cursor = $last->getId(); /** + * Since we delete data, no cursor will be found later on * Independent Cursor data regardless to find selects queries * todo: add specific selects... (order by , $id, $internalId)) * Do we need silent here? From a395a6e3c8c8567b6415c659b5edd13b533cb1c4 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 09:06:43 +0300 Subject: [PATCH 13/23] comment --- src/Database/Database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 3adf6d0d2..1347afd22 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -597,7 +597,7 @@ protected function trigger(string $event, mixed $args = null): void } /** - * Executes $callback with $timestamp set to $requestTimestamp + * Executes $callback with $cursor Document * * @template T * @param ?\DateTime $requestTimestamp From 4a68dee9bf0bd32e253b79a01db23011cf245d5d Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 09:07:37 +0300 Subject: [PATCH 14/23] comment --- src/Database/Database.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 1347afd22..fa8691acb 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -597,7 +597,7 @@ protected function trigger(string $event, mixed $args = null): void } /** - * Executes $callback with $cursor Document + * Executes $callback with $cursor Document set to $requestTimestamp * * @template T * @param ?\DateTime $requestTimestamp @@ -617,16 +617,16 @@ public function withRequestTimestamp(?\DateTime $requestTimestamp, callable $cal } /** - * Executes $callback with $timestamp set to $requestTimestamp + * Executes $callback with $cursor Document * * @template T * @param callable(): T $callback * @return T */ - public function withCursor(?Document $document, callable $callback): mixed + public function withCursor(?Document $cursor, callable $callback): mixed { $previous = $this->cursor; - $this->cursor = $document; + $this->cursor = $cursor; try { $result = $callback(); From a3f9dfd73cb87241d4852d3f55e826eb07399cb3 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 09:08:43 +0300 Subject: [PATCH 15/23] lint --- src/Database/Validator/Query/Cursor.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Database/Validator/Query/Cursor.php b/src/Database/Validator/Query/Cursor.php index 925f3b21e..197c192b7 100644 --- a/src/Database/Validator/Query/Cursor.php +++ b/src/Database/Validator/Query/Cursor.php @@ -29,9 +29,9 @@ public function isValid($value): bool if ($method === Query::TYPE_CURSOR_AFTER || $method === Query::TYPE_CURSOR_BEFORE) { $cursor = $value->getValue(); -// if ($cursor instanceof Document) { -// $cursor = $cursor->getId(); -// } + // if ($cursor instanceof Document) { + // $cursor = $cursor->getId(); + // } $validator = new UID(); if ($validator->isValid($cursor)) { From 9f20fd57d943da9ee9081a849c0323c7efe2b812 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 09:11:56 +0300 Subject: [PATCH 16/23] lint --- src/Database/Database.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index fa8691acb..63c9fae45 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5796,14 +5796,12 @@ public function deleteDocuments( * @var array $batch */ - $batch = $this->silent(fn () => - - $this->withCursor($last, fn () => - $this->find( - $collection->getId(), - array_merge($new, $queries), - forPermission: Database::PERMISSION_DELETE - ))); + $batch = $this->silent(fn () => $this->withCursor($last, + fn () => $this->find( + $collection->getId(), array_merge($new, $queries), + forPermission: Database::PERMISSION_DELETE + ) + )); if (empty($batch)) { break; From 5fa32aad6c36323d3ec02f41892f6fa4e4b0e8ad Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 09:14:53 +0300 Subject: [PATCH 17/23] comment --- src/Database/Database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 63c9fae45..48e963b2e 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5837,7 +5837,7 @@ public function deleteDocuments( $last = $batch[array_key_last($batch)]; $cursor = $last->getId(); /** - * Since we delete data, no cursor will be found later on + * Since we delete data, no cursor will be found later on so we need to assign a payload * Independent Cursor data regardless to find selects queries * todo: add specific selects... (order by , $id, $internalId)) * Do we need silent here? From 44e170483c65c32a3123324425259d0f5fe8a214 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 09:17:36 +0300 Subject: [PATCH 18/23] All tests --- src/Database/Database.php | 6 ++++-- tests/e2e/Adapter/Base.php | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 48e963b2e..9b9a26539 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5796,9 +5796,11 @@ public function deleteDocuments( * @var array $batch */ - $batch = $this->silent(fn () => $this->withCursor($last, + $batch = $this->silent(fn () => $this->withCursor( + $last, fn () => $this->find( - $collection->getId(), array_merge($new, $queries), + $collection->getId(), + array_merge($new, $queries), forPermission: Database::PERMISSION_DELETE ) )); diff --git a/tests/e2e/Adapter/Base.php b/tests/e2e/Adapter/Base.php index 06445a09e..a57fe2748 100644 --- a/tests/e2e/Adapter/Base.php +++ b/tests/e2e/Adapter/Base.php @@ -17,7 +17,7 @@ abstract class Base extends TestCase { - //use CollectionTests; + use CollectionTests; use DocumentTests; use AttributeTests; use IndexTests; From a5cb243188c435849101de00bd8d3b95eddb597f Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 09:29:09 +0300 Subject: [PATCH 19/23] Fix unit test --- tests/unit/QueryTest.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/unit/QueryTest.php b/tests/unit/QueryTest.php index 8b0ec2633..6db33a599 100644 --- a/tests/unit/QueryTest.php +++ b/tests/unit/QueryTest.php @@ -67,12 +67,11 @@ public function testCreate(): void $this->assertEquals('', $query->getAttribute()); $this->assertEquals([10], $query->getValues()); - $cursor = new Document(); - $query = Query::cursorAfter($cursor->getId()); + $query = Query::cursorAfter('abc'); $this->assertEquals(Query::TYPE_CURSOR_AFTER, $query->getMethod()); $this->assertEquals('', $query->getAttribute()); - $this->assertEquals([$cursor], $query->getValues()); + $this->assertEquals('abc', $query->getValue()); $query = Query::isNull('title'); From 3cab0dec8491eb3dedafb3d8b0fb4603fe353512 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 10:06:17 +0300 Subject: [PATCH 20/23] Comment --- src/Database/Database.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Database/Database.php b/src/Database/Database.php index 9b9a26539..05a8ef877 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5993,6 +5993,9 @@ public function find(string $collection, array $queries = [], string $forPermiss if (!is_null($this->cursor) && !$this->cursor->isEmpty()) { $cursor = $this->cursor; } else { + /** + * todo: add specific select queries, Only what you need for the cursor + */ $cursor = $this->getDocument($collection->getId(), $cursorId); } From 9d3c62348819f4c09c08e3ac9fa113e19f6b8cdb Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 10:10:34 +0300 Subject: [PATCH 21/23] Fix comment --- src/Database/Database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 05a8ef877..1fda8b4fe 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -597,7 +597,7 @@ protected function trigger(string $event, mixed $args = null): void } /** - * Executes $callback with $cursor Document set to $requestTimestamp + * Executes $callback with $timestamp set to $requestTimestamp * * @template T * @param ?\DateTime $requestTimestamp From 9ccd6170b0b43c01baaef03881e2a49fed7dcc63 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 10:19:57 +0300 Subject: [PATCH 22/23] Some exceptions --- src/Database/Database.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Database/Database.php b/src/Database/Database.php index 1fda8b4fe..2633f2e19 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5812,7 +5812,16 @@ public function deleteDocuments( $internalIds = []; $permissionIds = []; foreach ($batch as $document) { + if (empty($document->getInternalId())){ + throw new QueryException('$internalId must not be empty'); + } + $internalIds[] = $document->getInternalId(); + + if (!array_key_exists('$permissions', $document)) { + throw new QueryException('$permissions key is missing'); + } + if (!empty($document->getPermissions())) { $permissionIds[] = $document->getId(); } @@ -5825,6 +5834,10 @@ public function deleteDocuments( } // Check if document was updated after the request timestamp + if (empty($document->getUpdatedAt())){ + throw new QueryException('$updatedAt must not be empty'); + } + try { $oldUpdatedAt = new \DateTime($document->getUpdatedAt()); } catch (Exception $e) { From 3d627f1a2b21e8ba8f1006a710c93e2b4834f17c Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 20 May 2025 10:24:15 +0300 Subject: [PATCH 23/23] Use isset --- src/Database/Database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Database.php b/src/Database/Database.php index 2633f2e19..224a08f45 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -5818,7 +5818,7 @@ public function deleteDocuments( $internalIds[] = $document->getInternalId(); - if (!array_key_exists('$permissions', $document)) { + if (!isset($document['$permissions'])) { throw new QueryException('$permissions key is missing'); }