Class: Queries::Source::Filter

Inherits:
Query::Filter show all
Includes:
Concerns::Attributes, Concerns::DataAttributes, Concerns::Empty, Concerns::Notes, Concerns::Tags
Defined in:
lib/queries/source/filter.rb

Constant Summary collapse

ATTRIBUTES =
(::Source.core_attributes - %w{bibtex_type title author serial_id}).map(&:to_sym).freeze
PARAMS =
[
  *ATTRIBUTES,
  :source_id,
  :taxon_name_id,
  :descendants,
  :author,
  :author_id_or,
  :bibtex_type,
  :citations,
  :citations_on_otus,
  :documents,
  :exact_author,
  :exact_title,
  :in_project,
  :nomenclature,
  :query_term,
  :roles,
  :serial,
  :source_type,
  :title,
  :with_doi,
  :with_title,
  :year_end,
  :year_start,
  author_id: [],
  bibtex_type: [],
  citation_object_type: [],
  empty: [],
  not_empty: [],
  serial_id: [],
  source_id: [],
  taxon_name_id: [],
  topic_id: [],
].freeze

Constants inherited from Query::Filter

Query::Filter::FILTER_QUERIES, Query::Filter::SUBQUERIES

Instance Attribute Summary collapse

Attributes inherited from Query::Filter

#api, #asserted_distribution_query, #biological_association_query, #biological_associations_graph_query, #collecting_event_query, #collection_object_query, #content_query, #controlled_vocabulary_term_query, #data_attribute_query, #descriptor_query, #document_query, #dwc_occurrence_query, #extract_query, #field_occurrence_query, #image_query, #loan_query, #object_global_id, #observation_query, #order_by, #otu_query, #page, #paginate, #params, #per, #person_query, #project_id, #recent, #recent_target, #taxon_name_query, #venn, #venn_mode

Attributes inherited from Query

#query_string, #terms

Instance Method Summary collapse

Methods inherited from Query::Filter

#all, #all_and_clauses, #all_merge_clauses, #annotator_and_clauses, #annotator_merge_clauses, annotator_params, api_except_params, api_excluded_params, #apply_venn, #attribute_exact_facet, base_filter, base_query_name, base_query_to_h, #deep_permit, included_annotator_facets, instantiated_base_filter, inverted_subqueries, #model_id_facet, #object_global_id_facet, #only_project?, params, #permitted_params, #process_url_into_params, query_name, #query_name, #set_nested_queries, #shared_and_clauses, #subquery_vector, #target_and_clauses, #venn_query

Methods inherited from Query

#alphabetic_strings, #alphanumeric_strings, base_name, #base_name, #base_query, #build_terms, #cached_facet, #end_wildcard, #levenshtein_distance, #match_ordered_wildcard_pieces_in_cached, #no_terms?, referenced_klass, #referenced_klass, #referenced_klass_except, #referenced_klass_intersection, #referenced_klass_union, #start_and_end_wildcard, #start_wildcard, #table, #wildcard_pieces

Constructor Details

#initialize(query_params) ⇒ Filter

Returns a new instance of Filter.

Parameters:

  • params (Hash)


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/queries/source/filter.rb', line 156

def initialize(query_params)
  super

  @author = params[:author]
  @author_id = params[:author_id]
  @author_id_or =  boolean_param(params,:author_id_or)
  @bibtex_type = params[:bibtex_type]
  @citation_object_type = params[:citation_object_type]
  @citations = boolean_param(params,:citations) # TODO: rename coming to reflect conflict with Citations concern
  @citations_on_otus = boolean_param(params,:citations_on_otus)
  @descendants = boolean_param(params, :descendants)
  @documents = boolean_param(params,:documents)
  @exact_author = boolean_param(params,:exact_author)
  @exact_title = boolean_param(params,:exact_title)
  @in_project = boolean_param(params,:in_project)
  @nomenclature = boolean_param(params,:nomenclature)
  @query_string = params[:query_term]&.delete("\u0000") # TODO: likely remove with current permit() paradigm
  @roles = boolean_param(params,:roles)
  @serial = boolean_param(params,:serial)
  @serial_id = params[:serial_id]
  @source_id = params[:source_id]
  @source_type = params[:source_type]
  @taxon_name_id = params[:taxon_name_id]
  @title = params[:title]
  @topic_id = params[:topic_id]
  @with_doi = boolean_param(params, :with_doi)
  @with_title = boolean_param(params, :with_title)
  @year_end = params[:year_end]
  @year_start = params[:year_start]

  build_terms

  set_data_attributes_params(params)
  set_attributes_params(params)
  set_empty_params(params)
  set_tags_params(params)
  set_notes_params(params)
  set_user_dates(params)
end

Instance Attribute Details

#authorObject

Returns the value of attribute author.



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

def author
  @author
end

#author_idObject

Returns the value of attribute author_id.



69
70
71
# File 'lib/queries/source/filter.rb', line 69

def author_id
  @author_id
end

#author_id_orObject

Returns the value of attribute author_id_or.



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

def author_id_or
  @author_id_or
end

#bibtex_typeArray, ...

one of the allowed BibTeX types

