Class: Queries::Source::Filter

Inherits:
Query
  • Object
show all
Includes:
Concerns::Empty, Concerns::Tags, Concerns::Users
Defined in:
lib/queries/source/filter.rb

Constant Summary collapse

ATTRIBUTES =

TODO: likely move to model (replicated in Source too) Params exists for all CollectingEvent attributes except these

(::Source.column_names - %w{id project_id created_by_id updated_by_id created_at updated_at cached})

Instance Attribute Summary collapse

Attributes inherited from Query

#dynamic_limit, #options, #project_id, #query_string, #terms

Instance Method Summary collapse

Methods inherited from Query

#alphabetic_strings, #attribute_exact_facet, #autocomplete, #autocomplete_cached, #autocomplete_cached_wildcard_anywhere, #autocomplete_common_name_exact, #autocomplete_common_name_like, #autocomplete_exact_id, #autocomplete_exactly_named, #autocomplete_named, #autocomplete_ordered_wildcard_pieces_in_cached, #build_terms, #cached, #combine_or_clauses, #common_name_name, #common_name_table, #common_name_wild_pieces, #end_wildcard, #exactly_named, #fragments, #integers, #levenshtein_distance, #match_ordered_wildcard_pieces_in_cached, #match_wildcard_end_in_cached, #match_wildcard_in_cached, #named, #no_terms?, #only_ids, #only_integers?, #parent, #parent_child_join, #parent_child_where, #pieces, #result, #scope, #start_and_end_wildcard, #start_wildcard, #wildcard_pieces, #wildcard_wrapped_integers, #wildcard_wrapped_years, #with_cached, #with_cached_like, #with_id, #with_project_id, #year_letter, #years

Constructor Details

#initialize(params) ⇒ Filter

Returns a new instance of Filter.

Parameters:

  • params (Hash)


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/queries/source/filter.rb', line 111

def initialize(params)
  @query_string = params[:query_term]

  @author = params[:author]
  @author_ids = params[:author_ids] || []

  @author_ids_or = (params[:author_ids_or]&.downcase == 'true' ? true : false) if !params[:author_ids_or].nil?

  @ids = params[:ids] || []
  @topic_ids = params[:topic_ids] || []
  @serial_ids = params[:serial_ids] || []
  @citation_object_type = params[:citation_object_type] || []
  @citations = (params[:citations]&.downcase == 'true' ? true : false) if !params[:citations].nil?
  @documents = (params[:documents]&.downcase == 'true' ? true : false) if !params[:documents].nil?
  @exact_author = (params[:exact_author]&.downcase == 'true' ? true : false) if !params[:exact_author].nil?
  @exact_title = (params[:exact_title]&.downcase == 'true' ? true : false) if !params[:exact_title].nil?
  @in_project = (params[:in_project]&.downcase == 'true' ? true : false) if !params[:in_project].nil?
  @nomenclature = (params[:nomenclature]&.downcase == 'true' ? true : false) if !params[:nomenclature].nil?
  @notes = (params[:notes]&.downcase == 'true' ? true : false) if !params[:notes].nil?
  @project_id = params[:project_id] # TODO: also in Queries::Query
  @roles = (params[:roles]&.downcase == 'true' ? true : false) if !params[:roles].nil?
  @source_type = params[:source_type]
  @title = params[:title]
  @with_doi = (params[:with_doi]&.downcase == 'true' ? true : false) if !params[:with_doi].nil?
  @year_end = params[:year_end]
  @year_start = params[:year_start]
  @recent = (params[:recent]&.downcase == 'true' ? true : false) if !params[:recent].nil?

  @citations_on_otus = (params[:citations_on_otus]&.downcase == 'true' ? true : false) if !params[:citations_on_otus].nil?
  @ancestor_id = params[:ancestor_id]

  build_terms
  set_identifier(params)
  set_tags_params(params)
  set_user_dates(params)

  set_empty_params(params)
end

Instance Attribute Details

#ancestor_idProtonym.id?

Return all sources in Citations linked to this name or descendants to this TaxonName

Returns:

  • (Protonym.id, nil)

    return all sources in Citations linked to this name or descendants to this TaxonName



103
104
105
# File 'lib/queries/source/filter.rb', line 103

def ancestor_id
  @ancestor_id
end

#authorObject

Returns the value of attribute author.



26
27
28
# File 'lib/queries/source/filter.rb', line 26

def author
  @author
end

#author_idsObject

Returns the value of attribute author_ids.



36
37
38
# File 'lib/queries/source/filter.rb', line 36

def author_ids
  @author_ids
end

#author_ids_orObject

Returns the value of attribute author_ids_or.



39
40
41
# File 'lib/queries/source/filter.rb', line 39

def author_ids_or
  @author_ids_or
end

#citation_object_typeArray?

TODO: move tc citations concern

Returns:

  • (Array, nil)


84
85
86
# File 'lib/queries/source/filter.rb', line 84

def citation_object_type
  @citation_object_type
end

#citationsBoolean?

Returns:

  • (Boolean, nil)


59
60
61
# File 'lib/queries/source/filter.rb', line 59

def citations
  @citations
end

#citations_on_otusBoolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/queries/source/filter.rb', line 108

def citations_on_otus
  @citations_on_otus
end

#documentsBoolean?

Returns:

  • (Boolean, nil)


71
72
73
# File 'lib/queries/source/filter.rb', line 71

def documents
  @documents
end

#exact_authorBoolean?

Returns:

  • (Boolean, nil)


33
34
35
# File 'lib/queries/source/filter.rb', line 33

def exact_author
  @exact_author
end

#exact_titleBoolean?

Returns:

  • (Boolean, nil)


55
56
57
# File 'lib/queries/source/filter.rb', line 55

def exact_title
  @exact_title
end

#idsObject

Returns the value of attribute ids.



29
30
31
# File 'lib/queries/source/filter.rb', line 29

def ids
  @ids
end

#in_projectBoolean?

! requires `project_id`

Returns:

  • (Boolean, nil)


23
24
25
# File 'lib/queries/source/filter.rb', line 23

def in_project
  @in_project
end

#nomenclatureBoolean?

Returns:

  • (Boolean, nil)


75
76
77
# File 'lib/queries/source/filter.rb', line 75

def nomenclature
  @nomenclature
end

#notesBoolean?

Returns:

  • (Boolean, nil)


91
92
93
# File 'lib/queries/source/filter.rb', line 91

def notes
  @notes
end

#recentBoolean?

Returns:

  • (Boolean, nil)


63
64
65
# File 'lib/queries/source/filter.rb', line 63

def recent
  @recent
end

#rolesBoolean?

Returns:

  • (Boolean, nil)


67
68
69
# File 'lib/queries/source/filter.rb', line 67

def roles
  @roles
end

#serial_idsObject

Returns the value of attribute serial_ids.



98
99
100
# File 'lib/queries/source/filter.rb', line 98

def serial_ids
  @serial_ids
end

#source_typeString?

Returns:

  • (String, nil)


95
96
97
# File 'lib/queries/source/filter.rb', line 95

def source_type
  @source_type
end

#titleObject

Returns the value of attribute title.



51
52
53
# File 'lib/queries/source/filter.rb', line 51

def title
  @title
end

#topic_idsObject

Returns the value of attribute topic_ids.



42
43
44
# File 'lib/queries/source/filter.rb', line 42

def topic_ids
  @topic_ids
end

#with_doiBoolean?

Returns:

  • (Boolean, nil)


79
80
81
# File 'lib/queries/source/filter.rb', line 79

def with_doi
  @with_doi
end

#year_endObject

Returns the value of attribute year_end.



48
49
50
# File 'lib/queries/source/filter.rb', line 48

def year_end
  @year_end
end

#year_startObject

Returns the value of attribute year_start.



45
46
47
# File 'lib/queries/source/filter.rb', line 45

def year_start
  @year_start
end

Instance Method Details

#allActiveRecord::Relation

Returns:

  • (ActiveRecord::Relation)


406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
# File 'lib/queries/source/filter.rb', line 406

def all
  a = and_clauses
  b = merge_clauses

  q = nil
  if a && b
    q = b.where(a)
  elsif a
    q = ::Source.where(a)
  elsif b
    q = b
  else
    q = ::Source.all
  end

  q = q.order(updated_at: :desc) if recent
  q
end

#ancestor_otus_joinObject (private)



427
428
429
430
431
432
433
434
435
436
437
# File 'lib/queries/source/filter.rb', line 427

def ancestor_otus_join
  h = Arel::Table.new(:taxon_name_hierarchies)
  c = ::Citation.arel_table
  o = ::Otu.arel_table

  c.join(o, Arel::Nodes::InnerJoin).on(
    o[:id].eq(c[:citation_object_id]).and(c[:citation_object_type].eq('Otu'))
  ).join(h, Arel::Nodes::InnerJoin).on(
    o[:taxon_name_id].eq(h[:descendant_id]).and(h[:ancestor_id].eq(ancestor_id))
  )
end

#ancestor_taxon_name_classifications_joinObject (private)



451
452
453
454
455
456
457
458
459
460
461
462
463
# File 'lib/queries/source/filter.rb', line 451

def ancestor_taxon_name_classifications_join
  return nil if ancestor_id.nil?

  h = Arel::Table.new(:taxon_name_hierarchies)
  c = ::Citation.arel_table
  t = ::TaxonNameClassification.arel_table

  c.join(t, Arel::Nodes::InnerJoin).on(
    t[:id].eq(c[:citation_object_id]).and(c[:citation_object_type].eq('TaxonNameClassification'))
  ).join(h, Arel::Nodes::InnerJoin).on(
    t[:taxon_name_id].eq(h[:descendant_id]).and(h[:ancestor_id].eq(ancestor_id))
  )
end

#ancestor_taxon_name_relationship_join(join_on = :subject_taxon_name_id) ⇒ Object (private)



465
466
467
468
469
470
471
472
473
474
475
476
477
# File 'lib/queries/source/filter.rb', line 465

def ancestor_taxon_name_relationship_join(join_on = :subject_taxon_name_id)
  return nil if ancestor_id.nil?

  h = Arel::Table.new(:taxon_name_hierarchies)
  c = ::Citation.arel_table
  t = ::TaxonNameRelationship.arel_table

  c.join(t, Arel::Nodes::InnerJoin).on(
    t[:id].eq(c[:citation_object_id]).and(c[:citation_object_type].eq('TaxonNameRelationship'))
  ).join(h, Arel::Nodes::InnerJoin).on(
    t[join_on].eq(h[:descendant_id]).and(h[:ancestor_id].eq(ancestor_id))
  )
end

#ancestor_taxon_names_joinObject (private)



439
440
441
442
443
444
445
446
447
448
449
# File 'lib/queries/source/filter.rb', line 439

def ancestor_taxon_names_join
  h = Arel::Table.new(:taxon_name_hierarchies)
  c = ::Citation.arel_table
  t = ::TaxonName.arel_table

  c.join(t, Arel::Nodes::InnerJoin).on(
    t[:id].eq(c[:citation_object_id]).and(c[:citation_object_type].eq('TaxonName'))
  ).join(h, Arel::Nodes::InnerJoin).on(
    t[:id].eq(h[:descendant_id]).and(h[:ancestor_id].eq(ancestor_id))
  )
end

#ancestors_facetObject

Return all citations on Taxon names and descendants, and optionally OTUs.



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/queries/source/filter.rb', line 178

def ancestors_facet
  return nil if ancestor_id.nil?

  joins = [
    ancestor_taxon_names_join,
    ancestor_taxon_name_classifications_join,
    ancestor_taxon_name_relationship_join(:subject_taxon_name_id),
    ancestor_taxon_name_relationship_join(:object_taxon_name_id)
  ]

  joins.push ancestor_otus_join if citations_on_otus

  union = joins.collect{|j| '(' + ::Source.joins(:citations).joins( j.join_sources).to_sql + ')'}.join(' UNION ')

  ::Source.from("( #{union} ) as sources")
