diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index 7ff0770c4..055324dc7 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -774,12 +774,11 @@ abstract public function deleteDocuments(string $collection, array $sequences, a * @param array $orderAttributes * @param array $orderTypes * @param array $cursor - * @param string $cursorDirection * @param string $forPermission * * @return array */ - abstract public function find(string $collection, array $queries = [], ?int $limit = 25, ?int $offset = null, array $orderAttributes = [], array $orderTypes = [], array $cursor = [], string $cursorDirection = Database::CURSOR_AFTER, string $forPermission = Database::PERMISSION_READ): array; + abstract public function find(string $collection, array $queries = [], ?int $limit = 25, ?int $offset = null, array $orderAttributes = [], array $orderTypes = [], array $cursor = [], string $forPermission = Database::PERMISSION_READ): array; /** * Sum an attribute diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index a76349209..d48161b45 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -1483,14 +1483,13 @@ public function deleteDocument(string $collection, string $id): bool * @param array $orderAttributes * @param array $orderTypes * @param array $cursor - * @param string $cursorDirection * @param string $forPermission * @return array * @throws DatabaseException * @throws TimeoutException * @throws Exception */ - public function find(string $collection, array $queries = [], ?int $limit = 25, ?int $offset = null, array $orderAttributes = [], array $orderTypes = [], array $cursor = [], string $cursorDirection = Database::CURSOR_AFTER, string $forPermission = Database::PERMISSION_READ): array + public function find(string $collection, array $queries = [], ?int $limit = 25, ?int $offset = null, array $orderAttributes = [], array $orderTypes = [], array $cursor = [], string $forPermission = Database::PERMISSION_READ): array { $name = $this->filter($collection); $roles = Authorization::getRoles(); @@ -1508,24 +1507,14 @@ public function find(string $collection, array $queries = [], ?int $limit = 25, $attribute = $this->filter($attribute); $orderType = $this->filter($orderTypes[$i] ?? Database::ORDER_ASC); - $direction = $orderType; - if ($cursorDirection === Database::CURSOR_BEFORE) { - $direction = ($direction === Database::ORDER_ASC) - ? Database::ORDER_DESC - : Database::ORDER_ASC; - } + $orders[] = "{$this->quote($attribute)} {$orderType}"; - $orders[] = "{$this->quote($attribute)} {$direction}"; + $operator = ($orderType === Database::ORDER_DESC) ? Query::TYPE_LESSER : Query::TYPE_GREATER; - // Build pagination WHERE clause only if we have a cursor if (!empty($cursor)) { // Special case: No tie breaks. only 1 attribute and it's a unique primary key if (count($orderAttributes) === 1 && $i === 0 && $originalAttribute === '$sequence') { - $operator = ($direction === Database::ORDER_DESC) - ? Query::TYPE_LESSER - : Query::TYPE_GREATER; - $bindName = ":cursor_pk"; $binds[$bindName] = $cursor[$originalAttribute]; @@ -1546,11 +1535,6 @@ public function find(string $collection, array $queries = [], ?int $limit = 25, $conditions[] = "{$this->quote($alias)}.{$this->quote($prevAttr)} = {$bindName}"; } - // Add comparison for current attribute - $operator = ($direction === Database::ORDER_DESC) - ? Query::TYPE_LESSER - : Query::TYPE_GREATER; - $bindName = ":cursor_{$i}"; $binds[$bindName] = $cursor[$originalAttribute]; @@ -1648,10 +1632,6 @@ public function find(string $collection, array $queries = [], ?int $limit = 25, $results[$index] = new Document($results[$index]); } - if ($cursorDirection === Database::CURSOR_BEFORE) { - $results = \array_reverse($results); - } - return $results; } diff --git a/src/Database/Adapter/Pool.php b/src/Database/Adapter/Pool.php index d255a1d1e..a60710b3b 100644 --- a/src/Database/Adapter/Pool.php +++ b/src/Database/Adapter/Pool.php @@ -260,7 +260,7 @@ public function deleteDocuments(string $collection, array $sequences, array $per return $this->delegate(__FUNCTION__, \func_get_args()); } - public function find(string $collection, array $queries = [], ?int $limit = 25, ?int $offset = null, array $orderAttributes = [], array $orderTypes = [], array $cursor = [], string $cursorDirection = Database::CURSOR_AFTER, string $forPermission = Database::PERMISSION_READ): array + public function find(string $collection, array $queries = [], ?int $limit = 25, ?int $offset = null, array $orderAttributes = [], array $orderTypes = [], array $cursor = [], string $forPermission = Database::PERMISSION_READ): array { return $this->delegate(__FUNCTION__, \func_get_args()); } diff --git a/src/Database/Adapter/Postgres.php b/src/Database/Adapter/Postgres.php index e207148ce..01a591a2d 100644 --- a/src/Database/Adapter/Postgres.php +++ b/src/Database/Adapter/Postgres.php @@ -1382,14 +1382,13 @@ public function deleteDocument(string $collection, string $id): bool * @param array $orderAttributes * @param array $orderTypes * @param array $cursor - * @param string $cursorDirection * @param string $forPermission * @return array * @throws DatabaseException * @throws TimeoutException * @throws Exception */ - public function find(string $collection, array $queries = [], ?int $limit = 25, ?int $offset = null, array $orderAttributes = [], array $orderTypes = [], array $cursor = [], string $cursorDirection = Database::CURSOR_AFTER, string $forPermission = Database::PERMISSION_READ): array + public function find(string $collection, array $queries = [], ?int $limit = 25, ?int $offset = null, array $orderAttributes = [], array $orderTypes = [], array $cursor = [], string $forPermission = Database::PERMISSION_READ): array { $name = $this->filter($collection); $roles = Authorization::getRoles(); @@ -1407,27 +1406,16 @@ public function find(string $collection, array $queries = [], ?int $limit = 25, $attribute = $this->filter($attribute); $orderType = $this->filter($orderTypes[$i] ?? Database::ORDER_ASC); - $direction = $orderType; - if ($cursorDirection === Database::CURSOR_BEFORE) { - $direction = ($direction === Database::ORDER_ASC) - ? Database::ORDER_DESC - : Database::ORDER_ASC; - } + $orders[] = "{$this->quote($attribute)} {$orderType}"; - $orders[] = "{$this->quote($attribute)} {$direction}"; + $operator = ($orderType === Database::ORDER_DESC) ? Query::TYPE_LESSER : Query::TYPE_GREATER; - // Build pagination WHERE clause only if we have a cursor if (!empty($cursor)) { - // Special case: only 1 attribute and it's a unique primary key + // Special case: No tie breaks. only 1 attribute and it's a unique primary key if (count($orderAttributes) === 1 && $i === 0 && $originalAttribute === '$sequence') { - $operator = ($direction === Database::ORDER_DESC) - ? Query::TYPE_LESSER - : Query::TYPE_GREATER; - $bindName = ":cursor_pk"; $binds[$bindName] = $cursor[$originalAttribute]; - $cursorWhere[] = "{$this->quote($alias)}.{$this->quote($attribute)} {$this->getSQLOperator($operator)} {$bindName}"; break; } @@ -1445,11 +1433,6 @@ public function find(string $collection, array $queries = [], ?int $limit = 25, $conditions[] = "{$this->quote($alias)}.{$this->quote($prevAttr)} = {$bindName}"; } - // Add comparison for current attribute - $operator = ($direction === Database::ORDER_DESC) - ? Query::TYPE_LESSER - : Query::TYPE_GREATER; - $bindName = ":cursor_{$i}"; $binds[$bindName] = $cursor[$originalAttribute]; @@ -1550,10 +1533,6 @@ public function find(string $collection, array $queries = [], ?int $limit = 25, $results[$index] = new Document($results[$index]); } - if ($cursorDirection === Database::CURSOR_BEFORE) { - $results = \array_reverse($results); - } - return $results; } diff --git a/src/Database/Database.php b/src/Database/Database.php index 51e2ab6a1..f272f0cc5 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -6034,25 +6034,22 @@ public function find(string $collection, array $queries = [], string $forPermiss $cursor = $grouped['cursor']; $cursorDirection = $grouped['cursorDirection'] ?? Database::CURSOR_AFTER; - $uniqueOrderBy = false; - foreach ($orderAttributes as $order) { - if ($order === '$id' || $order === '$sequence') { - $uniqueOrderBy = true; - } - } - - if ($uniqueOrderBy === false) { + if (!in_array('$id', $orderAttributes) && !in_array('$sequence', $orderAttributes)) { $orderAttributes[] = '$sequence'; } - if (!empty($cursor)) { - foreach ($orderAttributes as $order) { - if ($cursor->getAttribute($order) === null) { - throw new OrderException( - message: "Order attribute '{$order}' is empty", - attribute: $order - ); - } + foreach ($orderAttributes as $i => $order) { + if (!empty($cursor) && $cursor->getAttribute($order) === null) { + throw new OrderException( + message: "Order attribute '{$order}' is empty", + attribute: $order + ); + } + + $orderTypes[$i] = $orderTypes[$i] ?? Database::ORDER_ASC; + + if ($cursorDirection === Database::CURSOR_BEFORE) { + $orderTypes[$i] = ($orderTypes[$i] === Database::ORDER_ASC) ? Database::ORDER_DESC : Database::ORDER_ASC; } } @@ -6122,12 +6119,15 @@ public function find(string $collection, array $queries = [], string $forPermiss $orderAttributes, $orderTypes, $cursor, - $cursorDirection, $forPermission ); $results = $skipAuth ? Authorization::skip($getResults) : $getResults(); + if ($cursorDirection === Database::CURSOR_BEFORE) { + $results = \array_reverse($results); + } + foreach ($results as &$node) { if ($this->resolveRelationships && (empty($selects) || !empty($nestedSelections))) { $node = $this->silent(fn () => $this->populateDocumentRelationships($collection, $node, $nestedSelections));