Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Revert "Create alternative mechanism for school search API"" #21995

Merged
merged 1 commit into from
Apr 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion dashboard/app/controllers/api/v1/schools_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ def show
def search
render json: Api::V1::SchoolAutocomplete.get_matches(
params.require(:q),
params[:limit]
params[:limit],
params[:use_new_search]
)
end
end
2 changes: 1 addition & 1 deletion dashboard/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ module OPS
# the constraint on :q to match anything but a slash.
# @see http://guides.rubyonrails.org/routing.html#specifying-constraints
get '/dashboardapi/v1/districtsearch/:q/:limit', to: 'api/v1/school_districts#search', defaults: {format: 'json'}, constraints: {q: /[^\/]+/}
get '/dashboardapi/v1/schoolsearch/:q/:limit', to: 'api/v1/schools#search', defaults: {format: 'json'}, constraints: {q: /[^\/]+/}
get '/dashboardapi/v1/schoolsearch/:q/:limit(/:use_new_search)', to: 'api/v1/schools#search', defaults: {format: 'json'}, constraints: {q: /[^\/]+/}

get '/dashboardapi/v1/regional-partners/:school_district_id', to: 'api/v1/regional_partners#index', defaults: {format: 'json'}
get '/dashboardapi/v1/projects/section/:section_id', to: 'api/v1/projects/section_projects#index', defaults: {format: 'json'}
Expand Down
14 changes: 12 additions & 2 deletions dashboard/lib/api/v1/school_autocomplete.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@ class Api::V1::SchoolAutocomplete < AutocompleteHelper
# @param query [String] the user-define query string
# @param limit [int] the maximum number of results to return
# @return [Array] an array of JSON formatted schools
def self.get_matches(query, limit)
def self.get_matches(query, limit, use_new_search)
limit = format_limit(limit)

rows = School.limit(limit)
if search_by_zip?((query = query.strip))
if use_new_search
terms = get_query_terms query
match_terms = []
terms.each do |term|
match_terms.push "CASE when (MATCH(name, city) AGAINST('#{term}' IN BOOLEAN MODE) OR zip = '#{term}') THEN 1 ELSE 0 END"
end
matches = match_terms.join ' + '
rows = rows.
where("MATCH(name, city) AGAINST(? IN BOOLEAN MODE)", terms.join(' ')).
order("(#{matches}) DESC, state, city, name")
elsif search_by_zip?((query = query.strip))
query = "#{query[0, 5]}%"
rows = rows.where("zip LIKE ?", query)
else
Expand Down
11 changes: 7 additions & 4 deletions dashboard/lib/autocomplete_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ def self.format_limit(limit)
return [MIN_LIMIT, [limit.to_i, MAX_LIMIT].min].max
end

def self.get_query_terms(query)
query.strip.split(/\s+|\W+/).map do |w|
w.upcase.presence
end.compact
end

# Formats the query string for boolean full-text search.
# For instance, if the user-defined query string is 'abc def',
# the string is reformatted to '+ABC +DEF*'.
Expand All @@ -23,10 +29,7 @@ def self.format_limit(limit)
# @param query [String] the user-defined query string
# @return [String] the formatted query string
def self.format_query(query)
words = query.strip.split(/\s+/).map do |w|
w.gsub(/\W/, '').upcase.presence
end.compact

words = get_query_terms query
# Don't filter the last word if it is short since we will
# append it with * for a wildcard search.
words = words.select.with_index do |w, i|
Expand Down
74 changes: 74 additions & 0 deletions dashboard/test/controllers/api/v1/schools_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,28 @@ class Api::V1::SchoolsControllerTest < ActionController::TestCase
longitude: "-162.273056"
}.deep_stringify_keys.freeze

QUALITY_EDUCATION_ACADEMY = {
nces_id: '370002502096',
name: 'Quality Education Academy',
city: "Winston Salem",
state: 'NC',
zip: '27105',
school_type: 'charter',
latitude: "36.15115",
longitude: "-80.21101",
}.deep_stringify_keys.freeze

CHILDRENS_VILLAGE = {
nces_id: "530537003179",
name: "Children's Village",
city: "Moxee",
state: "WA",
zip: "98936",
school_type: "public",
latitude: "46.552088",
longitude: "-120.381461"
}.deep_stringify_keys.freeze

test 'search by school name prefix' do
get :search, params: {q: 'glad', limit: 40}
assert_response :success
Expand Down Expand Up @@ -87,4 +109,56 @@ class Api::V1::SchoolsControllerTest < ActionController::TestCase
assert_response :success
assert_equal [JOANN_A_ALEXIE_MEMORIAL_SCHOOL], JSON.parse(@response.body)
end

test 'search with hyphen' do
get :search, params: {q: 'winston-salem', limit: 40}
assert_response :success
assert_equal [QUALITY_EDUCATION_ACADEMY], JSON.parse(@response.body)
end

