• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MushroomObserver / mushroom-observer / 14145571326

29 Mar 2025 12:22PM UTC coverage: 84.27% (-9.7%) from 93.985%
14145571326

Pull #2808

github

nimmolo
Update rss_logs_controller_test.rb

Add more tests for filters
Pull Request #2808: Convert Query to AR scopes

477 of 2306 new or added lines in 78 files covered. (20.69%)

1381 existing lines in 27 files now uncovered.

26562 of 31520 relevant lines covered (84.27%)

540.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.11
/app/classes/query/scope_modules/initialization.rb
1
# frozen_string_literal: true
2

3
# Helper methods for turning Query parameters into AR conditions.
4
module Query::ScopeModules::Initialization
1✔
5
  attr_accessor :scopes, :order, :last_query
1✔
6

7
  def initialized?
1✔
8
    @initialized ? true : false
9,705✔
9
  end
10

11
  def initialize_query
1✔
12
    @initialized = true
2,117✔
13
    @order       = ""
2,117✔
14
    @scopes      = model
2,117✔
15
    initialize_scopes
2,117✔
16
    initialize_order
2,117✔
17
    @last_query  = sql
2,117✔
18
  end
19

20
  def sql
1✔
21
    initialize_query unless initialized?
2,915✔
22

23
    @sql = scopes.all.to_sql
2,915✔
24
  end
25

26
  def query
1✔
27
    initialize_query unless initialized?
265✔
28

29
    @query = scopes.all
265✔
30
  end
31

32
  def initialize_scopes
1✔
33
    # `where`/`join` strings never come from user, so no need to sanitize.
34
    # (I believe they are only used by the site stats page. -JPH 20190708)
35
    self.where += params[:where] if params[:where]
2,117✔
36
    add_join(params[:join]) if params[:join]
2,117✔
37
    send_content_filters_to_rss_log_subqueries
2,117✔
38
    initialize_parameter_set
2,117✔
39
    filter_misspellings_for_name_queries
2,117✔
40
  end
41

42
  # In the case of RssLogs, pack any content filter params into subqueries.
43
  # (Content filters may add params to RssLog queries that RssLog scopes
44
  # can't handle, because they're intended for one or more related subqueries.)
45
  # Some params may go into more than one subquery if >1 `type` requested.
46
  def send_content_filters_to_rss_log_subqueries
1✔
47
    return if model != RssLog || !content_filters_present
2,117✔
48

49
    rss_logs_current_types.each do |model|
4✔
50
      subquery_params = content_filter_subquery_params(model)
4✔
51
      if subquery_params.present?
4✔
52
        @scopes = @scopes.send(:"#{model.name.downcase}_query",
4✔
53
                               **subquery_params)
54
      end
55
    end
56
  end
57

58
  # Current types requested on the RssLog page. Defaults to :all.
59
  def rss_logs_current_types
1✔
60
    types = [:observation, :name, :location]
4✔
61
    active_types = case params[:type]
4✔
62
                   when nil, "", :all, "all"
NEW
63
                     types
×
64
                   when Array
NEW
65
                     params[:type]
×
66
                   when String
67
                     params[:type].split
4✔
68
                   end
69
    active_types.map { |type| type.to_s.camelize.constantize }
8✔
70
  end
71

72
  # Use Query::Filter.by_model to find any filters relevant to a model.
73
  def content_filter_subquery_params(model)
1✔
74
    Query::Filter.by_model(model).
4✔
75
      each_with_object({}) do |fltr, subquery_params|
76
        next if (val = params[fltr.sym]).to_s == ""
20✔
77

78
        subquery_params[fltr.sym] = val
4✔
79
      end
80
  end
81

82
  def content_filters_present
1✔
83
    @content_filters_present ||=
26✔
84
      params.slice(*content_filter_parameters.keys).compact.present?
85
  end
86

87
  def initialize_parameter_set
1✔
88
    skippable_vals = ["[]", "{}", "", nil].freeze # keep false values
2,117✔
89
    sendable_params.each do |param, val|
2,117✔
90
      next if (param != :id_in_set && skippable_vals.include?(val.to_s)) ||
2,864✔
91
              (param == :id_in_set && val.nil?) # keep empty array
2,672✔
92

93
      @scopes = if val.is_a?(Hash)
2,672✔
94
                  @scopes.send(param, **val)
383✔
95
                else
96
                  @scopes.send(param, val)
