Skip to content

Commit

Permalink
Merge branch 'mongodb:4.1' into 4.1
Browse files Browse the repository at this point in the history
  • Loading branch information
hans-thomas committed Oct 31, 2023
2 parents 3201ece + 698711c commit 823d801
Show file tree
Hide file tree
Showing 15 changed files with 526 additions and 25 deletions.
33 changes: 33 additions & 0 deletions src/Eloquent/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,22 @@

namespace MongoDB\Laravel\Eloquent;

use Brick\Math\BigDecimal;
use Brick\Math\Exception\MathException as BrickMathException;
use Brick\Math\RoundingMode;
use DateTimeInterface;
use Illuminate\Contracts\Queue\QueueableCollection;
use Illuminate\Contracts\Queue\QueueableEntity;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\Casts\Json;
use Illuminate\Database\Eloquent\Model as BaseModel;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Arr;
use Illuminate\Support\Exceptions\MathException;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Str;
use MongoDB\BSON\Binary;
use MongoDB\BSON\Decimal128;
use MongoDB\BSON\ObjectID;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Laravel\Query\Builder as QueryBuilder;
Expand Down Expand Up @@ -211,6 +217,11 @@ public function setAttribute($key, $value)
{
$key = (string) $key;

//Add casts
if ($this->hasCast($key)) {
$value = $this->castAttribute($key, $value);
}

// Convert _id to ObjectID.
if ($key === '_id' && is_string($value)) {
$builder = $this->newBaseQueryBuilder();
Expand All @@ -237,6 +248,28 @@ public function setAttribute($key, $value)
return parent::setAttribute($key, $value);
}

/** @inheritdoc */
protected function asDecimal($value, $decimals)
{
try {
$value = (string) BigDecimal::of((string) $value)->toScale((int) $decimals, RoundingMode::HALF_UP);

return new Decimal128($value);
} catch (BrickMathException $e) {
throw new MathException('Unable to cast value to a decimal.', previous: $e);
}
}

/** @inheritdoc */
public function fromJson($value, $asObject = false)
{
if (! is_string($value)) {
$value = Json::encode($value ?? '');
}

return Json::decode($value ?? '', ! $asObject);
}

/** @inheritdoc */
public function attributesToArray()
{
Expand Down
3 changes: 1 addition & 2 deletions src/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
use function is_callable;
use function is_float;
use function is_int;
use function is_null;
use function is_string;
use function md5;
use function preg_match;
Expand Down Expand Up @@ -987,7 +986,7 @@ public function where($column, $operator = null, $value = null, $boolean = 'and'
throw new ArgumentCountError(sprintf('Too few arguments to function %s(%s), 1 passed and at least 2 expected when the 1st is not an array or a callable', __METHOD__, var_export($column, true)));
}

if (is_float($column) || is_bool($column) || is_null($column)) {
if (is_float($column) || is_bool($column) || $column === null) {
throw new InvalidArgumentException(sprintf('First argument of %s must be a field path as "string". Got "%s"', __METHOD__, get_debug_type($column)));
}

Expand Down
12 changes: 6 additions & 6 deletions tests/Casts/BinaryUuidTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use Generator;
use MongoDB\BSON\Binary;
use MongoDB\Laravel\Tests\Models\CastBinaryUuid;
use MongoDB\Laravel\Tests\Models\Casting;
use MongoDB\Laravel\Tests\TestCase;

use function hex2bin;
Expand All @@ -17,15 +17,15 @@ protected function setUp(): void
{
parent::setUp();

CastBinaryUuid::truncate();
Casting::truncate();
}

/** @dataProvider provideBinaryUuidCast */
public function testBinaryUuidCastModel(string $expectedUuid, string|Binary $saveUuid, Binary $queryUuid): void
{
CastBinaryUuid::create(['uuid' => $saveUuid]);
Casting::create(['uuid' => $saveUuid]);

$model = CastBinaryUuid::firstWhere('uuid', $queryUuid);
$model = Casting::firstWhere('uuid', $queryUuid);
$this->assertNotNull($model);
$this->assertSame($expectedUuid, $model->uuid);
}
Expand All @@ -43,9 +43,9 @@ public function testQueryByStringDoesNotCast(): void
{
$uuid = '0c103357-3806-48c9-a84b-867dcb625cfb';

CastBinaryUuid::create(['uuid' => $uuid]);
Casting::create(['uuid' => $uuid]);

$model = CastBinaryUuid::firstWhere('uuid', $uuid);
$model = Casting::firstWhere('uuid', $uuid);
$this->assertNull($model);
}
}
54 changes: 54 additions & 0 deletions tests/Casts/BooleanTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

namespace MongoDB\Laravel\Tests\Casts;

use MongoDB\Laravel\Tests\Models\Casting;
use MongoDB\Laravel\Tests\TestCase;

class BooleanTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();

Casting::truncate();
}

public function testBool(): void
{
$model = Casting::query()->create(['booleanValue' => true]);

self::assertIsBool($model->booleanValue);
self::assertSame(true, $model->booleanValue);

$model->update(['booleanValue' => false]);

self::assertIsBool($model->booleanValue);
self::assertSame(false, $model->booleanValue);

$model->update(['booleanValue' => 1]);

self::assertIsBool($model->booleanValue);
self::assertSame(true, $model->booleanValue);

$model->update(['booleanValue' => 0]);

self::assertIsBool($model->booleanValue);
self::assertSame(false, $model->booleanValue);
}

public function testBoolAsString(): void
{
$model = Casting::query()->create(['booleanValue' => '1.79']);

self::assertIsBool($model->booleanValue);
self::assertSame(true, $model->booleanValue);

$model->update(['booleanValue' => '0']);

self::assertIsBool($model->booleanValue);
self::assertSame(false, $model->booleanValue);
}
}
34 changes: 34 additions & 0 deletions tests/Casts/CollectionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace MongoDB\Laravel\Tests\Casts;

