Skip to content

Commit 1f124f5

Browse files
committed
feat: add ExtractYear time function
1 parent 51c3c25 commit 1f124f5

File tree

4 files changed

+75
-0
lines changed

4 files changed

+75
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
### Added
10+
* `ExtractYear` time function to extract the year from date/datetime columns
11+
812
## [1.5.0] - 2025-02-14
913
### Added
1014
* Laravel 12 support

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,12 +360,25 @@ Schema::table('users', function (Blueprint $table): void {
360360
361361
#### Time
362362
```php
363+
use Tpetry\QueryExpressions\Function\Time\ExtractYear;
363364
use Tpetry\QueryExpressions\Function\Time\Now;
364365
use Tpetry\QueryExpressions\Function\Time\TimestampBin;
365366

367+
new ExtractYear(string|Expression $column);
366368
new Now();
367369
new TimestampBin(string|Expression $expression, DateInterval $step, ?DateTimeInterface $origin = null);
368370

371+
// Extract year for filtering or grouping
372+
User::select([
373+
new Alias(new ExtractYear('created_at'), 'registration_year'),
374+
new Count('*'),
375+
])->groupBy(new ExtractYear('created_at'))->get();
376+
377+
// Use with CountFilter for year-based aggregations
378+
Movie::select([
379+
new Alias(new CountFilter(new Equal(new ExtractYear('released_at'), new Value(2024))), 'released_2024'),
380+
])->get();
381+
369382
BlogVisit::select([
370383
'url',
371384
new TimestampBin('created_at', DateInterval::createFromDateString('5 minutes')),

src/Function/Time/ExtractYear.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tpetry\QueryExpressions\Function\Time;
6+
7+
use Illuminate\Contracts\Database\Query\Expression;
8+
use Illuminate\Database\Grammar;
9+
use Tpetry\QueryExpressions\Concerns\IdentifiesDriver;
10+
use Tpetry\QueryExpressions\Concerns\StringizeExpression;
11+
12+
class ExtractYear implements Expression
13+
{
14+
use IdentifiesDriver;
15+
use StringizeExpression;
16+
17+
public function __construct(
18+
private readonly string|Expression $column,
19+
) {}
20+
21+
public function getValue(Grammar $grammar): string
22+
{
23+
$column = $this->stringize($grammar, $this->column);
24+
25+
return match ($this->identify($grammar)) {
26+
'mariadb', 'mysql', 'sqlsrv' => "year({$column})",
27+
'pgsql' => "extract(year from {$column})::int",
28+
'sqlite' => "cast(strftime('%Y', {$column}) as integer)",
29+
};
30+
}
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Illuminate\Database\Query\Expression;
6+
use Illuminate\Database\Schema\Blueprint;
7+
use Tpetry\QueryExpressions\Function\Time\ExtractYear;
8+
9+
it('can extract the year from a column')
10+
->expect(new ExtractYear('val'))
11+
->toBeExecutable(function (Blueprint $table) {
12+
$table->date('val');
13+
})
14+
->toBeMysql('year(`val`)')
15+
->toBePgsql('extract(year from "val")::int')
16+
->toBeSqlite('cast(strftime(\'%Y\', "val") as integer)')
17+
->toBeSqlsrv('year([val])');
18+
19+
it('can extract the year from an expression')
20+
->expect(new ExtractYear(new Expression('current_date')))
21+
->toBeExecutable(function (Blueprint $table) {
22+
$table->date('val');
23+
})
24+
->toBeMysql('year(current_date)')
25+
->toBePgsql('extract(year from current_date)::int')
26+
->toBeSqlite('cast(strftime(\'%Y\', current_date) as integer)')
27+
->toBeSqlsrv('year(current_date)');

0 commit comments

Comments
 (0)