Skip to content

Commit 4440a8b

Browse files
TheBnlryanmitchell
andauthored
Optimize taxonomy <> collection queries (#376)
* wip * pluck the slug * use whereIn and wrap column * test match driver * test match driver * support pgsql * remove todo * fix typo in variable name * refactor * Use config'd models * Some more co-ercing * 🍺 * update comment * add case for postgress * add test case for TermQueryBuilder where entries.driver is file * cleanup dump * We can't assume that the taxonomy is held in data now --------- Co-authored-by: Bram de Leeuw <[email protected]> Co-authored-by: Ryan Mitchell <[email protected]>
1 parent 01b187d commit 4440a8b

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

src/Taxonomies/TermQueryBuilder.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Statamic\Eloquent\Taxonomies;
44

5+
use Illuminate\Database\Query\Expression;
6+
use Illuminate\Support\Facades\DB;
57
use Illuminate\Support\Str;
68
use Statamic\Contracts\Taxonomies\Term as TermContract;
79
use Statamic\Facades\Blink;
@@ -222,13 +224,39 @@ private function applyCollectionAndTaxonomyWheres()
222224
return [];
223225
}
224226

227+
// workaround to handle potential n+1 queries in the database
228+
// if/when Statamic core supports relationships in a meaningful way this should be removed
229+
if (config('statamic.eloquent-driver.entries.driver', 'file') == 'eloquent') {
230+
$entryClass = app('statamic.eloquent.entries.model');
231+
$termClass = app('statamic.eloquent.terms.model');
232+
233+
$entriesTable = (new $entryClass)->getTable();
234+
$termsTable = (new $termClass)->getTable();
235+
236+
return TermModel::where('taxonomy', $taxonomy)
237+
->whereExists(function ($query) use ($entriesTable, $taxonomy, $termsTable) {
238+
$wrappedColumn = $query->getGrammar()->wrap("{$termsTable}.slug");
239+
$value = match ($query->getConnection()->getDriverName()) {
240+
'sqlite' => new Expression($wrappedColumn),
241+
'pgsql' => new Expression("to_jsonb({$wrappedColumn}::text)"),
242+
default => DB::raw("concat('\"', {$wrappedColumn}, '\"')"),
243+
};
244+
245+
$query->select(DB::raw(1))
246+
->from($entriesTable)
247+
->whereIn('collection', $this->collections)
248+
->whereJsonContains(Entry::query()->column($taxonomy->handle()), $value);
249+
})
250+
->pluck('slug');
251+
}
252+
225253
return TermModel::where('taxonomy', $taxonomy)
226254
->select('slug')
227255
->get()
228256
->map(function ($term) use ($taxonomy) {
229257
return Entry::query()
230258
->whereIn('collection', $this->collections)
231-
->whereJsonContains('data->'.$taxonomy, [$term->slug])
259+
->whereJsonContains($taxonomy->handle(), [$term->slug])
232260
->count() > 0 ? $term->slug : null;
233261
})
234262
->filter()

tests/Data/Taxonomies/TermQueryBuilderTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,16 @@ public function terms_are_found_using_where_column()
207207
$this->assertEquals(['a', 'b', 'e'], $terms->map->slug()->all());
208208
}
209209

210+
#[Test]
211+
public function it_filters_usage_in_collections_using_file_based_entries()
212+
{
213+
config()->set('statamic.eloquent-driver.entries.driver', 'file');
214+
$this->it_filters_usage_in_collections();
215+
216+
// revert config to original
217+
config()->set('statamic.eloquent-driver.entries.driver', 'eloquent');
218+
}
219+
210220
#[Test]
211221
public function it_filters_usage_in_collections()
212222
{

0 commit comments

Comments
 (0)