Skip to content

Commit 7b8e2dc

Browse files
Merge pull request #9 from mgcostaParedes/mgcosta_feat_returnModels
feat: added feature to return instance of models
2 parents 2ab62c7 + 87a48db commit 7b8e2dc

9 files changed

Lines changed: 155 additions & 8 deletions

File tree

src/Spanner/Builder/Builder.php

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,46 @@ class Builder implements Operator, Aggregator, Fetchable
6868
*/
6969
public $wheres = [];
7070

71+
/**
72+
* The group constraints which query is targeting
73+
*
74+
* @var array
75+
*/
7176
public $groups;
7277

78+
/**
79+
* The having constraints which query is targeting
80+
*
81+
* @var array
82+
*/
7383
public $havings;
7484

85+
/**
86+
* The orders constraints which query is targeting
87+
*
88+
* @var array
89+
*/
7590
public $orders;
7691

92+
/**
93+
* The maximum number of results to return.
94+
*
95+
* @var int
96+
*/
7797
public $limit;
7898

99+
/**
100+
* The number of results to skip.
101+
*
102+
* @var int
103+
*/
79104
public $offset;
80105

106+
/**
107+
* The query union statements.
108+
*
109+
* @var array
110+
*/
81111
public $unions;
82112

83113
public $bindings = [
@@ -618,9 +648,16 @@ public function first(array $columns = ['*'])
618648

619649
public function get(array $columns = ['*']): Collection
620650
{
621-
return collect($this->onceWithColumns(Arr::wrap($columns), function () {
651+
$result = collect($this->onceWithColumns(Arr::wrap($columns), function () {
622652
return $this->runSelect();
623653
}));
654+
655+
if ($this->model) {
656+
$models = $this->hydrate($result->toArray())->all();
657+
return $this->getModel()->newCollection($models);
658+
}
659+
660+
return $result;
624661
}
625662

626663
public function find($id, $columns = ['*']): array
@@ -689,6 +726,15 @@ public function toSql(): string
689726
return $this->grammar->compile($this);
690727
}
691728

729+
protected function hydrate(array $items): Collection
730+
{
731+
$instance = $this->model->newInstance();
732+
733+
return $instance->newCollection(array_map(function ($item) use ($instance) {
734+
return $instance->newFromBuilder($item);
735+
}, $items));
736+
}
737+
692738
protected function invalidOperatorOrValue($operator, $value): bool
693739
{
694740
if (is_null($value) && is_null($operator)) {

src/Spanner/Model/Model.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ abstract class Model
3232

3333
protected $keyStrategy = 'uuid4';
3434

35-
public $strategies = ['uuid4', 'increment', false];
35+
protected $strategies = ['uuid4', 'increment', false];
3636

3737
public function getTable(): string
3838
{
@@ -56,6 +56,11 @@ public function getConnection(): Database
5656
return static::$connection;
5757
}
5858

59+
public function setConnection(Database $connection): void
60+
{
61+
static::$connection = $connection;
62+
}
63+
5964
public static function setConnectionDatabase(Database $connection)
6065
{
6166
static::$connection = $connection;
@@ -118,6 +123,28 @@ public function save(): bool
118123
return true;
119124
}
120125

126+
public function newCollection(array $models = []): Collection
127+
{
128+
return new Collection($models);
129+
}
130+
131+
public function newInstance(): self
132+
{
133+
$model = new static();
134+
$model->setTable($this->getTable());
135+
136+
return $model;
137+
}
138+
139+
public function newFromBuilder($attributes = [], $connection = null): self
140+
{
141+
$model = $this->newInstance();
142+
$model->setRawAttributes((array) $attributes);
143+
$model->setConnection($connection ?: $this->getConnection());
144+
145+
return $model;
146+
}
147+
121148
private function isValidStrategy(): bool
122149
{
123150
if (!in_array($this->keyStrategy, $this->strategies)) {

src/Spanner/Model/Strategies/IncrementStrategy.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public function generateKey(Model $model): int
1313
// find latest result on database
1414
$lastResult = $model->newQuery()->orderBy($model->getPrimaryKey(), 'desc')->first();
1515
if (!empty($lastResult)) {
16-
return $lastResult[$model->getPrimaryKey()] + 1;
16+
return $lastResult->{$model->getPrimaryKey()} + 1;
1717
}
1818
return 1;
1919
}

src/Spanner/Traits/ModelAttributes.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,18 @@ public function getAttributes(): array
2323

2424
return $attributes;
2525
}
26+
27+
public function setRawAttributes(array $attributes): void
28+
{
29+
$reflect = new ReflectionObject($this);
30+
$props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);
31+
foreach ($attributes as $key => $attribute) {
32+
$exists = array_filter($props, function ($prop) use ($key) {
33+
return $prop->name == $key && $prop->class == get_called_class();
34+
});
35+
if (!empty($exists)) {
36+
$this->{$key} = $attribute;
37+
}
38+
}
39+
}
2640
}

tests/unit/BuilderTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Google\Cloud\Spanner\Result;
77
use Google\Cloud\Spanner\Timestamp;
88
use Google\Cloud\Spanner\Transaction;
9+
use Illuminate\Support\Collection;
910
use MgCosta\Spanner\Builder\Builder;
1011
use MgCosta\Spanner\Builder\ParamCounter;
1112
use MgCosta\Spanner\Builder\Expression;
@@ -613,6 +614,8 @@ public function testShouldReturnNullWhenCallingAggregateMethodWithoutResults()
613614
$mockResult = m::mock(Result::class);
614615
$mockResult->shouldReceive('getIterator')->andReturn(new ArrayIterator([]));
615616
$this->mockedModel->shouldReceive('getPrimaryKey')->andReturn('DummyID');
617+
$this->mockedModel->shouldReceive('newInstance')->andReturnSelf();
618+
$this->mockedModel->shouldReceive('newCollection')->andReturn(new Collection([]));
616619
$this->database->shouldReceive('execute')->andReturn($mockResult);
617620
$result = $this->builder->where('age', '>', 35)->count();
618621
$this->assertEquals(null, $result);
@@ -623,6 +626,9 @@ public function testShouldReturnAnIntegerWhenCallingCountMethod()
623626
$mockResult = m::mock(Result::class);
624627
$mockResult->shouldReceive('getIterator')->andReturn(new ArrayIterator([['aggregate' => 39]]));
625628
$this->mockedModel->shouldReceive('getPrimaryKey')->andReturn('DummyID');
629+
$this->mockedModel->shouldReceive('newInstance')->andReturnSelf();
630+
$this->mockedModel->shouldReceive('newFromBuilder')->andReturnSelf();
631+
$this->mockedModel->shouldReceive('newCollection')->andReturn(new Collection($mockResult));
626632
$this->database->shouldReceive('execute')->andReturn($mockResult);
627633
$result = $this->builder->where('age', '>', 35)->count();
628634
$this->assertEquals(39, $result);
@@ -633,6 +639,9 @@ public function testShouldReturnAnIntegerWhenCallingMaxMethod()
633639
$mockResult = m::mock(Result::class);
634640
$mockResult->shouldReceive('getIterator')->andReturn(new ArrayIterator([['aggregate' => 200]]));
635641
$this->mockedModel->shouldReceive('getPrimaryKey')->andReturn('DummyID');
642+
$this->mockedModel->shouldReceive('newInstance')->andReturnSelf();
643+
$this->mockedModel->shouldReceive('newFromBuilder')->andReturnSelf();
644+
$this->mockedModel->shouldReceive('newCollection')->andReturn(new Collection($mockResult));
636645
$this->database->shouldReceive('execute')->andReturn($mockResult);
637646
$result = $this->builder->where('age', '>', 35)->max('age');
638647
$this->assertEquals(200, $result);
@@ -643,6 +652,9 @@ public function testShouldReturnAnIntegerWhenCallingMinMethod()
643652
$mockResult = m::mock(Result::class);
644653
$mockResult->shouldReceive('getIterator')->andReturn(new ArrayIterator([['aggregate' => 20]]));
645654
$this->mockedModel->shouldReceive('getPrimaryKey')->andReturn('DummyID');
655+
$this->mockedModel->shouldReceive('newInstance')->andReturnSelf();
656+
$this->mockedModel->shouldReceive('newFromBuilder')->andReturnSelf();
657+
$this->mockedModel->shouldReceive('newCollection')->andReturn(new Collection($mockResult));
646658
$this->database->shouldReceive('execute')->andReturn($mockResult);
647659
$result = $this->builder->where('age', '>', 35)->min('age');
648660
$this->assertEquals(20, $result);
@@ -653,6 +665,9 @@ public function testShouldReturnAnIntegerWhenCallingSumMethod()
653665
$mockResult = m::mock(Result::class);
654666
$mockResult->shouldReceive('getIterator')->andReturn(new ArrayIterator([['aggregate' => 333]]));
655667
$this->mockedModel->shouldReceive('getPrimaryKey')->andReturn('DummyID');
668+
$this->mockedModel->shouldReceive('newInstance')->andReturnSelf();
669+
$this->mockedModel->shouldReceive('newFromBuilder')->andReturnSelf();
670+
$this->mockedModel->shouldReceive('newCollection')->andReturn(new Collection($mockResult));
656671
$this->database->shouldReceive('execute')->andReturn($mockResult);
657672
$result = $this->builder->where('age', '>', 35)->sum('age');
658673
$this->assertEquals(333, $result);
@@ -663,6 +678,9 @@ public function testShouldReturnAFloatWhenCallingAvgMethod()
663678
$mockResult = m::mock(Result::class);
664679
$mockResult->shouldReceive('getIterator')->andReturn(new ArrayIterator([['aggregate' => 333.67]]));
665680
$this->mockedModel->shouldReceive('getPrimaryKey')->andReturn('DummyID');
681+
$this->mockedModel->shouldReceive('newInstance')->andReturnSelf();
682+
$this->mockedModel->shouldReceive('newFromBuilder')->andReturnSelf();
683+
$this->mockedModel->shouldReceive('newCollection')->andReturn(new Collection($mockResult));
666684
$this->database->shouldReceive('execute')->andReturn($mockResult);
667685
$result = $this->builder->where('age', '>', 35)->avg('age');
668686
$this->assertEquals(333.67, $result);
@@ -673,6 +691,9 @@ public function testShouldReturnAValueWhenCallingValueMethod()
673691
$mockResult = m::mock(Result::class);
674692
$mockResult->shouldReceive('getIterator')->andReturn(new ArrayIterator([['columnA' => 'A', 'columnB' => 'B']]));
675693
$this->mockedModel->shouldReceive('getPrimaryKey')->andReturn('DummyID');
694+
$this->mockedModel->shouldReceive('newInstance')->andReturnSelf();
695+
$this->mockedModel->shouldReceive('newFromBuilder')->andReturnSelf();
696+
$this->mockedModel->shouldReceive('newCollection')->andReturn(new Collection($mockResult));
676697
$this->database->shouldReceive('execute')->andReturn($mockResult);
677698
$result = $this->builder->where('age', '>', 35)->value('columnA');
678699
$this->assertEquals('A', $result);
@@ -683,6 +704,9 @@ public function testShouldReturnACollectionWhenCallingFindMethodProperly()
683704
$mockResult = m::mock(Result::class);
684705
$mockResult->shouldReceive('getIterator')->andReturn($this->getRandomData(55));
685706
$this->mockedModel->shouldReceive('getPrimaryKey')->andReturn('DummyID');
707+
$this->mockedModel->shouldReceive('newInstance')->andReturnSelf();
708+
$this->mockedModel->shouldReceive('newFromBuilder')->andReturnSelf();
709+
$this->mockedModel->shouldReceive('newCollection')->andReturn(new Collection($mockResult));
686710
$this->database->shouldReceive('execute')->andReturn($mockResult);
687711
$result = $this->builder->find('55');
688712
$this->assertIsArray($result);

tests/unit/FacadeSpannerDBTest.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,46 @@
33
namespace Tests\unit;
44

55
use Google\Cloud\Spanner\Database;
6+
use Google\Cloud\Spanner\Result;
67
use MgCosta\Spanner\Builder\Builder;
78
use MgCosta\Spanner\Facade\SpannerDB;
89
use Codeception\Test\Unit;
910
use MgCosta\Spanner\Manager\Manager;
11+
use ArrayIterator;
1012
use Mockery as m;
1113

1214
class FacadeSpannerDBTest extends Unit
1315
{
1416
private $facade;
17+
private $connection;
1518

1619
public function setUp(): void
1720
{
1821
parent::setUp();
19-
new Manager(m::mock(Database::class));
22+
$database = m::mock(Database::class);
23+
new Manager($database);
24+
$this->connection = $database;
2025
$this->facade = new SpannerDB();
2126
}
2227

2328
public function testShouldReturnAQueryBuilderInstanceWhenCallingWithinMethodTable()
2429
{
2530
$this->assertInstanceOf(Builder::class, $this->facade->table('test'));
2631
}
32+
33+
public function testShouldReturnACollectionOfArrayWhenCallingMethodToFetchResultFromFacade()
34+
{
35+
$data = new ArrayIterator([
36+
[
37+
'id' => 1,
38+
'name' => 'test'
39+
]
40+
]);
41+
$mockResult = m::mock(Result::class);
42+
$mockResult->shouldReceive('getIterator')->andReturn($data);
43+
44+
$this->connection->shouldReceive('execute')->andReturn($mockResult);
45+
$result = $this->facade->table('test')->where('id', 1)->first();
46+
$this->assertIsArray($result);
47+
}
2748
}

tests/unit/IncrementStrategyTest.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Codeception\Test\Unit;
1010
use Mockery as m;
1111
use ArrayIterator;
12+
use Tests\unit\stubs\DummyModel;
1213

1314
class IncrementStrategyTest extends Unit
1415
{
@@ -18,7 +19,7 @@ class IncrementStrategyTest extends Unit
1819

1920
public function setUp(): void
2021
{
21-
$this->model = $this->getMockForAbstractClass(Model::class);
22+
$this->model = new DummyModel();
2223
$this->connection = m::mock(Database::class);
2324
Model::setConnectionDatabase($this->connection);
2425
$this->strategy = new IncrementStrategy();
@@ -43,9 +44,7 @@ public function testShouldGetAnIncrementedValueWhenCallingGenerateKeyAndFetchAnV
4344

4445
public function testShouldGetTheStartIncrementValueAs1WhenCallingGenerateKeyAndFetchAnEmptyResultFromDatabase()
4546
{
46-
$data = new ArrayIterator([
47-
[]
48-
]);
47+
$data = new ArrayIterator([]);
4948
$mockResult = m::mock(Result::class);
5049
$mockResult->shouldReceive('getIterator')->andReturn($data);
5150

tests/unit/ModelAttributesTraitTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,18 @@ public function testShouldGetAllPropertiesAsAnArrayWhenCallingGetAttributesMetho
3131
];
3232
$this->assertEquals($expectedArray, $this->trait->getAttributes());
3333
}
34+
35+
public function testShouldAssignClassPropertiesWhenCallingSetRawAttributesWithinAValidArray()
36+
{
37+
$this->trait->setRawAttributes([
38+
'id' => 1,
39+
'firstName' => 'Michael',
40+
'lastName' => 'Brandon',
41+
'age' => 30
42+
]);
43+
$this->assertEquals(1, $this->trait->id);
44+
$this->assertEquals('Michael', $this->trait->firstName);
45+
$this->assertEquals('Brandon', $this->trait->lastName);
46+
$this->assertEquals(30, $this->trait->age);
47+
}
3448
}

tests/unit/stubs/DummyModel.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@
77
class DummyModel extends Model
88
{
99
protected $keyStrategy = 'increment';
10+
11+
public $id;
1012
}

0 commit comments

Comments
 (0)