module JamRuby class BaseSearch < JsonStore attr_accessor :page_count, :results, :page_number ANY_VAL_STR = 'any' ANY_VAL_INT = -1 VAL_YES = 'yes' VAL_NO = 'no' PER_PAGE = 10 PG_SMALLINT_MAX = 32767 KEY_SKILL = 'skill_level' KEY_GENRES = 'genres' KEY_INSTRUMENTS = 'instruments' KEY_GIGS = 'concert_gigs' KEY_SORT_ORDER = 'sort_order' KEY_JOINED_WITHIN = 'joined_within_days' KEY_ACTIVE_WITHIN = 'active_within_days' SORT_VALS = %W{ latency distance } SORT_ORDERS = { SORT_VALS[0] => 'Latency to Me', SORT_VALS[1] => 'Distance to Me' } SKILL_VALS = [ANY_VAL_INT, 1, 2] SKILL_LEVELS = { SKILL_VALS[0] => 'Any', SKILL_VALS[1] => 'Amateur', SKILL_VALS[2] => 'Pro', } JOINED_WITHIN_VALS = [ANY_VAL_INT, 1, 7, 30, 90] JOINED_WITHIN_LABELS = { JOINED_WITHIN_VALS[0] => ANY_VAL_STR, JOINED_WITHIN_VALS[1] => 'Within Last 1 Day', JOINED_WITHIN_VALS[2] => 'Within Last 7 Day', JOINED_WITHIN_VALS[3] => 'Within Last 30 Day', JOINED_WITHIN_VALS[4] => 'Within Last 90 Day', } ACTIVE_WITHIN_VALS = [ANY_VAL_INT, 1, 7, 30, 90] ACTIVE_WITHIN_LABELS = { ACTIVE_WITHIN_VALS[0] => ANY_VAL_STR, ACTIVE_WITHIN_VALS[1] => 'Within Last 1 Day', ACTIVE_WITHIN_VALS[2] => 'Within Last 7 Day', ACTIVE_WITHIN_VALS[3] => 'Within Last 30 Day', ACTIVE_WITHIN_VALS[4] => 'Within Last 90 Day', } GIG_COUNTS = [ANY_VAL_INT, 0, 1, 2, 3, 4] GIG_LABELS = { GIG_COUNTS[0] => 'Any', GIG_COUNTS[1] => 'under 10', GIG_COUNTS[2] => '10 to 50', GIG_COUNTS[3] => '50 to 100', GIG_COUNTS[4] => 'over 100' } INSTRUMENT_PROFICIENCY = { 1 => 'Beginner', 2 => 'Intermediate', 3 => 'Expert', } def self.json_schema { KEY_SORT_ORDER => self::SORT_VALS[0], KEY_INSTRUMENTS => [], KEY_GENRES => [], KEY_GIGS => self::GIG_COUNTS[0].to_s, KEY_JOINED_WITHIN => self::JOINED_WITHIN_VALS[0], } end def self.search_filter_meta(jschema=nil, sort_order=nil) jschema ||= self.json_schema schema_keys = jschema.keys sort_order ||= { keys: self::SORT_VALS, map: self::SORT_ORDERS } multi_keys = jschema.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact { per_page: self::PER_PAGE, filter_keys: { keys: schema_keys, multi: multi_keys, single: schema_keys - multi_keys, }, sort_order: sort_order } end RESULT_FOLLOW = :follows RESULT_FRIEND = :friends COUNT_FRIEND = :count_friend COUNT_FOLLOW = :count_follow COUNT_RECORD = :count_record COUNT_SESSION = :count_session COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION] def self.user_search_filter(user) unless ss = user.send(self.name.demodulize.tableize.singularize) ss = self.create_search(user) end ss end def self.search_filter_json(user) self.user_search_filter(user).json end def self.create_search(user) ms = self.new ms.user = user ms.data_blob = self.json_schema ms.save! ms end def self.search_target_class end def self.genre_ids @@genre_ids ||= Hash[ *Genre.pluck(:id).collect { |v| [ v, v ] }.flatten ] end def self.instrument_ids @@instrument_ids ||= Hash[ *Instrument.pluck(:id).collect { |v| [ v, v ] }.flatten ] end def _genres(rel, query_data=json) gids = query_data[KEY_GENRES] unless gids.blank? allgids = self.class.genre_ids gids = gids.select { |gg| allgids.has_key?(gg) } unless gids.blank? gidsql = gids.join("','") gpsql = "SELECT player_id FROM genre_players WHERE (player_type = '#{self.class.search_target_class.name}' AND genre_id IN ('#{gidsql}'))" rel = rel.where("#{self.class.search_target_class.table_name}.id IN (#{gpsql})") end end rel end def _instruments(rel, query_data=json) unless (instruments = query_data[KEY_INSTRUMENTS]).blank? instrids = self.class.instrument_ids instruments = instruments.select { |ii| instrids.has_key?(ii['instrument_id']) } unless instruments.blank? instsql = "SELECT player_id FROM musicians_instruments WHERE ((" instsql += instruments.collect do |inst| unless MusicianInstrument::PROFICIENCY_RANGE === (proflvl=inst['proficiency_level'].to_i) proflvl = MusicianInstrument::LEVEL_INTERMEDIATE end "instrument_id = '#{inst['instrument_id']}' AND proficiency_level = #{proflvl}" end.join(") OR (") instsql += "))" rel = rel.where("#{self.class.search_target_class.table_name}.id IN (#{instsql})") end end rel end def _gigs(rel) gg = json[KEY_GIGS].to_i rel = rel.where('concert_count = ?',gg) if 0 <= gg rel end def _skills(rel) if 0 < (val = json[KEY_SKILL].to_i) rel = rel.where(['skill_level = ?', val]) end rel end def _joined_within(rel) #debugger if 0 < (val = json[KEY_JOINED_WITHIN].to_i) rel = rel.where("users.created_at >= ?", val.days.ago.at_beginning_of_day) end rel end def _sort_order(rel) end def do_search(params={}) end def process_results_page(objs) end def search_includes(rel) rel end def search_results_page(filter=nil, page=1, user_ids=nil) if filter self.data_blob = filter self.save else filter = self.data_blob end #NOTE: user_ids parameter is used to track users returned from neo4j user's latency data service. if this variable is not null means we are calling this method with user_ids returned from neo4j if user_ids rel = do_filter(user_ids) else rel = do_search(filter, user_ids) end @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 def reset_filter self.data_blob = self.class.json_schema self.save end def reset_search_results reset_filter search_results_page end def search_type self.class.to_s end def is_blank? self.data_blob == self.class.json_schema end def description end end end