activerecord-multirange 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +44 -10
- data/CHANGELOG.md +11 -1
- data/Gemfile.lock +4 -1
- data/README.md +215 -12
- data/lib/activerecord-multirange/adapter.rb +21 -16
- data/lib/activerecord-multirange/oid/multi_range.rb +12 -4
- data/lib/activerecord-multirange/schema_statements.rb +1 -8
- data/lib/activerecord-multirange/type_map.rb +16 -4
- data/lib/activerecord-multirange/version.rb +1 -1
- data/lib/activerecord-multirange.rb +52 -11
- metadata +3 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b09cdb0717d19e40572d66ecb2e7774494057658fb3409fefdf04a67db06345
|
4
|
+
data.tar.gz: aa643ce5bf82da7e69b042478ee884668fd1970da0861b91e43e7a5c2e4ae3e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31209bbe807b481f93275650fae69c2c23fa76518fc987890daec2c619f595571467cb55fdd8cc526e8bc4e007af68eb9f239e68d810854dc3e6977c4631d248
|
7
|
+
data.tar.gz: 87c60c9246d43e7b148c02798171df9747b7aa2fb5c21b40969ed77b8461064440d4f9f73840f2b5d8aa11cd47d33017d48fbfb9a9c9ad28da7ce952e713fa26
|
data/.rubocop.yml
CHANGED
@@ -1,22 +1,56 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion: 2
|
2
|
+
TargetRubyVersion: 3.1.2
|
3
|
+
EnabledByDefault: true
|
4
|
+
Exclude:
|
5
|
+
- 'db/**/*'
|
6
|
+
- 'config/**/*'
|
7
|
+
- 'script/**/*'
|
8
|
+
- 'bin/{rails,rake}'
|
3
9
|
|
4
|
-
|
10
|
+
require:
|
11
|
+
- rubocop-rails
|
12
|
+
|
13
|
+
inherit_from:
|
14
|
+
- node_modules/@prettier/plugin-ruby/rubocop.yml
|
15
|
+
|
16
|
+
Style:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Metrics:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Lint:
|
5
23
|
Enabled: true
|
6
|
-
EnforcedStyle: double_quotes
|
7
24
|
|
8
|
-
|
25
|
+
Lint/ConstantResolution:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
Lint/AssignmentInCondition:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
Lint/NumberConversion:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
Rails:
|
9
35
|
Enabled: true
|
10
|
-
EnforcedStyle: double_quotes
|
11
36
|
|
12
|
-
|
37
|
+
Rails/SkipsModelValidations:
|
13
38
|
Enabled: false
|
14
39
|
|
15
|
-
|
40
|
+
Rails/DefaultScope:
|
16
41
|
Enabled: false
|
17
42
|
|
18
|
-
|
43
|
+
Rails/HasManyOrHasOneDependent:
|
19
44
|
Enabled: false
|
20
45
|
|
21
|
-
|
22
|
-
|
46
|
+
Rails/InverseOf:
|
47
|
+
Enabled: false
|
48
|
+
|
49
|
+
Rails/Date:
|
50
|
+
Enabled: false
|
51
|
+
|
52
|
+
Rails/TimeZone:
|
53
|
+
Enabled: false
|
54
|
+
|
55
|
+
Rails/RequestReferer:
|
56
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
-
## [
|
3
|
+
## [1.1.1] - 2025-06-11
|
4
|
+
|
5
|
+
- Added automatic registration of multirange types in `NATIVE_DATABASE_TYPES` for Rails 8 compatibility
|
6
|
+
- Fixed `rails db:schema:dump` support without requiring manual type registration
|
7
|
+
- Centralized multirange type definitions in `MULTIRANGE_TYPES` constant
|
8
|
+
|
9
|
+
## [1.1.0] - 2024-06-01
|
10
|
+
|
11
|
+
- Minor version bump with improvements and updates
|
12
|
+
|
13
|
+
## [1.0.0] - 2023-05-29
|
4
14
|
|
5
15
|
- Initial release
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
activerecord-multirange (1.
|
4
|
+
activerecord-multirange (1.1.1)
|
5
5
|
pg (>= 1)
|
6
6
|
rails (>= 6)
|
7
7
|
|
@@ -116,6 +116,8 @@ GEM
|
|
116
116
|
net-smtp (0.3.3)
|
117
117
|
net-protocol
|
118
118
|
nio4r (2.5.9)
|
119
|
+
nokogiri (1.15.4-arm64-darwin)
|
120
|
+
racc (~> 1.4)
|
119
121
|
nokogiri (1.15.4-x86_64-darwin)
|
120
122
|
racc (~> 1.4)
|
121
123
|
nokogiri (1.15.4-x86_64-linux)
|
@@ -200,6 +202,7 @@ GEM
|
|
200
202
|
zeitwerk (2.6.11)
|
201
203
|
|
202
204
|
PLATFORMS
|
205
|
+
arm64-darwin-23
|
203
206
|
x86_64-darwin-22
|
204
207
|
x86_64-linux
|
205
208
|
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# Activercord Multirange
|
2
|
-
|
1
|
+
# Activercord Multirange
|
2
|
+
|
3
3
|
This gem adds full suppport of [Postgress Multiranges](https://www.postgresql.org/docs/14/rangetypes.html#RANGETYPES-BUILTIN) types.
|
4
4
|
|
5
5
|
[](https://badge.fury.io/rb/activerecord-multirange)
|
@@ -12,30 +12,233 @@ Install the gem and add to the application's Gemfile by executing:
|
|
12
12
|
|
13
13
|
If bundler is not being used to manage dependencies, install the gem by executing:
|
14
14
|
|
15
|
-
$ gem install activerecord-multirange
|
15
|
+
$ gem install activerecord-multirange
|
16
16
|
|
17
17
|
## Usage
|
18
18
|
|
19
19
|
### Initialize it
|
20
20
|
|
21
|
-
```
|
22
|
-
# config/initializers/activerecord_multirange
|
21
|
+
```ruby
|
22
|
+
# config/initializers/activerecord_multirange.rb
|
23
23
|
|
24
24
|
Activerecord::Multirange.add_multirange_column_type
|
25
25
|
```
|
26
26
|
|
27
27
|
### Migrations
|
28
28
|
|
29
|
-
All multirange types are available
|
29
|
+
All multirange types are available in migrations. Here are examples for different multirange types:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
class CreateSchedules < ActiveRecord::Migration[7.0]
|
33
|
+
def change
|
34
|
+
create_table :schedules do |t|
|
35
|
+
t.string :name
|
36
|
+
t.tsmultirange :available_times # Timestamp multirange
|
37
|
+
t.tstzmultirange :available_times_tz # Timestamp with timezone multirange
|
38
|
+
t.datemultirange :available_dates # Date multirange
|
39
|
+
t.nummultirange :price_ranges # Numeric multirange
|
40
|
+
t.int8multirange :id_ranges # Bigint multirange
|
41
|
+
t.int4multirange :quantity_ranges # Integer multirange
|
42
|
+
|
43
|
+
t.timestamps
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
class CreateBookings < ActiveRecord::Migration[7.0]
|
51
|
+
def change
|
52
|
+
create_table :bookings do |t|
|
53
|
+
t.string :title
|
54
|
+
t.tstzmultirange :booked_periods
|
55
|
+
t.datemultirange :blackout_dates
|
56
|
+
|
57
|
+
t.timestamps
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
### Models
|
64
|
+
|
65
|
+
Define your models to work with multirange columns:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
class Schedule < ApplicationRecord
|
69
|
+
# Multirange columns are automatically handled by ActiveRecord
|
70
|
+
# No special configuration needed
|
71
|
+
end
|
72
|
+
|
73
|
+
class Booking < ApplicationRecord
|
74
|
+
validates :title, presence: true
|
75
|
+
|
76
|
+
scope :overlapping_with, ->(time_range) { where('booked_periods && ?', time_range) }
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
### Creating and Working with Multirange Data
|
81
|
+
|
82
|
+
#### Creating Records with Multirange Values
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
# Using timestamp multiranges for scheduling
|
86
|
+
schedule =
|
87
|
+
Schedule.create!(
|
88
|
+
name: 'Conference Room A',
|
89
|
+
available_times: [
|
90
|
+
Time.parse('2024-01-15 09:00')..Time.parse('2024-01-15 12:00'),
|
91
|
+
Time.parse('2024-01-15 14:00')..Time.parse('2024-01-15 17:00')
|
92
|
+
]
|
93
|
+
)
|
94
|
+
|
95
|
+
# Using date multiranges for availability periods
|
96
|
+
booking =
|
97
|
+
Booking.create!(
|
98
|
+
title: 'Annual Maintenance',
|
99
|
+
booked_periods: [
|
100
|
+
Time.zone.parse('2024-03-01 00:00')..Time.zone.parse('2024-03-03 23:59'),
|
101
|
+
Time.zone.parse('2024-06-15 00:00')..Time.zone.parse('2024-06-17 23:59')
|
102
|
+
],
|
103
|
+
blackout_dates: [
|
104
|
+
Date.parse('2024-12-24')..Date.parse('2024-12-26'),
|
105
|
+
Date.parse('2024-12-31')..Date.parse('2024-01-01')
|
106
|
+
]
|
107
|
+
)
|
108
|
+
|
109
|
+
# Using numeric multiranges for pricing tiers
|
110
|
+
product = Product.create!(name: 'Premium Service', price_ranges: [10.0..50.0, 100.0..500.0, 1000.0..5000.0])
|
111
|
+
```
|
112
|
+
|
113
|
+
#### Reading and Manipulating Multirange Data
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
schedule = Schedule.find(1)
|
117
|
+
|
118
|
+
# Access multirange values
|
119
|
+
puts schedule.available_times
|
120
|
+
# => [2024-01-15 09:00:00 UTC..2024-01-15 12:00:00 UTC, 2024-01-15 14:00:00 UTC..2024-01-15 17:00:00 UTC]
|
121
|
+
|
122
|
+
# Check if multirange contains a specific value
|
123
|
+
morning_slot = Time.parse('2024-01-15 10:30')
|
124
|
+
puts schedule.available_times.any? { |range| range.cover?(morning_slot) }
|
125
|
+
# => true
|
126
|
+
|
127
|
+
# Add new time ranges
|
128
|
+
schedule.available_times += [Time.parse('2024-01-15 18:00')..Time.parse('2024-01-15 20:00')]
|
129
|
+
schedule.save!
|
30
130
|
|
131
|
+
# Working with individual ranges
|
132
|
+
schedule.available_times.each { |time_range| puts "Available from #{time_range.begin} to #{time_range.end}" }
|
133
|
+
```
|
134
|
+
|
135
|
+
### Querying Multirange Columns
|
136
|
+
|
137
|
+
#### Overlap Queries
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
# Find schedules that overlap with a specific time range
|
141
|
+
search_range = Time.parse('2024-01-15 10:00')..Time.parse('2024-01-15 11:00')
|
142
|
+
overlapping_schedules = Schedule.where('available_times && ?', search_range)
|
143
|
+
|
144
|
+
# Find bookings that don't overlap with a date range
|
145
|
+
available_dates = Date.parse('2024-03-01')..Date.parse('2024-03-05')
|
146
|
+
non_conflicting_bookings = Booking.where('NOT (blackout_dates && ?)', available_dates)
|
147
|
+
```
|
148
|
+
|
149
|
+
#### Contains Queries
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
# Find schedules that contain a specific timestamp
|
153
|
+
specific_time = Time.parse('2024-01-15 10:30')
|
154
|
+
containing_schedules = Schedule.where('available_times @> ?', specific_time)
|
155
|
+
|
156
|
+
# Find products within a specific price range
|
157
|
+
price_point = 75.0
|
158
|
+
products_in_range = Product.where('price_ranges @> ?', price_point)
|
159
|
+
```
|
160
|
+
|
161
|
+
#### Other Useful Queries
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
# Check if multirange is contained within another range
|
165
|
+
broad_range = Time.parse('2024-01-15 08:00')..Time.parse('2024-01-15 18:00')
|
166
|
+
fully_contained = Schedule.where('available_times <@ ?', broad_range)
|
167
|
+
|
168
|
+
# Find records where multiranges are strictly left of a range
|
169
|
+
cutoff_time = Time.parse('2024-01-15 12:00')..Time.parse('2024-01-15 24:00')
|
170
|
+
morning_only = Schedule.where('available_times << ?', cutoff_time)
|
31
171
|
|
172
|
+
# Find records where multiranges are strictly right of a range
|
173
|
+
start_time = Time.parse('2024-01-15 00:00')..Time.parse('2024-01-15 12:00')
|
174
|
+
afternoon_only = Schedule.where('available_times >> ?', start_time)
|
32
175
|
```
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
176
|
+
|
177
|
+
### Practical Examples
|
178
|
+
|
179
|
+
#### Availability Scheduling System
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
class Room < ApplicationRecord
|
183
|
+
def available_during?(time_range)
|
184
|
+
available_times.any? { |range| range.cover?(time_range) }
|
185
|
+
end
|
186
|
+
|
187
|
+
def book_time!(time_range)
|
188
|
+
# Remove the booked time from available times
|
189
|
+
new_availability = []
|
190
|
+
available_times.each do |available_range|
|
191
|
+
if available_range.overlaps?(time_range)
|
192
|
+
# Split the range if needed
|
193
|
+
if available_range.begin < time_range.begin
|
194
|
+
new_availability << (available_range.begin...time_range.begin)
|
195
|
+
end
|
196
|
+
if time_range.end < available_range.end
|
197
|
+
new_availability << (time_range.end...available_range.end)
|
198
|
+
end
|
199
|
+
else
|
200
|
+
new_availability << available_range
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
update!(available_times: new_availability)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Usage
|
209
|
+
room = Room.find(1)
|
210
|
+
booking_time = Time.parse('2024-01-15 10:00')..Time.parse('2024-01-15 11:00')
|
211
|
+
|
212
|
+
if room.available_during?(booking_time)
|
213
|
+
room.book_time!(booking_time)
|
214
|
+
puts 'Room booked successfully!'
|
215
|
+
else
|
216
|
+
puts 'Room not available during requested time'
|
217
|
+
end
|
218
|
+
```
|
219
|
+
|
220
|
+
#### Price Range Management
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
class Product < ApplicationRecord
|
224
|
+
def price_tier_for(quantity)
|
225
|
+
price_ranges.each_with_index do |range, index|
|
226
|
+
if range.cover?(quantity)
|
227
|
+
return index + 1
|
228
|
+
end
|
229
|
+
end
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
|
233
|
+
def applies_to_quantity?(quantity)
|
234
|
+
quantity_ranges.any? { |range| range.cover?(quantity) }
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Usage
|
239
|
+
product = Product.find(1)
|
240
|
+
puts "Quantity 25 is in tier: #{product.price_tier_for(25)}"
|
241
|
+
puts "Product applies to quantity 150: #{product.applies_to_quantity?(150)}"
|
39
242
|
```
|
40
243
|
|
41
244
|
## Development
|
@@ -8,28 +8,33 @@ module Activerecord
|
|
8
8
|
load_multirange_types
|
9
9
|
end
|
10
10
|
|
11
|
-
def native_database_types
|
12
|
-
super.merge(
|
13
|
-
datemultirange: { name: "datemultirange" },
|
14
|
-
nummultirange: { name: "nummultirange" },
|
15
|
-
tsmultirange: { name: "tsmultirange" },
|
16
|
-
tstzmultirange: { name: "tstzmultirange" },
|
17
|
-
int4multirange: { name: "int4multirange" },
|
18
|
-
int8multirange: { name: "int8multirange" }
|
19
|
-
})
|
11
|
+
def self.native_database_types
|
12
|
+
super.merge(Activerecord::Multirange::MULTIRANGE_TYPES)
|
20
13
|
end
|
21
14
|
|
22
15
|
def load_multirange_types
|
23
|
-
initializer =
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
16
|
+
initializer =
|
17
|
+
::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::TypeMapInitializer
|
18
|
+
.new(type_map)
|
19
|
+
|
20
|
+
# Query for multirange types and their corresponding base types (not range types)
|
21
|
+
# We need to get the range's subtype (e.g., date) not the range type itself
|
22
|
+
query = <<-QUERY.squish
|
23
|
+
SELECT m.oid, m.typname, m.typelem, m.typdelim, m.typinput,
|
24
|
+
pr.rngsubtype, m.typtype, m.typbasetype
|
25
|
+
FROM pg_type m
|
26
|
+
JOIN pg_type r ON REPLACE(m.typname, 'multirange', 'range') = r.typname
|
27
|
+
JOIN pg_range pr ON r.oid = pr.rngtypid
|
28
|
+
WHERE m.typtype = 'm';
|
28
29
|
QUERY
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
# Use exec_query for all Rails versions since execute_and_clear is private
|
32
|
+
result = exec_query(query, 'SCHEMA', [])
|
33
|
+
# Convert rows to hash format with column names as keys
|
34
|
+
records = result.rows.map do |row|
|
35
|
+
result.columns.zip(row).to_h
|
32
36
|
end
|
37
|
+
initializer.register_multirange_type(records)
|
33
38
|
end
|
34
39
|
end
|
35
40
|
end
|
@@ -78,6 +78,8 @@ module Activerecord
|
|
78
78
|
# * https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-IO
|
79
79
|
# * https://www.postgresql.org/docs/current/rowtypes.html#ROWTYPES-IO-SYNTAX
|
80
80
|
def unquote(value)
|
81
|
+
return value if value.nil?
|
82
|
+
|
81
83
|
if value.start_with?('"') && value.end_with?('"')
|
82
84
|
unquoted_value = value[1..-2]
|
83
85
|
unquoted_value.gsub!('""', '"')
|
@@ -89,15 +91,21 @@ module Activerecord
|
|
89
91
|
end
|
90
92
|
|
91
93
|
def parse_lower(value)
|
92
|
-
return infinity_value(value, negative: true) if ["", "-infinity"].include?(value)
|
94
|
+
return infinity_value(value, negative: true) if value.nil? || ["", "-infinity"].include?(value)
|
93
95
|
|
94
|
-
|
96
|
+
unquoted = unquote(value)
|
97
|
+
return nil if unquoted.nil?
|
98
|
+
|
99
|
+
@subtype.deserialize(unquoted)
|
95
100
|
end
|
96
101
|
|
97
102
|
def parse_upper(value)
|
98
|
-
return infinity_value(value) if ["", "infinity"].include?(value)
|
103
|
+
return infinity_value(value) if value.nil? || ["", "infinity"].include?(value)
|
99
104
|
|
100
|
-
|
105
|
+
unquoted = unquote(value)
|
106
|
+
return nil if unquoted.nil?
|
107
|
+
|
108
|
+
@subtype.deserialize(unquoted)
|
101
109
|
end
|
102
110
|
|
103
111
|
def extract_range_data(value)
|
@@ -4,14 +4,7 @@ module Activerecord
|
|
4
4
|
module Multirange
|
5
5
|
module SchemaStatements
|
6
6
|
def native_database_types
|
7
|
-
super.merge(
|
8
|
-
tsmultirange: { name: "tsmultirange" },
|
9
|
-
datemultirange: { name: "datemultirange" },
|
10
|
-
tstzmultirange: { name: "tstzmultirange" },
|
11
|
-
nummultirange: { name: "nummultirange" },
|
12
|
-
int8multirange: { name: "int8multirange" },
|
13
|
-
int4multirange: { name: "int4multirange" }
|
14
|
-
})
|
7
|
+
super.merge(Activerecord::Multirange::MULTIRANGE_TYPES)
|
15
8
|
end
|
16
9
|
end
|
17
10
|
end
|
@@ -1,15 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'activerecord-multirange/oid/multi_range'
|
4
4
|
|
5
5
|
module Activerecord
|
6
6
|
module Multirange
|
7
7
|
module TypeMap
|
8
8
|
def register_multirange_type(records)
|
9
9
|
records.each do |row|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
multirange_oid = row['oid']
|
11
|
+
range_oid = row['rngsubtype']
|
12
|
+
type_name = row['typname']
|
13
|
+
|
14
|
+
# Get the range subtype from the type map
|
15
|
+
range_type = @store.lookup(range_oid)
|
16
|
+
next unless range_type
|
17
|
+
|
18
|
+
# Create and register the multirange type
|
19
|
+
multirange_type = Activerecord::Multirange::OID::MultiRange.new(
|
20
|
+
range_type,
|
21
|
+
type_name.to_sym
|
22
|
+
)
|
23
|
+
|
24
|
+
register(multirange_oid, multirange_type)
|
13
25
|
end
|
14
26
|
end
|
15
27
|
end
|
@@ -1,24 +1,65 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
3
|
+
require 'activerecord-multirange/version'
|
4
|
+
require 'activerecord-multirange/adapter'
|
5
|
+
require 'activerecord-multirange/quoting'
|
6
|
+
require 'activerecord-multirange/schema_statements'
|
7
|
+
require 'activerecord-multirange/table_definition'
|
8
|
+
require 'activerecord-multirange/type_map'
|
9
|
+
require 'active_record'
|
10
10
|
|
11
11
|
module Activerecord
|
12
12
|
module Multirange
|
13
|
-
class Error < StandardError
|
13
|
+
class Error < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
# Multirange types that need to be registered
|
17
|
+
MULTIRANGE_TYPES = {
|
18
|
+
tsmultirange: { name: "tsmultirange" },
|
19
|
+
datemultirange: { name: "datemultirange" },
|
20
|
+
tstzmultirange: { name: "tstzmultirange" },
|
21
|
+
nummultirange: { name: "nummultirange" },
|
22
|
+
int8multirange: { name: "int8multirange" },
|
23
|
+
int4multirange: { name: "int4multirange" }
|
24
|
+
}.freeze
|
14
25
|
|
15
26
|
def self.add_multirange_column_type
|
16
27
|
ActiveSupport.on_load(:active_record) do
|
28
|
+
# Register multirange types in NATIVE_DATABASE_TYPES for Rails 8 compatibility
|
29
|
+
Activerecord::Multirange.register_native_database_types
|
30
|
+
|
17
31
|
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(Adapter)
|
18
|
-
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::TypeMapInitializer
|
32
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::TypeMapInitializer
|
33
|
+
.prepend(TypeMap)
|
19
34
|
ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting.prepend(Quoting)
|
20
|
-
ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements.prepend(
|
21
|
-
|
35
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements.prepend(
|
36
|
+
SchemaStatements
|
37
|
+
)
|
38
|
+
ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition.prepend(
|
39
|
+
TableDefinition
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.register_native_database_types
|
45
|
+
# Ensure the PostgreSQL adapter is loaded
|
46
|
+
return unless defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
47
|
+
|
48
|
+
adapter_class = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
49
|
+
|
50
|
+
# Check if NATIVE_DATABASE_TYPES is already defined and modifiable
|
51
|
+
if adapter_class.const_defined?(:NATIVE_DATABASE_TYPES)
|
52
|
+
current_types = adapter_class::NATIVE_DATABASE_TYPES
|
53
|
+
|
54
|
+
# Only modify if our types aren't already registered
|
55
|
+
unless current_types.key?(:tsmultirange)
|
56
|
+
# Create a new hash with existing types plus our multirange types
|
57
|
+
new_types = current_types.merge(MULTIRANGE_TYPES)
|
58
|
+
|
59
|
+
# Replace the constant with the updated hash
|
60
|
+
adapter_class.send(:remove_const, :NATIVE_DATABASE_TYPES)
|
61
|
+
adapter_class.const_set(:NATIVE_DATABASE_TYPES, new_types.freeze)
|
62
|
+
end
|
22
63
|
end
|
23
64
|
end
|
24
65
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-multirange
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gustavo Warmling Teixeira
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-06-11 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: pg
|
@@ -139,7 +138,6 @@ licenses:
|
|
139
138
|
metadata:
|
140
139
|
homepage_uri: https://github.com/gustavowt/activerecord-multirange
|
141
140
|
source_code_uri: https://github.com/gustavowt/activerecord-multirange
|
142
|
-
post_install_message:
|
143
141
|
rdoc_options: []
|
144
142
|
require_paths:
|
145
143
|
- lib
|
@@ -154,8 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
152
|
- !ruby/object:Gem::Version
|
155
153
|
version: '0'
|
156
154
|
requirements: []
|
157
|
-
rubygems_version: 3.
|
158
|
-
signing_key:
|
155
|
+
rubygems_version: 3.6.6
|
159
156
|
specification_version: 4
|
160
157
|
summary: PostgreSQL multiranges support
|
161
158
|
test_files: []
|