Skip to content

Conversation

@Danieth
Copy link

@Danieth Danieth commented Mar 31, 2023

  1. Adding range_combine_end method

PostgreSQL 14 handles overlaps slightly differently than the current implementation.

PG Multirange Column Ruby Class Overlap between inclusive end Ranges?
int4multirange Integer end + 1 >= begin
int8multirange Integer end + 1 >= begin
nummultirange Float end >= begin
datemultirange Date end + '1 day' >= begin
tsmultirange Time end >= begin
tstzmultirange ActiveSupport::TimeWithZone end >= begin

The existing logic to handle overlaps works perfectly for Integers, Floats & Dates. This logic, however, does not work for Time or ActiveSupport::TimeWithZone.

The current logic (+ 1) adds 1 day to Time, ActiveSupport::TimeWithZone - when merge overlaps is called, this can lead to ranges being merged that wouldn't be merged in PostgreSQL.

PostgreSQL truncates timestamps to microseconds and then merges ranges that overlap - I duplicated this logic by adding nanoseconds to handle rounding the end temporarily and then checking if the end is greater or equal to the beginning of the next range.

PostgreSQL is the only Database to have Multiranges - so I believe it is ok for this library duplicate the logic present there.

  1. Adding sort_ranges parameter to initializer

When working with an already sorted multirange (like when pulling PostgreSQL Multiranges directly from the database), it's going to be a lot faster to have the MultiRange skip sorting the ranges.

I believe this parameter could also be used internally to make the data structure faster in some cases (When creating new ranges during difference & intersection for example).

closes #27

@khiav223577
Copy link
Owner

Hi Danieth,

Thank you for submitting your PR. I really appreciate your contribution and I'm looking forward to taking a closer look later. However, before that, could you please fix the indentation issue? Once that's done, I'll be able to review it more effectively. Thank you again for your hard work!

@Danieth
Copy link
Author

Danieth commented Mar 31, 2023

Yes, it's fixed now!

@Danieth
Copy link
Author

Danieth commented Apr 6, 2023

@khiav223577 bumping this for review.

I've realized, it may make sense to limit the scope of this solution to be less Postgres specific - an alternative solution might look like:

    case range_end
    when Float
      increase_float ? range_end.next_float : range_end
    when Time # ActiveSupport::TimeWithZone
      range_end
    else
      range_end + 1
    end

It would be a lot simpler. Just a thought.

Danieth added a commit to Danieth/pg_multirange that referenced this pull request Apr 7, 2023
* My fork adds support for Time & ActiveSupport::TimeWithZone. Without direct
support for these fields, the MultiRange library is very limited.

* My fork also adds support for skipping sorting, which, should lead to a
tremendous speedup when reading the already sorted ranges from the database.

PR on MultiRange gem: khiav223577/multi_range#28
Comment on lines +129 to +132
require 'active_support/time_with_zone'
require 'active_support/time'
Time.zone = 'Eastern Time (US & Canada)'

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test case fails at Line 131. It may need to add require "active_support/isolated_execution_state" here?

The error message is:

ContainOverlapTest#test_active_support_time_with_timezone_overlaps:
NameError: uninitialized constant ActiveSupport::IsolatedExecutionState
    /home/runner/work/multi_range/multi_range/vendor/bundle/ruby/2.7.0/gems/activesupport-7.0.4.3/lib/active_support/core_ext/time/zones.rb:42:in `zone='
    /home/runner/work/multi_range/multi_range/test/contain_overlap_test.rb:131:in `test_active_support_time_with_timezone_overlaps'

@is_float = @ranges.any?{|range| range.begin.is_a?(Float) || range.end.is_a?(Float) }
@ranges = ranges.map{ |s| s.is_a?(Numeric) ? s..s : s }
@ranges = @ranges.sort_by(&:begin) if sort_ranges
@ranges = @ranges.freeze
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR: We don't have to reassign the value here.

Suggested change
@ranges = @ranges.freeze
@ranges.freeze

@khiav223577
Copy link
Owner

Others LGTM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Postgres Multirange behaviors for types

2 participants