From a92305cf4547615eebc9faa622f89725df1afeb7 Mon Sep 17 00:00:00 2001 From: Matt Lewis Date: Wed, 24 Sep 2025 17:21:18 -0500 Subject: [PATCH] Remove influence of sorting configuration on applied sort --- lib/sift/filtrator.rb | 26 +++++++++++++------ test/controller_test.rb | 15 +++++++++++ .../dummy/app/controllers/posts_controller.rb | 1 + 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/lib/sift/filtrator.rb b/lib/sift/filtrator.rb index 36cc6b0..a5feafd 100644 --- a/lib/sift/filtrator.rb +++ b/lib/sift/filtrator.rb @@ -17,7 +17,7 @@ def initialize(collection, params, _sort, filters = []) end def filter - active_filters.reduce(collection) do |col, filter| + ordered_active_filters.reduce(collection) do |col, filter| apply(col, filter) end end @@ -33,15 +33,17 @@ def filter_params end def active_sorts_hash - active_sorts_hash = {} - Array(sort).each do |s| - if s.starts_with?("-") - active_sorts_hash[s[1..-1].to_sym] = :desc - else - active_sorts_hash[s.to_sym] = :asc + @active_sorts_hash ||= begin + active_sorts_hash = {} + Array(sort).each do |s| + if s.starts_with?("-") + active_sorts_hash[s[1..-1].to_sym] = :desc + else + active_sorts_hash[s.to_sym] = :asc + end end + active_sorts_hash end - active_sorts_hash end def active_filters @@ -49,5 +51,13 @@ def active_filters filter_params[filter.param].present? || filter.default || filter.always_active? end end + + def ordered_active_filters + active_filters.sort_by { |filter| sorts_by_index.fetch(filter.param, Float::INFINITY) } + end + + def sorts_by_index + @sorts_by_index ||= active_sorts_hash.keys.each_with_index.to_h + end end end diff --git a/test/controller_test.rb b/test/controller_test.rb index ec3137f..da47833 100644 --- a/test/controller_test.rb +++ b/test/controller_test.rb @@ -183,6 +183,21 @@ class PostsControllerTest < ActionDispatch::IntegrationTest assert_equal [nil, 10, 1, nil], json.map(&:priority) end + test "it can do multiple sorts contrary to the order in which sorts are configured" do + Post.create!(title: "a", priority: 1) + Post.create!(title: "b", visible: true) + Post.create!(title: "f", priority: 10, visible: true) + Post.create!(title: "c", priority: 10, visible: false) + Post.create!(title: "d", priority: 10) + + get("/posts", params: { sort: "priority,-visible,title" }) + + json = JSON.parse(@response.body, object_class: OpenStruct) + assert_equal ["b", "a", "f", "c", "d"], json.map(&:title) + assert_equal [nil, 1, 10, 10, 10], json.map(&:priority) + assert_equal [true, nil, true, false, nil], json.map(&:visible) + end + test "it errors on unknown fields" do expected_json = { "errors" => { "sort" => ["is not included in the list"] } } diff --git a/test/dummy/app/controllers/posts_controller.rb b/test/dummy/app/controllers/posts_controller.rb index 0eb847d..072e3e5 100644 --- a/test/dummy/app/controllers/posts_controller.rb +++ b/test/dummy/app/controllers/posts_controller.rb @@ -43,6 +43,7 @@ class PostsController < ApplicationController before_action :render_filter_errors, unless: :filters_valid? + sort_on :visible, type: :int sort_on :title, type: :string sort_on :priority, type: :string sort_on :foobar, type: :string, internal_name: :title