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

MushroomObserver / mushroom-observer / 14249333043

03 Apr 2025 05:40PM UTC coverage: 93.803% (-0.05%) from 93.848%
14249333043

push

github

web-flow
Merge pull request #2863 from MushroomObserver/query-ar-el-es-apikeys-proj-spl-users

Query AR - fourth round: APIKeys, ExternalLinks, ExternalSites, Projects, Users

25 of 26 new or added lines in 5 files covered. (96.15%)

16 existing lines in 4 files now uncovered.

27776 of 29611 relevant lines covered (93.8%)

584.38 hits per line

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

92.86
/app/classes/query/modules/joining.rb
1
# frozen_string_literal: true
2

3
# create SQL JOIN clauses
4
module Query::Modules::Joining
1✔
5
  JOIN_CONDITIONS = {
6
    api_keys: {
1✔
7
      users: :user_id
8
    },
9
    articles: {
10
      rss_logs: :rss_log_id,
11
      users: :user_id
12
    },
13
    collection_numbers: {
14
      users: :user_id
15
    },
16
    observation_collection_numbers: {
17
      collection_numbers: :collection_number_id,
18
      observations: :observation_id
19
    },
20
    comments: {
21
      location_descriptions: :target,
22
      locations: :target,
23
      name_descriptions: :target,
24
      names: :target,
25
      observations: :target,
26
      projects: :target,
27
      species_lists: :target,
28
      users: :user_id
29
    },
30
    donations: {
31
      users: :user_id
32
    },
33
    external_links: {
34
      external_sites: :external_site_id,
35
      observations: :observation_id,
36
      users: :user_id
37
    },
38
    external_sites: {
39
      projects: :project_id
40
    },
41
    field_slips: {
42
      observations: :observation_id
43
    },
44
    glossary_terms: {
45
      "images.thumb_image": :thumb_image_id,
46
      rss_logs: :rss_log_id,
47
      users: :user_id
48
    },
49
    glossary_term_images: {
50
      images: :image_id,
51
      glossary_terms: :glossary_term_id
52
    },
53
    herbaria: {
54
      locations: :location_id,
55
      users: :personal_user_id
56
    },
57
    herbarium_curators: {
58
      herbaria: :herbarium_id,
59
      users: :user_id
60
    },
61
    image_votes: {
62
      images: :image_id,
63
      users: :user_id
64
    },
65
    images: {
66
      users: :user_id,
67
      licenses: :license_id
68
    },
69
    observation_images: {
70
      images: :image_id,
71
      observations: :observation_id
72
    },
73
    project_images: {
74
      images: :image_id,
75
      projects: :project_id
76
    },
77
    interests: {
78
      locations: :target,
79
      names: :target,
80
      observations: :target,
81
      users: :user_id
82
    },
83
    location_descriptions: {
84
      locations: :location_id,
85
      users: :user_id
86
    },
87
    location_description_admins: {
88
      location_descriptions: :location_description_id,
89
      user_groups: :user_group_id
90
    },
91
    location_description_authors: {
92
      location_descriptions: :location_description_id,
93
      users: :user_id
94
    },
95
    location_description_editors: {
96
      location_descriptions: :location_description_id,
97
      users: :user_id
98
    },
99
    location_description_readers: {
100
      location_descriptions: :location_description_id,
101
      user_groups: :user_group_id
102
    },
103
    location_description_versions: {
104
      location_descriptions: :location_description_id
105
    },
106
    location_description_writers: {
107
      location_descriptions: :location_description_id,
108
      user_groups: :user_group_id
109
    },
110
    locations: {
111
      licenses: :license_id,
112
      "location_descriptions.default": :description_id,
113
      rss_logs: :rss_log_id,
114
      users: :user_id
115
    },
116
    location_versions: {
117
      locations: :location_id
118
    },
119
    name_descriptions: {
120
      names: :name_id,
121
      users: :user_id
122
    },
123
    name_description_admins: {
124
      name_descriptions: :name_description_id,
125
      user_groups: :user_group_id
126
    },
127
    name_description_authors: {
128
      name_descriptions: :name_description_id,
129
      users: :user_id
130
    },
131
    name_description_editors: {
132
      name_descriptions: :name_description_id,
133
      users: :user_id
134
    },
135
    name_description_readers: {
136
      name_descriptions: :name_description_id,
137
      user_groups: :user_group_id
138
    },
139
    name_description_versions: {
140
      name_descriptions: :name_description_id
141
    },
142
    name_description_writers: {
143
      name_descriptions: :name_description_id,
144
      user_groups: :user_group_id
145
    },
146
    names: {
147
      licenses: :license_id,
148
      "name_descriptions.default": :description_id,
149
      rss_logs: :rss_log_id,
150
      users: :user_id,
151
      "users.reviewer": :reviewer_id
152
    },
153
    name_versions: {
154
      names: :name_id
155
    },
156
    name_trackers: {
157
      names: :name,
158
      users: :user_id
159
    },
160
    naming_reasons: {
161
      namings: :naming_id
162
    },
163
    namings: {
164
      names: :name_id,
165
      observations: :observation_id,
166
      users: :user_id
167
    },
168
    observations: {
169
      locations: :location_id,
170
      names: :name_id,
171
      rss_logs: :rss_log_id,
172
      users: :user_id,
173
      "images.thumb_image": :thumb_image_id,
174
      "image_votes.thumb_image": [:thumb_image_id, :image_id]
175
    },
176
    project_observations: {
177
      observations: :observation_id,
178
      projects: :project_id
179
    },
180
    species_list_observations: {
181
      observations: :observation_id,
182
      species_lists: :species_list_id
183
    },
184
    observation_herbarium_records: {
185
      observations: :observation_id,
186
      herbarium_records: :herbarium_record_id
187
    },
188
    projects: {
189
      users: :user_id,
190
      rss_logs: :rss_log_id,
191
      user_groups: :user_group_id,
192
      "user_groups.admin_group": :admin_group_id,
193
      "user_group_users.members": [:user_group_id, :user_group_id],
194
      "user_group_users.admins": [:admin_group_id, :user_group_id]
195
    },
196
    project_species_lists: {
197
      projects: :project_id,
198
      species_lists: :species_list_id
199
    },
200
    publications: {
201
      users: :user_id
202
    },
203
    rss_logs: {
204
      locations: :location_id,
205
      names: :name_id,
206
      observations: :observation_id,
207
      species_lists: :species_list_id
208
    },
209
    sequences: {
210
      observations: :observation_id,
211
      users: :user_id
212
    },
213
    species_lists: {
214
      locations: :location_id,
215
      rss_logs: :rss_log_id,
216
      users: :user_id
217
    },
218
    herbarium_records: {
219
      herbaria: :herbarium_id,
220
      users: :user_id
221
    },
222
    user_group_users: {
223
      user_groups: :user_group_id,
224
      users: :user_id
225
    },
226
    users: {
227
      images: :image_id,
228
      licenses: :license_id,
229
      locations: :location_id
230
    },
231
    votes: {
232
      namings: :naming_id,
233
      observations: :observation_id,
234
      users: :user_id
235
    }
236
  }.freeze