Returns:

  • (Array, String, nil)


153
154
155
# File 'lib/queries/source/filter.rb', line 153

def bibtex_type
  @bibtex_type
end

#citation_object_typeArray?

TODO: move tc citations concern

Returns:

  • (Array, nil)


116
117
118
# File 'lib/queries/source/filter.rb', line 116

def citation_object_type
  @citation_object_type
end

#citationsBoolean?

!! TODO - conflicts with citations? !! - yes, this is *used in citations*

Returns:

  • (Boolean, nil)


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

def citations
  @citations
end

#citations_on_otusBoolean

Returns:

  • (Boolean)


137
138
139
# File 'lib/queries/source/filter.rb', line 137

def citations_on_otus
  @citations_on_otus
end

#descendantsObject

Returns the value of attribute descendants.



132
133
134
# File 'lib/queries/source/filter.rb', line 132

def descendants
  @descendants
end

#documentsBoolean?

Returns:

  • (Boolean, nil)


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

def documents
  @documents
end

#exact_authorBoolean?

Returns:

  • (Boolean, nil)


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

def exact_author
  @exact_author
end

#exact_titleBoolean?

Returns:

  • (Boolean, nil)


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

def exact_title
  @exact_title
end

#in_projectBoolean?

! requires ‘project_id`

Returns:

  • (Boolean, nil)


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

def in_project
  @in_project
end

#nomenclatureBoolean?

Returns:

  • (Boolean, nil)


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

def nomenclature
  @nomenclature
end

#rolesBoolean?

Returns:

  • (Boolean, nil)


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

def roles
  @roles
end

#serialBoolean?

true - with serial_id false - without_serial_id nil - both

Returns:

  • (Boolean, nil)


143
144
145
# File 'lib/queries/source/filter.rb', line 143

def serial
  @serial
end

#serial_idObject

Returns the value of attribute serial_id.



126
127
128
# File 'lib/queries/source/filter.rb', line 126

def serial_id
  @serial_id
end

#source_idObject

TODO: Change to source_id



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

def source_id
  @source_id
end

#source_typeString?

Returns:

  • (String, nil)


123
124
125
# File 'lib/queries/source/filter.rb', line 123

def source_type
  @source_type
end

#taxon_name_idProtonym.id?

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

Returns:

  • (Protonym.id, nil)

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



131
132
133
# File 'lib/queries/source/filter.rb', line 131

def taxon_name_id
  @taxon_name_id
end

#titleObject

Returns the value of attribute title.



86
87
88
# File 'lib/queries/source/filter.rb', line 86

def title
  @title
end

#topic_idObject

Returns the value of attribute topic_id.



77
78
79
# File 'lib/queries/source/filter.rb', line 77

def topic_id
  @topic_id
end

#with_doiBoolean?

Returns:

  • (Boolean, nil)


111
112
113
# File 'lib/queries/source/filter.rb', line 111

def with_doi
  @with_doi
end

#with_titleBoolean?

true - with a title false - without a title nil - both

Returns:

  • (Boolean, nil)


149
150
151
# File 'lib/queries/source/filter.rb', line 149

def with_title
  @with_title
end

#year_endObject

Returns the value of attribute year_end.



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

def year_end
  @year_end
end

#year_startObject

Returns the value of attribute year_start.



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

def year_start
  @year_start
end

Instance Method Details

#ancestor_otus_joinObject (private)



469
470
471
472
473
474
475
476
477
478
479
# File 'lib/queries/source/filter.rb', line 469

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].in(taxon_name_id))
  )
end

#ancestor_taxon_name_classifications_joinObject (private)



493
494
495
496
497
498
499
500
501
502
503
504
505
# File 'lib/queries/source/filter.rb', line 493

def ancestor_taxon_name_classifications_join
  return nil if taxon_name_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].in(taxon_name_id))
  )
end

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



507
508
509
510
511
512
513
514
515
516
517
518
519
# File 'lib/queries/source/filter.rb', line 507

def ancestor_taxon_name_relationship_join(join_on = :subject_taxon_name_id)
  return nil if taxon_name_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].in(taxon_name_id))
  )
end

#ancestor_taxon_names_joinObject (private)



481
482
483
484
485
486
487
488
489
490
491
# File 'lib/queries/source/filter.rb', line 481

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].in(taxon_name_id))
  )
end

#and_clausesObject



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

def and_clauses
  [
    attribute_exact_facet(:author),
    attribute_exact_facet(:title),
    bibtex_type_facet,
    cached_facet,
    serial_facet,
    serial_id_facet,
    source_type_facet,
    with_title_facet,
    year_facet,
  ]
end

#author_id_facetObject



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/queries/source/filter.rb', line 272

def author_id_facet
  return nil if author_id.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].in(author_id)

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

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

#bibtex_type_facetObject



225
226
227
228
# File 'lib/queries/source/filter.rb', line 225

def bibtex_type_facet
  return nil if bibtex_type.empty?
  table[:type].eq('Source::Bibtex').and(table[:bibtex_type].in(bibtex_type))
end

#citation_object_type_facetObject



382
383
384
385
386
# File 'lib/queries/source/filter.rb', line 382

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

#citations_facetObject



402
403
404
405
406
407
408
409
# File 'lib/queries/source/filter.rb', line 402

def citations_facet
  return nil if citations.nil?
  if citations
    ::Source.joins(:citations).distinct
  else
    ::Source.where.missing(:citations).distinct
  end
end

#document_facetObject

TODO: move to a concern



359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/queries/source/filter.rb', line 359

def document_facet
  return nil if documents.nil?

  if documents
    ::Source.joins(:documents, :project_sources).where(project_sources: {project_id:}).distinct
  else
    a = ::Source.where.missing(:documents).distinct
    b = ::Source.joins(:project_sources).where(project_sources: {project_id: }).where.missing(:documentation).distinct

    ::Source.from("((#{a.to_sql}) UNION (#{b.to_sql})) as sources")
  end
end

#identifier_type_facetObject

Over-rides Query::Filter identifier_type_facet to handle with_doi exception



319
320
321
322
323
324
# File 'lib/queries/source/filter.rb', line 319

def identifier_type_facet
  return nil if identifier_type.empty? || with_doi
  q = referenced_klass.joins(:identifiers)
  w = identifier_table[:type].in(identifier_type)
  q.where(w).distinct
end

#in_project_facetObject



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

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

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

#merge_clausesObject



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'lib/queries/source/filter.rb', line 434

def merge_clauses
  s = ::Queries::Query::Filter::SUBQUERIES.select{|k,v| v.include?(:source)}.keys.map(&:to_s)
  [
    *s.collect{|m| query_facets_facet(m)}, # Reference all the Source referencing SUBQUERIES
    author_id_facet,
    citation_object_type_facet,
    citations_facet,
    document_facet,
    empty_fields_facet, # See Queries::Concerns::Empty
    in_project_facet,
    nomenclature_facet,
    not_empty_fields_facet,
    role_facet,
    taxon_name_id_facet,
    topic_id_facet,
    with_doi_facet,
  ]
end

#nomenclature_facetObject



388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/queries/source/filter.rb', line 388

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

#project_id_facetObject

Over-ride the inclusion of this facet at the Filter level.



412
413
414
# File 'lib/queries/source/filter.rb', line 412

def project_id_facet
  nil
end

#project_sources_tableArel::Table

Returns:

  • (Arel::Table)


217
218
219
# File 'lib/queries/source/filter.rb', line 217

def project_sources_table
  ::ProjectSource.arel_table
end

#query_facets_facet(name = nil) ⇒ Object



416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/queries/source/filter.rb', line 416

def query_facets_facet(name = nil)
  return nil if name.nil?

  q = send((name + '_query').to_sym)

  return nil if q.nil?

  n = "query_#{name}_src"

  s = "WITH #{n} AS (" + q.all.to_sql + ') ' +
    ::Source
    .joins(:citations)
    .joins("JOIN #{n} as #{n}1 on citations.citation_object_id = #{n}1.id AND citations.citation_object_type = '#{name.treetop_camelize}'")
    .to_sql

  ::Source.from('(' + s + ') as sources').distinct
end

#role_facetObject

TODO: move to a concern



347
348
349
350
351
352
353
354
355
356
# File 'lib/queries/source/filter.rb', line 347

def role_facet
  return nil if roles.nil?

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

#serial_facetObject



372
373
374
375
376
377
378
379
380
# File 'lib/queries/source/filter.rb', line 372

def serial_facet
  return nil if serial.nil?

  if serial
    table[:serial_id].not_eq(nil)
  else
    table[:serial_id].eq(nil)
  end
end

#serial_id_facetObject



268
269
270
# File 'lib/queries/source/filter.rb', line 268

def serial_id_facet
  serial_id.empty? ? nil : table[:serial_id].in(serial_id)
end

#source_type_facetObject



253
254
255
256
# File 'lib/queries/source/filter.rb', line 253

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

#taxon_name_id_facetObject

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



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/queries/source/filter.rb', line 236

def taxon_name_id_facet
  return nil if taxon_name_id.empty?

  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").distinct
end

#topic_id_facetObject



300
301
302
303
# File 'lib/queries/source/filter.rb', line 300

def topic_id_facet
  return nil if topic_id.empty?
  ::Source.joins(:citation_topics).where(citation_topics: { topic_id:}).distinct
end

#with_doi_facetObject

TODO: move to generalized code in Identifiers concern



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

def with_doi_facet
  return nil if with_doi.nil?
  if with_doi
    ::Source.joins(:identifiers).where(identifiers: {type: 'Identifier::Global::Doi'}).distinct
  else
    ::Source.left_outer_joins(:identifiers).where("(identifiers.type != 'Identifier::Global::Doi') OR (identifiers.identifier_object_id is null)").distinct
  end
end

#with_title_facetObject



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

def with_title_facet
  return nil if with_title.nil?

  if with_title
    table[:title].not_eq(nil)
  else
    table[:title].eq(nil)
  end
end

#year_facetObject



258
259
260
261
262
263
264
265
266
# File 'lib/queries/source/filter.rb', line 258

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