From 8c78d2627c753244d2a030662ac4210f4b58e09f Mon Sep 17 00:00:00 2001 From: Miguel de los Reyes Date: Fri, 8 May 2026 16:49:45 +0000 Subject: [PATCH 1/2] Fix decklist card exclusion filter and add tests --- app/resources/decklist_resource.rb | 4 +-- .../resources/decklist_resource_reads_spec.rb | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/app/resources/decklist_resource.rb b/app/resources/decklist_resource.rb index 10a3df1..c894fca 100644 --- a/app/resources/decklist_resource.rb +++ b/app/resources/decklist_resource.rb @@ -39,9 +39,7 @@ class DecklistResource < ApplicationResource # Will return decklists that do NOT contain any of the specified cards. filter :exclude_card_id, :string do eq do |scope, card_ids| - scope.left_joins(:decklist_cards) - .group('decklists.id') - .having('COUNT(CASE WHEN decklists_cards.card_id IN (?) THEN 1 END) = 0', card_ids) + scope.where.not(id: DecklistCard.where(card_id: card_ids).select(:decklist_id)) end end diff --git a/spec/resources/decklist_resource_reads_spec.rb b/spec/resources/decklist_resource_reads_spec.rb index 53fd0c7..ac566b3 100644 --- a/spec/resources/decklist_resource_reads_spec.rb +++ b/spec/resources/decklist_resource_reads_spec.rb @@ -96,6 +96,35 @@ expect(decklist_ids).to include(runner_decklist.id) end end + + context 'with card_id and exclude_card_id combined' do + let!(:corp_decklist) { Decklist.find('11111111-1111-1111-1111-111111111111') } + let!(:runner_decklist) { Decklist.find('22222222-2222-2222-2222-222222222222') } + + it 'returns the decklist that contains the card and lacks the excluded card' do + params[:filter] = { card_id: { eq: 'pennyshaver' }, exclude_card_id: { eq: 'hedge_fund' } } + render + expect(d.map(&:id)).to eq([runner_decklist.id]) + end + + it 'returns no decklists when the contained card is also excluded' do + params[:filter] = { card_id: { eq: 'pennyshaver' }, exclude_card_id: { eq: 'pennyshaver' } } + render + expect(d).to be_empty + end + + it 'returns no decklists when the only matching decklist also has the excluded card' do + params[:filter] = { card_id: { eq: 'pennyshaver' }, exclude_card_id: { eq: 'stargate' } } + render + expect(d).to be_empty + end + + it 'returns the decklist when the excluded card is absent from the matching decklist' do + params[:filter] = { card_id: { eq: 'adonis_campaign' }, exclude_card_id: { eq: 'stargate' } } + render + expect(d.map(&:id)).to eq([corp_decklist.id]) + end + end end describe 'sideloading' do From a1588e9e2930e492ab81f34d91523dd6fda73f83 Mon Sep 17 00:00:00 2001 From: Miguel de los Reyes Date: Fri, 8 May 2026 17:29:43 +0000 Subject: [PATCH 2/2] Rewrite card_id filter --- app/resources/decklist_resource.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/resources/decklist_resource.rb b/app/resources/decklist_resource.rb index c894fca..949841b 100644 --- a/app/resources/decklist_resource.rb +++ b/app/resources/decklist_resource.rb @@ -29,10 +29,11 @@ class DecklistResource < ApplicationResource # Will return decklists where all cards specified are present. filter :card_id, :string do eq do |scope, card_ids| - scope.joins(:decklist_cards) - .where(decklist_cards: { card_id: card_ids }) - .group('decklists.id') - .having('COUNT(DISTINCT decklist_cards.card_id) = ?', card_ids.length) + matching = DecklistCard.where(card_id: card_ids) + .group(:decklist_id) + .having('COUNT(DISTINCT card_id) = ?', card_ids.length) + .select(:decklist_id) + scope.where(id: matching) end end