VRFS-2795 musician search first draft

This commit is contained in:
Jonathan Kolyer 2015-02-23 06:21:36 +00:00
parent 3ca304b612
commit 83f3d56238
6 changed files with 348 additions and 0 deletions

View File

@ -61,6 +61,7 @@ group :test do
gem 'resque_spec' #, :path => "/home/jam/src/resque_spec/"
gem 'timecop'
gem 'rspec-prof'
gem 'time_difference'
end
# Specify your gem's dependencies in jam_ruby.gemspec

View File

@ -202,6 +202,8 @@ require "jam_ruby/models/text_message"
require "jam_ruby/jam_tracks_manager"
require "jam_ruby/models/performance_sample"
require "jam_ruby/models/online_presence"
require "jam_ruby/models/json_store"
require "jam_ruby/models/musician_search"
include Jampb

View File

@ -0,0 +1,29 @@
module JamRuby
class JsonStore < ActiveRecord::Base
self.table_name = 'json_stores'
serialize :data_blob, JSON
before_create do
self.data_blob ||= {}
end
after_save do
@json = nil
end
attr_accessible :user_id
belongs_to :user, class_name: "JamRuby::User"
def json
@json ||= self.data_blob
end
def update_json_value(key, val)
self.json[key] = val
self.update_attribute(:data_blob, self.json)
end
end
end

View File

@ -0,0 +1,229 @@
module JamRuby
class MusicianSearch < JsonStore
ANY_VAL_STR = 'any'
ANY_VAL_INT = 0
PER_PAGE = 10
KEY_GIG = 'gig_count'
KEY_AGES = 'ages'
SORT_VALS = %W{ latency distance }
SORT_ORDERS = {
SORT_VALS[0] => 'Latency to Me',
SORT_VALS[1] => 'Distance to Me'
}
SKILL_VALS = [ANY_VAL_STR, 'pro', 'amateur']
SKILL_LEVELS = {
SKILL_VALS[0] => 'Any',
SKILL_VALS[1] => 'Pro',
SKILL_VALS[2] => 'Amateur'
}
GIG_COUNTS = [ANY_VAL_INT, 1, 11, 51, 101]
GIG_LABELS = {
GIG_COUNTS[0] => 'Any',
GIG_COUNTS[1] => 'More than 0',
GIG_COUNTS[2] => 'More than 10',
GIG_COUNTS[3] => 'More than 50',
GIG_COUNTS[4] => 'More than 100'
}
STUDIO_COUNTS = [ANY_VAL_INT, 1, 11, 51, 101]
STUDIOS_LABELS = {
STUDIO_COUNTS[0] => 'Any',
STUDIO_COUNTS[1] => 'More than 0',
STUDIO_COUNTS[2] => 'More than 10',
STUDIO_COUNTS[3] => 'More than 50',
STUDIO_COUNTS[4] => 'More than 100'
}
AGE_COUNTS = [ANY_VAL_INT, 10, 20, 30, 40, 50]
AGES = {
AGE_COUNTS[0] => 'Any',
AGE_COUNTS[1] => 'Teens',
AGE_COUNTS[2] => "20's",
AGE_COUNTS[3] => "30's",
AGE_COUNTS[4] => "40's",
AGE_COUNTS[5] => "50+"
}
INTEREST_VALS = [ANY_VAL_STR,
GenrePlayer::VIRTUAL_BAND,
GenrePlayer::TRADITIONAL_BAND,
GenrePlayer::PAID_SESSION,
GenrePlayer::FREE_SESSION,
GenrePlayer::COWRITING,
]
INTERESTS = {
INTEREST_VALS[0] => 'Any',
INTEREST_VALS[1] => 'Virtual Band',
INTEREST_VALS[2] => 'Traditional Band',
INTEREST_VALS[3] => 'Paid Sessions',
INTEREST_VALS[4] => 'Free Sessions',
INTEREST_VALS[5] => 'Co-Writing'
}
JSON_SCHEMA = {
:sort_order => '',
:instruments => [],
:interests => '',
KEY_GIG => 0,
:studio_session_count => '',
:genres => [],
:skills => '',
KEY_AGES => []
}
def self.create_search(user)
ms = self.new
ms.user = user
ms.data_blob = JSON_SCHEMA
ms.save!
ms
end
def _genres(rel)
gids = json['genres']
unless gids.blank?
rel = rel.joins("RIGHT JOIN genre_players AS ugenres ON ugenres.player_id = users.id")
.where(['ugenres.genre_id IN ("?") AND users.id IS NOT NULL', gids.join('","')])
end
rel
end
def _instruments(rel)
unless (instruments = json['instruments']).blank?
rel = rel.joins("inner JOIN musicians_instruments AS minst ON minst.user_id = users.id")
sql = ''
instruments.each do |inst_level|
sql += "(minst.instrument_id = '#{inst_level['id']}' AND minst.proficiency_level = #{inst_level['level']}) OR "
end
sql.chomp!(' OR ')
rel = rel.where(sql)
end
rel
end
def _ages(rel)
unless (vals = json[KEY_AGES]).blank?
return rel if vals.detect { |vv| ANY_VAL_INT == vv }
arels = []
vals.each do |val|
today = Date.today
case val
when 10
arels << User.where("birth_date >= ? AND birth_date < ?",
today - 20.years, today - 10.years)
when 20
arels << User.where("birth_date >= ? AND birth_date < ?",
today - 30.years, today - 20.years)
when 30
arels << User.where("birth_date >= ? AND birth_date < ?",
today - 40.years, today - 50.years)
when 40
arels << User.where("birth_date >= ? AND birth_date < ?",
today - 50.years, today - 40.years)
when 50
arels << User.where("birth_date <= ?", today - 50.years)
end
end
rel = rel.where("birth_date IS NOT NULL")
.where(arels.map(&:where_values).flatten.join(" OR "))
end
rel
end
def _studios(rel)
if 0 < (count = json['studio_session_count'].to_i)
rel = rel.where('studio_session_count IS NOT NULL')
case count
when STUDIO_COUNTS[1]
rel = rel.where('studio_session_count >= ? AND studio_session_count < ',
count, STUDIO_COUNTS[2])
when STUDIO_COUNTS[2]
rel = rel.where('studio_session_count >= ? AND studio_session_count < ',
count, STUDIO_COUNTS[3])
when STUDIO_COUNTS[3]
rel = rel.where('studio_session_count >= ? AND studio_session_count < ',
count, STUDIO_COUNTS[4])
when STUDIO_COUNTS[4]
rel = rel.where('studio_session_count >= ?', count)
end
end
rel
end
def _gigs(rel)
if 0 < (count = json[KEY_GIG].to_i)
rel = rel.where('concert_count IS NOT NULL')
case count
when GIG_COUNTS[1]
rel = rel.where('concert_count >= ? AND concert_count < ',
count, GIG_COUNTS[2])
when GIG_COUNTS[2]
rel = rel.where('concert_count >= ? AND concert_count < ',
count, GIG_COUNTS[3])
when GIG_COUNTS[3]
rel = rel.where('concert_count >= ? AND concert_count < ',
count, GIG_COUNTS[4])
when GIG_COUNTS[4]
rel = rel.where('concert_count >= ?', count)
end
end
rel
end
def _skills(rel)
if 0 < (count = json['skill_level'].to_i)
rel = rel.where('skill_level IS NOT NULL')
case count
when SKILL_VALS[1]
rel = rel.where('skill_level >= ? AND skill_level < ',
count, SKILL_VALS[2])
when SKILL_VALS[2]
rel = rel.where('skill_level >= ? AND skill_level < ',
count, SKILL_VALS[3])
when SKILL_VALS[3]
rel = rel.where('skill_level >= ? AND skill_level < ',
count, SKILL_VALS[4])
when SKILL_VALS[4]
rel = rel.where('skill_level >= ?', count)
end
end
rel
end
def _interests(rel)
val = json['interests']
if val.present? && ANY_VAL_STR != val
rel = rel.joins("RIGHT JOIN genre_players AS interest ON interest.player_id = users.id")
.where(['interest..genre_type = ? AND users.id IS NOT NULL', val])
end
rel
end
def pagination(rel, params)
perpage = [(params[:per_page] || PER_PAGE).to_i, 100].min
page = [params[:page].to_i, 1].max
[rel.paginate(:page => page, :per_page => perpage), page]
end
def do_search(params={})
rel = User.musicians
rel = self._genres(rel)
rel = self._ages(rel)
rel = self._studios(rel)
rel = self._gigs(rel)
rel = self._skills(rel)
rel = self._instruments(rel)
rel = self._interests(rel)
rel, page = self.pagination(rel, params)
rel
end
end
end

