module ActiveHashRelation class FilterApplier include Helpers include ColumnFilters include AssociationFilters include ScopeFilters include SortFilters include LimitFilters attr_reader :configuration def initialize(resource, params, include_associations: false, model: nil, is_not: false) @configuration = Module.nesting.last.configuration @resource = resource if params.respond_to?(:to_unsafe_h) @params = HashWithIndifferentAccess.new(params.to_unsafe_h) else @params = HashWithIndifferentAccess.new(params) end @include_associations = include_associations @model = find_model(model) is_not ? @is_not = true : @is_not = false end def apply_filters run_or_filters run_not_filters table_name = @model.table_name @model.columns.each do |c| next if @params[c.name.to_s].nil? next if @params[c.name.to_s].is_a?(String) && @params[c.name.to_s].blank? case c.type when :integer if @model.defined_enums[c.name] && @model.defined_enums[c.name][@params[c.name]] @params[c.name] = @model.defined_enums[c.name][@params[c.name]] end @resource = filter_integer(@resource, c.name, table_name, @params[c.name]) when :float @resource = filter_float(@resource, c.name, table_name, @params[c.name]) when :decimal @resource = filter_decimal(@resource, c.name, table_name, @params[c.name]) when :string, :uuid, :text @resource = filter_string(@resource, c.name, table_name, @params[c.name]) when :date @resource = filter_date(@resource, c.name, table_name, @params[c.name]) when :datetime, :timestamp @resource = filter_datetime(@resource, c.name, table_name, @params[c.name]) when :boolean @resource = filter_boolean(@resource, c.name, table_name, @params[c.name]) end end if @params.include?(:scopes) if ActiveHashRelation.configuration.filter_active_record_scopes @resource = filter_scopes(@resource, @params[:scopes], @model) else Rails.logger.warn('Ignoring ActiveRecord scope filters because they are not enabled') end end @resource = filter_associations(@resource, @params, @model) if @include_associations @resource = apply_limit(@resource, @params[:limit]) if @params.include?(:limit) @resource = apply_sort(@resource, @params[:sort], @model) if @params.include?(:sort) return @resource end def filter_class(resource_name) "#{configuration.filter_class_prefix}#{resource_name.pluralize}#{configuration.filter_class_suffix}".constantize end def run_or_filters if @params[:or].is_a?(Array) if ActiveRecord::VERSION::MAJOR < 5 return Rails.logger.warn("OR query is supported on ActiveRecord 5+") end if @params[:or].length >= 2 array = @params[:or].map do |or_param| self.class.new(@resource, or_param, include_associations: @include_associations).apply_filters end @resource = @resource.merge(array[0]) array[1..-1].each{|query| @resource = @resource.or(query)} else Rails.logger.warn("Can't run an OR with 1 element!") end end end def run_not_filters if @params[:not].is_a?(Hash) && !@params[:not].blank? @resource = self.class.new( @resource, @params[:not], include_associations: @include_associations, is_not: true ).apply_filters end end end end