Skip to content

Commit

Permalink
feat(Database): Store database like value and add null support to Flo…
Browse files Browse the repository at this point in the history
…atCast

To support isDirty logic in models we need to simulate database decimal value formatting.
By default expects 2 decimals points, Use different value using FloatCast::FourDecimals
  • Loading branch information
pionl committed Jun 23, 2023
1 parent fc332a3 commit c7b8e75
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 2 deletions.
27 changes: 25 additions & 2 deletions src/Database/Models/Casts/FloatCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,36 @@
*/
final class FloatCast implements CastsAttributes
{
// Laravel casts supports creating cast with arguments.
public const OneDecimal = self::class . ':1';

public const ThreeDecimals = self::class . ':3';

public const FourDecimals = self::class . ':4';

public function __construct(
private readonly int $decimals = 2
) {
}

public function get($model, string $key, $value, array $attributes)
{
if ($value === null || $value === '') {
return null;
}

return (float) $value;
}

public function set($model, string $key, $value, array $attributes)
public function set($model, string $key, $value, array $attributes): ?string
{
return Value::toFloat((string) $value);
$floatVal = Value::toFloat((string) $value);

if ($floatVal === null) {
return null;
}

// Simulate value from database in DECIMAL format.
return number_format($floatVal, $this->decimals, '.', '');
}
}
147 changes: 147 additions & 0 deletions tests/Feature/Database/Models/Casts/FloatCastTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Database\Models\Casts;

use Closure;
use LaraStrict\Database\Models\Casts\FloatCast;
use PHPUnit\Framework\TestCase;
use Tests\LaraStrict\Feature\Database\Models\Test;

class FloatCastTest extends TestCase
{
/**
* @return array<string|int, array{0: Closure(static):void}>
*/
public function dataEnsureThatFloatIsReturned(): array
{
return [
'decimals' => [
static fn (self $self) => $self->assertEnsureThatFloatIsReturned(value: '123.00', expected: 123.0),
],
'decimals - long' => [
static fn (self $self) => $self->assertEnsureThatFloatIsReturned(
value: '123.0002',
expected: 123.0002,
),
],
'decimals - short' => [
static fn (self $self) => $self->assertEnsureThatFloatIsReturned(value: '123.5', expected: 123.5),
],
'no decimals' => [
static fn (self $self) => $self->assertEnsureThatFloatIsReturned(value: '7', expected: 7.0),
],
'null' => [
static fn (self $self) => $self->assertEnsureThatFloatIsReturned(value: null, expected: null),
],
'empty string' => [
static fn (self $self) => $self->assertEnsureThatFloatIsReturned(value: '', expected: null),
],
];
}

/**
* @param Closure(static):void $assert
*
* @dataProvider dataEnsureThatFloatIsReturned
*/
public function testEnsureThatFloatIsReturned(Closure $assert): void
{
$assert($this);
}

public function assertEnsureThatFloatIsReturned(?string $value, ?float $expected): void
{
$cast = new FloatCast();
$this->assertSame(
expected: $expected,
actual: $cast->get(model: new Test(), key: '', value: $value, attributes: []),
);
}

/**
* @return array<string|int, array{0: Closure(static):void}>
*/
public function dataConvertFloatToModelDecimalValue(): array
{
return [
'4 decimals - 1' => [
static fn (self $self) => $self->assertConvertFloatToModelDecimalValue(
value: 123.0,
expected: '123.0000',
cast: new FloatCast(4),
),
],
'4 decimals - 2' => [
static fn (self $self) => $self->assertConvertFloatToModelDecimalValue(
value: 123.005,
expected: '123.0050',
cast: new FloatCast(4),
),
],
'4 decimals - cut' => [
static fn (self $self) => $self->assertConvertFloatToModelDecimalValue(
value: 123.00005,
expected: '123.0001',
cast: new FloatCast(4),
),
],
'2 decimals' => [
static fn (self $self) => $self->assertConvertFloatToModelDecimalValue(
value: 123.0,
expected: '123.00',
cast: new FloatCast(),
),
],
'1 decimal' => [
static fn (self $self) => $self->assertConvertFloatToModelDecimalValue(
value: 123.0,
expected: '123.0',
cast: new FloatCast(1),
),
],
'0 decimals' => [
static fn (self $self) => $self->assertConvertFloatToModelDecimalValue(
value: 123.0,
expected: '123',
cast: new FloatCast(0),
),
],
'null' => [
static fn (self $self) => $self->assertConvertFloatToModelDecimalValue(
value: null,
expected: null,
cast: new FloatCast(),
),
],
'empty string' => [
static fn (self $self) => $self->assertConvertFloatToModelDecimalValue(
value: '',
expected: null,
cast: new FloatCast(),
),
],
];
}

/**
* @param Closure(static):void $assert
* @dataProvider dataConvertFloatToModelDecimalValue
*/
public function testConvertFloatToModelDecimalValue(Closure $assert): void
{
$assert($this);
}

public function assertConvertFloatToModelDecimalValue(
float|string|null $value,
?string $expected,
FloatCast $cast
): void {
$this->assertSame(
expected: $expected,
actual: $cast->set(model: new Test(), key: '', value: $value, attributes: []),
);
}
}

0 comments on commit c7b8e75

Please sign in to comment.