From a8104ae4e0d7cde6668d58c016e34501951961a5 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Wed, 16 Mar 2022 23:49:03 +0100 Subject: [PATCH] Refactor code for merge packages --- composer.json | 4 +- src/Builder.php | 53 +----- src/Grammars/MySqlGrammar.php | 83 +-------- src/Grammars/PostgresGrammar.php | 3 +- src/Grammars/SQLiteGrammar.php | 26 +-- src/Grammars/SqlServerGrammar.php | 21 +-- .../{ => Traits}/CompilesGroupLimit.php | 2 +- .../Traits/CompilesMySqlGroupLimit.php | 89 +++++++++ .../Traits/CompilesPostgresGroupLimit.php | 8 + .../Traits/CompilesSQLiteGroupLimit.php | 32 ++++ .../Traits/CompilesSqlServerGroupLimit.php | 26 +++ src/HasEagerLimit.php | 174 +---------------- src/Traits/BuildsGroupLimitQueries.php | 58 ++++++ src/Traits/HasEagerLimitRelationships.php | 176 ++++++++++++++++++ tests/BelongsToManyTest.php | 4 +- tests/BuilderTest.php | 2 +- tests/HasManyTest.php | 4 +- tests/HasManyThroughTest.php | 4 +- tests/HasOneTest.php | 4 +- tests/HasOneThroughTest.php | 4 +- tests/Models/Comment.php | 3 +- tests/Models/Country.php | 2 +- tests/Models/Model.php | 2 +- tests/Models/Post.php | 2 +- tests/Models/Role.php | 3 +- tests/Models/Tag.php | 3 +- tests/Models/User.php | 2 +- tests/MorphManyTest.php | 4 +- tests/MorphOneTest.php | 4 +- tests/MorphToManyTest.php | 4 +- tests/TestCase.php | 14 +- 31 files changed, 439 insertions(+), 381 deletions(-) rename src/Grammars/{ => Traits}/CompilesGroupLimit.php (97%) create mode 100644 src/Grammars/Traits/CompilesMySqlGroupLimit.php create mode 100644 src/Grammars/Traits/CompilesPostgresGroupLimit.php create mode 100644 src/Grammars/Traits/CompilesSQLiteGroupLimit.php create mode 100644 src/Grammars/Traits/CompilesSqlServerGroupLimit.php create mode 100644 src/Traits/BuildsGroupLimitQueries.php create mode 100644 src/Traits/HasEagerLimitRelationships.php diff --git a/composer.json b/composer.json index c0c441e..4ffcc03 100644 --- a/composer.json +++ b/composer.json @@ -22,9 +22,9 @@ }, "autoload-dev": { "psr-4": { - "Tests\\": "tests/" + "Staudenmeir\\EloquentEagerLimit\\Tests\\": "tests/" } }, "minimum-stability": "dev", - "prefer-stable" : true + "prefer-stable": true } diff --git a/src/Builder.php b/src/Builder.php index 6865aa8..a7d9960 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -3,58 +3,9 @@ namespace Staudenmeir\EloquentEagerLimit; use Illuminate\Database\Query\Builder as Base; +use Staudenmeir\EloquentEagerLimit\Traits\BuildsGroupLimitQueries; class Builder extends Base { - /** - * The maximum number of records to return per group. - * - * @var array - */ - public $groupLimit; - - /** - * Add a "group limit" clause to the query. - * - * @param int $value - * @param string $column - * @return $this - */ - public function groupLimit($value, $column) - { - if ($value >= 0) { - $this->groupLimit = compact('value', 'column'); - } - - return $this; - } - - /** - * Execute the query as a "select" statement. - * - * @param array $columns - * @return \Illuminate\Support\Collection - */ - public function get($columns = ['*']) - { - $items = parent::get($columns); - - if (!$this->groupLimit) { - return $items; - } - - $column = last(explode('.', $this->groupLimit['column'])); - - $keys = [ - 'laravel_row', - '@laravel_partition := '.$this->grammar->wrap($column), - '@laravel_partition := '.$this->grammar->wrap('pivot_'.$column), - ]; - - foreach ($items as $item) { - unset($item->{$keys[0]}, $item->{$keys[1]}, $item->{$keys[2]}); - } - - return $items; - } + use BuildsGroupLimitQueries; } diff --git a/src/Grammars/MySqlGrammar.php b/src/Grammars/MySqlGrammar.php index 1c0af4f..ab86cf0 100644 --- a/src/Grammars/MySqlGrammar.php +++ b/src/Grammars/MySqlGrammar.php @@ -2,89 +2,10 @@ namespace Staudenmeir\EloquentEagerLimit\Grammars; -use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\Grammars\MySqlGrammar as Base; -use Illuminate\Support\Str; -use PDO; +use Staudenmeir\EloquentEagerLimit\Grammars\Traits\CompilesMySqlGroupLimit; class MySqlGrammar extends Base { - use CompilesGroupLimit { - compileGroupLimit as compileGroupLimitParent; - } - - /** - * Determine whether to use a group limit clause for MySQL < 8.0. - * - * @param \Illuminate\Database\Query\Builder $query - * @return bool - */ - public function useLegacyGroupLimit(Builder $query) - { - $version = $query->getConnection()->getReadPdo()->getAttribute(PDO::ATTR_SERVER_VERSION); - - return version_compare($version, '8.0.11') < 0 && !Str::contains($version, 'MariaDB'); - } - - /** - * Compile a group limit clause. - * - * @param \Illuminate\Database\Query\Builder $query - * @return string - */ - protected function compileGroupLimit(Builder $query) - { - return $this->useLegacyGroupLimit($query) - ? $this->compileLegacyGroupLimit($query) - : $this->compileGroupLimitParent($query); - } - - /** - * Compile a group limit clause for MySQL < 8.0. - * - * Derived from https://softonsofa.com/tweaking-eloquent-relations-how-to-get-n-related-models-per-parent/. - * - * @param \Illuminate\Database\Query\Builder $query - * @return string - */ - protected function compileLegacyGroupLimit(Builder $query) - { - $limit = (int) $query->groupLimit['value']; - - $offset = $query->offset; - - if (isset($offset)) { - $limit += (int) $offset; - - $query->offset = null; - } - - $column = last(explode('.', $query->groupLimit['column'])); - - $column = $this->wrap($column); - - $partition = ', @laravel_row := if(@laravel_partition = '.$column.', @laravel_row + 1, 1) as laravel_row'; - - $partition .= ', @laravel_partition := '.$column; - - $orders = (array) $query->orders; - - array_unshift($orders, ['column' => $query->groupLimit['column'], 'direction' => 'asc']); - - $query->orders = $orders; - - $components = $this->compileComponents($query); - - $sql = $this->concatenate($components); - - $from = '(select @laravel_row := 0, @laravel_partition := 0) as laravel_vars, ('.$sql.') as laravel_table'; - - $sql = 'select laravel_table.*'.$partition.' from '.$from.' having laravel_row <= '.$limit; - - if (isset($offset)) { - $sql .= ' and laravel_row > '.(int) $offset; - } - - return $sql.' order by laravel_row'; - } + use CompilesMySqlGroupLimit; } diff --git a/src/Grammars/PostgresGrammar.php b/src/Grammars/PostgresGrammar.php index a444788..f496bff 100644 --- a/src/Grammars/PostgresGrammar.php +++ b/src/Grammars/PostgresGrammar.php @@ -3,8 +3,9 @@ namespace Staudenmeir\EloquentEagerLimit\Grammars; use Illuminate\Database\Query\Grammars\PostgresGrammar as Base; +use Staudenmeir\EloquentEagerLimit\Grammars\Traits\CompilesPostgresGroupLimit; class PostgresGrammar extends Base { - use CompilesGroupLimit; + use CompilesPostgresGroupLimit; } diff --git a/src/Grammars/SQLiteGrammar.php b/src/Grammars/SQLiteGrammar.php index dd8bb48..d389b40 100644 --- a/src/Grammars/SQLiteGrammar.php +++ b/src/Grammars/SQLiteGrammar.php @@ -2,32 +2,10 @@ namespace Staudenmeir\EloquentEagerLimit\Grammars; -use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\Grammars\SQLiteGrammar as Base; -use PDO; +use Staudenmeir\EloquentEagerLimit\Grammars\Traits\CompilesSQLiteGroupLimit; class SQLiteGrammar extends Base { - use CompilesGroupLimit { - compileGroupLimit as compileGroupLimitParent; - } - - /** - * Compile a group limit clause. - * - * @param \Illuminate\Database\Query\Builder $query - * @return string - */ - protected function compileGroupLimit(Builder $query) - { - $version = $query->getConnection()->getReadPdo()->getAttribute(PDO::ATTR_SERVER_VERSION); - - if (version_compare($version, '3.25.0') >= 0) { - return $this->compileGroupLimitParent($query); - } - - $query->groupLimit = null; - - return $this->compileSelect($query); - } + use CompilesSQLiteGroupLimit; } diff --git a/src/Grammars/SqlServerGrammar.php b/src/Grammars/SqlServerGrammar.php index 1134d9e..d2c9eb5 100644 --- a/src/Grammars/SqlServerGrammar.php +++ b/src/Grammars/SqlServerGrammar.php @@ -3,26 +3,9 @@ namespace Staudenmeir\EloquentEagerLimit\Grammars; use Illuminate\Database\Query\Grammars\SqlServerGrammar as Base; +use Staudenmeir\EloquentEagerLimit\Grammars\Traits\CompilesSqlServerGroupLimit; class SqlServerGrammar extends Base { - use CompilesGroupLimit { - compileRowNumber as compileRowNumberParent; - } - - /** - * Compile a row number clause. - * - * @param string $partition - * @param string $orders - * @return string - */ - protected function compileRowNumber($partition, $orders) - { - if (empty($orders)) { - $orders = 'order by (select 0)'; - } - - return $this->compileRowNumberParent($partition, $orders); - } + use CompilesSqlServerGroupLimit; } diff --git a/src/Grammars/CompilesGroupLimit.php b/src/Grammars/Traits/CompilesGroupLimit.php similarity index 97% rename from src/Grammars/CompilesGroupLimit.php rename to src/Grammars/Traits/CompilesGroupLimit.php index 8ff3dfa..542c3d3 100644 --- a/src/Grammars/CompilesGroupLimit.php +++ b/src/Grammars/Traits/CompilesGroupLimit.php @@ -1,6 +1,6 @@ getConnection()->getReadPdo()->getAttribute(PDO::ATTR_SERVER_VERSION); + + return version_compare($version, '8.0.11') < 0 && !Str::contains($version, 'MariaDB'); + } + + /** + * Compile a group limit clause. + * + * @param \Illuminate\Database\Query\Builder $query + * @return string + */ + protected function compileGroupLimit(Builder $query) + { + return $this->useLegacyGroupLimit($query) + ? $this->compileLegacyGroupLimit($query) + : $this->compileGroupLimitParent($query); + } + + /** + * Compile a group limit clause for MySQL < 8.0. + * + * Derived from https://softonsofa.com/tweaking-eloquent-relations-how-to-get-n-related-models-per-parent/. + * + * @param \Illuminate\Database\Query\Builder $query + * @return string + */ + protected function compileLegacyGroupLimit(Builder $query) + { + $limit = (int) $query->groupLimit['value']; + + $offset = $query->offset; + + if (isset($offset)) { + $limit += (int) $offset; + + $query->offset = null; + } + + $column = last(explode('.', $query->groupLimit['column'])); + + $column = $this->wrap($column); + + $partition = ', @laravel_row := if(@laravel_partition = '.$column.', @laravel_row + 1, 1) as laravel_row'; + + $partition .= ', @laravel_partition := '.$column; + + $orders = (array) $query->orders; + + array_unshift($orders, ['column' => $query->groupLimit['column'], 'direction' => 'asc']); + + $query->orders = $orders; + + $components = $this->compileComponents($query); + + $sql = $this->concatenate($components); + + $from = '(select @laravel_row := 0, @laravel_partition := 0) as laravel_vars, ('.$sql.') as laravel_table'; + + $sql = 'select laravel_table.*'.$partition.' from '.$from.' having laravel_row <= '.$limit; + + if (isset($offset)) { + $sql .= ' and laravel_row > '.(int) $offset; + } + + return $sql.' order by laravel_row'; + } +} diff --git a/src/Grammars/Traits/CompilesPostgresGroupLimit.php b/src/Grammars/Traits/CompilesPostgresGroupLimit.php new file mode 100644 index 0000000..5da7850 --- /dev/null +++ b/src/Grammars/Traits/CompilesPostgresGroupLimit.php @@ -0,0 +1,8 @@ +getConnection()->getReadPdo()->getAttribute(PDO::ATTR_SERVER_VERSION); + + if (version_compare($version, '3.25.0') >= 0) { + return $this->compileGroupLimitParent($query); + } + + $query->groupLimit = null; + + return $this->compileSelect($query); + } +} diff --git a/src/Grammars/Traits/CompilesSqlServerGroupLimit.php b/src/Grammars/Traits/CompilesSqlServerGroupLimit.php new file mode 100644 index 0000000..e6375f9 --- /dev/null +++ b/src/Grammars/Traits/CompilesSqlServerGroupLimit.php @@ -0,0 +1,26 @@ +compileRowNumberParent($partition, $orders); + } +} diff --git a/src/HasEagerLimit.php b/src/HasEagerLimit.php index 8148b23..255a46e 100644 --- a/src/HasEagerLimit.php +++ b/src/HasEagerLimit.php @@ -3,24 +3,17 @@ namespace Staudenmeir\EloquentEagerLimit; use Illuminate\Database\Connection; -use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\Model; use RuntimeException; use Staudenmeir\EloquentEagerLimit\Grammars\MySqlGrammar; use Staudenmeir\EloquentEagerLimit\Grammars\PostgresGrammar; use Staudenmeir\EloquentEagerLimit\Grammars\SQLiteGrammar; use Staudenmeir\EloquentEagerLimit\Grammars\SqlServerGrammar; -use Staudenmeir\EloquentEagerLimit\Relations\BelongsToMany; -use Staudenmeir\EloquentEagerLimit\Relations\HasMany; -use Staudenmeir\EloquentEagerLimit\Relations\HasManyThrough; -use Staudenmeir\EloquentEagerLimit\Relations\HasOne; -use Staudenmeir\EloquentEagerLimit\Relations\HasOneThrough; -use Staudenmeir\EloquentEagerLimit\Relations\MorphMany; -use Staudenmeir\EloquentEagerLimit\Relations\MorphOne; -use Staudenmeir\EloquentEagerLimit\Relations\MorphToMany; +use Staudenmeir\EloquentEagerLimit\Traits\HasEagerLimitRelationships; trait HasEagerLimit { + use HasEagerLimitRelationships; + /** * Get a new query builder instance for the connection. * @@ -62,165 +55,4 @@ protected function getQueryGrammar(Connection $connection) throw new RuntimeException('This database is not supported.'); // @codeCoverageIgnore } - - /** - * Instantiate a new HasOne relationship. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Model $parent - * @param string $foreignKey - * @param string $localKey - * @return \Illuminate\Database\Eloquent\Relations\HasOne - */ - protected function newHasOne(Builder $query, Model $parent, $foreignKey, $localKey) - { - return new HasOne($query, $parent, $foreignKey, $localKey); - } - - /** - * Instantiate a new HasOneThrough relationship. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Model $farParent - * @param \Illuminate\Database\Eloquent\Model $throughParent - * @param string $firstKey - * @param string $secondKey - * @param string $localKey - * @param string $secondLocalKey - * @return \Illuminate\Database\Eloquent\Relations\HasOneThrough - */ - protected function newHasOneThrough(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey) - { - return new HasOneThrough($query, $farParent, $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey); - } - - /** - * Instantiate a new MorphOne relationship. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Model $parent - * @param string $type - * @param string $id - * @param string $localKey - * @return \Illuminate\Database\Eloquent\Relations\MorphOne - */ - protected function newMorphOne(Builder $query, Model $parent, $type, $id, $localKey) - { - return new MorphOne($query, $parent, $type, $id, $localKey); - } - - /** - * Instantiate a new HasMany relationship. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Model $parent - * @param string $foreignKey - * @param string $localKey - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - protected function newHasMany(Builder $query, Model $parent, $foreignKey, $localKey) - { - return new HasMany($query, $parent, $foreignKey, $localKey); - } - - /** - * Instantiate a new HasManyThrough relationship. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Model $farParent - * @param \Illuminate\Database\Eloquent\Model $throughParent - * @param string $firstKey - * @param string $secondKey - * @param string $localKey - * @param string $secondLocalKey - * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough - */ - protected function newHasManyThrough(Builder $query, Model $farParent, Model $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey) - { - return new HasManyThrough($query, $farParent, $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey); - } - - /** - * Instantiate a new MorphMany relationship. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Model $parent - * @param string $type - * @param string $id - * @param string $localKey - * @return \Illuminate\Database\Eloquent\Relations\MorphMany - */ - protected function newMorphMany(Builder $query, Model $parent, $type, $id, $localKey) - { - return new MorphMany($query, $parent, $type, $id, $localKey); - } - - /** - * Instantiate a new BelongsToMany relationship. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Model $parent - * @param string $table - * @param string $foreignPivotKey - * @param string $relatedPivotKey - * @param string $parentKey - * @param string $relatedKey - * @param string $relationName - * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany - */ - protected function newBelongsToMany( - Builder $query, - Model $parent, - $table, - $foreignPivotKey, - $relatedPivotKey, - $parentKey, - $relatedKey, - $relationName = null - ) - { - return new BelongsToMany($query, $parent, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $relationName); - } - - /** - * Instantiate a new MorphToMany relationship. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Model $parent - * @param string $name - * @param string $table - * @param string $foreignPivotKey - * @param string $relatedPivotKey - * @param string $parentKey - * @param string $relatedKey - * @param string $relationName - * @param bool $inverse - * @return \Illuminate\Database\Eloquent\Relations\MorphToMany - */ - protected function newMorphToMany( - Builder $query, - Model $parent, - $name, - $table, - $foreignPivotKey, - $relatedPivotKey, - $parentKey, - $relatedKey, - $relationName = null, - $inverse = false - ) - { - return new MorphToMany( - $query, - $parent, - $name, - $table, - $foreignPivotKey, - $relatedPivotKey, - $parentKey, - $relatedKey, - $relationName, - $inverse - ); - } } diff --git a/src/Traits/BuildsGroupLimitQueries.php b/src/Traits/BuildsGroupLimitQueries.php new file mode 100644 index 0000000..f3da469 --- /dev/null +++ b/src/Traits/BuildsGroupLimitQueries.php @@ -0,0 +1,58 @@ += 0) { + $this->groupLimit = compact('value', 'column'); + } + + return $this; + } + + /** + * Execute the query as a "select" statement. + * + * @param array $columns + * @return \Illuminate\Support\Collection + */ + public function get($columns = ['*']) + { + $items = parent::get($columns); + + if (!$this->groupLimit) { + return $items; + } + + $column = last(explode('.', $this->groupLimit['column'])); + + $keys = [ + 'laravel_row', + '@laravel_partition := '.$this->grammar->wrap($column), + '@laravel_partition := '.$this->grammar->wrap('pivot_'.$column), + ]; + + foreach ($items as $item) { + unset($item->{$keys[0]}, $item->{$keys[1]}, $item->{$keys[2]}); + } + + return $items; + } +} diff --git a/src/Traits/HasEagerLimitRelationships.php b/src/Traits/HasEagerLimitRelationships.php new file mode 100644 index 0000000..de10615 --- /dev/null +++ b/src/Traits/HasEagerLimitRelationships.php @@ -0,0 +1,176 @@ +