From 772d5a0709f27a8d6ff02bb521a7325e257f7784 Mon Sep 17 00:00:00 2001 From: Wes Copeland Date: Sat, 25 Jan 2025 16:43:37 -0500 Subject: [PATCH 1/5] fix(SharedHubStrategy): exclude Meta and Misc hubs --- .../Services/GameSuggestions/Strategies/SharedHubStrategy.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php b/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php index 1bfc4d3f2b..148088a5d1 100644 --- a/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php +++ b/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php @@ -36,6 +36,8 @@ public function select(): ?Game ->whereHas('games', function ($query) { $query->where('game_id', '!=', $this->sourceGame->id); // needs other games too! }) + ->where('Title', 'NOT LIKE', "%Meta%") + ->where('Title', 'NOT LIKE', "%Misc%") ->inRandomOrder() ->first(); From 761caa8dc8d1b1685877994949739099ba7a6c08 Mon Sep 17 00:00:00 2001 From: Wes Copeland Date: Sun, 26 Jan 2025 10:56:54 -0500 Subject: [PATCH 2/5] fix: address feedback --- .../Services/GameSuggestions/Strategies/SharedHubStrategy.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php b/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php index 148088a5d1..964f44e002 100644 --- a/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php +++ b/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php @@ -36,8 +36,8 @@ public function select(): ?Game ->whereHas('games', function ($query) { $query->where('game_id', '!=', $this->sourceGame->id); // needs other games too! }) - ->where('Title', 'NOT LIKE', "%Meta%") - ->where('Title', 'NOT LIKE', "%Misc%") + ->where('Title', 'NOT LIKE', "%Meta - %") + ->where('Title', 'NOT LIKE', "%Misc. - %") ->inRandomOrder() ->first(); From db40edf3b1baa37b798e3edd1120b6257163ed5e Mon Sep 17 00:00:00 2001 From: Wes Copeland Date: Sun, 26 Jan 2025 12:22:27 -0500 Subject: [PATCH 3/5] fix: address feedback --- .../Strategies/CommonPlayersStrategy.php | 37 +----------- .../Strategies/SharedHubStrategy.php | 60 +++++++++++++++---- 2 files changed, 52 insertions(+), 45 deletions(-) diff --git a/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php b/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php index a8aeae3296..25090f6791 100644 --- a/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php +++ b/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php @@ -12,7 +12,6 @@ use App\Platform\Data\GameSuggestionContextData; use App\Platform\Enums\GameSuggestionReason; use Illuminate\Support\Collection; -use Illuminate\Support\Facades\DB; class CommonPlayersStrategy implements GameSuggestionStrategy { @@ -39,7 +38,7 @@ public function select(): ?Game ->whereAllAchievementsUnlocked() ->where('achievements_total', '>', 0) ->where('game_id', '!=', $this->sourceGame->id) - ->whereNull('deleted_at') + ->withTrashed() ->groupBy('game_id') ->orderByRaw('COUNT(*) DESC') ->limit(10) @@ -76,44 +75,14 @@ public function reasonContext(): ?GameSuggestionContextData * @return Collection */ private function getMasterUserIds(): Collection - { - $connection = DB::connection()->getDriverName(); - - return match ($connection) { - 'sqlite' => $this->getMasterUserIdsSQLite(), - default => $this->getMasterUserIdsMariaDB(), - }; - } - - /** - * @return Collection - */ - private function getMasterUserIdsMariaDB(): Collection { // Use the optimized index hint for MariaDB. // This is unfortunately not supported by SQLite. - return PlayerGame::from(DB::raw('`player_games` FORCE INDEX (player_games_completion_sample_idx)')) - ->where('game_id', $this->sourceGame->id) - ->where('user_id', '!=', $this->user->id) - ->whereAllAchievementsUnlocked() - ->whereNull('deleted_at') - ->whereRaw('id % 100 < 5') - ->limit(5) - ->pluck('user_id'); - } - - /** - * @return Collection - */ - private function getMasterUserIdsSQLite(): Collection - { - // For SQLite, we'll use a different approach to get a stable random sample. - // We use the rowid (which SQLite automatically provides) for sampling. return PlayerGame::where('game_id', $this->sourceGame->id) ->where('user_id', '!=', $this->user->id) ->whereAllAchievementsUnlocked() - ->whereNull('deleted_at') - ->orderByRaw('rowid % 100') + ->withTrashed() + ->whereRaw('id % 100 < 5') ->limit(5) ->pluck('user_id'); } diff --git a/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php b/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php index 964f44e002..4a09d859f2 100644 --- a/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php +++ b/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php @@ -13,6 +13,7 @@ use App\Platform\Enums\GameSetType; use App\Platform\Enums\GameSuggestionReason; use App\Platform\Services\GameSuggestions\Enums\SourceGameKind; +use Illuminate\Support\Facades\DB; class SharedHubStrategy implements GameSuggestionStrategy { @@ -29,17 +30,7 @@ public function __construct( public function select(): ?Game { // First, get a random hub that contains our source game. - $this->selectedHub = GameSet::whereType(GameSetType::Hub) - ->whereHas('games', function ($query) { - $query->whereGameId($this->sourceGame->id); // needs our source game - }) - ->whereHas('games', function ($query) { - $query->where('game_id', '!=', $this->sourceGame->id); // needs other games too! - }) - ->where('Title', 'NOT LIKE', "%Meta - %") - ->where('Title', 'NOT LIKE', "%Misc. - %") - ->inRandomOrder() - ->first(); + $this->selectedHub = $this->getRandomHub(); if (!$this->selectedHub) { return null; @@ -59,6 +50,53 @@ public function select(): ?Game return $this->selectedGame; } + private function getRandomHub(): ?GameSet + { + $connection = DB::connection()->getDriverName(); + + return match ($connection) { + 'sqlite' => $this->getRandomHubSQLite(), + default => $this->getRandomHubMariaDB(), + }; + } + + private function getRandomHubMariaDB(): ?GameSet + { + return GameSet::whereType(GameSetType::Hub) + ->whereHas('games', function ($query) { + $query->whereGameId($this->sourceGame->id); // needs our source game. + }) + ->whereHas('games', function ($query) { + $query->where('game_id', '!=', $this->sourceGame->id); // needs other games too. + }) + /** + * Exclude certain hubs via regex. + * We don't want to recommend something just because it's in the Noncompliant Writing hub. + */ + ->whereRaw("game_sets.title NOT REGEXP '^(Meta[| -]|Misc\\.[ -])'") + ->inRandomOrder() + ->first(); + } + + private function getRandomHubSQLite(): ?GameSet + { + // For SQLite, we use LIKE with multiple patterns instead of REGEXP. + return GameSet::whereType(GameSetType::Hub) + ->whereHas('games', function ($query) { + $query->whereGameId($this->sourceGame->id); // needs our source game. + }) + ->whereHas('games', function ($query) { + $query->where('game_id', '!=', $this->sourceGame->id); // needs other games too. + }) + ->where(function ($query) { + $query->where('title', 'NOT LIKE', 'Meta - %') + ->where('title', 'NOT LIKE', 'Meta|%') + ->where('title', 'NOT LIKE', 'Misc. - %'); + }) + ->inRandomOrder() + ->first(); + } + public function reason(): GameSuggestionReason { return GameSuggestionReason::SharedHub; From 7acb411673c50a5eaf80a90093cd0290e02b2813 Mon Sep 17 00:00:00 2001 From: Wes Copeland Date: Sun, 26 Jan 2025 12:26:59 -0500 Subject: [PATCH 4/5] chore: revert some stuff --- .../Strategies/CommonPlayersStrategy.php | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php b/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php index 25090f6791..a8aeae3296 100644 --- a/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php +++ b/app/Platform/Services/GameSuggestions/Strategies/CommonPlayersStrategy.php @@ -12,6 +12,7 @@ use App\Platform\Data\GameSuggestionContextData; use App\Platform\Enums\GameSuggestionReason; use Illuminate\Support\Collection; +use Illuminate\Support\Facades\DB; class CommonPlayersStrategy implements GameSuggestionStrategy { @@ -38,7 +39,7 @@ public function select(): ?Game ->whereAllAchievementsUnlocked() ->where('achievements_total', '>', 0) ->where('game_id', '!=', $this->sourceGame->id) - ->withTrashed() + ->whereNull('deleted_at') ->groupBy('game_id') ->orderByRaw('COUNT(*) DESC') ->limit(10) @@ -75,15 +76,45 @@ public function reasonContext(): ?GameSuggestionContextData * @return Collection */ private function getMasterUserIds(): Collection + { + $connection = DB::connection()->getDriverName(); + + return match ($connection) { + 'sqlite' => $this->getMasterUserIdsSQLite(), + default => $this->getMasterUserIdsMariaDB(), + }; + } + + /** + * @return Collection + */ + private function getMasterUserIdsMariaDB(): Collection { // Use the optimized index hint for MariaDB. // This is unfortunately not supported by SQLite. - return PlayerGame::where('game_id', $this->sourceGame->id) + return PlayerGame::from(DB::raw('`player_games` FORCE INDEX (player_games_completion_sample_idx)')) + ->where('game_id', $this->sourceGame->id) ->where('user_id', '!=', $this->user->id) ->whereAllAchievementsUnlocked() - ->withTrashed() + ->whereNull('deleted_at') ->whereRaw('id % 100 < 5') ->limit(5) ->pluck('user_id'); } + + /** + * @return Collection + */ + private function getMasterUserIdsSQLite(): Collection + { + // For SQLite, we'll use a different approach to get a stable random sample. + // We use the rowid (which SQLite automatically provides) for sampling. + return PlayerGame::where('game_id', $this->sourceGame->id) + ->where('user_id', '!=', $this->user->id) + ->whereAllAchievementsUnlocked() + ->whereNull('deleted_at') + ->orderByRaw('rowid % 100') + ->limit(5) + ->pluck('user_id'); + } } From d49d9c093e44bc41b1dfc83de8553e0f4ff454a6 Mon Sep 17 00:00:00 2001 From: Wes Copeland Date: Tue, 28 Jan 2025 21:22:34 -0500 Subject: [PATCH 5/5] fix: address pr feedback --- .../GameSuggestions/Strategies/SharedHubStrategy.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php b/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php index 4a09d859f2..65517d1956 100644 --- a/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php +++ b/app/Platform/Services/GameSuggestions/Strategies/SharedHubStrategy.php @@ -73,7 +73,7 @@ private function getRandomHubMariaDB(): ?GameSet * Exclude certain hubs via regex. * We don't want to recommend something just because it's in the Noncompliant Writing hub. */ - ->whereRaw("game_sets.title NOT REGEXP '^(Meta[| -]|Misc\\.[ -])'") + ->whereRaw("game_sets.title NOT REGEXP '^\\\\[(Meta[| -]|Misc\\\\.[ -])'") ->inRandomOrder() ->first(); } @@ -89,9 +89,9 @@ private function getRandomHubSQLite(): ?GameSet $query->where('game_id', '!=', $this->sourceGame->id); // needs other games too. }) ->where(function ($query) { - $query->where('title', 'NOT LIKE', 'Meta - %') - ->where('title', 'NOT LIKE', 'Meta|%') - ->where('title', 'NOT LIKE', 'Misc. - %'); + $query->where('title', 'NOT LIKE', '[Meta - %') + ->where('title', 'NOT LIKE', '[Meta|%') + ->where('title', 'NOT LIKE', '[Misc. - %'); }) ->inRandomOrder() ->first();