class MARC::Spec::Queries::Query

Attributes

condition[R]
selector[R]
subqueries[R]
tag[R]

Public Class Methods

new(tag: nil, selector: nil, condition: nil, subqueries: []) click to toggle source

TODO: separate factory methods for possible cases? (see transform.rb) TODO: separate query (w/o subqueries) from wrapper w/subqueries?

# File lib/marc/spec/queries/query.rb, line 14
def initialize(tag: nil, selector: nil, condition: nil, subqueries: [])
  @tag = ensure_type(tag, Tag, allow_nil: true)
  # TODO: do we need the Selector interface at all?
  @selector = ensure_type(selector, Applicable, allow_nil: true)
  @condition = ensure_type(condition, Condition, allow_nil: true)
  @subqueries = subqueries.map { |sq| ensure_type(sq, Query) }
end

Public Instance Methods

any_results?(executor, context_fields, context_result = nil) click to toggle source
# File lib/marc/spec/queries/query.rb, line 43
def any_results?(executor, context_fields, context_result = nil)
  fields = tag_or_context_fields(executor, context_fields)
  return false if fields.empty?

  any_field_results?(executor, fields, context_result)
end
execute(executor, context_fields, context_result = nil) click to toggle source

TODO: don’t support nested subqueries

# File lib/marc/spec/queries/query.rb, line 36
def execute(executor, context_fields, context_result = nil)
  fields = tag_or_context_fields(executor, context_fields)
  return [] if fields.empty?

  field_results(executor, fields, context_result)
end
tag_str() click to toggle source
# File lib/marc/spec/queries/query.rb, line 22
def tag_str
  tag.to_s if tag
end
to_s() click to toggle source
# File lib/marc/spec/queries/query.rb, line 26
def to_s
  StringIO.new.tap do |out|
    out << tag if tag
    out << selector if selector
    out << "{#{condition}}" if condition
    out << subqueries.join
  end.string
end

Protected Instance Methods

equality_attrs() click to toggle source
# File lib/marc/spec/queries/query.rb, line 52
def equality_attrs
  %i[tag selector condition subqueries]
end
to_s_inspect() click to toggle source

rubocop:disable Metrics/AbcSize

# File lib/marc/spec/queries/query.rb, line 57
def to_s_inspect
  StringIO.new.tap do |out|
    out << tag.inspect if tag
    out << selector.inspect if selector
    out << "{#{condition.inspect}}" if condition
    out << subqueries.map(&:inspect).join
  end.string
end

Private Instance Methods

any_field_results?(executor, fields, context_result) click to toggle source
# File lib/marc/spec/queries/query.rb, line 118
def any_field_results?(executor, fields, context_result)
  return any_root_results?(executor, fields, context_result) if subqueries.empty?

  any_subfield_results?(executor, fields)
end
any_root_results?(executor, fields, context_result) click to toggle source
# File lib/marc/spec/queries/query.rb, line 124
def any_root_results?(executor, fields, context_result)
  root_results(fields, executor, context_result).any?
end
any_subfield_results?(executor, fields) click to toggle source
# File lib/marc/spec/queries/query.rb, line 128
def any_subfield_results?(executor, fields)
  fields.any? do |field|
    subqueries.any? { |sq| sq.any_results?(executor, [field]) }
  end
end
field_results(executor, fields, context_result) click to toggle source
# File lib/marc/spec/queries/query.rb, line 73
def field_results(executor, fields, context_result)
  return root_results(fields, executor, context_result) if subqueries.empty?

  subquery_results(executor, fields)
end
results_for_field(executor, field) click to toggle source
# File lib/marc/spec/queries/query.rb, line 111
def results_for_field(executor, field)
  results = executor.apply_selector(selector, field)
  return results unless condition

  results.select { |result| executor.condition_met?(condition, field, result) }
end
results_for_fields(executor, fields) click to toggle source
# File lib/marc/spec/queries/query.rb, line 104
def results_for_fields(executor, fields)
  fields.each_with_object([]) do |field, results|
    field_results = results_for_field(executor, field)
    results.concat(field_results)
  end
end
root_results(fields, executor, context_result) click to toggle source
# File lib/marc/spec/queries/query.rb, line 79
def root_results(fields, executor, context_result)
  field_results = results_for_fields(executor, fields)
  # TODO: something less ridiculous
  return field_results unless field_results.empty? && select_from_context?(context_result)

  selector.apply(context_result)
end
select_from_context?(context_result) click to toggle source
# File lib/marc/spec/queries/query.rb, line 100
def select_from_context?(context_result)
  tag.nil? && context_result && selector.can_apply?(context_result)
end
subquery_results(executor, fields) click to toggle source
# File lib/marc/spec/queries/query.rb, line 87
def subquery_results(executor, fields)
  # NOTE: we do this one field at a time so that results are grouped
  #       by field, rather than by subfield code. Which isn't part of
  #       the MARCSpec spec, but it seems more in the spirit of MARC
  #       to preserve order wherever possible.
  fields.each_with_object([]) do |field, results|
    subqueries.each do |subquery|
      subquery_results = subquery.execute(executor, [field])
      results.concat(subquery_results)
    end
  end
end
tag_or_context_fields(executor, context_fields) click to toggle source

rubocop:enable Metrics/AbcSize

# File lib/marc/spec/queries/query.rb, line 69
def tag_or_context_fields(executor, context_fields)
  tag ? executor.apply_tag(tag) : context_fields
end