237

238
  # Create SQL "JOIN ON" clause to join two tables. Append an exclamation to
239
  # make it an outer join. Append ".field" to specify alternate association.
240
  def calc_join_condition(from, to, done)
1✔
241
    from = from.sub(/\..*/, "")
1,355✔
242
    to = to.dup
1,355✔
243
    do_outer = to.sub!(/!$/, "")
1,355✔
244

245
    result = []
1,355✔
246
    unless done.include?(to)
1,355✔
247
      done << to
1,093✔
248

249
      # Check for "forward" join first, e.g., if joining from observatons
250
      # to rss_logs, use "observations.rss_log_id = rss_logs.id",
251
      # because that will take advantage of the primary key on rss_logs.id.
252
      if (col = JOIN_CONDITIONS[from.to_sym] &&
1,093✔
253
                  JOIN_CONDITIONS[from.to_sym][to.to_sym])
254
        to.sub!(/\..*/, "")
618✔
255
        target_table = to
618✔
256

257
      # Now look for "reverse" join. (In the above example,
258
      # and this was how it used to be, it would be
259
      # "observations.id = rss_logs.observation_id".)
260
      elsif (col = JOIN_CONDITIONS[to.to_sym] &&
475✔
261
                    JOIN_CONDITIONS[to.to_sym][from.to_sym])
262
        to.sub!(/\..*/, "")
475✔
263
        target_table = to
475✔
264
        from, to = to, from
475✔
265
      else
266
        raise("Don't know how to join from #{from} to #{to}.")
×
267
      end
268

269
      # By default source table column is just "id"; enter both target and
270
      # source columns explcitly by making join table value an Array.
271
      if col.is_a?(Array)
1,093✔
UNCOV
272
        col1, col2 = *col
×
273
      else
274
        col1 = col
1,093✔
275
        col2 = :id
1,093✔
276
      end
277

278
      # Calculate conditions.
279
      conds = if col1.to_s.end_with?("_id")
1,093✔
280
                "#{from}.#{col1} = #{to}.#{col2}"
1,053✔
281
              else
282
                "#{from}.#{col1}_id = #{to}.id AND " \
40✔
283
                "#{from}.#{col1}_type = '#{to.singularize.camelize}'"
284
              end
285

286
      # Put the whole JOIN clause together.
287
      result << if do_outer
1,093✔
288
                  ["LEFT OUTER JOIN `#{target_table}` ON #{conds}"]
87✔
289
                else
290
                  ["JOIN `#{target_table}` ON #{conds}"]
1,006✔
291
                end
292
    end
293
    result
1,355✔
294
  end
295
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