Skip to content

Commit 12feb91

Browse files
committed
Correctly build cache key for whereIn subqueries
1 parent 4e57da5 commit 12feb91

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

Diff for: src/CacheKey.php

+13
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,19 @@ protected function getInAndNotInClauses(array $where) : string
274274
}
275275

276276
$subquery = preg_replace('/\?(?=(?:[^"]*"[^"]*")*[^"]*\Z)/m', "_??_", $subquery);
277+
278+
/**
279+
* For whereIn(<subquery>) we will gather all of the values from the bindings, adjust the index so any
280+
* subsequent wheres carry on from the right binding index, and then build the full select query as a string.
281+
*/
282+
$replacementsCount = Str::substrCount($subquery, "_??_");
283+
if (Str::startsWith(strtolower($subquery), 'select') && $replacementsCount > $values->count()) {
284+
$values = collect()->times($replacementsCount, function ($i) {
285+
return $this->query->bindings["where"][$i-1] ?? null;
286+
});
287+
$this->currentBinding += $replacementsCount;
288+
}
289+
277290
$subquery = collect(vsprintf(str_replace("_??_", "%s", $subquery), $values->toArray()));
278291
$values = $this->recursiveImplode($subquery->toArray(), "_");
279292

Diff for: tests/Integration/CachedBuilder/WhereInTest.php

+46
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Author;
44
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Book;
5+
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Post;
6+
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\Publisher;
7+
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\UncachedPublisher;
8+
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\UncachedPost;
59
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\UncachedAuthor;
610
use GeneaLabs\LaravelModelCaching\Tests\Fixtures\UncachedBook;
711
use GeneaLabs\LaravelModelCaching\Tests\IntegrationTestCase;
@@ -99,4 +103,46 @@ public function testWhereInUsesCorrectBindings()
99103
$this->assertEmpty($authors->diffKeys($cachedResults));
100104
$this->assertEmpty($liveResults->diffKeys($cachedResults));
101105
}
106+
107+
public function testWhereInSubQueryUsesCorrectBindings()
108+
{
109+
$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");
110+
$tags = [
111+
"genealabs:laravel-model-caching:testing:{$this->testingSqlitePath}testing.sqlite:genealabslaravelmodelcachingtestsfixturesbook",
112+
];
113+
114+
/** @var Collection $publishers */
115+
$publishers = factory(UncachedPublisher::class, 5)->create();
116+
$publishers->get(1)->update(['name' => 'Publisher Foo']);
117+
$publishers->get(3)->update(['name' => 'Publisher Bar']);
118+
119+
$publishers->each(function (UncachedPublisher $publisher) {
120+
factory(UncachedBook::class, 2)->create(['publisher_id' => $publisher->id]);
121+
});
122+
123+
$books = Book::query()
124+
->whereIn('publisher_id',
125+
Publisher::select('id')
126+
->where('name', 'Publisher Foo')
127+
->orWhere('name', 'Publisher Bar')
128+
)
129+
->where('id', '>', 0)
130+
->get()->pluck('id')->toArray();
131+
132+
$cachedResults = $this
133+
->cache()
134+
->tags($tags)
135+
->get($key)['value'];
136+
137+
$liveResults = Book::query()
138+
->whereIn('publisher_id',
139+
Publisher::select('id')
140+
->where('name', 'Publisher Foo')
141+
->orWhere('name', 'Publisher Bar')
142+
)->get()->pluck('id')->toArray();
143+
144+
$this->assertCount(4, $books);
145+
$this->assertSame($liveResults, $books);
146+
$this->assertSame($liveResults, $cachedResults->pluck('id')->filter()->toArray());
147+
}
102148
}

0 commit comments

Comments
 (0)