From 195ded510dc2d51b40644924157c534505010354 Mon Sep 17 00:00:00 2001 From: abdulhp Date: Fri, 22 Sep 2023 11:17:49 +0700 Subject: [PATCH] Moving method closer to `chunk` --- src/Illuminate/Database/Query/Builder.php | 186 +++++++++++----------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 143b3277..2f6ad663 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -1522,6 +1522,99 @@ public function chunk($count, callable $callback) } } + /** + * Chunk the results of a query by comparing IDs. + * + * @param int $count + * @param callable $callback + * @param string|null $column + * @param string|null $alias + * @return bool + */ + public function chunkById(int $count, callable $callback, string|null $column = null, string|null $alias = null): bool + { + $column ??= $this->defaultKeyName(); + + $alias ??= $column; + + $lastId = null; + + $page = 1; + + do { + $clone = clone $this; + + // We'll execute the query for the given page and get the results. If there are + // no results we can just break and return from here. When there are results + // we will call the callback with the current chunk of these results here. + $results = $clone->forPageAfterId($count, $lastId, $column)->get(); + + $countResults = count($results); + + if ($countResults === 0) { + break; + } + + // On each chunk result set, we will pass them to the callback and then let the + // developer take care of everything within the callback, which allows us to + // keep the memory low for spinning through large result sets for working. + if ($callback($results, $page) === false) { + return false; + } + + $lastId = data_get(end($results), $alias); + + if ($lastId === null) { + throw new RuntimeException("The chunkById operation was aborted because the [{$alias}] column is not present in the query result."); + } + + unset($results); + + $page++; + } while ($countResults === $count); + + return true; + } + + /** + * Constrain the query to the next "page" of results after a given ID. + * + * @param int $perPage + * @param int|null $lastId + * @param string $column + * @return $this + */ + public function forPageAfterId(int $perPage = 15, int|null $lastId = 0, string $column = 'id'): Builder + { + $this->orders = $this->removeExistingOrdersFor($column); + + if (! is_null($lastId)) { + $this->where($column, '>', $lastId); + } + + return $this->orderBy($column, 'asc') + ->limit($perPage); + } + + /** + * Get an array with all orders with a given column removed. + * + * @param string $column + * @return array + */ + protected function removeExistingOrdersFor(string $column): array + { + return Collection::make($this->orders) + ->reject(function ($order) use ($column) { + return isset($order['column']) && $order['column'] === $column; + })->values()->all(); + } + + private function defaultKeyName(): string + { + return 'id'; + } + /** * Get an array with the values of a given column. * @@ -2185,97 +2278,4 @@ public function __call($method, $parameters) throw new \BadMethodCallException("Call to undefined method {$className}::{$method}()"); } - /** - * Chunk the results of a query by comparing IDs. - * - * @param int $count - * @param callable $callback - * @param string|null $column - * @param string|null $alias - * @return bool - */ - public function chunkById(int $count, callable $callback, string|null $column = null, string|null $alias = null): bool - { - $column ??= $this->defaultKeyName(); - - $alias ??= $column; - - $lastId = null; - - $page = 1; - - do { - $clone = clone $this; - - // We'll execute the query for the given page and get the results. If there are - // no results we can just break and return from here. When there are results - // we will call the callback with the current chunk of these results here. - $results = $clone->forPageAfterId($count, $lastId, $column)->get(); - - $countResults = count($results); - - if ($countResults === 0) { - break; - } - - // On each chunk result set, we will pass them to the callback and then let the - // developer take care of everything within the callback, which allows us to - // keep the memory low for spinning through large result sets for working. - if ($callback($results, $page) === false) { - return false; - } - - $lastId = data_get(end($results), $alias); - - if ($lastId === null) { - throw new RuntimeException("The chunkById operation was aborted because the [{$alias}] column is not present in the query result."); - } - - unset($results); - - $page++; - } while ($countResults === $count); - - return true; - } - - /** - * Constrain the query to the next "page" of results after a given ID. - * - * @param int $perPage - * @param int|null $lastId - * @param string $column - * @return $this - */ - public function forPageAfterId(int $perPage = 15, int|null $lastId = 0, string $column = 'id'): Builder - { - $this->orders = $this->removeExistingOrdersFor($column); - - if (! is_null($lastId)) { - $this->where($column, '>', $lastId); - } - - return $this->orderBy($column, 'asc') - ->limit($perPage); - } - - /** - * Get an array with all orders with a given column removed. - * - * @param string $column - * @return array - */ - protected function removeExistingOrdersFor(string $column): array - { - return Collection::make($this->orders) - ->reject(function ($order) use ($column) { - return isset($order['column']) && $order['column'] === $column; - })->values()->all(); - } - - private function defaultKeyName(): string - { - return 'id'; - } - }