use Illuminate\Support\Collection;
use MongoDB\Laravel\Tests\Models\Casting;
use MongoDB\Laravel\Tests\TestCase;

use function collect;

class CollectionTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();

Casting::truncate();
}

public function testCollection(): void
{
$model = Casting::query()->create(['collectionValue' => ['g' => 'G-Eazy']]);

self::assertInstanceOf(Collection::class, $model->collectionValue);
self::assertEquals(collect(['g' => 'G-Eazy']), $model->collectionValue);

$model->update(['collectionValue' => ['Dont let me go' => 'Even the longest of nights turn days']]);

self::assertInstanceOf(Collection::class, $model->collectionValue);
self::assertEquals(collect(['Dont let me go' => 'Even the longest of nights turn days']), $model->collectionValue);
}
}
64 changes: 64 additions & 0 deletions tests/Casts/DateTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

namespace MongoDB\Laravel\Tests\Casts;

use DateTime;
use Illuminate\Support\Carbon;
use MongoDB\Laravel\Tests\Models\Casting;
use MongoDB\Laravel\Tests\TestCase;

use function now;

class DateTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();

Casting::truncate();
}

public function testDate(): void
{
$model = Casting::query()->create(['dateField' => now()]);

self::assertInstanceOf(Carbon::class, $model->dateField);
self::assertEquals(now()->startOfDay()->format('Y-m-d H:i:s'), (string) $model->dateField);

$model->update(['dateField' => now()->subDay()]);

self::assertInstanceOf(Carbon::class, $model->dateField);
self::assertEquals(now()->subDay()->startOfDay()->format('Y-m-d H:i:s'), (string) $model->dateField);

$model->update(['dateField' => new DateTime()]);

self::assertInstanceOf(Carbon::class, $model->dateField);
self::assertEquals(now()->startOfDay()->format('Y-m-d H:i:s'), (string) $model->dateField);

$model->update(['dateField' => (new DateTime())->modify('-1 day')]);

self::assertInstanceOf(Carbon::class, $model->dateField);
self::assertEquals(now()->subDay()->startOfDay()->format('Y-m-d H:i:s'), (string) $model->dateField);
}

public function testDateAsString(): void
{
$model = Casting::query()->create(['dateField' => '2023-10-29']);

self::assertInstanceOf(Carbon::class, $model->dateField);
self::assertEquals(
Carbon::createFromTimestamp(1698577443)->startOfDay()->format('Y-m-d H:i:s'),
(string) $model->dateField,
);

$model->update(['dateField' => '2023-10-28']);

self::assertInstanceOf(Carbon::class, $model->dateField);
self::assertEquals(
Carbon::createFromTimestamp(1698577443)->subDay()->startOfDay()->format('Y-m-d H:i:s'),
(string) $model->dateField,
);
}
}
53 changes: 53 additions & 0 deletions tests/Casts/DatetimeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

namespace MongoDB\Laravel\Tests\Casts;

use Illuminate\Support\Carbon;
use MongoDB\Laravel\Tests\Models\Casting;
use MongoDB\Laravel\Tests\TestCase;

use function now;

class DatetimeTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();

Casting::truncate();
}

public function testDate(): void
{
$model = Casting::query()->create(['datetimeField' => now()]);

self::assertInstanceOf(Carbon::class, $model->datetimeField);
self::assertEquals(now()->format('Y-m-d H:i:s'), (string) $model->datetimeField);

$model->update(['datetimeField' => now()->subDay()]);

self::assertInstanceOf(Carbon::class, $model->datetimeField);
self::assertEquals(now()->subDay()->format('Y-m-d H:i:s'), (string) $model->datetimeField);
}

public function testDateAsString(): void
{
$model = Casting::query()->create(['datetimeField' => '2023-10-29']);

self::assertInstanceOf(Carbon::class, $model->datetimeField);
self::assertEquals(
Carbon::createFromTimestamp(1698577443)->startOfDay()->format('Y-m-d H:i:s'),
(string) $model->datetimeField,
);

$model->update(['datetimeField' => '2023-10-28 11:04:03']);

self::assertInstanceOf(Carbon::class, $model->datetimeField);
self::assertEquals(
Carbon::createFromTimestamp(1698577443)->subDay()->format('Y-m-d H:i:s'),
(string) $model->datetimeField,
);
}
}
45 changes: 45 additions & 0 deletions tests/Casts/DecimalTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace MongoDB\Laravel\Tests\Casts;

use MongoDB\BSON\Decimal128;
use MongoDB\Laravel\Tests\Models\Casting;
use MongoDB\Laravel\Tests\TestCase;

class DecimalTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();

Casting::truncate();
}

public function testDecimal(): void
{
$model = Casting::query()->create(['decimalNumber' => 100.99]);

self::assertInstanceOf(Decimal128::class, $model->decimalNumber);
self::assertEquals('100.99', $model->decimalNumber);

$model->update(['decimalNumber' => 9999.9]);

self::assertInstanceOf(Decimal128::class, $model->decimalNumber);
self::assertEquals('9999.90', $model->decimalNumber);
}

public function testDecimalAsString(): void
{
$model = Casting::query()->create(['decimalNumber' => '120.79']);

self::assertInstanceOf(Decimal128::class, $model->decimalNumber);
self::assertEquals('120.79', $model->decimalNumber);

$model->update(['decimalNumber' => '795']);

self::assertInstanceOf(Decimal128::class, $model->decimalNumber);
self::assertEquals('795.00', $model->decimalNumber);
}
}

0 comments on commit 823d801

Please sign in to comment.