-
Notifications
You must be signed in to change notification settings - Fork 11.4k
[12.x] feat: configure default datetime precision on per-grammar basis #51821
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[12.x] feat: configure default datetime precision on per-grammar basis #51821
Conversation
Just want your 👀 on this one if you have a sec @hafezdivandari. |
We have framework/src/Illuminate/Database/Schema/Builder.php Lines 37 to 42 in ae63a5b
I suggest to add public function dateTime($column, $precision = null)
{
$precision ??= Builder::$defaultTimePrecision;
return $this->addColumn('dateTime', $column, compact('precision'));
} No need to change anything on |
This would mean that the precision is no longer configurable on a per grammar basis (just like the I didn't like adding the logic in the I've created a fixup commit (which can be squshed later) so you can preview the changes. If we don't like it then I can pop that commit off |
f604439
to
2dc1cd1
Compare
Why per grammer and not per schema builder? You can do |
I originally put it on the grammar right underneath the
That changes the default value for all the schema Builders, not just for Postgres: |
This feels like a lot of changes for such a simple change 🙃 |
Yeah 🫤, it was more involved than I would like. Most of this is the fallout from injecting the Connection/Grammar via the Blueprint constructor instead of the I can split the refactor (injecting the Connection/Grammar into the Blueprint constructor) into a separate PR if you like, or I can update if you have other ideas on a better way to do this (being able to configure the default precision on a per-grammar basis). |
As I said on this comment, we already have properties with similar functionality on the
You may define class Builder
{
public static $defaultTimePrecision = 0;
public static function defaultTimePrecision(?int $precision)
{
static::$defaultTimePrecision = $precision;
}
}
class PostgresBuilder extends Builder
{
public static $defaultTimePrecision = 0;
} Then use it like this: PostgresBuilder::$defaultTimePrecision; // 0
MySqlBuilder::$defaultTimePrecision; // 0
PostgresBuilder::defaultTimePrecision(6);
PostgresBuilder::$defaultTimePrecision; // 6
MySqlBuilder::$defaultTimePrecision; // 0 Using connection: $connection->getSchemaBuilder()::$defaultTimePrecision; |
Ah okay, but we'd still need the connection injected into the Blueprint constructor so we have access to it when the time methods execute |
Yes, and it may be considered as a useful change IMO - Having direct access to connection instance on |
7fe952c
to
e5101b0
Compare
@hafezdivandari, I've moved the precision to the builder |
e5101b0
to
ffabb41
Compare
8d53dcd
to
6b9db74
Compare
6b9db74
to
f29df47
Compare
@hafezdivandari, it's been a hot minute, but I finally got around to rebasing this after your changes made it to |
@calebdw sorry for late response, still lgtm, thanks. PS: It may be better to summarize the changes on the PR description:
|
Thanks! |
Thank you sir! |
I might be wrong, but I think this was actually a breaking change for Postgres users. Before this change, when you specified To get
|
This added the necessary mechanics to be able to change the default precision on a per database basis. This was the sister PR to #51363 which never got merged. If you want full precision, then you should explicitly use: $table->timestampsTz(6);
// or this in a service provider
PostgresBuilder::defaultTimePrecision(6); If there's enough interest in the linked PR then I might try to reopen that against 13.x. Regarding this being a BC: this was merged into If it helps, here's a PHPStan architecture test I wrote to enforce that PHPStan Architecture Test<?php
declare(strict_types=1);
namespace Tests\Architecture\Rules;
use Illuminate\Database\Schema\Blueprint;
use Override;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Scalar\LNumber;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use Tests\Architecture\Concerns\CanGetArg;
/** @implements Rule<MethodCall> */
final class PostgresTimestampsWithTimezoneRule implements Rule
{
use CanGetArg;
/** @var list<string> */
private array $methods = ['dateTimeTz', 'softDeletesTz', 'timestampTz', 'timestampsTz'];
#[Override]
public function getNodeType(): string
{
return MethodCall::class;
}
#[Override]
public function processNode(Node $node, Scope $scope): array
{
$errors = [];
$calledMethods = $node->name instanceof Identifier
? [$node->name->toString()]
: array_map(
fn ($name) => $name->getValue(),
$scope->getType($node->name)->getConstantStrings(),
);
foreach ($scope->getType($node->var)->getObjectClassReflections() as $reflection) {
if (! $reflection->is(Blueprint::class)) {
continue;
}
foreach ($calledMethods as $method) {
if (! in_array($method, $this->methods, strict: true)) {
continue;
}
$position = $method === 'timestampsTz' ? 0 : 1;
$precision = $this->getArg($node, 'precision', $position)?->value;
if ($precision instanceof LNumber && $precision->value === 6) {
continue;
}
$errors[] = RuleErrorBuilder::message('Timestamp precision must be 6.')
->identifier('db.timestampPrecision')
->build();
}
}
return $errors;
}
} <?php
declare(strict_types=1);
namespace Tests\Architecture\Concerns;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\CallLike;
/**
* This can be removed after functionality is added to the CallLike class.
* @see https://github.com/nikic/PHP-Parser/pull/1089
*/
trait CanGetArg
{
/**
* Retrieves a specific argument from the given call-like node.
*
* Returns the named argument that matches the given `$name`, or the
* positional (unnamed) argument that exists at the given `$position`,
* otherwise, returns `null` for first-class callables or if no match is found.
*/
private function getArg(CallLike $node, string $name, int $position): ?Arg
{
if ($node->isFirstClassCallable()) {
return null;
}
foreach ($node->getArgs() as $i => $arg) {
if ($arg->unpack) {
continue;
}
if (
$arg->name?->toString() === $name
|| ($i === $position && $arg->name === null)
) {
return $arg;
}
}
return null;
}
} You can then add this to your phptstan config via: rules:
- Tests\Architecture\Rules\PostgresTimestampsWithTimezoneRule Best, |
@calebdw, I didn't say it wasn't acceptable, just that it was a BC. I don't actually recall reading anything about it, but I might've missed it. Tbh, I just want a regular
|
There wasn't anything in the upgrade docs because I didn't know about this particular case. There is no difference in postgres between |
Until Postgres introduces nanoseconds 😉 |
Lol, well we can cross that bridge if it ever happens (no need to prematurely optimize). If I reopen the linked PR then we could set the default precision to |
Hello!
Please see my previous PR (#51793) for context. This adds the following properties:
$connection
and$grammar
properties onIlluminate/Database/Schema/Blueprint
.Illuminate/Database/Schema/Blueprint
requires$connection
in constructor$defaultTimePrecision
property onIlluminate/Database/Schema/Builder
.Thanks!