Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Correctly build cache key for whereIn subqueries
  • Loading branch information
Nutickets committed Oct 15, 2021
1 parent 4e57da5 commit 12feb91
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/CacheKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,19 @@ protected function getInAndNotInClauses(array $where) : string
}

$subquery = preg_replace('/\?(?=(?:[^"]*"[^"]*")*[^"]*\Z)/m', "_??_", $subquery);

/**
* For whereIn(<subquery>) we will gather all of the values from the bindings, adjust the index so any
* subsequent wheres carry on from the right binding index, and then build the full select query as a string.
*/
$replacementsCount = Str::substrCount($subquery, "_??_");
if (Str::startsWith(strtolower($subquery), 'select') && $replacementsCount > $values->count()) {
$values = collect()->times($replacementsCount, function ($i) {
return $this->query->bindings["where"][$i-1] ?? null;
});
$this->currentBinding += $replacementsCount;
}

$subquery = collect(vsprintf(str_replace("_??_", "%s", $subquery), $values->toArray()));
$values = $this->recursiveImplode($subquery->toArray(), "_");

Expand Down
46 changes: 46 additions & 0 deletions tests/Integration/CachedBuilder/WhereInTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Author;
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Book;
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Post;
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Publisher;
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\UncachedPublisher;
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\UncachedPost;
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\UncachedAuthor;
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\UncachedBook;
use GeneaLabs\LaravelModelCaching\Tests\IntegrationTestCase;
Expand Down Expand Up @@ -99,4 +103,46 @@ public function testWhereInUsesCorrectBindings()
$this->assertEmpty($authors->diffKeys($cachedResults));
$this->assertEmpty($liveResults->diffKeys($cachedResults));
}

public function testWhereInSubQueryUsesCorrectBindings()
{
$key = sha1("genealabs:laravel-model-caching:testing:{$this->testingSqlitePath}testing.sqlite:books:genealabslaravelmodelcachingtestsfixturesbook-publisher_id_in_select_id_from_publishers_where_name_=_Publisher_Foo_or_name_=_Publisher_Bar-id_>_0");
$tags = [
"genealabs:laravel-model-caching:testing:{$this->testingSqlitePath}testing.sqlite:genealabslaravelmodelcachingtestsfixturesbook",
];

/** @var Collection $publishers */
$publishers = factory(UncachedPublisher::class, 5)->create();
$publishers->get(1)->update(['name' => 'Publisher Foo']);
$publishers->get(3)->update(['name' => 'Publisher Bar']);

$publishers->each(function (UncachedPublisher $publisher) {
factory(UncachedBook::class, 2)->create(['publisher_id' => $publisher->id]);
});

$books = Book::query()
->whereIn('publisher_id',
Publisher::select('id')
->where('name', 'Publisher Foo')
->orWhere('name', 'Publisher Bar')
)
->where('id', '>', 0)
->get()->pluck('id')->toArray();

$cachedResults = $this
->cache()
->tags($tags)
->get($key)['value'];

$liveResults = Book::query()
->whereIn('publisher_id',
Publisher::select('id')
->where('name', 'Publisher Foo')
->orWhere('name', 'Publisher Bar')
)->get()->pluck('id')->toArray();

$this->assertCount(4, $books);
$this->assertSame($liveResults, $books);
$this->assertSame($liveResults, $cachedResults->pluck('id')->filter()->toArray());
}
}

0 comments on commit 12feb91

Please sign in to comment.