module JamRuby class BandSearch < BaseSearch cattr_accessor :jschema, :search_meta attr_accessor :user_counters serialize :data_blob, JSON KEY_BAND_SEARCH_TYPE = 'band_search_type' KEY_BAND_TYPE = 'band_type' KEY_PLAY_COMMIT = 'play_commit' KEY_TOUR_OPTION = 'tour_option' KEY_PERF_SAMPLES = 'perform_samples' KEY_HIRE_MAX_COST = 'max_cost' KEY_HIRE_FREE = 'free_gigs' TO_JOIN = 'to_join' TO_HIRE = 'to_hire' BAND_SEARCH_TYPE_VALS = [TO_JOIN, TO_HIRE] BAND_SEARCH_TYPES = { TO_JOIN => 'search bands', TO_HIRE => 'search bands to hire', } SORT_VALS = %W{ distance latency } SORT_ORDERS = { SORT_VALS[0] => 'Distance to Me', SORT_VALS[1] => 'Latency to Me', } HIRE_SORT_VALS = %W{ distance price_asc price_desc } HIRE_SORT_ORDERS = { HIRE_SORT_VALS[0] => 'Distance to Me', HIRE_SORT_VALS[1] => 'Gig Minimum Price (Low to High)', HIRE_SORT_VALS[2] => 'Gig Minimum Price (High to Low)', } BAND_TYPE_VALS = [ANY_VAL_STR, GenrePlayer::VIRTUAL_BAND, GenrePlayer::TRADITIONAL_BAND, ] BAND_TYPES = { BAND_TYPE_VALS[0] => 'Any', BAND_TYPE_VALS[1] => 'Virtual Band', BAND_TYPE_VALS[2] => 'Traditional Band', } PLAY_COMMIT_VALS = [ANY_VAL_STR, '1', '2', '3', ] PLAY_COMMITS = { PLAY_COMMIT_VALS[0] => 'Any', PLAY_COMMIT_VALS[1] => 'Infrequent', PLAY_COMMIT_VALS[2] => 'Once a week', PLAY_COMMIT_VALS[3] => 'More than once a week', } TOUR_OPTION_VALS = [ANY_VAL_STR, 'yes', 'no', ] TOUR_OPTIONS = { TOUR_OPTION_VALS[0] => 'Any', TOUR_OPTION_VALS[1] => 'Yes', TOUR_OPTION_VALS[2] => 'No', } PERF_SAMPLES_VALS = TOUR_OPTION_VALS.clone PERF_SAMPLES = TOUR_OPTIONS.clone def self.json_schema return @@jschema if @@jschema @@jschema = { TO_JOIN => BaseSearch.json_schema.merge({ KEY_BAND_TYPE => BAND_TYPE_VALS[0], KEY_PLAY_COMMIT => PLAY_COMMIT_VALS[0], KEY_TOUR_OPTION => TOUR_OPTION_VALS[0], }), TO_HIRE => { KEY_SORT_ORDER => self::HIRE_SORT_VALS[0], KEY_GENRES => [], KEY_SKILL => self::SKILL_VALS[0].to_s, KEY_GIGS => self::GIG_COUNTS[0].to_s, KEY_PERF_SAMPLES => self::PERF_SAMPLES[0].to_s, KEY_HIRE_MAX_COST => 0, KEY_HIRE_FREE => 1, }, } end def self.search_filter_meta return @@search_meta if @@search_meta toJoinMeta = super(self.json_schema[TO_JOIN]) toJoinMeta.merge!({ KEY_BAND_TYPE => { keys: BAND_TYPE_VALS, map: BAND_TYPES }, KEY_PLAY_COMMIT => { keys: PLAY_COMMIT_VALS, map: PLAY_COMMITS }, KEY_TOUR_OPTION => { keys: TOUR_OPTION_VALS, map: TOUR_OPTIONS } }) toHireMeta = super(self.json_schema[TO_HIRE], { keys: HIRE_SORT_VALS, map: HIRE_SORT_ORDERS }) toHireMeta.merge!({ KEY_PERF_SAMPLES => { keys: PERF_SAMPLES_VALS, map: PERF_SAMPLES }, }) @@search_meta = { TO_JOIN => toJoinMeta, TO_HIRE => toHireMeta, } end def self.search_target_class Band end def _sort_order(rel, filter) rel end def _genres(rel, filter) super(rel, filter) end def _concert_gigs(rel, filter) gg = filter[KEY_GIGS].to_i rel = rel.where(concert_count: gg) if 0 <= gg rel end def _band_type(rel, filter) case filter[KEY_BAND_TYPE] when GenrePlayer::VIRTUAL_BAND rel.where(band_type: GenrePlayer::VIRTUAL_BAND) when GenrePlayer::TRADITIONAL_BAND rel.where(band_type: GenrePlayer::TRADITIONAL_BAND) else rel end end def _play_commit(rel, filter) unless ANY_VAL_STR == filter[KEY_PLAY_COMMIT] rel = rel.where(play_commitment: filter[KEY_PLAY_COMMIT].to_i) end rel end def _tour_option(rel, filter) case filter[KEY_TOUR_OPTION] when 'yes' rel.where(touring_option: true) when 'no' rel.where(touring_option: false) else rel end end def _perform_samples(rel, filter) rel end def _max_cost(rel, filter) if 0 < (max_cost = filter[KEY_HIRE_MAX_COST].to_i) col = Band.arel_table[:gig_minimum] rel = rel.where(col.lteq(max_cost)) end rel end def _free_gigs(rel, filter) case filter[KEY_FREE_GIGS] when 'yes' rel.where(free_gigs: true) when 'no' rel.where(free_gigs: false) else rel end end def _skill_level(rel, filter) case filter[KEY_SKILL].to_i when SKILL_VALS[1] rel.where(free_gigs: true) when SKILL_VALS[2] rel.where(paid_gigs: true) else rel end end def do_search(filter) rel = Band.unscoped filter.keys.each do |fkey| mname = "_#{fkey}" if self.respond_to?(mname) rel = self.send(mname.to_sym, rel, filter) end end rel end def search_includes(rel) rel.includes([:instruments]) end def process_results_page(_results) @results = _results if user @user_counters = @results.inject({}) { |hh,val| hh[val.id] = []; hh } mids = "'#{@results.map(&:id).join("','")}'" # this gets counts for each search result @results.each do |bb| counters = { } @user_counters[bb.id] << counters end else @user_counters = {} end self end private def _count(musician, key) if mm = @user_counters[musician.id] return mm.detect { |ii| ii.is_a?(Hash) }[key] end if @user_counters 0 end public def follow_count(musician) _count(musician, COUNT_FOLLOW) end def friend_count(musician) _count(musician, COUNT_FRIEND) end def record_count(musician) _count(musician, COUNT_RECORD) end def session_count(musician) _count(musician, COUNT_SESSION) end def is_friend?(musician) if mm = @user_counters[musician.id] return mm.include?(RESULT_FRIEND) end if @user_counters false end def is_follower?(musician) if mm = @user_counters[musician.id] return mm.include?(RESULT_FOLLOW) end if @user_counters false end def search_type self.class.to_s end def is_blank? self.data_blob == self.class.json_schema end def description if self.is_blank? return 'Click search button to look for musicians with similar interests, skill levels, etc.' end jj = self.json str = 'Current Search: ' str += "Sort = #{SORT_ORDERS[json_value(BandSearch::KEY_SORT_ORDER)]}" str end def reset_filter(subtype, data=nil) data ||= self.class.json_schema[subtype] dblob = self.data_blob dblob[subtype] = data self.data_blob = dblob self.save end def reset_search_results(subtype=TO_JOIN) reset_filter(subtype) search_results_page(subtype) end def self.search_filter_json(user, subtype=TO_JOIN) self.user_search_filter(user).json[subtype] end def search_filter_for_subtype(subtype) self.data_blob[subtype] end def search_results_page(subtype=TO_JOIN, filter=nil, page=1) if filter reset_filter(subtype, filter) else filter = self.search_filter_for_subtype(subtype) end rel = do_search(filter) @page_number = [page.to_i, 1].max rel = rel.paginate(:page => @page_number, :per_page => self.class::PER_PAGE) rel = self.search_includes(rel) @page_count = rel.total_pages process_results_page(rel.all) end end end