Skip to content

Commit

Permalink
Fixed aggregates; Added tests for withCount, withSum and whereHas
Browse files Browse the repository at this point in the history
  • Loading branch information
korridor committed Apr 20, 2022
1 parent 71cf54d commit 1c9cdc9
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 6 deletions.
34 changes: 34 additions & 0 deletions src/HasManyMerged.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ public function getParentKey()
return $this->parent->getAttribute($this->localKey);
}

/**
* Get the fully qualified parent key name.
*
* @return string
*/
public function getQualifiedParentKeyName()
{
return $this->parent->qualifyColumn($this->localKey);
}

/**
* Set the constraints for an eager load of the relation.
* Note: Used to load relations of multiple models at once.
Expand All @@ -91,6 +101,30 @@ public function addEagerConstraints(array $models)
});
}

/**
* Add the constraints for an internal relationship existence query.
*
* Essentially, these queries compare on column names like whereColumn.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parentQuery
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
{
$foreignKeys = $this->foreignKeys;

return $query->select($columns)->where(function ($query) use ($foreignKeys) {
foreach ($foreignKeys as $foreignKey) {
$query->orWhere(function ($query) use ($foreignKey) {
$query->whereColumn($this->getQualifiedParentKeyName(), '=', $foreignKey)
->whereNotNull($foreignKey);
});
}
});
}

/**
* Get the name of the "where in" method for eager loading.
* Note: Similar to whereInMethod of Relation class.
Expand Down
93 changes: 87 additions & 6 deletions tests/HasManyMergedTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

namespace Korridor\LaravelHasManyMerged\Tests;

use Illuminate\Database\Eloquent\Builder;
use Korridor\LaravelHasManyMerged\HasManyMerged;
use Korridor\LaravelHasManyMerged\Tests\Models\Message;
use Korridor\LaravelHasManyMerged\Tests\Models\User;

class HasManyMergedTest extends TestCase
{
private function createTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessages()
private function createTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessages(): void
{
User::create([
'id' => 11,
Expand All @@ -26,28 +27,32 @@ private function createTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessages(
'content' => 'A - This is a message!',
'sender_user_id' => 1,
'receiver_user_id' => 1,
'content_integer' => 1,
]);
Message::create([
'id' => 2,
'content' => 'B - This is a message!',
'sender_user_id' => 1,
'receiver_user_id' => 2,
'content_integer' => 1,
]);
Message::create([
'id' => 3,
'content' => 'C - This is a message!',
'sender_user_id' => 2,
'receiver_user_id' => 1,
'content_integer' => 1,
]);
Message::create([
'id' => 4,
'content' => 'D - This is a message!',
'sender_user_id' => 2,
'receiver_user_id' => 2,
'content_integer' => 2,
]);
}

public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithLazyLoading()
public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithLazyLoading(): void
{
// Arrange
$this->createTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessages();
Expand All @@ -71,7 +76,7 @@ public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSam
$this->assertEquals(2, $user2->sentMessages()->count());
}

public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithEagerLoading()
public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithEagerLoading(): void
{
// Arrange
$this->createTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessages();
Expand All @@ -96,7 +101,83 @@ public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSam
$this->assertEquals(2, $user2->sentMessages()->count());
}

public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithLazyEagerLoading()
public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithEagerLoadingWithCount(): void
{
// Arrange
$this->createTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessages();

// Act
$this->db::connection()->enableQueryLog();
$users = User::with(['messages'])->withCount(['messages', 'sentMessages'])->get();
$user1 = $users->firstWhere('id', 11);
$user2 = $users->firstWhere('id', 12);
$messagesOfUser1 = $user1->messages;
$messagesOfUser2 = $user2->messages;
$queries = $this->db::getQueryLog();
$this->db::connection()->disableQueryLog();

// Assert
$this->assertEquals(2, count($queries));
$this->assertEquals(3, $messagesOfUser1->count());
$this->assertEquals(3, $messagesOfUser2->count());
$this->assertEquals(3, $user1->messages_count);
$this->assertEquals(3, $user2->messages_count);
$this->assertEquals(2, $user1->receivedMessages()->count());
$this->assertEquals(2, $user1->sentMessages()->count());
$this->assertEquals(2, $user2->receivedMessages()->count());
$this->assertEquals(2, $user2->sentMessages()->count());
}

public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithEagerLoadingWithSum(): void
{
if (! method_exists(Builder::class, 'withSum')) {
$this->markTestSkipped('withSum is not supported');
}

// Arrange
$this->createTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessages();

// Act
$this->db::connection()->enableQueryLog();
$users = User::with(['messages'])->withSum('messages', 'content_integer')->get();
$user1 = $users->firstWhere('id', 11);
$user2 = $users->firstWhere('id', 12);
$messagesOfUser1 = $user1->messages;
$messagesOfUser2 = $user2->messages;
$queries = $this->db::getQueryLog();
$this->db::connection()->disableQueryLog();

// Assert
$this->assertEquals(2, count($queries));
$this->assertEquals(3, $messagesOfUser1->count());
$this->assertEquals(3, $messagesOfUser2->count());
$this->assertEquals(3, $user1->messages_sum_content_integer);
$this->assertEquals(4, $user2->messages_sum_content_integer);
$this->assertEquals(2, $user1->receivedMessages()->count());
$this->assertEquals(2, $user1->sentMessages()->count());
$this->assertEquals(2, $user2->receivedMessages()->count());
$this->assertEquals(2, $user2->sentMessages()->count());
}

public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithEagerLoadingWhereHas(): void
{
// Arrange
$this->createTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessages();

// Act
$this->db::connection()->enableQueryLog();
$users = User::with(['messages'])->whereHas('messages', function (Builder $builder) {
$builder->where('content_integer', '=', 2);
})->get();
$queries = $this->db::getQueryLog();
$this->db::connection()->disableQueryLog();

// Assert
$this->assertEquals(1, count($users));
$this->assertEquals(2, $users->first()->other_unique_id);
}

public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithLazyEagerLoading(): void
{
// Arrange
$this->createTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessages();
Expand All @@ -122,7 +203,7 @@ public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSam
$this->assertEquals(2, $user2->sentMessages()->count());
}

public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithConstrainedEagerLoading()
public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithConstrainedEagerLoading(): void
{
// Arrange
$this->createTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessages();
Expand Down Expand Up @@ -151,7 +232,7 @@ public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSam
$this->assertEquals(2, $user2->sentMessages()->count());
}

public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithEagerLoadingAndOrderCheck()
public function testHasManyMergedWithTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessagesWithEagerLoadingAndOrderCheck(): void
{
// Arrange
$this->createTwoUsersWereBothAreSenderOrReceiverOfTheSameFourMessages();
Expand Down
1 change: 1 addition & 0 deletions tests/Models/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Message extends Model
protected $fillable = [
'id',
'content',
'content_integer',
'sender_user_id',
'receiver_user_id',
];
Expand Down
1 change: 1 addition & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ protected function setUp(): void
$this->db::schema()->create('messages', function (Blueprint $table) {
$table->increments('id');
$table->text('content');
$table->integer('content_integer')->default(0);
$table->unsignedInteger('sender_user_id');
$table->unsignedInteger('receiver_user_id');
$table->timestamps();
Expand Down

0 comments on commit 1c9cdc9

Please sign in to comment.