Skip to content

IComparable<TRange> in PostgreSQL's range order #39

Closed

Description

@CaffeinatedCoder

Implement IComparable<TRange> on the range unions, ordered the way PostgreSQL orders ranges (lower bound first, then upper; empty sorts first).

TypeKit can't generate comparison for a value object that wraps a range without it (spike finding 1 in CodoMetis.TypeKit/spikes/RangeValueObjects).

This isn't behaviour-neutral. Sorted collections treat CompareTo == 0 as a duplicate key, and generic code branches on IComparable. So:

  • CompareTo == 0 exactly when Equals is true
  • a total order, including the empty range and both infinities
  • a documented null policy
  • PostgreSQL's range order stays separate from RangeSet's internal lower-bound comparer

Done when a live test sorts every ordered shape pair with ORDER BY and agrees with CompareTo, in the same way ShapeMatrixParityTests checks the relations.

Activity

  1. added this to the 9.1.0 milestone on Oct 17, 2026
  2. removed this from the 9.1.0 milestone on Oct 17, 2026
  3. CaffeinatedCoder commented on Oct 17, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Moved off 9.1.0 into the backlog (#83), with no milestone.

    release/9.x has been cut, and 9.1.0 ships with the work that's already finished. Nothing has started on this issue, and it shouldn't hold up the tag. This is an addition, so the 10.0.0 epic (#58) doesn't take it either: that epic is kept to the silent and breaking fixes so they aren't held up behind new features.

    When someone picks it up, it goes under the epic of the release it will ship in and takes that milestone. A 9.x minor would need the change cherry-picked onto release/9.x.

  4. CaffeinatedCoder commented on Oct 17, 2026

    @CaffeinatedCoder
    OwnerAuthor

    From the PostgreSQL catalogue sweep (2026-10-17): the same btree operators exist for multiranges (multirange_lt, _le, _gt, _ge on anymultirange), so RangeSet<TRange, T> should carry IComparable<RangeSet<TRange, T>> in the same order (elementwise by PostgreSQL's range order; the empty set first). On the EF side, ORDER BY on a range or multirange column already translates through Npgsql's mapping; a.CompareTo(b) < 0 in a predicate does not and should become <. Verified live on 17.11: int4range(1,5) < int4range(2,3) is true, 'empty'::int4range < int4range(1,2) is true.

  5. added this to the 10.0.0 milestone on Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/range-setRangeSet and multirange algebraarea/rangesRange unions, variants and the shape enginesenhancementNew feature or requestpackage/coreAffects CodoMetis.ValueRangespackage/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQLpackage/nodatimeAffects CodoMetis.ValueRanges.NodaTime

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions