From 7cd2953b62ea17df8f45bc8b52292a7f1d617e6a Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 13:51:41 +0100 Subject: [PATCH 01/25] fetchargs --- src/Illuminate/Database/Connection.php | 19 +-- .../Database/ConnectionInterface.php | 6 +- src/Illuminate/Database/Query/Builder.php | 112 +++--------------- .../Integration/Database/QueryBuilderTest.php | 6 + 4 files changed, 36 insertions(+), 107 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 17056a9e4de0..12c9b12d85e2 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -391,11 +391,12 @@ public function selectFromWriteConnection($query, $bindings = []) * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchArgs * @return array */ - public function select($query, $bindings = [], $useReadPdo = true) + public function select($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []) { - return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { + return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchArgs) { if ($this->pretending()) { return []; } @@ -411,7 +412,7 @@ public function select($query, $bindings = [], $useReadPdo = true) $statement->execute(); - return $statement->fetchAll(); + return $statement->fetchAll(...$fetchArgs); }); } @@ -421,11 +422,12 @@ public function select($query, $bindings = [], $useReadPdo = true) * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchArgs * @return array */ - public function selectResultSets($query, $bindings = [], $useReadPdo = true) + public function selectResultSets($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []) { - return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { + return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchArgs) { if ($this->pretending()) { return []; } @@ -441,7 +443,7 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true) $sets = []; do { - $sets[] = $statement->fetchAll(); + $sets[] = $statement->fetchAll($fetchArgs); } while ($statement->nextRowset()); return $sets; @@ -454,9 +456,10 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true) * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchArgs * @return \Generator */ - public function cursor($query, $bindings = [], $useReadPdo = true) + public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []) { $statement = $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { @@ -481,7 +484,7 @@ public function cursor($query, $bindings = [], $useReadPdo = true) return $statement; }); - while ($record = $statement->fetch()) { + while ($record = $statement->fetch(...$fetchArgs)) { yield $record; } } diff --git a/src/Illuminate/Database/ConnectionInterface.php b/src/Illuminate/Database/ConnectionInterface.php index 288adb4206e3..09884a1417bd 100755 --- a/src/Illuminate/Database/ConnectionInterface.php +++ b/src/Illuminate/Database/ConnectionInterface.php @@ -51,9 +51,10 @@ public function scalar($query, $bindings = [], $useReadPdo = true); * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchArgs * @return array */ - public function select($query, $bindings = [], $useReadPdo = true); + public function select($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []); /** * Run a select statement against the database and returns a generator. @@ -61,9 +62,10 @@ public function select($query, $bindings = [], $useReadPdo = true); * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchArgs * @return \Generator */ - public function cursor($query, $bindings = [], $useReadPdo = true); + public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []); /** * Run an insert statement against the database. diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 0296658a9ead..b5d7a1999823 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -26,6 +26,7 @@ use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; use LogicException; +use PDO; use RuntimeException; use UnitEnum; @@ -3124,13 +3125,13 @@ public function get($columns = ['*']) /** * Run the query as a "select" statement against the connection. - * + * @param array $fetchArgs * @return array */ - protected function runSelect() + protected function runSelect(array $fetchArgs = []) { return $this->connection->select( - $this->toSql(), $this->getBindings(), ! $this->useWritePdo + $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $fetchArgs ); } @@ -3374,110 +3375,27 @@ protected function enforceOrderBy() * Get a collection instance containing the values of a given column. * * @param \Illuminate\Contracts\Database\Query\Expression|string $column - * @param string|null $key + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $key * @return \Illuminate\Support\Collection */ public function pluck($column, $key = null) { - // First, we will need to select the results of the query accounting for the - // given columns / key. Once we have the results, we will be able to take - // the results and get the exact data that was requested for the query. - $queryResult = $this->onceWithColumns( - is_null($key) ? [$column] : [$column, $key], - function () { - return $this->processor->processSelect( - $this, $this->runSelect() - ); - } - ); - - if (empty($queryResult)) { - return collect(); - } - - // If the columns are qualified with a table or have an alias, we cannot use - // those directly in the "pluck" operations since the results from the DB - // are only keyed by the column itself. We'll strip the table out here. - $column = $this->stripTableForPluck($column); - - $key = $this->stripTableForPluck($key); - - return $this->applyAfterQueryCallbacks( - is_array($queryResult[0]) - ? $this->pluckFromArrayColumn($queryResult, $column, $key) - : $this->pluckFromObjectColumn($queryResult, $column, $key) - ); - } - - /** - * Strip off the table name or alias from a column identifier. - * - * @param string $column - * @return string|null - */ - protected function stripTableForPluck($column) - { - if (is_null($column)) { - return $column; - } - - $columnString = $column instanceof ExpressionContract - ? $this->grammar->getValue($column) - : $column; - - $separator = str_contains(strtolower($columnString), ' as ') ? ' as ' : '\.'; - - return last(preg_split('~'.$separator.'~i', $columnString)); - } - - /** - * Retrieve column values from rows represented as objects. - * - * @param array $queryResult - * @param string $column - * @param string $key - * @return \Illuminate\Support\Collection - */ - protected function pluckFromObjectColumn($queryResult, $column, $key) - { - $results = []; - - if (is_null($key)) { - foreach ($queryResult as $row) { - $results[] = $row->$column; - } + if(is_null($key)) { + $columns = [$column]; + $fetchArgs = [PDO::FETCH_COLUMN]; } else { - foreach ($queryResult as $row) { - $results[$row->$key] = $row->$column; - } + $columns = [$key, $column]; + $fetchArgs = [PDO::FETCH_COLUMN | PDO::FETCH_UNIQUE]; } - return collect($results); - } + [$original, $this->columns] = [$this->columns, $columns]; - /** - * Retrieve column values from rows represented as arrays. - * - * @param array $queryResult - * @param string $column - * @param string $key - * @return \Illuminate\Support\Collection - */ - protected function pluckFromArrayColumn($queryResult, $column, $key) - { - $results = []; + $queryResult = $this->processor->processSelect($this, $this->runSelect($fetchArgs)); - if (is_null($key)) { - foreach ($queryResult as $row) { - $results[] = $row[$column]; - } - } else { - foreach ($queryResult as $row) { - $results[$row[$key]] = $row[$column]; - } - } + // Revert to original columns so future queries can use the previous selection. + $this->columns = $original; - return collect($results); + return collect($queryResult); } /** diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index c323ff0e1513..85888ec34c72 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -600,6 +600,12 @@ public function testChunkMap() public function testPluck() { + // Test empty result set. + $this->assertSame( + [], + DB::table('posts')->whereRaw('0=1')->pluck('title')->toArray() + ); + // Test SELECT override, since pluck will take the first column. $this->assertSame([ 'Foo Post', From fb21722cbc55486af0efd35f4b3e14ba4ccbf167 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 15:05:36 +0100 Subject: [PATCH 02/25] add fetchArgs() function --- src/Illuminate/Database/Query/Builder.php | 76 +++++++++++------------ 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index b5d7a1999823..f814765b1aa7 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -249,6 +249,13 @@ class Builder implements BuilderContract */ public $useWritePdo = false; + /** + * Custom arguments for the PDOStatement::fetchAll/fetch functions. + * + * @var array + */ + public array $fetchArgs = []; + /** * Create a new query builder instance. * @@ -3114,9 +3121,14 @@ public function soleValue($column) */ public function get($columns = ['*']) { - $items = collect($this->onceWithColumns(Arr::wrap($columns), function () { - return $this->processor->processSelect($this, $this->runSelect()); - })); + $original = $this->columns; + + $this->columns ??= Arr::wrap($columns); + + $items = collect($this->processor->processSelect($this, $this->runSelect())); + + // Revert to original columns so future queries can use the previous selection. + $this->columns = $original; return $this->applyAfterQueryCallbacks( isset($this->groupLimit) ? $this->withoutGroupLimitKeys($items) : $items @@ -3125,13 +3137,12 @@ public function get($columns = ['*']) /** * Run the query as a "select" statement against the connection. - * @param array $fetchArgs * @return array */ - protected function runSelect(array $fetchArgs = []) + protected function runSelect() { return $this->connection->select( - $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $fetchArgs + $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchArgs ); } @@ -3380,20 +3391,20 @@ protected function enforceOrderBy() */ public function pluck($column, $key = null) { + $original = [$this->columns, $this->fetchArgs]; + if(is_null($key)) { - $columns = [$column]; - $fetchArgs = [PDO::FETCH_COLUMN]; + $this->columns = [$column]; + $this->fetchArgs = [PDO::FETCH_COLUMN]; } else { - $columns = [$key, $column]; - $fetchArgs = [PDO::FETCH_COLUMN | PDO::FETCH_UNIQUE]; + $this->columns = [$key, $column]; + $this->fetchArgs = [PDO::FETCH_KEY_PAIR]; } - [$original, $this->columns] = [$this->columns, $columns]; - - $queryResult = $this->processor->processSelect($this, $this->runSelect($fetchArgs)); + $queryResult = $this->processor->processSelect($this, $this->runSelect()); - // Revert to original columns so future queries can use the previous selection. - $this->columns = $original; + // Revert to original values so future queries can use the previous selection. + [$this->columns, $this->fetchArgs] = $original; return collect($queryResult); } @@ -3603,30 +3614,6 @@ protected function setAggregate($function, $columns) return $this; } - /** - * Execute the given callback while selecting the given columns. - * - * After running the callback, the columns are reset to the original value. - * - * @param array $columns - * @param callable $callback - * @return mixed - */ - protected function onceWithColumns($columns, $callback) - { - $original = $this->columns; - - if (is_null($original)) { - $this->columns = $columns; - } - - $result = $callback(); - - $this->columns = $original; - - return $result; - } - /** * Insert new records into the database. * @@ -4255,6 +4242,17 @@ public function useWritePdo() return $this; } + /** + * Set arguments for the PDOStatement::fetchAll/fetch functions. + * @param mixed ...$fetchArgs + * @return $this + */ + public function fetchArgs(...$fetchArgs): static + { + $this->fetchArgs = $fetchArgs; + return $this; + } + /** * Determine if the value is a query builder instance or a Closure. * From 7d9edc3c849f51030ca4985d9a722fc95b479cdc Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 13:51:41 +0100 Subject: [PATCH 03/25] fetchargs --- src/Illuminate/Database/Connection.php | 19 +-- .../Database/ConnectionInterface.php | 6 +- src/Illuminate/Database/Query/Builder.php | 112 +++--------------- .../Integration/Database/QueryBuilderTest.php | 6 + 4 files changed, 36 insertions(+), 107 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 8dd7213117c4..935263331e1a 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -391,11 +391,12 @@ public function selectFromWriteConnection($query, $bindings = []) * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchArgs * @return array */ - public function select($query, $bindings = [], $useReadPdo = true) + public function select($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []) { - return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { + return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchArgs) { if ($this->pretending()) { return []; } @@ -411,7 +412,7 @@ public function select($query, $bindings = [], $useReadPdo = true) $statement->execute(); - return $statement->fetchAll(); + return $statement->fetchAll(...$fetchArgs); }); } @@ -421,11 +422,12 @@ public function select($query, $bindings = [], $useReadPdo = true) * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchArgs * @return array */ - public function selectResultSets($query, $bindings = [], $useReadPdo = true) + public function selectResultSets($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []) { - return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { + return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchArgs) { if ($this->pretending()) { return []; } @@ -441,7 +443,7 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true) $sets = []; do { - $sets[] = $statement->fetchAll(); + $sets[] = $statement->fetchAll($fetchArgs); } while ($statement->nextRowset()); return $sets; @@ -454,9 +456,10 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true) * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchArgs * @return \Generator */ - public function cursor($query, $bindings = [], $useReadPdo = true) + public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []) { $statement = $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { @@ -481,7 +484,7 @@ public function cursor($query, $bindings = [], $useReadPdo = true) return $statement; }); - while ($record = $statement->fetch()) { + while ($record = $statement->fetch(...$fetchArgs)) { yield $record; } } diff --git a/src/Illuminate/Database/ConnectionInterface.php b/src/Illuminate/Database/ConnectionInterface.php index 288adb4206e3..09884a1417bd 100755 --- a/src/Illuminate/Database/ConnectionInterface.php +++ b/src/Illuminate/Database/ConnectionInterface.php @@ -51,9 +51,10 @@ public function scalar($query, $bindings = [], $useReadPdo = true); * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchArgs * @return array */ - public function select($query, $bindings = [], $useReadPdo = true); + public function select($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []); /** * Run a select statement against the database and returns a generator. @@ -61,9 +62,10 @@ public function select($query, $bindings = [], $useReadPdo = true); * @param string $query * @param array $bindings * @param bool $useReadPdo + * @param array $fetchArgs * @return \Generator */ - public function cursor($query, $bindings = [], $useReadPdo = true); + public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []); /** * Run an insert statement against the database. diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 4e7067a1f3aa..9bc90c62882c 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -26,6 +26,7 @@ use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; use LogicException; +use PDO; use RuntimeException; use UnitEnum; @@ -3125,13 +3126,13 @@ public function get($columns = ['*']) /** * Run the query as a "select" statement against the connection. - * + * @param array $fetchArgs * @return array */ - protected function runSelect() + protected function runSelect(array $fetchArgs = []) { return $this->connection->select( - $this->toSql(), $this->getBindings(), ! $this->useWritePdo + $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $fetchArgs ); } @@ -3375,110 +3376,27 @@ protected function enforceOrderBy() * Get a collection instance containing the values of a given column. * * @param \Illuminate\Contracts\Database\Query\Expression|string $column - * @param string|null $key + * @param \Illuminate\Contracts\Database\Query\Expression|string|null $key * @return \Illuminate\Support\Collection */ public function pluck($column, $key = null) { - // First, we will need to select the results of the query accounting for the - // given columns / key. Once we have the results, we will be able to take - // the results and get the exact data that was requested for the query. - $queryResult = $this->onceWithColumns( - is_null($key) ? [$column] : [$column, $key], - function () { - return $this->processor->processSelect( - $this, $this->runSelect() - ); - } - ); - - if (empty($queryResult)) { - return new Collection; - } - - // If the columns are qualified with a table or have an alias, we cannot use - // those directly in the "pluck" operations since the results from the DB - // are only keyed by the column itself. We'll strip the table out here. - $column = $this->stripTableForPluck($column); - - $key = $this->stripTableForPluck($key); - - return $this->applyAfterQueryCallbacks( - is_array($queryResult[0]) - ? $this->pluckFromArrayColumn($queryResult, $column, $key) - : $this->pluckFromObjectColumn($queryResult, $column, $key) - ); - } - - /** - * Strip off the table name or alias from a column identifier. - * - * @param string $column - * @return string|null - */ - protected function stripTableForPluck($column) - { - if (is_null($column)) { - return $column; - } - - $columnString = $column instanceof ExpressionContract - ? $this->grammar->getValue($column) - : $column; - - $separator = str_contains(strtolower($columnString), ' as ') ? ' as ' : '\.'; - - return last(preg_split('~'.$separator.'~i', $columnString)); - } - - /** - * Retrieve column values from rows represented as objects. - * - * @param array $queryResult - * @param string $column - * @param string $key - * @return \Illuminate\Support\Collection - */ - protected function pluckFromObjectColumn($queryResult, $column, $key) - { - $results = []; - - if (is_null($key)) { - foreach ($queryResult as $row) { - $results[] = $row->$column; - } + if(is_null($key)) { + $columns = [$column]; + $fetchArgs = [PDO::FETCH_COLUMN]; } else { - foreach ($queryResult as $row) { - $results[$row->$key] = $row->$column; - } + $columns = [$key, $column]; + $fetchArgs = [PDO::FETCH_COLUMN | PDO::FETCH_UNIQUE]; } - return new Collection($results); - } + [$original, $this->columns] = [$this->columns, $columns]; - /** - * Retrieve column values from rows represented as arrays. - * - * @param array $queryResult - * @param string $column - * @param string $key - * @return \Illuminate\Support\Collection - */ - protected function pluckFromArrayColumn($queryResult, $column, $key) - { - $results = []; + $queryResult = $this->processor->processSelect($this, $this->runSelect($fetchArgs)); - if (is_null($key)) { - foreach ($queryResult as $row) { - $results[] = $row[$column]; - } - } else { - foreach ($queryResult as $row) { - $results[$row[$key]] = $row[$column]; - } - } + // Revert to original columns so future queries can use the previous selection. + $this->columns = $original; - return new Collection($results); + return new Collection($queryResult); } /** diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index c323ff0e1513..85888ec34c72 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -600,6 +600,12 @@ public function testChunkMap() public function testPluck() { + // Test empty result set. + $this->assertSame( + [], + DB::table('posts')->whereRaw('0=1')->pluck('title')->toArray() + ); + // Test SELECT override, since pluck will take the first column. $this->assertSame([ 'Foo Post', From a6fb9c7c0f0a84f46391d1efa37ef1b30c2c0291 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 15:05:36 +0100 Subject: [PATCH 04/25] add fetchArgs() function --- src/Illuminate/Database/Query/Builder.php | 76 +++++++++++------------ 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 9bc90c62882c..5594824cbba2 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -249,6 +249,13 @@ class Builder implements BuilderContract */ public $useWritePdo = false; + /** + * Custom arguments for the PDOStatement::fetchAll/fetch functions. + * + * @var array + */ + public array $fetchArgs = []; + /** * Create a new query builder instance. * @@ -3115,9 +3122,14 @@ public function soleValue($column) */ public function get($columns = ['*']) { - $items = new Collection($this->onceWithColumns(Arr::wrap($columns), function () { - return $this->processor->processSelect($this, $this->runSelect()); - })); + $original = $this->columns; + + $this->columns ??= Arr::wrap($columns); + + $items = new Collection($this->processor->processSelect($this, $this->runSelect())); + + // Revert to original columns so future queries can use the previous selection. + $this->columns = $original; return $this->applyAfterQueryCallbacks( isset($this->groupLimit) ? $this->withoutGroupLimitKeys($items) : $items @@ -3126,13 +3138,12 @@ public function get($columns = ['*']) /** * Run the query as a "select" statement against the connection. - * @param array $fetchArgs * @return array */ - protected function runSelect(array $fetchArgs = []) + protected function runSelect() { return $this->connection->select( - $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $fetchArgs + $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchArgs ); } @@ -3381,20 +3392,20 @@ protected function enforceOrderBy() */ public function pluck($column, $key = null) { + $original = [$this->columns, $this->fetchArgs]; + if(is_null($key)) { - $columns = [$column]; - $fetchArgs = [PDO::FETCH_COLUMN]; + $this->columns = [$column]; + $this->fetchArgs = [PDO::FETCH_COLUMN]; } else { - $columns = [$key, $column]; - $fetchArgs = [PDO::FETCH_COLUMN | PDO::FETCH_UNIQUE]; + $this->columns = [$key, $column]; + $this->fetchArgs = [PDO::FETCH_KEY_PAIR]; } - [$original, $this->columns] = [$this->columns, $columns]; - - $queryResult = $this->processor->processSelect($this, $this->runSelect($fetchArgs)); + $queryResult = $this->processor->processSelect($this, $this->runSelect()); - // Revert to original columns so future queries can use the previous selection. - $this->columns = $original; + // Revert to original values so future queries can use the previous selection. + [$this->columns, $this->fetchArgs] = $original; return new Collection($queryResult); } @@ -3604,30 +3615,6 @@ protected function setAggregate($function, $columns) return $this; } - /** - * Execute the given callback while selecting the given columns. - * - * After running the callback, the columns are reset to the original value. - * - * @param array $columns - * @param callable $callback - * @return mixed - */ - protected function onceWithColumns($columns, $callback) - { - $original = $this->columns; - - if (is_null($original)) { - $this->columns = $columns; - } - - $result = $callback(); - - $this->columns = $original; - - return $result; - } - /** * Insert new records into the database. * @@ -4256,6 +4243,17 @@ public function useWritePdo() return $this; } + /** + * Set arguments for the PDOStatement::fetchAll/fetch functions. + * @param mixed ...$fetchArgs + * @return $this + */ + public function fetchArgs(...$fetchArgs): static + { + $this->fetchArgs = $fetchArgs; + return $this; + } + /** * Determine if the value is a query builder instance or a Closure. * From 9a7fc868b3a57299a3d74ccdd3b044ba35db2144 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 15:29:26 +0100 Subject: [PATCH 05/25] add afterquery callbacks --- src/Illuminate/Database/Query/Builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 5594824cbba2..27fa0a0333a9 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -3407,7 +3407,7 @@ public function pluck($column, $key = null) // Revert to original values so future queries can use the previous selection. [$this->columns, $this->fetchArgs] = $original; - return new Collection($queryResult); + return new Collection($this->applyAfterQueryCallbacks($queryResult)); } /** From c9924d38542174312f16bd38d468132aef1cc092 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 15:35:11 +0100 Subject: [PATCH 06/25] fix typo --- src/Illuminate/Database/Connection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 935263331e1a..22622ee32302 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -443,7 +443,7 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true, arr $sets = []; do { - $sets[] = $statement->fetchAll($fetchArgs); + $sets[] = $statement->fetchAll(...$fetchArgs); } while ($statement->nextRowset()); return $sets; From 18893a65629d1570f748d58822ae5d227d20c4a7 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 15:39:42 +0100 Subject: [PATCH 07/25] flip afterquerycallback --- src/Illuminate/Database/Query/Builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 27fa0a0333a9..63d923f27ee2 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -3407,7 +3407,7 @@ public function pluck($column, $key = null) // Revert to original values so future queries can use the previous selection. [$this->columns, $this->fetchArgs] = $original; - return new Collection($this->applyAfterQueryCallbacks($queryResult)); + return $this->applyAfterQueryCallbacks(new Collection($queryResult)); } /** From f66184152364ad386aeeae6af88332bcb2774237 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 16:26:39 +0100 Subject: [PATCH 08/25] fix expectations --- tests/Database/DatabaseQueryBuilderTest.php | 90 ++++++++++----------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 94cfdfbe2fc0..0f701b02bc11 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -81,12 +81,12 @@ public function testBasicSelectUseWritePdo() { $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with('select * from `users`', [], false); + ->with('select * from `users`', [], false, []); $builder->useWritePdo()->select('*')->from('users')->get(); $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with('select * from `users`', [], true); + ->with('select * from `users`', [], true, []); $builder->select('*')->from('users')->get(); } @@ -1621,31 +1621,31 @@ public function testUnionAggregate() { $expected = 'select count(*) as aggregate from ((select * from `posts`) union (select * from `videos`)) as `temp_table`'; $builder = $this->getMySqlBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getMySqlBuilder()->from('videos'))->count(); $expected = 'select count(*) as aggregate from ((select `id` from `posts`) union (select `id` from `videos`)) as `temp_table`'; $builder = $this->getMySqlBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->select('id')->union($this->getMySqlBuilder()->from('videos')->select('id'))->count(); $expected = 'select count(*) as aggregate from ((select * from "posts") union (select * from "videos")) as "temp_table"'; $builder = $this->getPostgresBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getPostgresBuilder()->from('videos'))->count(); $expected = 'select count(*) as aggregate from (select * from (select * from "posts") union select * from (select * from "videos")) as "temp_table"'; $builder = $this->getSQLiteBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getSQLiteBuilder()->from('videos'))->count(); $expected = 'select count(*) as aggregate from (select * from (select * from [posts]) as [temp_table] union select * from (select * from [videos]) as [temp_table]) as [temp_table]'; $builder = $this->getSqlServerBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true, []); $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getSqlServerBuilder()->from('videos'))->count(); } @@ -1655,7 +1655,7 @@ public function testHavingAggregate() $expected = 'select count(*) as aggregate from (select (select `count(*)` from `videos` where `posts`.`id` = `videos`.`post_id`) as `videos_count` from `posts` having `videos_count` > ?) as `temp_table`'; $builder = $this->getMySqlBuilder(); $builder->getConnection()->shouldReceive('getDatabaseName'); - $builder->getConnection()->shouldReceive('select')->once()->with($expected, [0 => 1], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [0 => 1], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2137,7 +2137,7 @@ public function testHavingFollowedBySelectGet() { $builder = $this->getBuilder(); $query = 'select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" > ?'; - $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular', 3], true)->andReturn([['category' => 'rock', 'total' => 5]]); + $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular', 3], true, [])->andReturn([['category' => 'rock', 'total' => 5]]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2148,7 +2148,7 @@ public function testHavingFollowedBySelectGet() // Using \Raw value $builder = $this->getBuilder(); $query = 'select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" > 3'; - $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular'], true)->andReturn([['category' => 'rock', 'total' => 5]]); + $builder->getConnection()->shouldReceive('select')->once()->with($query, ['popular'], true, [])->andReturn([['category' => 'rock', 'total' => 5]]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2241,7 +2241,7 @@ public function testGetCountForPaginationWithBindings() $q->select('body')->from('posts')->where('id', 4); }, 'post'); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2257,7 +2257,7 @@ public function testGetCountForPaginationWithColumnAliases() $columns = ['body as post_body', 'teaser', 'posts.created as published']; $builder->from('posts')->select($columns); - $builder->getConnection()->shouldReceive('select')->once()->with('select count("body", "teaser", "posts"."created") as aggregate from "posts"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count("body", "teaser", "posts"."created") as aggregate from "posts"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2271,7 +2271,7 @@ public function testGetCountForPaginationWithUnion() $builder = $this->getBuilder(); $builder->from('posts')->select('id')->union($this->getBuilder()->from('videos')->select('id')); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2285,7 +2285,7 @@ public function testGetCountForPaginationWithUnionOrders() $builder = $this->getBuilder(); $builder->from('posts')->select('id')->union($this->getBuilder()->from('videos')->select('id'))->latest(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -2299,7 +2299,7 @@ public function testGetCountForPaginationWithUnionLimitAndOffset() $builder = $this->getBuilder(); $builder->from('posts')->select('id')->union($this->getBuilder()->from('videos')->select('id'))->take(15)->skip(1); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from ((select "id" from "posts") union (select "id" from "videos")) as "temp_table"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3289,7 +3289,7 @@ public function testRawExpressionsInSelect() public function testFindReturnsFirstResultByID() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { return $results; }); @@ -3313,7 +3313,7 @@ public function testFindOrReturnsFirstResultByID() public function testFirstMethodReturnsFirstResult() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { return $results; }); @@ -3324,7 +3324,7 @@ public function testFirstMethodReturnsFirstResult() public function testFirstOrFailMethodReturnsFirstResult() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { return $results; }); @@ -3335,7 +3335,7 @@ public function testFirstOrFailMethodReturnsFirstResult() public function testFirstOrFailMethodThrowsRecordNotFoundException() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true)->andReturn([]); + $builder->getConnection()->shouldReceive('select')->once()->with('select * from "users" where "id" = ? limit 1', [1], true, [])->andReturn([]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [])->andReturn([]); @@ -3348,16 +3348,16 @@ public function testFirstOrFailMethodThrowsRecordNotFoundException() public function testPluckMethodGetsCollectionOfColumnValues() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->andReturn([['foo' => 'bar'], ['foo' => 'baz']]); - $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar'], ['foo' => 'baz']])->andReturnUsing(function ($query, $results) { + $builder->getConnection()->shouldReceive('select')->once()->andReturn(['bar', 'baz']); + $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, ['bar', 'baz'])->andReturnUsing(function ($query, $results) { return $results; }); $results = $builder->from('users')->where('id', '=', 1)->pluck('foo'); $this->assertEquals(['bar', 'baz'], $results->all()); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->andReturn([['id' => 1, 'foo' => 'bar'], ['id' => 10, 'foo' => 'baz']]); - $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['id' => 1, 'foo' => 'bar'], ['id' => 10, 'foo' => 'baz']])->andReturnUsing(function ($query, $results) { + $builder->getConnection()->shouldReceive('select')->once()->andReturn([1 => 'bar', 10 => 'baz']); + $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [1 => 'bar', 10 => 'baz'])->andReturnUsing(function ($query, $results) { return $results; }); $results = $builder->from('users')->where('id', '=', 1)->pluck('foo', 'id'); @@ -3368,8 +3368,8 @@ public function testImplode() { // Test without glue. $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->andReturn([['foo' => 'bar'], ['foo' => 'baz']]); - $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar'], ['foo' => 'baz']])->andReturnUsing(function ($query, $results) { + $builder->getConnection()->shouldReceive('select')->once()->andReturn(['bar', 'baz']); + $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, ['bar', 'baz'])->andReturnUsing(function ($query, $results) { return $results; }); $results = $builder->from('users')->where('id', '=', 1)->implode('foo'); @@ -3377,8 +3377,8 @@ public function testImplode() // Test with glue. $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->andReturn([['foo' => 'bar'], ['foo' => 'baz']]); - $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar'], ['foo' => 'baz']])->andReturnUsing(function ($query, $results) { + $builder->getConnection()->shouldReceive('select')->once()->andReturn(['bar', 'baz']); + $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, ['bar', 'baz'])->andReturnUsing(function ($query, $results) { return $results; }); $results = $builder->from('users')->where('id', '=', 1)->implode('foo', ','); @@ -3388,7 +3388,7 @@ public function testImplode() public function testValueMethodReturnsSingleColumn() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ? limit 1', [1], true)->andReturn([['foo' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['foo' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturn([['foo' => 'bar']]); $results = $builder->from('users')->where('id', '=', 1)->value('foo'); $this->assertSame('bar', $results); @@ -3397,7 +3397,7 @@ public function testValueMethodReturnsSingleColumn() public function testRawValueMethodReturnsSingleColumn() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select UPPER("foo") from "users" where "id" = ? limit 1', [1], true)->andReturn([['UPPER("foo")' => 'BAR']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select UPPER("foo") from "users" where "id" = ? limit 1', [1], true, [])->andReturn([['UPPER("foo")' => 'BAR']]); $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['UPPER("foo")' => 'BAR']])->andReturn([['UPPER("foo")' => 'BAR']]); $results = $builder->from('users')->where('id', '=', 1)->rawValue('UPPER("foo")'); $this->assertSame('BAR', $results); @@ -3406,7 +3406,7 @@ public function testRawValueMethodReturnsSingleColumn() public function testAggregateFunctions() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3424,7 +3424,7 @@ public function testAggregateFunctions() $this->assertTrue($results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select max("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select max("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3432,7 +3432,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select min("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select min("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3440,7 +3440,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3448,7 +3448,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3456,7 +3456,7 @@ public function testAggregateFunctions() $this->assertEquals(1, $results); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select avg("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3507,9 +3507,9 @@ public function testDoesntExistsOr() public function testAggregateResetFollowedByGet() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true)->andReturn([['aggregate' => 2]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select "column1", "column2" from "users"', [], true)->andReturn([['column1' => 'foo', 'column2' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select sum("id") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 2]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "column1", "column2" from "users"', [], true, [])->andReturn([['column1' => 'foo', 'column2' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3525,8 +3525,8 @@ public function testAggregateResetFollowedByGet() public function testAggregateResetFollowedBySelectGet() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true)->andReturn([['column2' => 'foo', 'column3' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true, [])->andReturn([['column2' => 'foo', 'column3' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3540,8 +3540,8 @@ public function testAggregateResetFollowedBySelectGet() public function testAggregateResetFollowedByGetWithColumns() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); - $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true)->andReturn([['column2' => 'foo', 'column3' => 'bar']]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count("column1") as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select "column2", "column3" from "users"', [], true, [])->andReturn([['column2' => 'foo', 'column3' => 'bar']]); $builder->getProcessor()->shouldReceive('processSelect')->andReturnUsing(function ($builder, $results) { return $results; }); @@ -3555,7 +3555,7 @@ public function testAggregateResetFollowedByGetWithColumns() public function testAggregateWithSubSelect() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from "users"', [], true, [])->andReturn([['aggregate' => 1]]); $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { return $results; }); @@ -5044,12 +5044,12 @@ public function testSelectWithLockUsesWritePdo() { $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with(m::any(), m::any(), false); + ->with(m::any(), m::any(), false, []); $builder->select('*')->from('foo')->where('bar', '=', 'baz')->lock()->get(); $builder = $this->getMySqlBuilderWithProcessor(); $builder->getConnection()->shouldReceive('select')->once() - ->with(m::any(), m::any(), false); + ->with(m::any(), m::any(), false, []); $builder->select('*')->from('foo')->where('bar', '=', 'baz')->lock(false)->get(); } From fae83f372bb6039eca3de189a6fb63ec3e85f712 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 16:47:16 +0100 Subject: [PATCH 09/25] add expectations --- .../DatabaseEloquentBelongsToManyCreateOrFirstTest.php | 10 ++++++++-- ...DatabaseEloquentHasManyThroughCreateOrFirstTest.php | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php b/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php index 3ea77e45aedc..0a067d209b8e 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyCreateOrFirstTest.php @@ -84,7 +84,7 @@ public function testCreateOrFirstMethodAssociatesExistingRelated(): void $source->getConnection() ->expects('select') - ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 456, 'attr' => 'foo', @@ -128,6 +128,7 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAlreadyAssociated 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([[ 'id' => 456, @@ -176,7 +177,7 @@ public function testCreateOrFirstMethodRetrievesExistingRelatedAssociatedJustNow $source->getConnection() ->expects('select') - ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 456, 'attr' => 'foo', @@ -199,6 +200,7 @@ public function testCreateOrFirstMethodRetrievesExistingRelatedAssociatedJustNow 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], false, + [], ) ->andReturn([[ 'id' => 456, @@ -243,6 +245,7 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAndAssociatesIt() 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -252,6 +255,7 @@ public function testFirstOrCreateMethodRetrievesExistingRelatedAndAssociatesIt() 'select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, + [], ) ->andReturn([[ 'id' => 456, @@ -326,6 +330,7 @@ protected function newBelongsToMany(Builder $query, Model $parent, $table, $fore 'select "related_table".*, "pivot_table"."source_id" as "pivot_source_id", "pivot_table"."related_id" as "pivot_related_id" from "related_table" inner join "pivot_table" on "related_table"."id" = "pivot_table"."related_id" where "pivot_table"."source_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -335,6 +340,7 @@ protected function newBelongsToMany(Builder $query, Model $parent, $table, $fore 'select * from "related_table" where ("attr" = ?) limit 1', ['foo'], true, + [], ) ->andReturn([]); diff --git a/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php b/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php index 1b364e57b9f7..63645d1d9b86 100644 --- a/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentHasManyThroughCreateOrFirstTest.php @@ -75,6 +75,7 @@ public function testCreateOrFirstMethodRetrievesExistingRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([[ 'id' => 789, @@ -114,6 +115,7 @@ public function testFirstOrCreateMethodCreatesNewRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -148,6 +150,7 @@ public function testFirstOrCreateMethodRetrievesExistingRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([[ 'id' => 789, @@ -187,6 +190,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -204,6 +208,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ? and "val" = ?) limit 1', [123, 'foo', 'bar'], true, + [], ) ->andReturn([[ 'id' => 789, @@ -243,6 +248,7 @@ public function testUpdateOrCreateMethodCreatesNewRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -280,6 +286,7 @@ public function testUpdateOrCreateMethodUpdatesExistingRecord(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([[ 'id' => 789, @@ -327,6 +334,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ?) limit 1', [123, 'foo'], true, + [], ) ->andReturn([]); @@ -344,6 +352,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void 'select "child".*, "pivot"."parent_id" as "laravel_through_key" from "child" inner join "pivot" on "pivot"."id" = "child"."pivot_id" where "pivot"."parent_id" = ? and ("attr" = ? and "val" = ?) limit 1', [123, 'foo', 'bar'], true, + [], ) ->andReturn([[ 'id' => 789, From 812b2888ebc9ca009b4f0e88077b72bee69fcc3a Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 17:20:37 +0100 Subject: [PATCH 10/25] add expectations --- ...tabaseEloquentBuilderCreateOrFirstTest.php | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php index b629194b6ea6..c50d0727215b 100755 --- a/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentBuilderCreateOrFirstTest.php @@ -66,7 +66,7 @@ public function testCreateOrFirstMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -95,7 +95,7 @@ public function testFirstOrCreateMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -124,7 +124,7 @@ public function testFirstOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -152,7 +152,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $sql = 'insert into "table" ("attr", "val", "updated_at", "created_at") values (?, ?, ?, ?)'; @@ -165,7 +165,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -194,7 +194,7 @@ public function testUpdateOrCreateMethodUpdatesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -231,7 +231,7 @@ public function testUpdateOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -259,7 +259,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $sql = 'insert into "table" ("attr", "val", "updated_at", "created_at") values (?, ?, ?, ?)'; @@ -272,7 +272,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -309,7 +309,7 @@ public function testIncrementOrCreateMethodIncrementsExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -351,7 +351,7 @@ public function testIncrementOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -379,7 +379,7 @@ public function testIncrementOrCreateMethodIncrementParametersArePassed(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', @@ -423,7 +423,7 @@ public function testIncrementOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], true, []) ->andReturn([]); $sql = 'insert into "table" ("attr", "count", "updated_at", "created_at") values (?, ?, ?, ?)'; @@ -436,7 +436,7 @@ public function testIncrementOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false) + ->with('select * from "table" where ("attr" = ?) limit 1', ['foo'], false, []) ->andReturn([[ 'id' => 123, 'attr' => 'foo', From 951144f295d235252959fef1dbc69ce8e39614d1 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 17:26:20 +0100 Subject: [PATCH 11/25] add expectations --- ...atabaseEloquentHasManyCreateOrFirstTest.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php b/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php index 09faed3f2654..0f5ade550751 100755 --- a/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php +++ b/tests/Database/DatabaseEloquentHasManyCreateOrFirstTest.php @@ -70,7 +70,7 @@ public function testCreateOrFirstMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false, []) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -102,7 +102,7 @@ public function testFirstOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -132,7 +132,7 @@ public function testFirstOrCreateMethodRetrievesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -164,7 +164,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([]); $sql = 'insert into "child_table" ("attr", "val", "parent_id", "updated_at", "created_at") values (?, ?, ?, ?, ?)'; @@ -177,7 +177,7 @@ public function testFirstOrCreateMethodRetrievesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false, []) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -209,7 +209,7 @@ public function testUpdateOrCreateMethodCreatesNewRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([]); $model->getConnection()->expects('insert')->with( @@ -239,7 +239,7 @@ public function testUpdateOrCreateMethodUpdatesExistingRecord(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([[ 'id' => 456, 'parent_id' => 123, @@ -276,7 +276,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], true, []) ->andReturn([]); $sql = 'insert into "child_table" ("attr", "val", "parent_id", "updated_at", "created_at") values (?, ?, ?, ?, ?)'; @@ -289,7 +289,7 @@ public function testUpdateOrCreateMethodUpdatesRecordCreatedJustNow(): void $model->getConnection() ->expects('select') - ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false) + ->with('select * from "child_table" where "child_table"."parent_id" = ? and "child_table"."parent_id" is not null and ("attr" = ?) limit 1', [123, 'foo'], false, []) ->andReturn([[ 'id' => 456, 'parent_id' => 123, From 1720c63995c851ef401085d601f77ed3c9735b64 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 2 Feb 2025 18:05:18 +0100 Subject: [PATCH 12/25] add raw expression test --- tests/Integration/Database/QueryBuilderTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index 85888ec34c72..6a6bc60ef15f 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -640,6 +640,12 @@ public function testPluck() $this->assertSame([ 'Lorem Ipsum.' => 'Bar Post', ], DB::table('posts')->pluck('title', 'content')->toArray()); + + // Test raw expressions. + $this->assertSame([ + 'FOO POST' => 'LOREM IPSUM.', + 'BAR POST' => 'LOREM IPSUM.', + ], DB::table('posts')->pluck(DB::raw('UPPER(content)'), DB::raw('UPPER(title)'))->toArray()); } protected function defineEnvironmentWouldThrowsPDOException($app) From 770f6985408f94b45ed71a5050dc59402fa5fe46 Mon Sep 17 00:00:00 2001 From: Bert Date: Fri, 7 Feb 2025 13:34:31 +0100 Subject: [PATCH 13/25] rename to fetchUsing --- src/Illuminate/Database/Connection.php | 22 +++++++++---------- .../Database/ConnectionInterface.php | 8 +++---- src/Illuminate/Database/Query/Builder.php | 22 +++++++++---------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 22622ee32302..4948a41530de 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -391,12 +391,12 @@ public function selectFromWriteConnection($query, $bindings = []) * @param string $query * @param array $bindings * @param bool $useReadPdo - * @param array $fetchArgs + * @param array $fetchUsing * @return array */ - public function select($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []) + public function select($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []) { - return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchArgs) { + return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchUsing) { if ($this->pretending()) { return []; } @@ -412,7 +412,7 @@ public function select($query, $bindings = [], $useReadPdo = true, array $fetchA $statement->execute(); - return $statement->fetchAll(...$fetchArgs); + return $statement->fetchAll(...$fetchUsing); }); } @@ -422,12 +422,12 @@ public function select($query, $bindings = [], $useReadPdo = true, array $fetchA * @param string $query * @param array $bindings * @param bool $useReadPdo - * @param array $fetchArgs + * @param array $fetchUsing * @return array */ - public function selectResultSets($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []) + public function selectResultSets($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []) { - return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchArgs) { + return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo, $fetchUsing) { if ($this->pretending()) { return []; } @@ -443,7 +443,7 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true, arr $sets = []; do { - $sets[] = $statement->fetchAll(...$fetchArgs); + $sets[] = $statement->fetchAll(...$fetchUsing); } while ($statement->nextRowset()); return $sets; @@ -456,10 +456,10 @@ public function selectResultSets($query, $bindings = [], $useReadPdo = true, arr * @param string $query * @param array $bindings * @param bool $useReadPdo - * @param array $fetchArgs + * @param array $fetchUsing * @return \Generator */ - public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []) + public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []) { $statement = $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { @@ -484,7 +484,7 @@ public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchA return $statement; }); - while ($record = $statement->fetch(...$fetchArgs)) { + while ($record = $statement->fetch(...$fetchUsing)) { yield $record; } } diff --git a/src/Illuminate/Database/ConnectionInterface.php b/src/Illuminate/Database/ConnectionInterface.php index 09884a1417bd..22f866b43763 100755 --- a/src/Illuminate/Database/ConnectionInterface.php +++ b/src/Illuminate/Database/ConnectionInterface.php @@ -51,10 +51,10 @@ public function scalar($query, $bindings = [], $useReadPdo = true); * @param string $query * @param array $bindings * @param bool $useReadPdo - * @param array $fetchArgs + * @param array $fetchUsing * @return array */ - public function select($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []); + public function select($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []); /** * Run a select statement against the database and returns a generator. @@ -62,10 +62,10 @@ public function select($query, $bindings = [], $useReadPdo = true, array $fetchA * @param string $query * @param array $bindings * @param bool $useReadPdo - * @param array $fetchArgs + * @param array $fetchUsing * @return \Generator */ - public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchArgs = []); + public function cursor($query, $bindings = [], $useReadPdo = true, array $fetchUsing = []); /** * Run an insert statement against the database. diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 63d923f27ee2..02a968349ce1 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -254,7 +254,7 @@ class Builder implements BuilderContract * * @var array */ - public array $fetchArgs = []; + public array $fetchUsing = []; /** * Create a new query builder instance. @@ -3143,7 +3143,7 @@ public function get($columns = ['*']) protected function runSelect() { return $this->connection->select( - $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchArgs + $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchUsing ); } @@ -3392,22 +3392,22 @@ protected function enforceOrderBy() */ public function pluck($column, $key = null) { - $original = [$this->columns, $this->fetchArgs]; + $original = [$this->columns, $this->fetchUsing]; if(is_null($key)) { $this->columns = [$column]; - $this->fetchArgs = [PDO::FETCH_COLUMN]; + $this->fetchUsing = [PDO::FETCH_COLUMN]; } else { $this->columns = [$key, $column]; - $this->fetchArgs = [PDO::FETCH_KEY_PAIR]; + $this->fetchUsing = [PDO::FETCH_KEY_PAIR]; } - $queryResult = $this->processor->processSelect($this, $this->runSelect()); + $items = new Collection($this->processor->processSelect($this, $this->runSelect())); // Revert to original values so future queries can use the previous selection. - [$this->columns, $this->fetchArgs] = $original; + [$this->columns, $this->fetchUsing] = $original; - return $this->applyAfterQueryCallbacks(new Collection($queryResult)); + return $this->applyAfterQueryCallbacks($items); } /** @@ -4245,12 +4245,12 @@ public function useWritePdo() /** * Set arguments for the PDOStatement::fetchAll/fetch functions. - * @param mixed ...$fetchArgs + * @param mixed ...$fetchUsing * @return $this */ - public function fetchArgs(...$fetchArgs): static + public function fetchUsing(...$fetchUsing): static { - $this->fetchArgs = $fetchArgs; + $this->fetchUsing = $fetchUsing; return $this; } From 9230cc12b8fb70d6e1895388318f4280c21a620e Mon Sep 17 00:00:00 2001 From: Bert Date: Fri, 7 Feb 2025 13:36:13 +0100 Subject: [PATCH 14/25] style --- src/Illuminate/Database/Query/Builder.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 02a968349ce1..4233dd74c6eb 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -3138,6 +3138,7 @@ public function get($columns = ['*']) /** * Run the query as a "select" statement against the connection. + * * @return array */ protected function runSelect() @@ -3394,7 +3395,7 @@ public function pluck($column, $key = null) { $original = [$this->columns, $this->fetchUsing]; - if(is_null($key)) { + if (is_null($key)) { $this->columns = [$column]; $this->fetchUsing = [PDO::FETCH_COLUMN]; } else { @@ -4245,12 +4246,14 @@ public function useWritePdo() /** * Set arguments for the PDOStatement::fetchAll/fetch functions. + * * @param mixed ...$fetchUsing * @return $this */ public function fetchUsing(...$fetchUsing): static { $this->fetchUsing = $fetchUsing; + return $this; } From 4f34bfda7d15bfc75f720d090337e22bd27b24ac Mon Sep 17 00:00:00 2001 From: Bert Date: Fri, 14 Feb 2025 17:34:05 +0100 Subject: [PATCH 15/25] Remove test from PR #54396 --- tests/Database/DatabaseQueryBuilderTest.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 91991c26f320..89b861fe0cfb 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -3487,17 +3487,6 @@ public function testPluckMethodGetsCollectionOfColumnValues() $this->assertEquals([1 => 'bar', 10 => 'baz'], $results->all()); } - public function testPluckAvoidsDuplicateColumnSelection() - { - $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ?', [1], true)->andReturn([['foo' => 'bar']]); - $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { - return $results; - }); - $results = $builder->from('users')->where('id', '=', 1)->pluck('foo', 'foo'); - $this->assertEquals(['bar' => 'bar'], $results->all()); - } - public function testImplode() { // Test without glue. From 5995132cba428ed38954f8c2230e0e2a7bb31038 Mon Sep 17 00:00:00 2001 From: Bert Date: Fri, 14 Feb 2025 21:02:13 +0100 Subject: [PATCH 16/25] Revert most Query\Builder changes --- src/Illuminate/Database/Query/Builder.php | 104 +++++++++++++++++++--- 1 file changed, 93 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 16b89b2eaac1..439b682dc86d 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -27,7 +27,6 @@ use Illuminate\Support\Traits\Macroable; use InvalidArgumentException; use LogicException; -use PDO; use RuntimeException; use UnitEnum; @@ -3360,27 +3359,110 @@ protected function enforceOrderBy() * Get a collection instance containing the values of a given column. * * @param \Illuminate\Contracts\Database\Query\Expression|string $column - * @param \Illuminate\Contracts\Database\Query\Expression|string|null $key + * @param string|null $key * @return \Illuminate\Support\Collection */ public function pluck($column, $key = null) { - $original = [$this->columns, $this->fetchUsing]; + $original = $this->columns; + + // First, we will need to select the results of the query accounting for the + // given columns / key. Once we have the results, we will be able to take + // the results and get the exact data that was requested for the query. + $this->columns = is_null($key) || $key === $column ? [$column] : [$column, $key]; + + $queryResult = $this->processor->processSelect($this, $this->runSelect()); + + // Revert to original columns so future queries can use the previous selection. + $this->columns = $original; + + if (empty($queryResult)) { + return new Collection; + } + + // If the columns are qualified with a table or have an alias, we cannot use + // those directly in the "pluck" operations since the results from the DB + // are only keyed by the column itself. We'll strip the table out here. + $column = $this->stripTableForPluck($column); + + $key = $this->stripTableForPluck($key); + + return $this->applyAfterQueryCallbacks( + is_array($queryResult[0]) + ? $this->pluckFromArrayColumn($queryResult, $column, $key) + : $this->pluckFromObjectColumn($queryResult, $column, $key) + ); + } + + /** + * Strip off the table name or alias from a column identifier. + * + * @param string $column + * @return string|null + */ + protected function stripTableForPluck($column) + { + if (is_null($column)) { + return $column; + } + + $columnString = $column instanceof ExpressionContract + ? $this->grammar->getValue($column) + : $column; + + $separator = str_contains(strtolower($columnString), ' as ') ? ' as ' : '\.'; + + return last(preg_split('~'.$separator.'~i', $columnString)); + } + + /** + * Retrieve column values from rows represented as objects. + * + * @param array $queryResult + * @param string $column + * @param string $key + * @return \Illuminate\Support\Collection + */ + protected function pluckFromObjectColumn($queryResult, $column, $key) + { + $results = []; if (is_null($key)) { - $this->columns = [$column]; - $this->fetchUsing = [PDO::FETCH_COLUMN]; + foreach ($queryResult as $row) { + $results[] = $row->$column; + } } else { - $this->columns = [$key, $column]; - $this->fetchUsing = [PDO::FETCH_KEY_PAIR]; + foreach ($queryResult as $row) { + $results[$row->$key] = $row->$column; + } } - $items = new Collection($this->processor->processSelect($this, $this->runSelect())); + return new Collection($results); + } - // Revert to original values so future queries can use the previous selection. - [$this->columns, $this->fetchUsing] = $original; + /** + * Retrieve column values from rows represented as arrays. + * + * @param array $queryResult + * @param string $column + * @param string $key + * @return \Illuminate\Support\Collection + */ + protected function pluckFromArrayColumn($queryResult, $column, $key) + { + $results = []; + + if (is_null($key)) { + foreach ($queryResult as $row) { + $results[] = $row[$column]; + } + } else { + foreach ($queryResult as $row) { + $results[$row[$key]] = $row[$column]; + } + } - return $this->applyAfterQueryCallbacks($items); + return new Collection($results); } /** From 10897c9a3dddcfffdb242e65e77ff3b8ce1241de Mon Sep 17 00:00:00 2001 From: Bert Date: Fri, 14 Feb 2025 21:05:12 +0100 Subject: [PATCH 17/25] remove DB::raw test --- tests/Integration/Database/QueryBuilderTest.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index 6a6bc60ef15f..85888ec34c72 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -640,12 +640,6 @@ public function testPluck() $this->assertSame([ 'Lorem Ipsum.' => 'Bar Post', ], DB::table('posts')->pluck('title', 'content')->toArray()); - - // Test raw expressions. - $this->assertSame([ - 'FOO POST' => 'LOREM IPSUM.', - 'BAR POST' => 'LOREM IPSUM.', - ], DB::table('posts')->pluck(DB::raw('UPPER(content)'), DB::raw('UPPER(title)'))->toArray()); } protected function defineEnvironmentWouldThrowsPDOException($app) From 1da6015757684227a7660243bd35dace8a979683 Mon Sep 17 00:00:00 2001 From: Bert Date: Fri, 14 Feb 2025 21:13:17 +0100 Subject: [PATCH 18/25] Revert QueryBuilder pluck tests --- tests/Database/DatabaseQueryBuilderTest.php | 27 +++++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 89b861fe0cfb..3671b47e90aa 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -3471,28 +3471,39 @@ public function testFirstOrFailMethodThrowsRecordNotFoundException() public function testPluckMethodGetsCollectionOfColumnValues() { $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->andReturn(['bar', 'baz']); - $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, ['bar', 'baz'])->andReturnUsing(function ($query, $results) { + $builder->getConnection()->shouldReceive('select')->once()->andReturn([['foo' => 'bar'], ['foo' => 'baz']]); + $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar'], ['foo' => 'baz']])->andReturnUsing(function ($query, $results) { return $results; }); $results = $builder->from('users')->where('id', '=', 1)->pluck('foo'); $this->assertEquals(['bar', 'baz'], $results->all()); $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->andReturn([1 => 'bar', 10 => 'baz']); - $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [1 => 'bar', 10 => 'baz'])->andReturnUsing(function ($query, $results) { + $builder->getConnection()->shouldReceive('select')->once()->andReturn([['id' => 1, 'foo' => 'bar'], ['id' => 10, 'foo' => 'baz']]); + $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['id' => 1, 'foo' => 'bar'], ['id' => 10, 'foo' => 'baz']])->andReturnUsing(function ($query, $results) { return $results; }); $results = $builder->from('users')->where('id', '=', 1)->pluck('foo', 'id'); $this->assertEquals([1 => 'bar', 10 => 'baz'], $results->all()); } + public function testPluckAvoidsDuplicateColumnSelection() + { + $builder = $this->getBuilder(); + $builder->getConnection()->shouldReceive('select')->once()->with('select "foo" from "users" where "id" = ?', [1], true, [])->andReturn([['foo' => 'bar']]); + $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar']])->andReturnUsing(function ($query, $results) { + return $results; + }); + $results = $builder->from('users')->where('id', '=', 1)->pluck('foo', 'foo'); + $this->assertEquals(['bar' => 'bar'], $results->all()); + } + public function testImplode() { // Test without glue. $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->andReturn(['bar', 'baz']); - $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, ['bar', 'baz'])->andReturnUsing(function ($query, $results) { + $builder->getConnection()->shouldReceive('select')->once()->andReturn([['foo' => 'bar'], ['foo' => 'baz']]); + $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar'], ['foo' => 'baz']])->andReturnUsing(function ($query, $results) { return $results; }); $results = $builder->from('users')->where('id', '=', 1)->implode('foo'); @@ -3500,8 +3511,8 @@ public function testImplode() // Test with glue. $builder = $this->getBuilder(); - $builder->getConnection()->shouldReceive('select')->once()->andReturn(['bar', 'baz']); - $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, ['bar', 'baz'])->andReturnUsing(function ($query, $results) { + $builder->getConnection()->shouldReceive('select')->once()->andReturn([['foo' => 'bar'], ['foo' => 'baz']]); + $builder->getProcessor()->shouldReceive('processSelect')->once()->with($builder, [['foo' => 'bar'], ['foo' => 'baz']])->andReturnUsing(function ($query, $results) { return $results; }); $results = $builder->from('users')->where('id', '=', 1)->implode('foo', ','); From 59e631f63d7e84ad9c57872f609644cfc084b99f Mon Sep 17 00:00:00 2001 From: Bert Date: Fri, 14 Feb 2025 21:34:43 +0100 Subject: [PATCH 19/25] Add base tests for $query->fetchUsing() --- src/Illuminate/Database/Query/Builder.php | 2 +- .../Integration/Database/QueryBuilderTest.php | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 439b682dc86d..292af080848d 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -3334,7 +3334,7 @@ public function cursor() return (new LazyCollection(function () { yield from $this->connection->cursor( - $this->toSql(), $this->getBindings(), ! $this->useWritePdo + $this->toSql(), $this->getBindings(), ! $this->useWritePdo, $this->fetchUsing ); }))->map(function ($item) { return $this->applyAfterQueryCallbacks(new Collection([$item]))->first(); diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index 85888ec34c72..cb4cc550b530 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Schema; use Illuminate\Testing\Assert as PHPUnit; use Orchestra\Testbench\Attributes\DefineEnvironment; +use PDO; use PDOException; class QueryBuilderTest extends DatabaseTestCase @@ -642,6 +643,49 @@ public function testPluck() ], DB::table('posts')->pluck('title', 'content')->toArray()); } + public function testFetchUsing() + { + // Fetch column as a list. + $this->assertSame([ + 'Foo Post', + 'Bar Post', + ], DB::table('posts')->select(['title'])->fetchUsing(PDO::FETCH_COLUMN)->get()->toArray()); + + // Fetch the second column as a list (zero-indexed). + $this->assertSame([ + 'Lorem Ipsum.', + 'Lorem Ipsum.', + ], DB::table('posts')->select(['title', 'content'])->fetchUsing(PDO::FETCH_COLUMN, 1)->get()->toArray()); + + // Fetch two columns as key value pairs. + $this->assertSame([ + 1 => 'Foo Post', + 2 => 'Bar Post', + ], DB::table('posts')->select(['id', 'title'])->fetchUsing(PDO::FETCH_KEY_PAIR)->get()->toArray()); + + // Fetch data as associative array with custom key. + $result = DB::table('posts')->select(['id', 'title'])->fetchUsing(PDO::FETCH_UNIQUE)->get()->toArray(); + // Note: results are keyed by their post id here. + $this->assertSame('Foo Post', $result[1]->title); + $this->assertSame('Bar Post', $result[2]->title); + + // Use a cursor. + $this->assertSame([ + 'Foo Post', + 'Bar Post', + ], DB::table('posts')->select(['title'])->fetchUsing(PDO::FETCH_COLUMN)->cursor()->collect()->toArray()); + + // Test the default 'object' fetch mode. + $result = DB::table('posts')->select(['title'])->fetchUsing(PDO::FETCH_OBJ)->get()->toArray(); + $result2 = DB::table('posts')->select(['title'])->fetchUsing()->get()->toArray(); + $this->assertSame('Foo Post', $result[0]->title); + $this->assertSame('Bar Post', $result[1]->title); + $this->assertSame('Foo Post', $result2[0]->title); + $this->assertSame('Bar Post', $result2[1]->title); + + + } + protected function defineEnvironmentWouldThrowsPDOException($app) { $this->afterApplicationCreated(function () { From 1740b0512c2042afb9d0b4e23773e76c7c75a252 Mon Sep 17 00:00:00 2001 From: Bert Date: Fri, 14 Feb 2025 21:40:26 +0100 Subject: [PATCH 20/25] style --- tests/Integration/Database/QueryBuilderTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index cb4cc550b530..4e964149659a 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -682,8 +682,6 @@ public function testFetchUsing() $this->assertSame('Bar Post', $result[1]->title); $this->assertSame('Foo Post', $result2[0]->title); $this->assertSame('Bar Post', $result2[1]->title); - - } protected function defineEnvironmentWouldThrowsPDOException($app) From ed7045867b7bb5f430f74c079c347cb3a143ee43 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 17 Feb 2025 12:11:05 -0600 Subject: [PATCH 21/25] formatting --- src/Illuminate/Database/Query/Builder.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 292af080848d..67555af673e4 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -250,7 +250,7 @@ class Builder implements BuilderContract public $useWritePdo = false; /** - * Custom arguments for the PDOStatement::fetchAll/fetch functions. + * Custom arguments for the PDOStatement::fetchAll / fetch functions. * * @var array */ @@ -3100,7 +3100,6 @@ public function get($columns = ['*']) $items = new Collection($this->processor->processSelect($this, $this->runSelect())); - // Revert to original columns so future queries can use the previous selection. $this->columns = $original; return $this->applyAfterQueryCallbacks( @@ -3369,11 +3368,12 @@ public function pluck($column, $key = null) // First, we will need to select the results of the query accounting for the // given columns / key. Once we have the results, we will be able to take // the results and get the exact data that was requested for the query. - $this->columns = is_null($key) || $key === $column ? [$column] : [$column, $key]; + $this->columns = is_null($key) || $key === $column + ? [$column] + : [$column, $key]; $queryResult = $this->processor->processSelect($this, $this->runSelect()); - // Revert to original columns so future queries can use the previous selection. $this->columns = $original; if (empty($queryResult)) { @@ -4282,12 +4282,12 @@ public function useWritePdo() } /** - * Set arguments for the PDOStatement::fetchAll/fetch functions. + * Specify arguments for the PDOStatement::fetchAll / fetch functions. * * @param mixed ...$fetchUsing * @return $this */ - public function fetchUsing(...$fetchUsing): static + public function fetchUsing(...$fetchUsing) { $this->fetchUsing = $fetchUsing; From ff9b98978f37a40f984fc4fb53a459b43f9ebf95 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 17 Feb 2025 12:11:37 -0600 Subject: [PATCH 22/25] Update Builder.php --- src/Illuminate/Database/Query/Builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 67555af673e4..108112b13f43 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -250,7 +250,7 @@ class Builder implements BuilderContract public $useWritePdo = false; /** - * Custom arguments for the PDOStatement::fetchAll / fetch functions. + * The custom arguments for the PDOStatement::fetchAll / fetch functions. * * @var array */ From 5da3eff5ac15ba439330a56e41f938c3ad79e5b9 Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 20 Feb 2025 19:26:00 +0100 Subject: [PATCH 23/25] Fix filled columns before calling pluck --- src/Illuminate/Database/Query/Builder.php | 2 +- tests/Integration/Database/QueryBuilderTest.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 108112b13f43..cb0960d09cd7 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -3368,7 +3368,7 @@ public function pluck($column, $key = null) // First, we will need to select the results of the query accounting for the // given columns / key. Once we have the results, we will be able to take // the results and get the exact data that was requested for the query. - $this->columns = is_null($key) || $key === $column + $this->columns ??= is_null($key) || $key === $column ? [$column] : [$column, $key]; diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index 4e964149659a..675e741b66c0 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -641,6 +641,15 @@ public function testPluck() $this->assertSame([ 'Lorem Ipsum.' => 'Bar Post', ], DB::table('posts')->pluck('title', 'content')->toArray()); + + // Test custom select query before calling pluck. + $this->assertSame( + [2, 2], + DB::table('posts') + ->selectSub(DB::table('posts')->selectRaw('COUNT(*)'), 'total_posts_count') + ->pluck('total_posts_count') + ->toArray(), + ); } public function testFetchUsing() From f733f11a74f94356eab5bd66274ec3b34d548a7e Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 20 Feb 2025 19:43:20 +0100 Subject: [PATCH 24/25] query db compatibility --- tests/Integration/Database/QueryBuilderTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index 675e741b66c0..ac274d971060 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -643,13 +643,13 @@ public function testPluck() ], DB::table('posts')->pluck('title', 'content')->toArray()); // Test custom select query before calling pluck. - $this->assertSame( - [2, 2], - DB::table('posts') - ->selectSub(DB::table('posts')->selectRaw('COUNT(*)'), 'total_posts_count') - ->pluck('total_posts_count') - ->toArray(), - ); + $result = DB::table('posts') + ->selectSub(DB::table('posts')->selectRaw('COUNT(*)'), 'total_posts_count') + ->pluck('total_posts_count') + ->toArray(); + // Cast for database compatibility. + $this->assertSame(2, (int) $result[0]); + $this->assertSame(2, (int) $result[1]); } public function testFetchUsing() From 014f3c5b7924afc8a10e07bc98baba4dcc940903 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 13 Apr 2025 17:24:32 +0200 Subject: [PATCH 25/25] remove unrelated test --- tests/Integration/Database/QueryBuilderTest.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index ac274d971060..57a1593dac69 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -601,12 +601,6 @@ public function testChunkMap() public function testPluck() { - // Test empty result set. - $this->assertSame( - [], - DB::table('posts')->whereRaw('0=1')->pluck('title')->toArray() - ); - // Test SELECT override, since pluck will take the first column. $this->assertSame([ 'Foo Post',