85 lines
2.5 KiB
Ruby
Executable file
85 lines
2.5 KiB
Ruby
Executable file
# frozen_string_literal: true
|
|
|
|
# A datastructure representing a batch of prompts. Used in order to speed up
|
|
# matching.
|
|
class PromptBatch
|
|
ALL = -1
|
|
|
|
attr_reader :signups, :prompt_type
|
|
attr_reader :prompts
|
|
|
|
def initialize(signups, prompt_type, index_tag_type, index_optional)
|
|
@signups = signups
|
|
@prompt_type = prompt_type
|
|
@index_tag_type = index_tag_type
|
|
@index_optional = index_optional
|
|
|
|
@prompts = if @prompt_type == :requests
|
|
@signups.flat_map(&:requests)
|
|
else
|
|
@signups.flat_map(&:offers)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
# For the given prompt, get the list of all tags of the indexed tag type.
|
|
def indexed_tags_for_prompt(prompt)
|
|
if @index_optional
|
|
prompt.full_tag_set.tag_ids_by_type[@index_tag_type] || []
|
|
else
|
|
prompt.tag_set.tag_ids_by_type[@index_tag_type] || []
|
|
end
|
|
end
|
|
|
|
# Build a list of prompts that accept "any" for the indexed tag type.
|
|
def build_prompts_with_any
|
|
@prompts_with_any = @prompts.select do |prompt|
|
|
prompt.accepts_any?(@index_tag_type)
|
|
end
|
|
end
|
|
|
|
# Build a mapping from tag IDs to lists of prompts that want that tag.
|
|
def build_prompts_with_tag
|
|
@prompts_with_tag = {}
|
|
|
|
@prompts.each do |prompt|
|
|
indexed_tags_for_prompt(prompt).each do |tag|
|
|
@prompts_with_tag[tag] ||= []
|
|
@prompts_with_tag[tag] << prompt
|
|
end
|
|
end
|
|
end
|
|
|
|
# Returns a list of prompts that accept "any" for the indexed tag type.
|
|
# Calls build_prompts_with_any if the list doesn't already exist.
|
|
def prompts_with_any
|
|
build_prompts_with_any if @prompts_with_any.nil?
|
|
@prompts_with_any
|
|
end
|
|
|
|
# Returns a list of prompts that have the given tag.
|
|
# Calls build_prompts_with_tag if the hash table doesn't already exist.
|
|
def prompts_with_tag(tag)
|
|
build_prompts_with_tag if @prompts_with_tag.nil?
|
|
@prompts_with_tag[tag] || []
|
|
end
|
|
|
|
public
|
|
|
|
# Computes the prompts in this set that are "candidates" for matching the
|
|
# passed-in prompt -- that is, prompts that share a tag, or prompts with any.
|
|
# If the passed-in prompt has no tags of the indexed type, or accepts any for
|
|
# the indexed type, this returns all prompts.
|
|
def candidates_for_matching(prompt)
|
|
tags = indexed_tags_for_prompt(prompt)
|
|
|
|
if tags.empty? || prompt.accepts_any?(@index_tag_type)
|
|
@prompts
|
|
else
|
|
candidates = tags.flat_map { |tag_id| prompts_with_tag(tag_id) }
|
|
candidates += prompts_with_any
|
|
candidates.uniq
|
|
end
|
|
end
|
|
end
|