Fix count filters and refactor apply_filters

This commit is contained in:
Justin Edmund 2025-02-13 22:27:01 -08:00
parent 82fa291398
commit 86287ec10a
2 changed files with 123 additions and 16 deletions

View file

@ -46,15 +46,11 @@ class PartyQueryBuilder
# Example edge case: If the request does not specify 'characters_count',
# then the default (e.g. 3) will be used, with the upper bound coming from a constant.
def apply_filters(query)
conditions = build_filters
query = query.where(conditions)
# If name_quality filtering is enabled via params, apply it.
query = query.where(name_quality) if @params[:name_quality].present?
query.where(
weapons_count: build_count(@params[:weapons_count], default_weapons_count)..max_weapons,
characters_count: build_count(@params[:characters_count], default_characters_count)..max_characters,
summons_count: build_count(@params[:summons_count], default_summons_count)..max_summons
)
query = apply_base_filters(query)
query = apply_name_quality_filter(query)
query = apply_count_filters(query)
query
end
# Example callback method: if no explicit status filter is provided, we may want
@ -148,6 +144,63 @@ class PartyQueryBuilder
query
end
# Applies base filtering conditions from build_filters to the query.
# @param query [ActiveRecord::QueryMethods::WhereChain] The current query.
# @return [ActiveRecord::Relation] The query with base filters applied.
def apply_base_filters(query)
query.where(build_filters)
end
# Applies the name quality filter to the query if the parameter is present.
# @param query [ActiveRecord::QueryMethods::WhereChain] The current query.
# @return [ActiveRecord::Relation] The query with the name quality filter applied.
def apply_name_quality_filter(query)
@params[:name_quality].present? ? query.where(name_quality) : query
end
# Applies count filters to the query based on provided parameters or default options.
# If apply_defaults is set in options, default ranges are applied.
# Otherwise, count ranges are built from provided parameters.
# @param query [ | ActiveRecord::QueryMethods::WhereChain] The current query.
# @return [ActiveRecord::Relation] The query with count filters applied.
def apply_count_filters(query)
if @options[:apply_defaults]
query.where(
weapons_count: default_weapons_count..max_weapons,
characters_count: default_characters_count..max_characters,
summons_count: default_summons_count..max_summons
)
elsif count_filter_provided?
query.where(build_count_conditions)
else
query
end
end
# Determines if any count filter parameters have been provided.
# @return [Boolean] True if any count filters are provided, false otherwise.
def count_filter_provided?
@params.key?(:weapons_count) || @params.key?(:characters_count) || @params.key?(:summons_count)
end
# Builds a hash of count conditions based on the count filter parameters.
# @return [Hash] A hash with keys :weapons_count, :characters_count, and :summons_count.
def build_count_conditions
{
weapons_count: build_range(@params[:weapons_count], max_weapons),
characters_count: build_range(@params[:characters_count], max_characters),
summons_count: build_range(@params[:summons_count], max_summons)
}
end
# Constructs a range for a given count parameter.
# @param param_value [String, nil] The count filter parameter value.
# @param max_value [Integer] The maximum allowed value for the count.
# @return [Range] A range from the provided count (or 0 if blank) to the max_value.
def build_range(param_value, max_value)
param_value.present? ? param_value.to_i..max_value : 0..max_value
end
# Maps an IDs first character to the corresponding grid table and object table names.
#
# For example:
@ -170,27 +223,27 @@ class PartyQueryBuilder
# Default values and maximum limits for counts.
def default_weapons_count
@options[:default_weapons_count] || 5;
@options[:default_weapons_count] || 5
end
def default_characters_count
@options[:default_characters_count] || 3;
@options[:default_characters_count] || 3
end
def default_summons_count
@options[:default_summons_count] || 2;
@options[:default_summons_count] || 2
end
def max_weapons
@options[:max_weapons] || 13;
@options[:max_weapons] || 13
end
def max_characters
@options[:max_characters] || 5;
@options[:max_characters] || 5
end
def max_summons
@options[:max_summons] || 8;
@options[:max_summons] || 8
end
# Stub method for name quality filtering.

View file

@ -34,7 +34,6 @@ RSpec.describe PartyQueryBuilder, type: :model do
it 'returns an ActiveRecord::Relation with filters applied' do
query = subject.build
sql = query.to_sql
# Expect the element filter to be applied (converted to integer)
expect(sql).to include('"parties"."element" = 3')
# Expect the raid filter to be applied
@ -192,6 +191,61 @@ RSpec.describe PartyQueryBuilder, type: :model do
expect(sql).not_to include('NOT EXISTS (')
end
end
context 'when apply_defaults option is true' do
subject do
described_class.new(
base_query,
params: params,
current_user: current_user,
options: { apply_defaults: true }
)
end
it 'adds count filters to the query' do
query = subject.build
sql = query.to_sql
expect(sql).to include('"weapons_count" BETWEEN')
expect(sql).to include('"characters_count" BETWEEN')
expect(sql).to include('"summons_count" BETWEEN')
end
end
context 'when apply_defaults option is false (or not provided)' do
let(:blanked_params) do
{
element: '3',
raid: '123e4567-e89b-12d3-a456-426614174000',
recency: '3600',
full_auto: '1',
auto_guard: '0',
charge_attack: '1',
weapons_count: '', # blank => should use default
characters_count: '',
summons_count: '',
includes: '300001,200002',
excludes: '100003',
name_quality: '1' # dummy flag for testing name_quality clause
}
end
subject do
described_class.new(
base_query,
params: blanked_params,
current_user: current_user,
options: {}
)
end
it 'does not add count filters to the query' do
query = subject.build
sql = query.to_sql
expect(sql).not_to include('weapons_count BETWEEN')
expect(sql).not_to include('characters_count BETWEEN')
expect(sql).not_to include('summons_count BETWEEN')
end
end
end
end
end