Skip to content

Commit 518b743

Browse files
authored
Merge pull request #48 from hschimpf/scope-support
Add model scope support
2 parents 7e27e64 + 1f64d98 commit 518b743

File tree

4 files changed

+131
-2
lines changed

4 files changed

+131
-2
lines changed

src/Kitar/Dynamodb/Model/Model.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ public function __call($method, $parameters)
374374
return $this->$method(...$parameters);
375375
}
376376

377-
if (! in_array($method, $allowedBuilderMethods)) {
377+
if (! in_array($method, $allowedBuilderMethods) && ! $this->hasNamedScope($method)) {
378378
static::throwBadMethodCallException($method);
379379
}
380380

src/Kitar/Dynamodb/Query/Builder.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,9 +472,38 @@ public function __call($method, $parameters)
472472
return $this;
473473
}
474474

475+
if ($this->hasNamedScope($method)) {
476+
return $this->callNamedScope($method, $parameters);
477+
}
478+
475479
throw new BadMethodCallException('Call to undefined method ' . static::class . "::{$method}()");
476480
}
477481

482+
/**
483+
* Determine if the given model has a scope.
484+
*
485+
* @param string $scope
486+
*
487+
* @return bool
488+
*/
489+
public function hasNamedScope(string $scope): bool
490+
{
491+
return $this->model_class && (new $this->model_class)->hasNamedScope($scope);
492+
}
493+
494+
/**
495+
* Apply the given named scope on the current builder instance.
496+
*
497+
* @param string $scope
498+
* @param array $parameters
499+
*
500+
* @return mixed
501+
*/
502+
protected function callNamedScope(string $scope, array $parameters = [])
503+
{
504+
return (new $this->model_class)->callNamedScope($scope, array_merge([$this], $parameters));
505+
}
506+
478507
/**
479508
* @inheritdoc
480509
*/

tests/Model/ModelTest.php

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,4 +629,94 @@ public function it_cannot_call_disallowed_builder_method()
629629

630630
UserA::clientQuery();
631631
}
632+
633+
/** @test */
634+
public function it_can_call_named_scopes_on_model()
635+
{
636+
$connection = $this->newConnectionMock();
637+
$connection->shouldReceive('clientQuery')->with([
638+
'TableName' => 'User',
639+
'KeyConditionExpression' => '#1 = :1',
640+
'FilterExpression' => '#2 = :2',
641+
'ExpressionAttributeNames' => [
642+
'#1' => 'partition',
643+
'#2' => 'status'
644+
],
645+
'ExpressionAttributeValues' => [
646+
':1' => [
647+
'S' => 'test'
648+
],
649+
':2' => [
650+
'S' => 'active'
651+
]
652+
]
653+
])->andReturn($this->sampleAwsResult())->once();
654+
$this->setConnectionResolver($connection);
655+
656+
UserA::keyCondition('partition', '=', 'test')->active()->query();
657+
}
658+
659+
/** @test */
660+
public function it_can_call_named_scopes_with_parameters_on_model()
661+
{
662+
$connection = $this->newConnectionMock();
663+
$connection->shouldReceive('clientQuery')->with([
664+
'TableName' => 'User',
665+
'KeyConditionExpression' => '#1 = :1',
666+
'FilterExpression' => '#2 = :2',
667+
'ExpressionAttributeNames' => [
668+
'#1' => 'partition',
669+
'#2' => 'name'
670+
],
671+
'ExpressionAttributeValues' => [
672+
':1' => [
673+
'S' => 'test'
674+
],
675+
':2' => [
676+
'S' => 'John'
677+
]
678+
]
679+
])->andReturn($this->sampleAwsResult())->once();
680+
$this->setConnectionResolver($connection);
681+
682+
UserA::keyCondition('partition', '=', 'test')->byName('John')->query();
683+
}
684+
685+
/** @test */
686+
public function it_can_chain_multiple_scopes()
687+
{
688+
$connection = $this->newConnectionMock();
689+
$connection->shouldReceive('clientQuery')->with([
690+
'TableName' => 'User',
691+
'KeyConditionExpression' => '#1 = :1',
692+
'FilterExpression' => '#2 = :2 and #3 = :3',
693+
'ExpressionAttributeNames' => [
694+
'#1' => 'partition',
695+
'#2' => 'status',
696+
'#3' => 'name'
697+
],
698+
'ExpressionAttributeValues' => [
699+
':1' => [
700+
'S' => 'test'
701+
],
702+
':2' => [
703+
'S' => 'active'
704+
],
705+
':3' => [
706+
'S' => 'John'
707+
]
708+
]
709+
])->andReturn($this->sampleAwsResult())->once();
710+
$this->setConnectionResolver($connection);
711+
712+
UserA::keyCondition('partition', '=', 'test')->active()->byName('John')->query();
713+
}
714+
715+
/** @test */
716+
public function it_cannot_call_non_existent_scope_on_model()
717+
{
718+
$this->expectException(BadMethodCallException::class);
719+
720+
UserA::nonExistentScope();
721+
}
632722
}

tests/Model/UserA.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ class UserA extends Model implements AuthenticatableContract
1313
protected $table = 'User';
1414
protected $primaryKey = 'partition';
1515
protected $fillable = [
16-
'partition', 'name', 'password'
16+
'partition', 'name', 'password', 'status',
1717
];
18+
19+
public function scopeActive($query)
20+
{
21+
return $query->filter('status', '=', 'active');
22+
}
23+
24+
public function scopeByName($query, $name)
25+
{
26+
return $query->filter('name', '=', $name);
27+
}
1828
}

0 commit comments

Comments
 (0)