diff --git a/CHANGELOG.md b/CHANGELOG.md index 09ddac4..934bf28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Added +* `ExtractYear` time function to extract the year from date/datetime columns + ## [1.5.0] - 2025-02-14 ### Added * Laravel 12 support diff --git a/README.md b/README.md index 49c4222..91db21d 100644 --- a/README.md +++ b/README.md @@ -360,12 +360,25 @@ Schema::table('users', function (Blueprint $table): void { #### Time ```php +use Tpetry\QueryExpressions\Function\Time\ExtractYear; use Tpetry\QueryExpressions\Function\Time\Now; use Tpetry\QueryExpressions\Function\Time\TimestampBin; +new ExtractYear(string|Expression $column); new Now(); new TimestampBin(string|Expression $expression, DateInterval $step, ?DateTimeInterface $origin = null); +// Extract year for filtering or grouping +User::select([ + new Alias(new ExtractYear('created_at'), 'registration_year'), + new Count('*'), +])->groupBy(new ExtractYear('created_at'))->get(); + +// Use with CountFilter for year-based aggregations +Movie::select([ + new Alias(new CountFilter(new Equal(new ExtractYear('released_at'), new Value(2024))), 'released_2024'), +])->get(); + BlogVisit::select([ 'url', new TimestampBin('created_at', DateInterval::createFromDateString('5 minutes')), diff --git a/src/Function/Time/ExtractYear.php b/src/Function/Time/ExtractYear.php new file mode 100644 index 0000000..9490c42 --- /dev/null +++ b/src/Function/Time/ExtractYear.php @@ -0,0 +1,31 @@ +stringize($grammar, $this->column); + + return match ($this->identify($grammar)) { + 'mariadb', 'mysql', 'sqlsrv' => "year({$column})", + 'pgsql' => "extract(year from {$column})::int", + 'sqlite' => "cast(strftime('%Y', {$column}) as integer)", + }; + } +} diff --git a/tests/Function/Time/ExtractYearTest.php b/tests/Function/Time/ExtractYearTest.php new file mode 100644 index 0000000..cbbfad2 --- /dev/null +++ b/tests/Function/Time/ExtractYearTest.php @@ -0,0 +1,27 @@ +expect(new ExtractYear('val')) + ->toBeExecutable(function (Blueprint $table) { + $table->date('val'); + }) + ->toBeMysql('year(`val`)') + ->toBePgsql('extract(year from "val")::int') + ->toBeSqlite('cast(strftime(\'%Y\', "val") as integer)') + ->toBeSqlsrv('year([val])'); + +it('can extract the year from an expression') + ->expect(new ExtractYear(new Expression('current_date'))) + ->toBeExecutable(function (Blueprint $table) { + $table->date('val'); + }) + ->toBeMysql('year(current_date)') + ->toBePgsql('extract(year from current_date)::int') + ->toBeSqlite('cast(strftime(\'%Y\', current_date) as integer)') + ->toBeSqlsrv('year(current_date)');