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} + %w{cached cached_author_string cached_nomenclature_date}).map(&:to_sym).freeze
PARAMS =
[
  *ATTRIBUTES,
  :source_id,
  :taxon_name_id,
  :descendants,
  :author,
  :author_id_or,
  :editor,
  :editor_id_or,
  :bibtex_type,
  :citations,
  :citations_on_otus,
  :documents,
  :exact_author,
  :exact_editor,
  :exact_title,
  :in_project,
  :nomenclature,
  :query_term,
  :roles,
  :serial,
  :source_type,
  :title,
  :with_doi,
  :with_pages,
  :with_title,
  :year_end,
  :year_start,
  author_id: [],
  editor_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, #conveyance_query, #data_attribute_query, #depiction_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, #roll_call, #sound_query, #taxon_name_query, #taxon_name_relationship_query, #venn, #venn_ignore_pagination, #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, #disable_paging, included_annotator_facets, instantiated_base_filter, inverted_subqueries, #model_id_facet, #object_global_id_facet, #only_project?, #paging_state, params, #permitted_params, #process_url_into_params, query_name, #set_nested_queries, #set_paging, set_paging, #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)


182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/queries/source/filter.rb', line 182

def initialize(query_params)
  super

  @author = params[:author]
  @author_id = params[:author_id]
  @editor = params[:editor]
  @editor_id = params[:editor_id]
  @author_id_or =  boolean_param(params,:author_id_or)
  @editor_id_or =  boolean_param(params,:editor_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_editor = boolean_param(params,:exact_editor)
  @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_pages = boolean_param(params, :with_pages)
  @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.



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

def author
  @author
end

#author_idObject

Returns the value of attribute author_id.



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

def author_id
  @author_id
end

#author_id_orObject

Returns the value of attribute author_id_or.



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

def author_id_or
  @author_id_or
end

#bibtex_typeArray, ...

one of the allowed BibTeX types

Returns:

  • (Array, String, nil)


179
180
181
# File 'lib/queries/source/filter.rb', line 179

def bibtex_type
  @bibtex_type
end

#citation_object_typeArray?

TODO: move tc citations concern

Returns:

  • (Array, nil)


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

def citation_object_type
  @citation_object_type
end

#citationsBoolean?

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

Returns:

  • (Boolean, nil)


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

def citations
  @citations
end

#citations_on_otusBoolean

Returns:

  • (Boolean)


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

def citations_on_otus
  @citations_on_otus
end

#descendantsObject

Returns the value of attribute descendants.



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

def descendants
  @descendants
end

#documentsBoolean?

Returns:

  • (Boolean, nil)


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

def documents
  @documents
end

#editorObject

Returns the value of attribute editor.



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

def editor
  @editor
end

#editor_idObject

Returns the value of attribute editor_id.



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

def editor_id
  @editor_id
end

#editor_id_orObject

Returns the value of attribute editor_id_or.



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

def editor_id_or
  @editor_id_or
end

#exact_authorBoolean?

Returns:

  • (Boolean, nil)


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

def exact_author
  @exact_author
end

#exact_editorBoolean?

Returns:

  • (Boolean, nil)


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

def exact_editor
  @exact_editor
end

#exact_titleBoolean?

Returns:

  • (Boolean, nil)


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

def exact_title
  @exact_title
end

#in_projectBoolean?

! requires ‘project_id`

Returns:

  • (Boolean, nil)


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

def in_project
  @in_project
end

#nomenclatureBoolean?

Returns:

  • (Boolean, nil)


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

def nomenclature
  @nomenclature
end

#rolesBoolean?

Returns:

  • (Boolean, nil)


119
120
121
# File 'lib/queries/source/filter.rb', line 119

def roles
  @roles
end

#serialBoolean?

true - with serial_id false - without_serial_id nil - both

Returns:

  • (Boolean, nil)


163
164
165
# File 'lib/queries/source/filter.rb', line 163

def serial
  @serial
end

#serial_idObject

Returns the value of attribute serial_id.



146
147
148
# File 'lib/queries/source/filter.rb', line 146

def serial_id
  @serial_id
end

#source_idObject

TODO: Change to source_id



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

def source_id
  @source_id
end

#source_typeString?

Returns:

  • (String, nil)


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

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



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

def taxon_name_id
  @taxon_name_id
end

#titleObject

Returns the value of attribute title.



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

def title
  @title
end

#topic_idObject

Returns the value of attribute topic_id.



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

def topic_id
  @topic_id
end

#with_doiBoolean?

Returns:

  • (Boolean, nil)


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

def with_doi
  @with_doi
end

#with_pagesBoolean?

true - with pages false - without pages nil - both

Returns:

  • (Boolean, nil)


169
170
171
# File 'lib/queries/source/filter.rb', line 169

def with_pages
  @with_pages
end

#with_titleBoolean?

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

Returns:

  • (Boolean, nil)


175
176
177
# File 'lib/queries/source/filter.rb', line 175

def with_title
  @with_title
end

#year_endObject

Returns the value of attribute year_end.



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

def year_end
  @year_end
end

#year_startObject

Returns the value of attribute year_start.



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

def year_start
  @year_start
end

Instance Method Details

#ancestor_otus_joinObject (private)



545
546
547
548
549
550
551
552
553
554
555
# File 'lib/queries/source/filter.rb', line 545

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)



569
570
571
572
573
574
575
576
577
578
579
580
581
# File 'lib/queries/source/filter.rb', line 569

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)



583
584
585
586
587
588
589
590
591
592
593
594
595
# File 'lib/queries/source/filter.rb', line 583

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)



557
558
559
560
561
562
563
564
565
566
567
# File 'lib/queries/source/filter.rb', line 557

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



527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
# File 'lib/queries/source/filter.rb', line 527

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

#author_id_facetObject



307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/queries/source/filter.rb', line 307

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



260
261
262
263
# File 'lib/queries/source/filter.rb', line 260

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



455
456
457
458
459
# File 'lib/queries/source/filter.rb', line 455

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

#citations_facetObject



475
476
477
478
479
480
481
482
# File 'lib/queries/source/filter.rb', line 475

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

#document_facetObject

TODO: move to a concern



432
433
434
435
436
437
438
439
440
441
442
443
# File 'lib/queries/source/filter.rb', line 432

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

#editor_id_facetObject



335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/queries/source/filter.rb', line 335

def editor_id_facet
  return nil if editor_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('SourceEditor'))
    )

  e = c[:id].not_eq(nil)
  f = c[:person_id].in(editor_id)

  b = b.where(e.and(f))
  b = b.group(a['id'])
  b = b.having(a['id'].count.eq(editor_id.length)) unless editor_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

#identifier_type_facetObject

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



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

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



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

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



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

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,
    editor_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



461
462
463
464
465
466
467
468
469
470
471
472
473
# File 'lib/queries/source/filter.rb', line 461

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.



485
486
487
# File 'lib/queries/source/filter.rb', line 485

def project_id_facet
  nil
end

#project_sources_tableArel::Table

Returns:

  • (Arel::Table)


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

def project_sources_table
  ::ProjectSource.arel_table
end

#query_facets_facet(name = nil) ⇒ Object



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

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



420
421
422
423
424
425
426
427
428
429
# File 'lib/queries/source/filter.rb', line 420

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



445
446
447
448
449
450
451
452
453
# File 'lib/queries/source/filter.rb', line 445

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



303
304
305
# File 'lib/queries/source/filter.rb', line 303

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

#source_type_facetObject



288
289
290
291
# File 'lib/queries/source/filter.rb', line 288

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.



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/queries/source/filter.rb', line 271

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



363
364
365
366
# File 'lib/queries/source/filter.rb', line 363

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



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

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_pages_facetObject



409
410
411
412
413
414
415
416
417
# File 'lib/queries/source/filter.rb', line 409

def with_pages_facet
  return nil if with_pages.nil?

  if with_pages
    table[:pages].not_eq(nil)
  else
    table[:pages].eq(nil)
  end
end

#with_title_facetObject



399
400
401
402
403
404
405
406
407
# File 'lib/queries/source/filter.rb', line 399

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



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

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