@@ -115,8 +115,9 @@ private function trigramSearch(PackageSearchRequest $request): LengthAwarePagina
115115 * Uses Composer\Semver to evaluate version constraints stored in the requires JSONB field,
116116 * supporting ranges like ">=11.5.19 <=12.9.99", caret (^12.4), tilde (~12.4), etc.
117117 *
118- * SQL narrows candidates using the GIN-indexed JSONB `?` operator (key existence) and
119- * scopes to the current package type. PHP then does precise constraint matching.
118+ * Optimization: instead of loading all releases into PHP, we first collect the distinct
119+ * constraint strings per key (typically only 20-50 unique values), run Semver::satisfies()
120+ * on those, then use SQL to find package IDs whose releases match the valid constraints.
120121 *
121122 * @param Builder<Package> $query
122123 */
@@ -126,23 +127,43 @@ private function applyRequiresFilter(Builder $query, PackageSearchRequest $reque
126127 return ;
127128 }
128129
129- // Narrow to releases of matching package type that have the required JSONB keys.
130- // Uses the GIN index on requires via the ? operator for fast key-existence checks.
131- $ candidateQuery = PackageRelease::query ()
132- ->select ('package_releases.package_id ' , 'package_releases.requires ' )
130+ // Build a subquery that finds package IDs with at least one release matching all constraints.
131+ // For each required key, we find the distinct constraint values, filter with Semver in PHP,
132+ // then add a SQL condition for only the valid constraints.
133+ $ releaseQuery = DB ::table ('package_releases ' )
134+ ->select ('package_releases.package_id ' )
133135 ->join ('packages ' , 'packages.id ' , '= ' , 'package_releases.package_id ' )
134136 ->where ('packages.type ' , $ request ->type );
135137
136138 foreach ($ request ->requires as $ key => $ version ) {
137- $ candidateQuery ->whereRaw ('jsonb_exists(package_releases.requires, ?) ' , [$ key ]);
139+ // Get distinct constraint strings for this key (e.g. ">=11.5.0 <=12.99.99", "^12.4")
140+ $ distinctConstraints = DB ::table ('package_releases ' )
141+ ->join ('packages ' , 'packages.id ' , '= ' , 'package_releases.package_id ' )
142+ ->where ('packages.type ' , $ request ->type )
143+ ->whereRaw ('jsonb_exists(package_releases.requires, ?) ' , [$ key ])
144+ ->selectRaw ('DISTINCT package_releases.requires->>? as constraint_value ' , [$ key ])
145+ ->pluck ('constraint_value ' );
146+
147+ // Filter to constraints that the provided version satisfies
148+ $ validConstraints = $ distinctConstraints
149+ ->filter (fn (string $ constraint ) => Semver::satisfies ($ version , $ constraint ))
150+ ->values ()
151+ ->all ();
152+
153+ if (empty ($ validConstraints )) {
154+ // No valid constraints found — no packages can match
155+ $ query ->whereRaw ('1 = 0 ' );
156+
157+ return ;
158+ }
159+
160+ $ releaseQuery ->whereRaw (
161+ 'package_releases.requires->>? IN ( ' . implode (', ' , array_fill (0 , count ($ validConstraints ), '? ' )) . ') ' ,
162+ [$ key , ...$ validConstraints ],
163+ );
138164 }
139165
140- $ matchingIds = $ candidateQuery ->get ()
141- ->filter (fn (PackageRelease $ release ) => $ this ->releaseSatisfies ($ release , $ request ->requires ))
142- ->pluck ('package_id ' )
143- ->unique ()
144- ->values ()
145- ->all ();
166+ $ matchingIds = $ releaseQuery ->distinct ()->pluck ('package_id ' )->all ();
146167
147168 $ query ->whereIn ('packages.id ' , $ matchingIds );
148169 }
0 commit comments