test 'search with apostrophe' do
get :search, params: {q: "children's village", limit: 40}
assert_response :success
assert_equal [CHILDRENS_VILLAGE], JSON.parse(@response.body)
end

test 'new search with apostrophe' do
get :search, params: {q: "children's village", limit: 40, use_new_search: true}
assert_response :success
assert_equal [CHILDRENS_VILLAGE], JSON.parse(@response.body)
end

test 'new search with hyphen' do
get :search, params: {q: 'winston-salem', limit: 40, use_new_search: true}
assert_response :success
assert_equal [QUALITY_EDUCATION_ACADEMY], JSON.parse(@response.body)
end

test 'new search with non-matching term' do
get :search, params: {q: 'Albert Einstein Elementary OTHERTERM', limit: 40, use_new_search: true}
assert_response :success
response_body = JSON.parse(@response.body)
assert_equal ALBERT_EINSTEIN_ACADEMY_ELEMENTARY, response_body.first, response_body
end

test 'new search with zip and text term' do
get :search, params: {q: 'Einstein 91355', limit: 40, use_new_search: true}
assert_response :success
response_body = JSON.parse(@response.body)
assert_equal ALBERT_EINSTEIN_ACADEMY_ELEMENTARY, response_body.first, response_body
end

test 'new search with name and city' do
get :search, params: {q: 'Jung Bethel', limit: 40, use_new_search: true}
assert_response :success
response_body = JSON.parse(@response.body)
assert_equal GLADYS_JUNG_ELEMENTARY, response_body.first, response_body
end

test 'new search with name, zip, city, and non-matching term' do
get :search, params: {q: 'Jung Bethel 99559 OTHERTERM', limit: 40, use_new_search: true}
assert_response :success
response_body = JSON.parse(@response.body)
assert_equal GLADYS_JUNG_ELEMENTARY, response_body.first, response_body
end
end
2 changes: 2 additions & 0 deletions dashboard/test/fixtures/school_districts.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ id name city state zip
4800004 POR VIDA ACADEMY SAN ANTONIO TX 78210
4800014 GEORGE GERVIN ACADEMY SAN ANTONIO TX 78218
1300060 APPLING COUNTY BAXLEY GA 31513
3700025 QUALITY EDUCATION ACADEMY WINSTON-SALEM NC 27105
5305370 EAST VALLEY SCHOOL DISTRICT (YAKIMA) YAKIMA WA 98901
2 changes: 2 additions & 0 deletions dashboard/test/fixtures/schools.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ id name address_line1 address_line2 address_line3 city state zip latitude longit
60000113717 ALBERT EINSTEIN ACADEMY ELEMENTARY 25300 RYE CANYON SANTA CLARITA CA 91355 34.4375 -118.576861 charter 600001 CA-1975309-0128603
60001411118 SUMMIT LEADERSHIP ACADEMY-HIGH DESERT 12850 MUSCATEL ST. HESPERIA CA 92345 34.412822 -117.38275 charter 600014 CA-3675044-0107516
60001411746 PATHWAYS TO COLLEGE 9144 THIRD AVE. HESPERIA CA 92345 34.417113 -117.308387 charter 600014 CA-3675044-0112441
370002502096 QUALITY EDUCATION ACADEMY 5012 D LANSING DR WINSTON-SALEM NC 27105 36.15115 -80.21101 charter 3700025
530537003179 CHILDREN'S VILLAGE 408 EAST SEATTLE AVE MOXEE WA 98936 46.552088 -120.381461 public 5305370
12 changes: 12 additions & 0 deletions dashboard/test/lib/autocomplete_helper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,16 @@ class AutocompleteHelperTest < ActiveSupport::TestCase
test 'to search string with special characters between two words' do
assert_equal '+ABC +DEF*', AutocompleteHelper.format_query('abc + def')
end

test 'terms split on hyphen' do
assert_equal ['WINSTON', 'SALEM'], AutocompleteHelper.get_query_terms('WINSTON-SALEM')
end

test 'terms split on space' do
assert_equal ['WINSTON', 'SALEM'], AutocompleteHelper.get_query_terms('WINSTON SALEM')
end

test 'terms split on apostrophe' do
assert_equal ['CHILDREN', 'S', 'VILLAGE', 'ACADEMY'], AutocompleteHelper.get_query_terms("CHILDREN'S VILLAGE ACADEMY")
end
end
2 changes: 1 addition & 1 deletion dashboard/test/models/school_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class SchoolTest < ActiveSupport::TestCase
SchoolDistrict.seed_all(stub_school_data: true, force: true)

schools = School.merge_from_csv(School.get_seed_filename(true))
assert_equal(18, schools.size, 'test data contains 17 schools')
assert_equal(20, schools.size, 'test data contains 20 schools')
assert_not_nil School.find_by(
{
id: '10000500871',
Expand Down