end

#and_clausesActiveRecord::Relation

Returns:

  • (ActiveRecord::Relation)


383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/queries/source/filter.rb', line 383

def and_clauses
  clauses = []

  clauses += [
    cached,
    source_ids_facet,
    serial_ids_facet,
    attribute_exact_facet(:author),
    attribute_exact_facet(:title),
    source_type_facet,
    year_facet
  ].compact

  return nil if clauses.empty?

  a = clauses.shift
  clauses.each do |b|
    a = a.and(b)
  end
  a
end

#author_ids_facetObject



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/queries/source/filter.rb', line 218

def author_ids_facet
  return nil if author_ids.empty?
  o = table
  r = ::Role.arel_table

  a = o.alias("a_") 
  b = o.project(a[Arel.star]).from(a)

  c = r.alias('r1')

  b = b.join(c, Arel::Nodes::OuterJoin)
    .on(
      a[:id].eq(c[:role_object_id])
    .and(c[:role_object_type].eq('Source'))
    .and(c[:type].eq('SourceAuthor'))
    )

  e = c[:id].not_eq(nil)
  f = c[:person_id].eq_any(author_ids)

  b = b.where(e.and(f))
  b = b.group(a['id'])
  b = b.having(a['id'].count.eq(author_ids.length)) unless author_ids_or
  b = b.as('aut_z1_')

  ::Source.joins(Arel::Nodes::InnerJoin.new(b, Arel::Nodes::On.new(b['id'].eq(o['id']))))
end

#base_queryObject



160
161
162
# File 'lib/queries/source/filter.rb', line 160

def base_query
  ::Source.select('sources.*')
end

#citation_facetObject

TODO: move to a concern



264
265
266
267
268
269
270
271
272
273
274
# File 'lib/queries/source/filter.rb', line 264

def citation_facet
  return nil if citations.nil?

  if citations
    ::Source.joins(:citations).distinct
  else
    ::Source.left_outer_joins(:citations)
      .where(citations: {id: nil})
      .distinct
  end
end

#citation_object_type_facetObject

TODO: move to citation concern



330
331
332
333
334
# File 'lib/queries/source/filter.rb', line 330

def citation_object_type_facet
  return nil if citation_object_type.empty?
  ::Source.joins(:citations)
    .where(citations: {citation_object_type: citation_object_type}).distinct
end

#document_facetObject

TODO: move to a concern



317
318
319
320
321
322
323
324
325
326
327
# File 'lib/queries/source/filter.rb', line 317

def document_facet
  return nil if documents.nil?

  if documents
    ::Source.joins(:documents).distinct
  else
    ::Source.left_outer_joins(:documents)
      .where(documents: {id: nil})
      .distinct
  end
end

#fragment_year_matchesActiveRecord::Relation?

Returns if user provides 5 or fewer strings and any number of years look for any string && year.

Returns:

  • (ActiveRecord::Relation, nil)

    if user provides 5 or fewer strings and any number of years look for any string && year



166
167
168
169
170
171
172
173
174
# File 'lib/queries/source/filter.rb', line 166

def fragment_year_matches
  if fragments.any?
    s = table[:cached].matches_any(fragments)
    s = s.and(table[:year].eq_any(years)) if !years.empty?
    s
  else
    nil
  end
end

#in_project_facetObject



250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/queries/source/filter.rb', line 250

def in_project_facet
  return nil if project_id.nil? || in_project.nil?

  if in_project
    ::Source.joins(:project_sources)
      .where(project_sources: {project_id: project_id})
  else
    ::Source.left_outer_joins(:project_sources)
      .where("project_sources.project_id != ? OR project_sources.id IS NULL", Current.project_id)
      .distinct
  end
end

#merge_clausesObject



350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
# File 'lib/queries/source/filter.rb', line 350

