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, #extract_query, #field_occurrence_query, #image_query, #loan_query, #object_global_id, #observation_query, #otu_query, #page, #paginate, #params, #per, #person_query, #project_id, #recent, #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, #deep_permit, included_annotator_facets, inverted_subqueries, #model_id_facet, #object_global_id_facet, params, #permitted_params, #process_url_into_params, query_name, #query_name, #set_nested_queries, #shared_and_clauses, #subquery_vector, #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
# 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_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)



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

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)



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

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)



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

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)



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

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



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

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



271
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
# File 'lib/queries/source/filter.rb', line 271

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



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

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



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

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

#citations_facetObject



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

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



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

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



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

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



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

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



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

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



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

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.



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

def project_id_facet
  nil
end

#project_sources_tableArel::Table

Returns:

  • (Arel::Table)


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

def project_sources_table
  ::ProjectSource.arel_table
end

#query_facets_facet(name = nil) ⇒ Object



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

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



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

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



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

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



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

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

#source_type_facetObject



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

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.



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

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



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

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



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

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



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

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



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

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