2,289✔
97
                end
98
    end
99
  end
100

101
  # Generally, these are the `scope_parameters` defined in Query::Base.
102
  # But for RssLogs, remove any content filters from the scope builder
103
  # since they're already handled in subqueries above.
104
  def sendable_params
1✔
105
    sendable = params.slice(*scope_parameters)
2,117✔
106
    return sendable unless model == RssLog
2,117✔
107

108
    sendable.except(*content_filter_parameters.keys)
26✔
109
  end
110

111
  # Most name queries are filtered to remove misspellings.
112
  def filter_misspellings_for_name_queries
1✔
113
    return if model != Name || !params[:misspellings].nil?
2,117✔
114

115
    @scopes = @scopes.with_correct_spelling
263✔
116
  end
117

118
  # Make a value safe for SQL.
119
  def escape(val)
1✔
NEW
120
    model.connection.quote(val)
×
121
  end
122

123
  # Put together a list of ids for use in a "id IN (1,2,...)" condition.
124
  #
125
  #   set = clean_id_set(name.children)
126
  #   @where << "names.id IN (#{set})"
127
  #
128
  def clean_id_set(ids)
1✔
NEW
129
    set = limited_id_set(ids).map(&:to_s).join(",")
×
NEW
130
    set.presence || "-1"
×
131
  end
132

133
  # array of max of MO.query_max_array unique ids for use with Arel "in"
134
  #    where(<x>.in(limited_id_set(ids)))
135
  def limited_id_set(ids)
1✔
136
    ids.map(&:to_i).uniq[0, MO.query_max_array]
1,549✔
137
  end
138

139
  # Combine args into one parenthesized condition by ANDing them.
140
  def and_clause(*args)
1✔
NEW
141
    if args.length > 1
×
142
      # "(#{args.join(" AND ")})"
NEW
143
      starting = args.shift
×
NEW
144
      args.reduce(starting) { |result, arg| result.and(arg) }
×
145
    else
NEW
146
      args.first
×
147
    end
148
  end
149

150
  # Combine args into one parenthesized condition by ORing them.
151
  def or_clause(*args)
1✔
NEW
152
    if args.length > 1
×
153
      # "(#{args.join(" OR ")})"
NEW
154
      starting = args.shift
×
NEW
155
      args.reduce(starting) { |result, arg| result.or(arg) }
×
156
    else
NEW
157
      args.first
×
158
    end
159
  end
160

161
  # Add a join condition if it doesn't already exist.  There are two forms:
162
  #
163
  #   # Add join from root table to the given table:
164
  #   add_join(:observations)
165
  #     => join << :observations
166
  #
167
  #   # Add join from one table to another: (will create join from root to
168
  #   # first table if it doesn't already exist)
169
  #   add_join(:observations, :names)
170
  #     => join << {:observations => :names}
171
  #   add_join(:names, :descriptions)
172
  #     => join << {:observations => {:names => :descriptions}}
173
  #
174
  # def add_join(*)
175
  #   @join.add_leaf(*)
176
  # end
177

178
  # Same as add_join but can provide chain of more than two tables.
179
  # def add_joins(*args)
180
  #   if args.length == 1
181
  #     @join.add_leaf(args[0])
182
  #   elsif args.length > 1
183
  #     while args.length > 1
184
  #       @join.add_leaf(args[0], args[1])
185
  #       args.shift
186
  #     end
187
  #   end
188
  # end
189

190
  # Safely add to :where in +args+. Dups <tt>args[:where]</tt>,
191
  # casts it into an Array, and returns the new Array.
192
  def extend_where(args)
1✔
NEW
193
    extend_arg(args, :where)
×
194
  end
195

196
  # Safely add to :join in +args+.  Dups <tt>args[:join]</tt>, casts it into
197
  # an Array, and returns the new Array.
198
  def extend_join(args)
1✔
NEW
199
    extend_arg(args, :join)
×
200
  end
201

202
  # Safely add to +arg+ in +args+.  Dups <tt>args[arg]</tt>, casts it into
203
  # an Array, and returns the new Array.
204
  def extend_arg(args, arg)
1✔
NEW
205
    args[arg] = case old_arg = args[arg]
×
206
                when Symbol, String
NEW
207
                  [old_arg]
×
208
                when Array
NEW
209
                  old_arg.dup
×
210
                else
NEW
211
                  []
×
212
                end
213
  end
214
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc