Skip to content

Commit

Permalink
fix: test the adapter-specific query ordering
Browse files Browse the repository at this point in the history
  • Loading branch information
bf4 committed Feb 2, 2023
1 parent d24e24a commit 8820e54
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 33 deletions.
59 changes: 31 additions & 28 deletions test/controllers/controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -494,15 +494,15 @@ def test_sorting_by_relationship_field

assert_response :success
assert json_response['data'].length > 10, 'there are enough records to show sort'
expected = Post
.all
.left_joins(:author)
.merge(Person.order(name: :asc))
.map(&:id)
.map(&:to_s)
ids = json_response['data'].map {|data| data['id'] }

# Postgres sorts nulls last, whereas sqlite and mysql sort nulls first
if ENV['DATABASE_URL'].starts_with?('postgres')
assert_equal '17', json_response['data'][-1]['id'], 'nil is at the start'
assert_equal post.id.to_s, json_response['data'][0]['id'], 'alphabetically first user is not first'
else
assert_equal '17', json_response['data'][0]['id'], 'nil is at the end'
assert_equal post.id.to_s, json_response['data'][1]['id'], 'alphabetically first user is second'
end
assert_equal expected, ids, "since adapter_sorts_nulls_last=#{adapter_sorts_nulls_last}"
end

def test_desc_sorting_by_relationship_field
Expand All @@ -512,14 +512,15 @@ def test_desc_sorting_by_relationship_field
assert_response :success
assert json_response['data'].length > 10, 'there are enough records to show sort'

# Postgres sorts nulls last, whereas sqlite and mysql sort nulls first
if ENV['DATABASE_URL'].starts_with?('postgres')
assert_equal '17', json_response['data'][0]['id'], 'nil is at the start'
assert_equal post.id.to_s, json_response['data'][-1]['id']
else
assert_equal '17', json_response['data'][-1]['id'], 'nil is at the end'
assert_equal post.id.to_s, json_response['data'][-2]['id'], 'alphabetically first user is second last'
end
expected = Post
.all
.left_joins(:author)
.merge(Person.order(name: :desc))
.map(&:id)
.map(&:to_s)
ids = json_response['data'].map {|data| data['id'] }

assert_equal expected, ids, "since adapter_sorts_nulls_last=#{adapter_sorts_nulls_last}"
end

def test_sorting_by_relationship_field_include
Expand All @@ -529,13 +530,15 @@ def test_sorting_by_relationship_field_include
assert_response :success
assert json_response['data'].length > 10, 'there are enough records to show sort'

if ENV['DATABASE_URL'].starts_with?('postgres')
assert_equal '17', json_response['data'][-1]['id'], 'nil is at the top'
assert_equal post.id.to_s, json_response['data'][0]['id']
else
assert_equal '17', json_response['data'][0]['id'], 'nil is at the top'
assert_equal post.id.to_s, json_response['data'][1]['id'], 'alphabetically first user is second'
end
expected = Post
.all
.left_joins(:author)
.merge(Person.order(name: :asc))
.map(&:id)
.map(&:to_s)
ids = json_response['data'].map {|data| data['id'] }

assert_equal expected, ids, "since adapter_sorts_nulls_last=#{adapter_sorts_nulls_last}"
end

def test_invalid_sort_param
Expand Down Expand Up @@ -4772,11 +4775,11 @@ def test_fetch_robots_with_sort_by_name
assert_cacheable_get :index, params: {sort: 'name'}
assert_response :success

if ENV['DATABASE_URL'].starts_with?('postgres')
assert_equal 'jane', json_response['data'].first['attributes']['name']
else
assert_equal 'John', json_response['data'].first['attributes']['name']
end
expected_names = Robot
.all
.order(name: :asc)
.map(&:name)
assert_equal expected_names.first, json_response['data'].first['attributes']['name'], "since adapter_sorts_nulls_last=#{adapter_sorts_nulls_last}"
end

def test_fetch_robots_with_sort_by_lower_name
Expand Down
26 changes: 21 additions & 5 deletions test/integration/requests/request_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1443,16 +1443,32 @@ def test_sort_primary_attribute
end

def test_sort_included_attribute
# Postgres sorts nulls last, whereas sqlite and mysql sort nulls first
pg = ENV['DATABASE_URL'].starts_with?('postgres')

get '/api/v6/authors?sort=author_detail.author_stuff', headers: { 'Accept' => JSONAPI::MEDIA_TYPE }
assert_jsonapi_response 200
assert_equal pg ? '1001' : '1000', json_response['data'][0]['id']
up_expected_ids = AuthorResource
._model_class
.all
.left_joins(:author_detail)
.merge(AuthorDetail.order(author_stuff: :asc))
.map(&:id)
expected = up_expected_ids.first.to_s
ids = json_response['data'].map {|data| data['id'] }
actual = ids.first
assert_equal expected, actual, "since adapter_sorts_nulls_last=#{adapter_sorts_nulls_last} ands actual=#{ids} vs. expected=#{up_expected_ids}"

get '/api/v6/authors?sort=-author_detail.author_stuff', headers: { 'Accept' => JSONAPI::MEDIA_TYPE }
assert_jsonapi_response 200
assert_equal pg ? '1000' : '1002', json_response['data'][0]['id']
down_expected_ids = AuthorResource
._model_class
.all
.left_joins(:author_detail)
.merge(AuthorDetail.order(author_stuff: :desc))
.map(&:id)
expected = down_expected_ids.first.to_s
ids = json_response['data'].map {|data| data['id'] }
actual = ids.first
assert_equal expected, actual, "since adapter_sorts_nulls_last=#{adapter_sorts_nulls_last} ands actual=#{ids} vs. expected=#{down_expected_ids}"
refute_equal up_expected_ids, down_expected_ids # sanity check
end

def test_include_parameter_quoted
Expand Down
10 changes: 10 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,16 @@ def adapter_name
ActiveRecord::Base.connection.adapter_name
end

# Postgres sorts nulls last, whereas sqlite and mysql sort nulls first
def adapter_sorts_nulls_last
case adapter_name
when 'PostgreSQL' then true
when 'SQLite', 'Mysql2' then false
else
fail ArgumentError, "Unhandled adapter #{adapter_name} in #{__callee__}"
end
end

def db_quote_identifier
case adapter_name
when 'SQLite', 'PostgreSQL'
Expand Down

0 comments on commit 8820e54

Please sign in to comment.