From 1b124f48f4e6163b78fad755035973ae0e7c22f8 Mon Sep 17 00:00:00 2001 From: Alex Castillo Date: Tue, 8 Sep 2026 19:40:18 -0400 Subject: [PATCH] Sort `nil` values last in `Relation#order` instead of raising MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `order` did `sort_by { it.public_send(attribute) }`, so a single resource whose ordering attribute is `nil` — a common case for optional frontmatter like a date or a position — raised `ArgumentError: comparison of NilClass with ... failed` and took the whole query down. `nil` values are now partitioned out of the sort and appended last, in their original relative order, for both directions. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01GtYgwYNfJ3wHrw9xrooVoB --- lib/perron/relation.rb | 11 ++++++++--- test/perron/relation_test.rb | 9 +++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/perron/relation.rb b/lib/perron/relation.rb index de2345d..849f297 100644 --- a/lib/perron/relation.rb +++ b/lib/perron/relation.rb @@ -34,9 +34,14 @@ def order(attribute, direction = :asc) attribute, direction = attribute.first end - sorted = sort_by { it.public_send(attribute) } - - Relation.new((direction == :desc) ? sorted.reverse : sorted, @model_class) + # Keep `nil` values out of the comparison (it raises `ArgumentError: + # comparison of NilClass with ... failed`) and place them last, in their + # original relative order, regardless of direction. + present, missing = partition { |resource| !resource.public_send(attribute).nil? } + present = present.sort_by { it.public_send(attribute) } + present = present.reverse if direction == :desc + + Relation.new(present + missing, @model_class) end def pluck(*attributes) diff --git a/test/perron/relation_test.rb b/test/perron/relation_test.rb index 96e07a0..135e6de 100644 --- a/test/perron/relation_test.rb +++ b/test/perron/relation_test.rb @@ -124,4 +124,13 @@ class Perron::RelationTest < ActiveSupport::TestCase assert_instance_of Perron::Relation, result assert_equal 0, result.size end + + test "#order sorts nil values last instead of raising" do + record = Struct.new(:id, :position) + relation = Perron::Relation.new([record.new(1, 30), record.new(2, nil), record.new(3, 10), record.new(4, nil)]) + + assert_equal [3, 1, 2, 4], relation.order(:position).map(&:id) + assert_equal [1, 3, 2, 4], relation.order(:position, :desc).map(&:id) + assert_instance_of Perron::Relation, relation.order(:position) + end end