Skip to content

Commit

Permalink
Merge pull request #104 from Stevemoretz/master
Browse files Browse the repository at this point in the history
Support multiple requests
  • Loading branch information
mpociot authored Dec 1, 2023
2 parents 722c45c + 4aa2269 commit cdf0649
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 8 deletions.
32 changes: 24 additions & 8 deletions src/QueryDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,29 @@ class QueryDetector
{
/** @var Collection */
private $queries;
/**
* @var bool
*/
private $booted = false;

public function __construct()
private function resetQueries()
{
$this->queries = Collection::make();
}

public function __construct()
{
$this->resetQueries();
}

public function boot()
{
DB::listen(function($query) {
if ($this->booted) {
$this->resetQueries();
return;
}

DB::listen(function ($query) {
$backtrace = collect(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 50));

$this->logQuery($query, $backtrace);
Expand All @@ -32,6 +46,8 @@ public function boot()
app()->singleton($outputType);
app($outputType)->boot();
}

$this->booted = true;
}

public function isEnabled(): bool
Expand All @@ -52,13 +68,13 @@ public function logQuery($query, Collection $backtrace)
});

// The query is coming from an Eloquent model
if (! is_null($modelTrace)) {
if (!is_null($modelTrace)) {
/*
* Relations get resolved by either calling the "getRelationValue" method on the model,
* or if the class itself is a Relation.
*/
$relation = $backtrace->first(function ($trace) {
return Arr::get($trace, 'function') === 'getRelationValue' || Arr::get($trace, 'class') === Relation::class ;
return Arr::get($trace, 'function') === 'getRelationValue' || Arr::get($trace, 'class') === Relation::class;
});

// We try to access a relation
Expand All @@ -81,8 +97,8 @@ public function logQuery($query, Collection $backtrace)

$key = md5($query->sql . $model . $relationName . $sources[0]->name . $sources[0]->line);

$count = Arr::get($this->queries, $key.'.count', 0);
$time = Arr::get($this->queries, $key.'.time', 0);
$count = Arr::get($this->queries, $key . '.count', 0);
$time = Arr::get($this->queries, $key . '.time', 0);

$this->queries[$key] = [
'count' => ++$count,
Expand Down Expand Up @@ -110,7 +126,7 @@ protected function findSource($stack)

public function parseTrace($index, array $trace)
{
$frame = (object) [
$frame = (object)[
'index' => $index,
'name' => null,
'line' => isset($trace['line']) ? $trace['line'] : '?',
Expand Down Expand Up @@ -195,7 +211,7 @@ protected function getOutputTypes()
{
$outputTypes = config('querydetector.output');

if (! is_array($outputTypes)) {
if (!is_array($outputTypes)) {
$outputTypes = [$outputTypes];
}

Expand Down
48 changes: 48 additions & 0 deletions tests/QueryDetectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,54 @@ public function it_detects_n1_query_on_properties()
$this->assertSame('profile', $queries[0]['relation']);
}

/** @test */
public function it_detects_n1_query_on_multiple_requests()
{
Route::get('/', function (){
$authors = Author::get();

foreach ($authors as $author) {
$author->profile;
}
});

// first request
$this->get('/');
$queries = app(QueryDetector::class)->getDetectedQueries();
$this->assertCount(1, $queries);
$this->assertSame(Author::count(), $queries[0]['count']);
$this->assertSame(Author::class, $queries[0]['model']);
$this->assertSame('profile', $queries[0]['relation']);

// second request
$this->get('/');
$queries = app(QueryDetector::class)->getDetectedQueries();
$this->assertCount(1, $queries);
$this->assertSame(Author::count(), $queries[0]['count']);
$this->assertSame(Author::class, $queries[0]['model']);
$this->assertSame('profile', $queries[0]['relation']);
}

/** @test */
public function it_does_not_detect_a_false_n1_query_on_multiple_requests()
{
Route::get('/', function (){
$authors = Author::with("profile")->get();

foreach ($authors as $author) {
$author->profile;
}
});

// first request
$this->get('/');
$this->assertCount(0, app(QueryDetector::class)->getDetectedQueries());

// second request
$this->get('/');
$this->assertCount(0, app(QueryDetector::class)->getDetectedQueries());
}

/** @test */
public function it_ignores_eager_loaded_relationships()
{
Expand Down

0 comments on commit cdf0649

Please sign in to comment.