View File

@ -155,6 +155,8 @@ module JamRuby
has_many :online_presences, :class_name => "JamRuby::OnlinePresence"
has_many :performance_samples, :class_name => "JamRuby::PerformanceSample"
has_one :musician_search, :class_name => 'JamRuby::MusicianSearch'
before_save :create_remember_token, :if => :should_validate_password?
before_save :stringify_avatar_info , :if => :updating_avatar

View File

@ -0,0 +1,85 @@
require 'spec_helper'
require 'time_difference'
require 'byebug'
describe 'Musician Search Model' do
let!(:searcher) { FactoryGirl.create(:austin_user) }
let!(:search) { MusicianSearch.create_search(searcher) }
before(:all) do
User.delete_all
@users = []
today = Date.today
MusicianSearch::AGE_COUNTS.each_with_index do |age, idx|
age = 0==idx ? MusicianSearch::AGE_COUNTS[1] : age
dd = today - age.years - 1.day
@users << FactoryGirl.create(:austin_user, :birth_date => dd)
@users << FactoryGirl.create(:dallas_user, :birth_date => dd)
@users << FactoryGirl.create(:miami_user, :birth_date => dd)
@users << FactoryGirl.create(:seattle_user, :birth_date => dd)
end
end
describe "creates search obj" do
it "associates to user" do
expect(search.user).to eq(searcher)
searcher.reload
expect(searcher.musician_search).to eq(search)
end
it "sets json" do
search.update_json_value(MusicianSearch::KEY_GIG, MusicianSearch::GIG_COUNTS[1])
expect(search.json[MusicianSearch::KEY_GIG]).to eq(MusicianSearch::GIG_COUNTS[1])
end
end
describe "filtering criteria" do
it "filters musicians" do
expect(search.do_search(per_page: User.musicians.count).count).to eq(User.musicians.count)
end
it "filters ages" do
age = MusicianSearch::AGE_COUNTS[1]
search.update_json_value(MusicianSearch::KEY_AGES, [age])
today = Date.today.to_time
search.do_search.all.each do |uu|
diff = TimeDifference.between(uu.birth_date.to_time, today).in_years
expect(diff).to be >= age
expect(diff).to be < MusicianSearch::AGE_COUNTS[2]
end
search.update_json_value(MusicianSearch::KEY_AGES, [0])
search.do_search.to_sql =~ /(birth_date)/
expect($1).to eq(nil)
end
it "filters genres" do
end
it "filters studio sessions" do
end
it "filters gigs" do
end
it "filters skills" do
end
it "filters instruments" do
end
it "filters interests" do
end
it "filters combinations" do
end
end
describe "pagination" do
it "first page results" do
end
it "second page results" do
end
end
describe "sort order" do
before(:each) do
create_phony_database
end
end
end