diff --git a/app/resources/decklist_resource.rb b/app/resources/decklist_resource.rb index 10a3df1..949841b 100644 --- a/app/resources/decklist_resource.rb +++ b/app/resources/decklist_resource.rb @@ -29,19 +29,18 @@ 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 # 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