From 9986163273de23924eaa99ef3b1e75624ee06458 Mon Sep 17 00:00:00 2001 From: Filippos Vasilakis Date: Sun, 12 Feb 2017 21:52:19 +0100 Subject: [PATCH] Simplify sorting --- README.md | 14 +- lib/active_hash_relation/sort_filters.rb | 12 +- lib/active_hash_relation/version.rb | 2 +- spec/tests/sorting_spec.rb | 240 +++++++++++++++++++++-- 4 files changed, 249 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index c140d55..0c77834 100644 --- a/README.md +++ b/README.md @@ -140,8 +140,20 @@ However I would strongly advice you to use a pagination gem like Kaminari, and u ### Sorting +You can apply sorting using the property as the key of the hash and order as the value. For instance: +* `{sort: {created_at: desc}}` + +You can also order by multiple attributes: +* `{sort: {created_at: desc, microposts_count: :asc}}` + +If there is no column named after the property value, sorting is skipped. + +#### Deprecated API (will be removed in version 3.0) You can apply sorting using the `property` and `order` attributes. For instance: -* `{sort: {property: 'created_at', order: 'desc'}}` +* `{sort: {property: :created_at, order: :desc}}` + +You can also order by multiple attributes: +* `{sort: [{property: :created_at, order: :desc}, {property: :created_at, order: :desc}]}` If there is no column named after the property value, sorting is skipped. diff --git a/lib/active_hash_relation/sort_filters.rb b/lib/active_hash_relation/sort_filters.rb index bfcc2c7..24093e9 100644 --- a/lib/active_hash_relation/sort_filters.rb +++ b/lib/active_hash_relation/sort_filters.rb @@ -12,8 +12,16 @@ def apply_sort(resource, params, model = nil) end def apply_hash_sort(resource, params, model = nil) - if model.columns.map(&:name).include?(params[:property].to_s) - resource = resource.order(params[:property] => (params[:order] || :desc) ) + if not params[:property].blank? + if model.columns.map(&:name).include?(params[:property].to_s) + resource = resource.order(params[:property] => (params[:order] || :desc) ) + end + else + params.each do |property, order| + if model.columns.map(&:name).include?(property.to_s) + resource = resource.order(property => (order || :desc) ) + end + end end return resource diff --git a/lib/active_hash_relation/version.rb b/lib/active_hash_relation/version.rb index 6c2a072..04ca7a7 100644 --- a/lib/active_hash_relation/version.rb +++ b/lib/active_hash_relation/version.rb @@ -1,3 +1,3 @@ module ActiveHashRelation - VERSION = "1.3.0" + VERSION = "1.4.0" end diff --git a/spec/tests/sorting_spec.rb b/spec/tests/sorting_spec.rb index f3da6b3..f0e08c9 100644 --- a/spec/tests/sorting_spec.rb +++ b/spec/tests/sorting_spec.rb @@ -2,11 +2,12 @@ include Helpers context 'sorting' do + context "one where clause" do it "asc" do hash = { microposts_count: 10, - sort: {property: :microposts_count, order: :asc} + sort: {microposts_count: :asc} } query = HelperClass.new.apply_filters(User.all, hash).to_sql @@ -19,10 +20,10 @@ expect(strip(query)).to eq expected_query.to_s end - it "multiple where clause" do + it "desc" do hash = { microposts_count: 10, - sort: {property: :microposts_count, order: :desc} + sort: {microposts_count: :desc} } query = HelperClass.new.apply_filters(User.all, hash).to_sql @@ -41,7 +42,7 @@ hash = { followers_count: {leq: 20}, microposts_count: 10, - sort: {property: :microposts_count, order: :asc} + sort: {microposts_count: :asc} } query = HelperClass.new.apply_filters(User.all, hash).to_sql @@ -55,11 +56,11 @@ expect(strip(query)).to eq expected_query.to_s end - it "multiple where clause" do + it "desc" do hash = { followers_count: {leq: 20}, microposts_count: 10, - sort: {property: :microposts_count, order: :desc} + sort: {microposts_count: :desc} } query = HelperClass.new.apply_filters(User.all, hash).to_sql @@ -75,26 +76,235 @@ end context "multiple sorting properties" do - it "with single where clause" do + context "as a hashe" do + it "with single where clause" do + hash = { + microposts_count: 10, + sort: { + microposts_count: :asc, + followings_count: :desc + } + } + + query = HelperClass.new.apply_filters(User.all, hash).to_sql + expected_query = q( + "SELECT users.* FROM users", + "WHERE (users.microposts_count = 10)", + "ORDER BY users.microposts_count ASC, users.followings_count DESC" + ) + + expect(strip(query)).to eq expected_query.to_s + end + + it "when the sorting column does not exist" do + hash = { + microposts_count: 10, + sort: { + i_do_not_exist: :asc, + followings_count: :desc + } + } + + query = HelperClass.new.apply_filters(User.all, hash).to_sql + expected_query = q( + "SELECT users.* FROM users", + "WHERE (users.microposts_count = 10)", + "ORDER BY users.followings_count DESC" + ) + + expect(strip(query)).to eq expected_query.to_s + end + end + + context "as an array of hashes (not recommended)" do + it "with single where clause" do + hash = { + microposts_count: 10, + sort: [{ + microposts_count: :asc, + }, { + followings_count: :desc + }] + } + + query = HelperClass.new.apply_filters(User.all, hash).to_sql + expected_query = q( + "SELECT users.* FROM users", + "WHERE (users.microposts_count = 10)", + "ORDER BY users.microposts_count ASC, users.followings_count DESC" + ) + + expect(strip(query)).to eq expected_query.to_s + end + + it "when the sorting column does not exist" do + hash = { + microposts_count: 10, + sort: [{ + i_do_not_exist: :asc, + }, { + followings_count: :desc + }] + } + + query = HelperClass.new.apply_filters(User.all, hash).to_sql + expected_query = q( + "SELECT users.* FROM users", + "WHERE (users.microposts_count = 10)", + "ORDER BY users.followings_count DESC" + ) + + expect(strip(query)).to eq expected_query.to_s + end + end + + it "when the sorting column does not exist" do hash = { microposts_count: 10, - sort: [{ - property: :microposts_count, order: :asc, - }, { - property: :followings_count, order: :desc - }] + sort: {i_do_not_exist: :asc} } query = HelperClass.new.apply_filters(User.all, hash).to_sql expected_query = q( "SELECT users.* FROM users", - "WHERE (users.microposts_count = 10)", - "ORDER BY users.microposts_count ASC, users.followings_count DESC" + "WHERE (users.microposts_count = 10)" ) expect(strip(query)).to eq expected_query.to_s + end end - end + context "deprecated API" do + context "one where clause" do + it "asc" do + hash = { + microposts_count: 10, + sort: {property: :microposts_count, order: :asc} + } + + query = HelperClass.new.apply_filters(User.all, hash).to_sql + expected_query = q( + "SELECT users.* FROM users", + "WHERE (users.microposts_count = 10)", + "ORDER BY users.microposts_count ASC" + ) + + expect(strip(query)).to eq expected_query.to_s + end + + it "desc" do + hash = { + microposts_count: 10, + sort: {property: :microposts_count, order: :desc} + } + + query = HelperClass.new.apply_filters(User.all, hash).to_sql + expected_query = q( + "SELECT users.* FROM users", + "WHERE (users.microposts_count = 10)", + "ORDER BY users.microposts_count DESC" + ) + + expect(strip(query)).to eq expected_query.to_s + end + end + + context "multiple where clauses" do + it "asc" do + hash = { + followers_count: {leq: 20}, + microposts_count: 10, + sort: {property: :microposts_count, order: :asc} + } + + query = HelperClass.new.apply_filters(User.all, hash).to_sql + expected_query = q( + "SELECT users.* FROM users", + "WHERE (users.microposts_count = 10)", + "AND (users.followers_count <= 20)", + "ORDER BY users.microposts_count ASC" + ) + + expect(strip(query)).to eq expected_query.to_s + end + + it "desc" do + hash = { + followers_count: {leq: 20}, + microposts_count: 10, + sort: {property: :microposts_count, order: :desc} + } + + query = HelperClass.new.apply_filters(User.all, hash).to_sql + expected_query = q( + "SELECT users.* FROM users", + "WHERE (users.microposts_count = 10)", + "AND (users.followers_count <= 20)", + "ORDER BY users.microposts_count DESC" + ) + + expect(strip(query)).to eq expected_query.to_s + end + end + + context "multiple sorting properties" do + it "with single where clause" do + hash = { + microposts_count: 10, + sort: [{ + property: :microposts_count, order: :asc, + }, { + property: :followings_count, order: :desc + }] + } + + query = HelperClass.new.apply_filters(User.all, hash).to_sql + expected_query = q( + "SELECT users.* FROM users", + "WHERE (users.microposts_count = 10)", + "ORDER BY users.microposts_count ASC, users.followings_count DESC" + ) + + expect(strip(query)).to eq expected_query.to_s + end + + it "when the sorting column does not exist" do + hash = { + microposts_count: 10, + sort: [{ + property: :i_do_not_exist, order: :asc, + }, { + property: :followings_count, order: :desc + }] + } + + query = HelperClass.new.apply_filters(User.all, hash).to_sql + expected_query = q( + "SELECT users.* FROM users", + "WHERE (users.microposts_count = 10)", + "ORDER BY users.followings_count DESC" + ) + + expect(strip(query)).to eq expected_query.to_s + end + end + + it "when the sorting column does not exist" do + hash = { + microposts_count: 10, + sort: {property: :i_do_not_exist, order: :asc} + } + + query = HelperClass.new.apply_filters(User.all, hash).to_sql + expected_query = q( + "SELECT users.* FROM users", + "WHERE (users.microposts_count = 10)" + ) + + expect(strip(query)).to eq expected_query.to_s + + end + end + end end