diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 3ce6fee36..de6546f84 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -111,23 +111,6 @@ module JamRuby return recordings end - def self.search(query, options = { :limit => 10 }) - - # only issue search if at least 2 characters are specified - if query.nil? || query.length < 2 - return [] - end - - # create 'anded' statement - query = Search.create_tsquery(query) - - if query.nil? || query.length == 0 - return [] - end - - return Band.where("name_tsv @@ to_tsquery('jamenglish', ?)", query).limit(options[:limit]) - end - # helper method for creating / updating a Band def self.save(id, name, website, biography, city, state, country, genres, user_id, photo_url, logo_url) user = User.find(user_id) diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index 930bb109c..5ca1db50c 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -1,73 +1,51 @@ module JamRuby - # not a active_record model; just a search result + # not a active_record model; just a search result container class Search - attr_accessor :bands, :musicians, :fans, :recordings, :friends, :search_type - attr_accessor :bands_filter, :musicians_filter + attr_accessor :filter_results, :text_results LIMIT = 10 - # performs a site-white search - def self.search(query, user_id = nil) + SEARCH_TEXT_TYPES = [:musicians, :bands, :fans] + SEARCH_TEXT_TYPE_ID = :search_text_type - users = User.search(query, :limit => LIMIT) - bands = Band.search(query, :limit => LIMIT) - # NOTE: I removed recordings from search here. This is because we switched - # to "claimed_recordings" so it's not clear what should be searched. - - friends = Friendship.search(query, user_id, :limit => LIMIT) - - return Search.new(users + bands + friends) + def self.band_search(txt, user = nil) + self.text_search({ SEARCH_TEXT_TYPE_ID => :bands, :query => txt }, user) end - # performs a friend search scoped to a specific user - # def self.search_by_user(query, user_id) - # friends = Friendship.search(query, user_id, :limit => LIMIT) - # return Search.new(friends) - # end + def self.fan_search(txt, user = nil) + self.text_search({ SEARCH_TEXT_TYPE_ID => :fans, :query => txt }, user) + end + + def self.musicians_search(txt, user = nil) + self.text_search({ SEARCH_TEXT_TYPE_ID => :musicians, :query => txt }, user) + end + + def self.text_search(params, user = nil) + return [] if params.blank? || params[:query].blank? || 2 >= params[:query].length + + tsquery = Search.create_tsquery(params[:query]) + return [] if tsquery.blank? + + rel = case params[SEARCH_TEXT_TYPE_ID] || SEARCH_TEXT_TYPES[0].to_s + when 'bands' + Band.where("name_tsv @@ to_tsquery('jamenglish', ?)", tsquery) + when 'fans' + User.fans.where("(name_tsv @@ to_tsquery('jamenglish', ?))", tsquery) + else + User.musicians.where("(name_tsv @@ to_tsquery('jamenglish', ?))", tsquery) + end + @text_results = rel.limit(10) + end - # search_results - results from a Tire search across band/user/recording def initialize(search_results=nil) - @bands = [] - @musicians = [] - @fans = [] - @recordings = [] - @friends = [] - @musicians_filter = [] - @bands_filter = [] - - if search_results.nil? - return - end - - search_results.take(LIMIT).each do |result| - if result.class == User - if result.musician - @musicians.push(result) - else - @fans.push(result) - end - elsif result.class == Band - @bands.push(result) - elsif result.class == Recording - @recordings.push(result) - elsif result.class == Friendship - @friends.push(result.friend) - else - raise Exception, "unknown class #{result.class} returned in search results" - end - end + @text_results, @filter_results = [], [] + self end def self.create_tsquery(query) - # empty queries don't hit back to elasticsearch - if query.nil? || query.length == 0 - return nil - end + return nil if query.nil? || query.length == 0 search_terms = query.split - - if search_terms.length == 0 - return nil - end + return nil if search_terms.length == 0 args = nil search_terms.each do |search_term| @@ -76,11 +54,9 @@ module JamRuby else args = args + " & " + search_term end - end args = args + ":*" - - return args + args end attr_accessor :user_counters, :page_num, :page_count @@ -105,7 +81,7 @@ module JamRuby ordering.blank? ? keys[0] : keys.detect { |oo| oo.to_s == ordering } end - def self.musician_search(params={}, current_user=nil) + def self.musician_filter(params={}, current_user=nil) rel = User.musicians unless (instrument = params[:instrument]).blank? rel = rel.joins("RIGHT JOIN musicians_instruments AS minst ON minst.user_id = users.id") @@ -160,10 +136,10 @@ module JamRuby COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION] def musician_results_for_user(results, user) - @search_type, @musicians_filter = PARAM_MUSICIAN, results + @filter_results = results if user @user_counters = results.inject({}) { |hh,val| hh[val.id] = []; hh } - mids = "'#{@musicians_filter.map(&:id).join("','")}'" + mids = "'#{@filter_results.map(&:id).join("','")}'" # this gets counts for each search result on friends/follows/records/sessions results.each do |uu| @@ -247,7 +223,7 @@ module JamRuby end end - def self.band_search(params={}, current_user=nil) + def self.band_filter(params={}, current_user=nil) rel = Band.scoped unless (genre = params[:genre]).blank? @@ -287,10 +263,10 @@ module JamRuby end def band_results_for_user(results, user) - @search_type, @bands_filter = PARAM_BAND, results + @filter_results = results if user @user_counters = results.inject({}) { |hh,val| hh[val.id] = []; hh } - mids = "'#{@bands_filter.map(&:id).join("','")}'" + mids = "'#{@filter_results.map(&:id).join("','")}'" # this gets counts for each search result results.each do |bb| diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 60a3b4dd6..024838e72 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -140,6 +140,7 @@ module JamRuby validate :update_email_case_insensitive_uniqueness, :if => :updating_email scope :musicians, where(:musician => true) + scope :fans, where(:musician => false) scope :geocoded_users, where(['lat IS NOT NULL AND lng IS NOT NULL']) scope :musicians_geocoded, musicians.geocoded_users @@ -924,31 +925,6 @@ module JamRuby end end - def self.search(query, options = { :limit => 10 }) - - # only issue search if at least 2 characters are specified - if query.nil? || query.length < 2 - return [] - end - - # save query for use in instrument search - search_criteria = query - - # create 'anded' statement - query = Search.create_tsquery(query) - - if query.nil? || query.length == 0 - return [] - end - - # remove email_confirmed restriction due to VRFS-378 - # .where("email_confirmed = true AND (name_tsv @@ to_tsquery('jamenglish', ?) OR users.id in (select user_id from musicians_instruments where instrument_id like '%#{search_criteria.downcase}%'))", query) - - return query = User - .where("(name_tsv @@ to_tsquery('jamenglish', ?) OR users.id in (select user_id from musicians_instruments where instrument_id like '%#{search_criteria.downcase}%'))", query) - .limit(options[:limit]) - end - def provides_location? !self.city.blank? && (!self.state.blank? || !self.country.blank?) end diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index 51e43f403..ebfb57e08 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -25,15 +25,15 @@ describe 'Band search' do it "finds all bands" do # expects all the bands num = Band.count - results = Search.band_search({ :per_page => num }) - expect(results.bands_filter.count).to eq(num) + results = Search.band_filter({ :per_page => num }) + expect(results.filter_results.count).to eq(num) end it "finds bands with proper ordering" do # the ordering should be create_at since no followers exist expect(BandFollower.count).to eq(0) - results = Search.band_search({ :per_page => Band.count }) - results.bands_filter.each_with_index do |uu, idx| + results = Search.band_filter({ :per_page => Band.count }) + results.filter_results.each_with_index do |uu, idx| expect(uu.id).to eq(@bands.reverse[idx].id) end end @@ -53,11 +53,11 @@ describe 'Band search' do # refresh the order to ensure it works right @band2.followers.concat(users[1..-1]) - results = Search.band_search({ :per_page => @bands.size }, users[0]) - expect(results.bands_filter[0].id).to eq(@band2.id) + results = Search.band_filter({ :per_page => @bands.size }, users[0]) + expect(results.filter_results[0].id).to eq(@band2.id) # check the follower count for given entry - expect(results.bands_filter[0].search_follow_count.to_i).not_to eq(0) + expect(results.filter_results[0].search_follow_count.to_i).not_to eq(0) # check the follow relationship between current_user and result expect(results.is_follower?(@band2)).to be true end @@ -65,8 +65,8 @@ describe 'Band search' do it 'paginates properly' do # make sure pagination works right params = { :per_page => 2, :page => 1 } - results = Search.band_search(params) - expect(results.bands_filter.count).to be 2 + results = Search.band_filter(params) + expect(results.filter_results.count).to be 2 end end @@ -87,8 +87,8 @@ describe 'Band search' do # establish sorting order @band1.followers.concat(users) - results = Search.band_search({},@band1) - uu = results.bands_filter.detect { |mm| mm.id == @band1.id } + results = Search.band_filter({},@band1) + uu = results.filter_results.detect { |mm| mm.id == @band1.id } expect(uu).to_not be_nil expect(results.follow_count(uu)).to eq(users.count) end @@ -96,8 +96,8 @@ describe 'Band search' do it "session stat shows session count" do make_session(@band1) @band1.reload - results = Search.band_search({},@band1) - uu = results.bands_filter.detect { |mm| mm.id == @band1.id } + results = Search.band_filter({},@band1) + uu = results.filter_results.detect { |mm| mm.id == @band1.id } expect(uu).to_not be_nil expect(results.session_count(uu)).to be 1 end @@ -112,9 +112,9 @@ describe 'Band search' do make_session(@band2) make_session(@band1) # order results by num recordings - results = Search.band_search({ :orderby => 'plays' }) - expect(results.bands_filter[0].id).to eq(@band2.id) - expect(results.bands_filter[1].id).to eq(@band1.id) + results = Search.band_filter({ :orderby => 'plays' }) + expect(results.filter_results[0].id).to eq(@band2.id) + expect(results.filter_results[1].id).to eq(@band1.id) end it "by now playing" do @@ -122,18 +122,18 @@ describe 'Band search' do session = make_session(@band3) FactoryGirl.create(:music_session_history, :music_session => session) - results = Search.band_search({ :orderby => 'playing' }) - expect(results.bands_filter.count).to be 1 - expect(results.bands_filter.first.id).to eq(@band3.id) + results = Search.band_filter({ :orderby => 'playing' }) + expect(results.filter_results.count).to be 1 + expect(results.filter_results.first.id).to eq(@band3.id) # should get 2 results with 2 active sessions # sort order should be created_at DESC session = make_session(@band4) FactoryGirl.create(:music_session_history, :music_session => session) - results = Search.band_search({ :orderby => 'playing' }) - expect(results.bands_filter.count).to be 2 - expect(results.bands_filter[0].id).to eq(@band4.id) - expect(results.bands_filter[1].id).to eq(@band3.id) + results = Search.band_filter({ :orderby => 'playing' }) + expect(results.filter_results.count).to be 2 + expect(results.filter_results[0].id).to eq(@band4.id) + expect(results.filter_results[1].id).to eq(@band3.id) end end @@ -146,40 +146,40 @@ describe 'Band search' do @band1.reload ggg = @band1.genres.detect { |gg| gg.id == genre.id } expect(ggg).to_not be_nil - results = Search.band_search({ :genre => ggg.id }) - results.bands_filter.each do |rr| + results = Search.band_filter({ :genre => ggg.id }) + results.filter_results.each do |rr| expect(rr.genres.detect { |gg| gg.id==ggg.id }.id).to eq(genre.id) end - expect(results.bands_filter.count).to be 1 + expect(results.filter_results.count).to be 1 end it "finds bands within a given distance of given location" do num = Band.count expect(@band1.lat).to_not be_nil # short distance - results = Search.band_search({ :per_page => num, + results = Search.band_filter({ :per_page => num, :distance => 10, :city => 'Apex' }, @band1) - expect(results.bands_filter.count).to be num + expect(results.filter_results.count).to be num # long distance - results = Search.band_search({ :per_page => num, + results = Search.band_filter({ :per_page => num, :distance => 1000, :city => 'Miami', :state => 'FL' }, @band1) - expect(results.bands_filter.count).to be num + expect(results.filter_results.count).to be num end it "finds bands within a given distance of bands location" do expect(@band1.lat).to_not be_nil # uses the location of @band1 - results = Search.band_search({ :distance => 10, :per_page => Band.count }, @band1) - expect(results.bands_filter.count).to be Band.count + results = Search.band_filter({ :distance => 10, :per_page => Band.count }, @band1) + expect(results.filter_results.count).to be Band.count end it "finds no bands within a given distance of location" do expect(@band1.lat).to_not be_nil - results = Search.band_search({ :distance => 10, :city => 'San Francisco' }, @band1) - expect(results.bands_filter.count).to be 0 + results = Search.band_filter({ :distance => 10, :city => 'San Francisco' }, @band1) + expect(results.filter_results.count).to be 0 end end diff --git a/ruby/spec/jam_ruby/models/band_search_spec.rb b/ruby/spec/jam_ruby/models/band_search_spec.rb index 40e26d50f..6d3c07d1c 100644 --- a/ruby/spec/jam_ruby/models/band_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_search_spec.rb @@ -13,7 +13,7 @@ describe User do end it "should allow search of one band with an exact match" do - ws = Band.search("Example Band") + ws = Search.band_search("Example Band") ws.length.should == 1 band_result = ws[0] band_result.name.should == @band.name @@ -22,61 +22,61 @@ describe User do end it "should allow search of one band with partial matches" do - ws = Band.search("Ex") + ws = Search.band_search("Ex") ws.length.should == 1 ws[0].id.should == @band.id - ws = Band.search("Exa") + ws = Search.band_search("Exa") ws.length.should == 1 ws[0].id.should == @band.id - ws = Band.search("Exam") + ws = Search.band_search("Exam") ws.length.should == 1 ws[0].id.should == @band.id - ws = Band.search("Examp") + ws = Search.band_search("Examp") ws.length.should == 1 ws[0].id.should == @band.id - ws = Band.search("Exampl") + ws = Search.band_search("Exampl") ws.length.should == 1 ws[0].id.should == @band.id - ws = Band.search("Example") + ws = Search.band_search("Example") ws.length.should == 1 ws[0].id.should == @band.id - ws = Band.search("Ba") + ws = Search.band_search("Ba") ws.length.should == 1 ws[0].id.should == @band.id - ws = Band.search("Ban") + ws = Search.band_search("Ban") ws.length.should == 1 ws[0].id.should == @band.id end it "should not match mid-word searchs" do - ws = Band.search("xa") + ws = Search.band_search("xa") ws.length.should == 0 - ws = Band.search("le") + ws = Search.band_search("le") ws.length.should == 0 end it "should delete band" do - ws = Band.search("Example Band") + ws = Search.band_search("Example Band") ws.length.should == 1 band_result = ws[0] band_result.id.should == @band.id @band.destroy # delete doesn't work; you have to use destroy. - ws = Band.search("Example Band") + ws = Search.band_search("Example Band") ws.length.should == 0 end it "should update band" do - ws = Band.search("Example Band") + ws = Search.band_search("Example Band") ws.length.should == 1 band_result = ws[0] band_result.id.should == @band.id @@ -84,10 +84,10 @@ describe User do @band.name = "bonus-stuff" @band.save - ws = Band.search("Example Band") + ws = Search.band_search("Example Band") ws.length.should == 0 - ws = Band.search("Bonus") + ws = Search.band_search("Bonus") ws.length.should == 1 band_result = ws[0] band_result.id.should == @band.id @@ -96,7 +96,7 @@ describe User do it "should tokenize correctly" do @band2 = Band.save(nil, "Peach pit", "www.bands.com", "zomg we rock", "Apex", "NC", "US", ["hip hop"], user.id, nil, nil) - ws = Band.search("pea") + ws = Search.band_search("pea") ws.length.should == 1 user_result = ws[0] user_result.id.should == @band2.id @@ -105,12 +105,12 @@ describe User do it "should not return anything with a 1 character search" do @band2 = Band.save(nil, "Peach pit", "www.bands.com", "zomg we rock", "Apex", "NC", "US", ["hip hop"], user.id, nil, nil) - ws = Band.search("pe") + ws = Search.band_search("pe") ws.length.should == 1 user_result = ws[0] user_result.id.should == @band2.id - ws = Band.search("p") + ws = Search.band_search("p") ws.length.should == 0 end end diff --git a/ruby/spec/jam_ruby/models/musician_search_spec.rb b/ruby/spec/jam_ruby/models/musician_search_spec.rb index 955b2f04f..5459b8b62 100644 --- a/ruby/spec/jam_ruby/models/musician_search_spec.rb +++ b/ruby/spec/jam_ruby/models/musician_search_spec.rb @@ -17,15 +17,15 @@ describe 'Musician search' do it "finds all musicians" do # expects all the users num = User.musicians.count - results = Search.musician_search({ :per_page => num }) - expect(results.musicians_filter.count).to eq(num) + results = Search.musician_filter({ :per_page => num }) + expect(results.filter_results.count).to eq(num) end it "finds musicians with proper ordering" do # the ordering should be create_at since no followers exist expect(UserFollower.count).to eq(0) - results = Search.musician_search({ :per_page => User.musicians.count }) - results.musicians_filter.each_with_index do |uu, idx| + results = Search.musician_filter({ :per_page => User.musicians.count }) + results.filter_results.each_with_index do |uu, idx| expect(uu.id).to eq(@users.reverse[idx].id) end end @@ -40,11 +40,11 @@ describe 'Musician search' do # refresh the order to ensure it works right @user2.followers.concat([@user3, @user4, @user2]) - results = Search.musician_search({ :per_page => @users.size }, @user3) - expect(results.musicians_filter[0].id).to eq(@user2.id) + results = Search.musician_filter({ :per_page => @users.size }, @user3) + expect(results.filter_results[0].id).to eq(@user2.id) # check the follower count for given entry - expect(results.musicians_filter[0].search_follow_count.to_i).not_to eq(0) + expect(results.filter_results[0].search_follow_count.to_i).not_to eq(0) # check the follow relationship between current_user and result expect(results.is_follower?(@user2)).to be true end @@ -52,8 +52,8 @@ describe 'Musician search' do it 'paginates properly' do # make sure pagination works right params = { :per_page => 2, :page => 1 } - results = Search.musician_search(params) - expect(results.musicians_filter.count).to be 2 + results = Search.musician_filter(params) + expect(results.filter_results.count).to be 2 end end @@ -95,8 +95,8 @@ describe 'Musician search' do # create friendship record Friendship.save(@user1.id, @user2.id) # search on user2 - results = Search.musician_search({}, @user2) - friend = results.musicians_filter.detect { |mm| mm.id == @user1.id } + results = Search.musician_filter({}, @user2) + friend = results.filter_results.detect { |mm| mm.id == @user1.id } expect(friend).to_not be_nil expect(results.friend_count(friend)).to be 1 @user1.reload @@ -114,8 +114,8 @@ describe 'Musician search' do expect(recording.claimed_recordings.length).to be 1 expect(@user1.recordings.detect { |rr| rr == recording }).to_not be_nil - results = Search.musician_search({},@user1) - uu = results.musicians_filter.detect { |mm| mm.id == @user1.id } + results = Search.musician_filter({},@user1) + uu = results.filter_results.detect { |mm| mm.id == @user1.id } expect(uu).to_not be_nil expect(results.record_count(uu)).to be 1 @@ -129,29 +129,29 @@ describe 'Musician search' do it "by plays" do make_recording(@user1) # order results by num recordings - results = Search.musician_search({ :orderby => 'plays' }, @user2) - expect(results.musicians_filter[0].id).to eq(@user1.id) + results = Search.musician_filter({ :orderby => 'plays' }, @user2) + expect(results.filter_results[0].id).to eq(@user1.id) # add more data and make sure order still correct make_recording(@user2); make_recording(@user2) - results = Search.musician_search({ :orderby => 'plays' }, @user2) - expect(results.musicians_filter[0].id).to eq(@user2.id) + results = Search.musician_filter({ :orderby => 'plays' }, @user2) + expect(results.filter_results[0].id).to eq(@user2.id) end it "by now playing" do # should get 1 result with 1 active session make_session(@user3) - results = Search.musician_search({ :orderby => 'playing' }, @user2) - expect(results.musicians_filter.count).to be 1 - expect(results.musicians_filter.first.id).to eq(@user3.id) + results = Search.musician_filter({ :orderby => 'playing' }, @user2) + expect(results.filter_results.count).to be 1 + expect(results.filter_results.first.id).to eq(@user3.id) # should get 2 results with 2 active sessions # sort order should be created_at DESC make_session(@user4) - results = Search.musician_search({ :orderby => 'playing' }, @user2) - expect(results.musicians_filter.count).to be 2 - expect(results.musicians_filter[0].id).to eq(@user4.id) - expect(results.musicians_filter[1].id).to eq(@user3.id) + results = Search.musician_filter({ :orderby => 'playing' }, @user2) + expect(results.filter_results.count).to be 2 + expect(results.filter_results[0].id).to eq(@user4.id) + expect(results.filter_results[1].id).to eq(@user3.id) end end @@ -165,40 +165,40 @@ describe 'Musician search' do @user1.reload ii = @user1.instruments.detect { |inst| inst.id == 'tuba' } expect(ii).to_not be_nil - results = Search.musician_search({ :instrument => ii.id }) - results.musicians_filter.each do |rr| + results = Search.musician_filter({ :instrument => ii.id }) + results.filter_results.each do |rr| expect(rr.instruments.detect { |inst| inst.id=='tuba' }.id).to eq(ii.id) end - expect(results.musicians_filter.count).to be 1 + expect(results.filter_results.count).to be 1 end it "finds musicians within a given distance of given location" do num = User.musicians.count expect(@user1.lat).to_not be_nil # short distance - results = Search.musician_search({ :per_page => num, + results = Search.musician_filter({ :per_page => num, :distance => 10, :city => 'Apex' }, @user1) - expect(results.musicians_filter.count).to be num + expect(results.filter_results.count).to be num # long distance - results = Search.musician_search({ :per_page => num, + results = Search.musician_filter({ :per_page => num, :distance => 1000, :city => 'Miami', :state => 'FL' }, @user1) - expect(results.musicians_filter.count).to be num + expect(results.filter_results.count).to be num end it "finds musicians within a given distance of users location" do expect(@user1.lat).to_not be_nil # uses the location of @user1 - results = Search.musician_search({ :distance => 10, :per_page => User.musicians.count }, @user1) - expect(results.musicians_filter.count).to be User.musicians.count + results = Search.musician_filter({ :distance => 10, :per_page => User.musicians.count }, @user1) + expect(results.filter_results.count).to be User.musicians.count end it "finds no musicians within a given distance of location" do expect(@user1.lat).to_not be_nil - results = Search.musician_search({ :distance => 10, :city => 'San Francisco' }, @user1) - expect(results.musicians_filter.count).to be 0 + results = Search.musician_filter({ :distance => 10, :city => 'San Francisco' }, @user1) + expect(results.filter_results.count).to be 0 end end