diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2cbb64d..e13b29b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,24 +64,21 @@ jobs: strategy: matrix: - php: [8.1, '8.0', 7.4, 7.3] + php: ['8.0', 8.1, 8.2] lib: - - { laravel: ^9.0, eager: ^1.7 } - - { laravel: ^8.0, eager: ^1.6 } - - { laravel: ^7.0, eager: ^1.5 } - - { laravel: ^6.0, eager: ^1.4 } +# - { laravel: ^11.0 } + - { laravel: ^10.0 } + - { laravel: ^9.0 } flags: [--prefer-lowest, ''] db: [mysql-5.7, mysql-8.0, pgsql, sqlite, sqlsrv] exclude: + - { php: 8.0, lib: { laravel: ^10.0 } } +# - { php: 8.0, lib: { laravel: ^11.0 } } - { php: 8.1, flags: --prefer-lowest } # Error about #[\ReturnTypeWillChange] - - { php: 8.1, lib: { laravel: ^7.0, eager: ^1.5 } } - - { php: 8.1, lib: { laravel: ^6.0, eager: ^1.4 } } - - { php: 7.4, lib: { laravel: ^9.0, eager: ^1.7 } } - - { php: 7.3, lib: { laravel: ^9.0, eager: ^1.7 } } - - { php: 7.3, lib: { laravel: ^6.0, eager: ^1.4 }, db: sqlsrv } # Unknown Error about Carbon +# - { php: 8.1, lib: { laravel: ^11.0 } } steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -89,17 +86,6 @@ jobs: php-version: ${{ matrix.php }} coverage: xdebug - - name: Set up MySQL 8.0 - if: matrix.db == 'mysql-8.0' - run: | - mysql \ - --host=127.0.0.1 \ - --port=3307 \ - --user=root \ - --password=testing <<< " - ALTER USER 'testing'@'%' IDENTIFIED WITH mysql_native_password BY 'testing'; - " - - name: Set up SQLServer if: matrix.db == 'sqlsrv' run: | @@ -113,16 +99,15 @@ jobs: - name: Adjust Package Versions run: | composer require "laravel/framework:${{ matrix.lib.laravel }}" --dev --no-update ${{ matrix.flags }} - composer require "staudenmeir/eloquent-eager-limit:${{ matrix.lib.eager }}" --no-update ${{ matrix.flags }} composer update ${{ matrix.flags }} - name: Show Important Package Versions id: package-versions run: | composer show | grep -E '(^awobaz/compoships)|(^staudenmeir/eloquent-eager-limit)|(^laravel/framework)|(^orchestra/testbench)|(^phpunit/phpunit)' - echo '::set-output name=compoships::'$(composer show | grep -E '^(awobaz/compoships)' | awk '{print $2}') - echo '::set-output name=eloquent-eager-limit::'$(composer show | grep -E '^(staudenmeir/eloquent-eager-limit)' | awk '{print $2}') - echo '::set-output name=laravel::'$(composer show | grep -E '^(laravel/framework)' | awk '{print $2}') + echo 'name=compoships::'$(composer show | grep -E '^(awobaz/compoships)' | awk '{print $2}') > "$GITHUB_OUTPUT" + echo 'name=eloquent-eager-limit::'$(composer show | grep -E '^(staudenmeir/eloquent-eager-limit)' | awk '{print $2}') > "$GITHUB_OUTPUT" + echo 'name=laravel::'$(composer show | grep -E '^(laravel/framework)' | awk '{print $2}') > "$GITHUB_OUTPUT" - name: Prepare Database Config run: mv tests/config/database.github.php tests/config/database.php diff --git a/.gitignore b/.gitignore index cf14100..83640ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ /vendor/ /.idea/ .php_cs.cache -.phpunit.result.cache +/.phpunit.cache/ composer.lock diff --git a/README.md b/README.md index fc8f989..464a577 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ ## Requirements -- PHP: `^7.3 || ^8.0` -- Laravel: `^6.0 || ^7.0 || ^8.0 || ^9.0` +- PHP: `^8.0` +- Laravel: `^9.0 || ^10.0` - [Compoships](https://github.com/topclaudy/compoships): `^2.0.4` -- [Eloquent Eager Limit](https://github.com/staudenmeir/eloquent-eager-limit): `^1.4` +- [Eloquent Eager Limit](https://github.com/staudenmeir/eloquent-eager-limit): `^1.7.1` ## Installing diff --git a/composer.json b/composer.json index 02281ef..a831f4d 100644 --- a/composer.json +++ b/composer.json @@ -31,16 +31,17 @@ } }, "require": { - "php": "^7.3 || ^8.0", - "illuminate/database": "^6.0 || ^7.0 || ^8.0 || ^9.0", - "illuminate/support": "^6.0 || ^7.0 || ^8.0 || ^9.0", + "php": "^8.0", + "illuminate/database": "^9.0 || ^10.0 || ^11.0", + "illuminate/support": "^9.0 || ^10.0 || ^11.0", "awobaz/compoships": "^2.0.4", - "staudenmeir/eloquent-eager-limit": "^1.4" + "staudenmeir/eloquent-eager-limit": "^1.7.1" }, "require-dev": { "orchestra/testbench": "*", - "orchestra/testbench-core": "^4.9 || ^5.9 || >=6.6", + "orchestra/testbench-core": ">=7.0", "phpunit/phpunit": ">=9.5", + "nesbot/carbon": "^2.62.1", "ext-json": "*" }, "minimum-stability": "dev", diff --git a/phpunit.xml b/phpunit.xml index f3db8cf..e0e3371 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,22 +1,13 @@ - + + + + src + + ./tests/ - - - src - - diff --git a/src/Database/Query/Builder.php b/src/Database/Query/Builder.php index 671e5fc..e29f8b6 100644 --- a/src/Database/Query/Builder.php +++ b/src/Database/Query/Builder.php @@ -3,69 +3,9 @@ namespace Mpyw\ComposhipsEagerLimit\Database\Query; use Awobaz\Compoships\Database\Query\Builder as ComposhipsBuilder; +use Mpyw\ComposhipsEagerLimit\Database\Query\Concerns\BuildsGroupLimitQueriesByMultipleColumnPartition; -/** - * Class Builder - * - * @mixin \Staudenmeir\EloquentEagerLimit\Builder - */ class Builder extends ComposhipsBuilder { - /** - * 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; - } - - $keys = ['laravel_row']; - - if (is_array($this->groupLimit['column'])) { - foreach ($this->groupLimit['column'] as $i => $column) { - $keys[] = "@laravel_partition_$i := " . $this->grammar->wrap(last(explode('.', $column))); - $keys[] = "@laravel_partition_$i := " . $this->grammar->wrap('pivot_' . last(explode('.', $column))); - } - } else { - $keys[] = '@laravel_partition := ' . $this->grammar->wrap(last(explode('.', $this->groupLimit['column']))); - $keys[] = '@laravel_partition := ' . $this->grammar->wrap('pivot_' . last(explode('.', $this->groupLimit['column']))); - } - - foreach ($items as $item) { - foreach ($keys as $key) { - unset($item->$key); - } - } - - return $items; - } + use BuildsGroupLimitQueriesByMultipleColumnPartition; } diff --git a/src/Database/Query/Concerns/BuildsGroupLimitQueriesByMultipleColumnPartition.php b/src/Database/Query/Concerns/BuildsGroupLimitQueriesByMultipleColumnPartition.php new file mode 100644 index 0000000..e42298e --- /dev/null +++ b/src/Database/Query/Concerns/BuildsGroupLimitQueriesByMultipleColumnPartition.php @@ -0,0 +1,50 @@ +groupLimit) { + return $items; + } + + $keys = ['laravel_row']; + + if (is_array($this->groupLimit['column'])) { + foreach ($this->groupLimit['column'] as $i => $column) { + $keys[] = "@laravel_partition_$i := " . $this->grammar->wrap(last(explode('.', $column))); + $keys[] = "@laravel_partition_$i := " . $this->grammar->wrap('pivot_' . last(explode('.', $column))); + } + } else { + $keys[] = '@laravel_partition := ' . $this->grammar->wrap(last(explode('.', $this->groupLimit['column']))); + $keys[] = '@laravel_partition := ' . $this->grammar->wrap('pivot_' . last(explode('.', $this->groupLimit['column']))); + } + + foreach ($items as $item) { + foreach ($keys as $key) { + unset($item->$key); + } + } + + return $items; + } +} \ No newline at end of file diff --git a/src/Database/Query/Grammar/Concerns/CompilesGroupLimitByMultipleColumnPartition.php b/src/Database/Query/Grammar/Concerns/CompilesGroupLimitByMultipleColumnPartition.php index 43298c7..8907a90 100644 --- a/src/Database/Query/Grammar/Concerns/CompilesGroupLimitByMultipleColumnPartition.php +++ b/src/Database/Query/Grammar/Concerns/CompilesGroupLimitByMultipleColumnPartition.php @@ -2,11 +2,15 @@ namespace Mpyw\ComposhipsEagerLimit\Database\Query\Grammar\Concerns; +use Staudenmeir\EloquentEagerLimit\Grammars\Traits\CompilesGroupLimit; + /** * Trait CompilesGroupLimitByMultipleColumnPartition */ trait CompilesGroupLimitByMultipleColumnPartition { + use CompilesGroupLimit; + /** * Compile a row number clause. * diff --git a/src/Database/Query/Grammar/Concerns/CompilesGroupLimitByMultipleColumnPartitionWithInternalRenameAsParent.php b/src/Database/Query/Grammar/Concerns/CompilesGroupLimitByMultipleColumnPartitionWithInternalRenameAsParent.php new file mode 100644 index 0000000..f5a56b6 --- /dev/null +++ b/src/Database/Query/Grammar/Concerns/CompilesGroupLimitByMultipleColumnPartitionWithInternalRenameAsParent.php @@ -0,0 +1,15 @@ +groupLimit['value'] + (int)$query->offset; + $offset = $query->offset; + + $query->offset = null; + $query->orders = (array)$query->orders; + + $partitionExpressions = []; + $partitionAssignments = []; + $partitionInitializations = []; + $partitionOrders = []; + + if (is_array($query->groupLimit['column'])) { + foreach ($query->groupLimit['column'] as $i => $column) { + $wrappedColumn = $this->wrap(last(explode('.', $column))); + + $partitionExpressions[] = "@laravel_partition_$i = $wrappedColumn"; + $partitionAssignments[] = "@laravel_partition_$i := $wrappedColumn"; + $partitionInitializations[] = "@laravel_partition_$i := 0"; + $partitionOrders[] = ['column' => $column, 'direction' => 'asc']; + } + } else { + $wrappedColumn = $this->wrap(last(explode('.', $query->groupLimit['column']))); + + $partitionExpressions[] = "@laravel_partition = $wrappedColumn"; + $partitionAssignments[] = "@laravel_partition := $wrappedColumn"; + $partitionInitializations[] = '@laravel_partition := 0'; + $partitionOrders[] = ['column' => $query->groupLimit['column'], 'direction' => 'asc']; + } + + $partition = sprintf( + ', @laravel_row := if(%s, @laravel_row + 1, 1) as laravel_row, %s', + implode(' and ', $partitionExpressions), + implode(', ', $partitionAssignments) + ); + + array_splice($query->orders, 0, 0, $partitionOrders); + + $components = $this->compileComponents($query); + + $sql = $this->concatenate($components); + + $from = sprintf( + '(select @laravel_row := 0, %s) as laravel_vars, (%s) as laravel_table', + implode(', ', $partitionInitializations), + $sql + ); + + $sql = 'select laravel_table.*' . $partition . ' from ' . $from . ' having laravel_row <= ' . $limit; + + if ($offset !== null) { + $sql .= ' and laravel_row > ' . (int)$offset; + } + + return $sql . ' order by laravel_row'; + } +} diff --git a/src/Database/Query/Grammar/Concerns/CompilesPostgresGroupLimitByMultipleColumnPartition.php b/src/Database/Query/Grammar/Concerns/CompilesPostgresGroupLimitByMultipleColumnPartition.php new file mode 100644 index 0000000..1f3ceef --- /dev/null +++ b/src/Database/Query/Grammar/Concerns/CompilesPostgresGroupLimitByMultipleColumnPartition.php @@ -0,0 +1,15 @@ +groupLimit['value'] + (int)$query->offset; - $offset = $query->offset; - - $query->offset = null; - $query->orders = (array)$query->orders; - - $partitionExpressions = []; - $partitionAssignments = []; - $partitionInitializations = []; - $partitionOrders = []; - - if (is_array($query->groupLimit['column'])) { - foreach ($query->groupLimit['column'] as $i => $column) { - $wrappedColumn = $this->wrap(last(explode('.', $column))); - - $partitionExpressions[] = "@laravel_partition_$i = $wrappedColumn"; - $partitionAssignments[] = "@laravel_partition_$i := $wrappedColumn"; - $partitionInitializations[] = "@laravel_partition_$i := 0"; - $partitionOrders[] = ['column' => $column, 'direction' => 'asc']; - } - } else { - $wrappedColumn = $this->wrap(last(explode('.', $query->groupLimit['column']))); - - $partitionExpressions[] = "@laravel_partition = $wrappedColumn"; - $partitionAssignments[] = "@laravel_partition := $wrappedColumn"; - $partitionInitializations[] = '@laravel_partition := 0'; - $partitionOrders[] = ['column' => $query->groupLimit['column'], 'direction' => 'asc']; - } - - $partition = sprintf( - ', @laravel_row := if(%s, @laravel_row + 1, 1) as laravel_row, %s', - implode(' and ', $partitionExpressions), - implode(', ', $partitionAssignments) - ); - - array_splice($query->orders, 0, 0, $partitionOrders); - - $components = $this->compileComponents($query); - - $sql = $this->concatenate($components); - - $from = sprintf( - '(select @laravel_row := 0, %s) as laravel_vars, (%s) as laravel_table', - implode(', ', $partitionInitializations), - $sql - ); - - $sql = 'select laravel_table.*' . $partition . ' from ' . $from . ' having laravel_row <= ' . $limit; - - if ($offset !== null) { - $sql .= ' and laravel_row > ' . (int)$offset; - } - - return $sql . ' order by laravel_row'; - } + use Concerns\CompilesMySqlGroupLimitByMultipleColumnPartition; } diff --git a/src/Database/Query/Grammar/PostgresGrammar.php b/src/Database/Query/Grammar/PostgresGrammar.php index 4e60e77..c8f75d3 100644 --- a/src/Database/Query/Grammar/PostgresGrammar.php +++ b/src/Database/Query/Grammar/PostgresGrammar.php @@ -6,5 +6,5 @@ class PostgresGrammar extends EagerLimitPostgresGrammar { - use Concerns\CompilesGroupLimitByMultipleColumnPartition; + use Concerns\CompilesPostgresGroupLimitByMultipleColumnPartition; } diff --git a/src/Database/Query/Grammar/SQLiteGrammar.php b/src/Database/Query/Grammar/SQLiteGrammar.php index 6fd762c..5e3e614 100644 --- a/src/Database/Query/Grammar/SQLiteGrammar.php +++ b/src/Database/Query/Grammar/SQLiteGrammar.php @@ -6,5 +6,5 @@ class SQLiteGrammar extends EagerLimitSQLiteGrammar { - use Concerns\CompilesGroupLimitByMultipleColumnPartition; + use Concerns\CompilesSQLiteGroupLimitByMultipleColumnPartition; } diff --git a/src/Database/Query/Grammar/SqlServerGrammar.php b/src/Database/Query/Grammar/SqlServerGrammar.php index 0c5f88b..5144e30 100644 --- a/src/Database/Query/Grammar/SqlServerGrammar.php +++ b/src/Database/Query/Grammar/SqlServerGrammar.php @@ -6,23 +6,5 @@ class SqlServerGrammar extends EagerLimitSqlServerGrammar { - use Concerns\CompilesGroupLimitByMultipleColumnPartition { - 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 Concerns\CompilesSqlServerGroupLimitByMultipleColumnPartition; }