Module: Motor::ApiQuery::Filter
- Defined in:
- lib/motor/api_query/filter.rb
Constant Summary collapse
- LIKE_FILTER_VALUE_REGEXP =
/\A%?(.*?)%?\z/.freeze
- DISTINCT_RESTRICTED_COLUMN_TYPES =
%i[json point].freeze
Class Method Summary collapse
- .apply_filters(rel, filters) ⇒ Object
- .apply_predicates(rel, filters) ⇒ Object
- .call(rel, params) ⇒ Object
- .can_apply_distinct?(rel) ⇒ Boolean
- .clean_filters(value) ⇒ Object
- .normalize_action(action, value) ⇒ Object
- .normalize_filter_hash(hash) ⇒ Object
- .normalize_params(params) ⇒ Object
Class Method Details
.apply_filters(rel, filters) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/motor/api_query/filter.rb', line 46 def apply_filters(rel, filters) filters = clean_filters(filters) rel = apply_predicates(rel, filters) alias_tracker = if Rails.version.to_f >= 7.2 rel.alias_tracker else ActiveRecord::Associations::AliasTracker.create(rel.connection, rel.table.name, []) end filter_clause_factory = ActiveRecord::Relation::FilterClauseFactory.new(rel.klass, rel.predicate_builder) where_clause = filter_clause_factory.build(filters, alias_tracker) rel_values = rel.instance_variable_get(:@values) if rel_values[:where] rel_values[:where] += where_clause else rel_values[:where] = where_clause end rel end |
.apply_predicates(rel, filters) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/motor/api_query/filter.rb', line 32 def apply_predicates(rel, filters) joins = ActiveRecord::PredicateBuilder.filter_joins(rel.klass, filters) joins.flatten.reduce(rel) do |acc, j| if j.is_a?(String) || j.is_a?(Arel::Nodes::Join) acc.joins(j) elsif j.present? acc.left_outer_joins(j) else acc end end end |
.call(rel, params) ⇒ Object
11 12 13 14 15 16 17 18 19 20 |
# File 'lib/motor/api_query/filter.rb', line 11 def call(rel, params) return rel if params.blank? normalized_params = normalize_params(Array.wrap(params)) rel = apply_filters(rel, normalized_params) rel = rel.distinct if can_apply_distinct?(rel) rel end |
.can_apply_distinct?(rel) ⇒ Boolean
105 106 107 108 109 |
# File 'lib/motor/api_query/filter.rb', line 105 def can_apply_distinct?(rel) rel.columns.none? do |column| DISTINCT_RESTRICTED_COLUMN_TYPES.include?(column.type) end end |
.clean_filters(value) ⇒ Object
22 23 24 25 26 27 28 29 30 |
# File 'lib/motor/api_query/filter.rb', line 22 def clean_filters(value) if value.class.name == 'ActionController::Parameters' value.to_unsafe_h elsif value.is_a?(Array) value.map { |v| clean_filters(v) } else value end end |
.normalize_action(action, value) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/motor/api_query/filter.rb', line 111 def normalize_action(action, value) case action when 'includes' ['contains', value] when 'contains' ['ilike', value.sub(LIKE_FILTER_VALUE_REGEXP, '%\1%')] when 'starts_with' ['ilike', value.sub(LIKE_FILTER_VALUE_REGEXP, '\1%')] when 'ends_with' ['ilike', value.sub(LIKE_FILTER_VALUE_REGEXP, '%\1')] when 'eqnull' ['eq', nil] when 'neqnull' ['neq', nil] else [action, value] end end |
.normalize_filter_hash(hash) ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/motor/api_query/filter.rb', line 90 def normalize_filter_hash(hash) hash.each_with_object({}) do |(action, value), acc| new_action, new_value = if value.is_a?(Hash) [action, normalize_filter_hash(value)] else normalize_action(action, value) end acc[new_action] = new_value acc end end |
.normalize_params(params) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/motor/api_query/filter.rb', line 73 def normalize_params(params) params.map do |item| next item if item.is_a?(String) next normalize_params(item) if item.is_a?(Array) item = item.to_unsafe_h if item.respond_to?(:to_unsafe_h) item.transform_values do |filter| if filter.is_a?(Hash) normalize_filter_hash(filter) else filter end end end.split('OR').product(['OR']).flatten(1)[0...-1] end |