def merge_clauses
  clauses = [
    ancestors_facet,
    author_ids_facet,
    topic_ids_facet,
    citation_facet,
    citation_object_type_facet,
    document_facet,
    in_project_facet,
    nomenclature_facet,
    role_facet,
    with_doi_facet,
    keyword_id_facet,
    tag_facet,
    note_facet,
    identifier_between_facet,
    identifier_facet,
    identifier_namespace_facet,
    created_updated_facet, # See Queries::Concerns::Users
    empty_fields_facet,    # See Queries::Concerns::Empty
    not_empty_fields_facet,
  ].compact

  return nil if clauses.empty?

  a = clauses.shift
  clauses.each do |b|
    a = a.merge(b)
  end
  a
end

#nomenclature_facetObject



336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/queries/source/filter.rb', line 336

def nomenclature_facet
  return nil if nomenclature.nil?

  if nomenclature 
    ::Source.joins(:citations)
      .where(citations: {citation_object_type: ['TaxonName', 'TaxonNameRelationship', 'TaxonNameClassification', 'TypeMaterial']})
      .distinct
  else
    ::Source.left_outer_joins(:citations)
      .where("(citations.citation_object_type NOT IN ('TaxonName','TaxonNameRelationship','TaxonNameClassification','TypeMaterial')) OR (citations.id is null)")
      .distinct
  end
end

#note_facetObject

TODO: move to a concern



305
306
307
308
309
310
311
312
313
314
# File 'lib/queries/source/filter.rb', line 305

def note_facet
  return nil if notes.nil?

  if notes 
    ::Source.joins(:notes).distinct
  else
    ::Source.left_outer_joins(:notes)
      .where(notes: {id: nil})
  end
end

#project_sources_tableArel::Table

Returns:

  • (Arel::Table)


156
157
158
# File 'lib/queries/source/filter.rb', line 156

def project_sources_table
  ::ProjectSource.arel_table
end

#role_facetObject

TODO: move to a concern



293
294
295
296
297
298
299
300
301
302
# File 'lib/queries/source/filter.rb', line 293

def role_facet
  return nil if roles.nil?

  if roles
    ::Source.joins(:roles).distinct
  else
    ::Source.left_outer_joins(:roles)
      .where(roles: {id: nil})
  end
end

#serial_ids_facetObject



214
215
216
# File 'lib/queries/source/filter.rb', line 214

def serial_ids_facet
  serial_ids.empty? ? nil : table[:serial_id].eq_any(serial_ids)
end

#source_ids_facetObject



210
211
212
# File 'lib/queries/source/filter.rb', line 210

def source_ids_facet
  ids.empty? ? nil : table[:id].eq_any(ids)
end

#source_type_facetObject



195
196
197
198
# File 'lib/queries/source/filter.rb', line 195

def source_type_facet
  return nil if source_type.blank?
  table[:type].eq(source_type)
end

#tableArel::Table

Returns:

  • (Arel::Table)


151
152
153
# File 'lib/queries/source/filter.rb', line 151

def table
  ::Source.arel_table
end

#topic_ids_facetObject



246
247
248
# File 'lib/queries/source/filter.rb', line 246

def topic_ids_facet
  ::Source.joins(:citation_topics).where(citation_topics: { topic_id: topic_ids }).distinct unless topic_ids.empty?
end

#with_doi_facetObject

TODO: move to generalized code in identifiers concern



277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/queries/source/filter.rb', line 277

def with_doi_facet
  return nil if with_doi.nil?

  # See lib/queries/concerns/identifiers.rb
  @identifier_type.push 'Identifier::Global::Doi'
  @identifier_type.uniq!

  if with_doi
    identifier_type_facet
  else
    ::Source.left_outer_joins(:identifiers)
      .where("(identifiers.type != 'Identifier::Global::Doi') OR (identifiers.identifier_object_id is null)")
  end
end

#year_facetObject



200
201
202
203
204
205
206
207
208
# File 'lib/queries/source/filter.rb', line 200

def year_facet
  return nil if year_start.blank?
  if year_start && !year_end.blank?
    table[:year].gteq(year_start)
      .and(table[:year].lteq(year_end))
  else # only start
    table[:year].eq(year_start)
  end
end